Use a fastutil map to store chunks, will be significantly slower when accessed from multiple threads but without generating any garbage, and better for single-threaded use.

This commit is contained in:
TheMode 2021-07-24 11:44:50 +02:00
parent 3a93ab045a
commit e3520f4294

View File

@ -1,5 +1,7 @@
package net.minestom.server.instance; package net.minestom.server.instance;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import net.minestom.server.MinecraftServer; import net.minestom.server.MinecraftServer;
import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Point;
import net.minestom.server.coordinate.Vec; import net.minestom.server.coordinate.Vec;
@ -28,7 +30,6 @@ import org.jetbrains.annotations.Nullable;
import java.util.*; import java.util.*;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReadWriteLock;
@ -49,7 +50,8 @@ public class InstanceContainer extends Instance {
// the chunk generator used, can be null // the chunk generator used, can be null
private ChunkGenerator chunkGenerator; private ChunkGenerator chunkGenerator;
// (chunk index -> chunk) map, contains all the chunks in the instance // (chunk index -> chunk) map, contains all the chunks in the instance
private final Map<Long, Chunk> chunks = new ConcurrentHashMap<>(); // used as a monitor when access is required
private final Long2ObjectMap<Chunk> chunks = new Long2ObjectOpenHashMap<>();
// contains all the chunks to remove during the next instance tick, should be synchronized // contains all the chunks to remove during the next instance tick, should be synchronized
protected final Set<Chunk> scheduledChunksToRemove = new HashSet<>(); protected final Set<Chunk> scheduledChunksToRemove = new HashSet<>();
@ -251,7 +253,9 @@ public class InstanceContainer extends Instance {
@Override @Override
public Chunk getChunk(int chunkX, int chunkZ) { public Chunk getChunk(int chunkX, int chunkZ) {
final long index = ChunkUtils.getChunkIndex(chunkX, chunkZ); final long index = ChunkUtils.getChunkIndex(chunkX, chunkZ);
return chunks.get(index); synchronized (chunks) {
return chunks.get(index);
}
} }
@Override @Override
@ -261,8 +265,7 @@ public class InstanceContainer extends Instance {
@Override @Override
public @NotNull CompletableFuture<Void> saveChunksToStorage() { public @NotNull CompletableFuture<Void> saveChunksToStorage() {
Collection<Chunk> chunksCollection = chunks.values(); return chunkLoader.saveChunks(getChunks());
return chunkLoader.saveChunks(chunksCollection);
} }
protected @NotNull CompletableFuture<@NotNull Chunk> retrieveChunk(int chunkX, int chunkZ) { protected @NotNull CompletableFuture<@NotNull Chunk> retrieveChunk(int chunkX, int chunkZ) {
@ -407,17 +410,17 @@ public class InstanceContainer extends Instance {
InstanceContainer copiedInstance = new InstanceContainer(UUID.randomUUID(), getDimensionType()); InstanceContainer copiedInstance = new InstanceContainer(UUID.randomUUID(), getDimensionType());
copiedInstance.srcInstance = this; copiedInstance.srcInstance = this;
copiedInstance.lastBlockChangeTime = lastBlockChangeTime; copiedInstance.lastBlockChangeTime = lastBlockChangeTime;
synchronized (chunks) {
for (Chunk chunk : chunks.values()) {
final int chunkX = chunk.getChunkX();
final int chunkZ = chunk.getChunkZ();
for (Chunk chunk : chunks.values()) { final Chunk copiedChunk = chunk.copy(copiedInstance, chunkX, chunkZ);
final int chunkX = chunk.getChunkX();
final int chunkZ = chunk.getChunkZ();
final Chunk copiedChunk = chunk.copy(copiedInstance, chunkX, chunkZ); copiedInstance.cacheChunk(copiedChunk);
UPDATE_MANAGER.signalChunkLoad(copiedChunk);
copiedInstance.cacheChunk(copiedChunk); }
UPDATE_MANAGER.signalChunkLoad(copiedChunk);
} }
return copiedInstance; return copiedInstance;
} }
@ -462,7 +465,9 @@ public class InstanceContainer extends Instance {
*/ */
public void cacheChunk(@NotNull Chunk chunk) { public void cacheChunk(@NotNull Chunk chunk) {
final long index = ChunkUtils.getChunkIndex(chunk); final long index = ChunkUtils.getChunkIndex(chunk);
this.chunks.put(index, chunk); synchronized (chunks) {
this.chunks.put(index, chunk);
}
} }
@Override @Override
@ -482,7 +487,9 @@ public class InstanceContainer extends Instance {
*/ */
@Override @Override
public @NotNull Collection<@NotNull Chunk> getChunks() { public @NotNull Collection<@NotNull Chunk> getChunks() {
return Collections.unmodifiableCollection(chunks.values()); synchronized (chunks) {
return List.copyOf(chunks.values());
}
} }
/** /**
@ -565,8 +572,10 @@ public class InstanceContainer extends Instance {
}); });
// Clear cache // Clear cache
this.chunks.remove(index); synchronized (chunks) {
synchronized (entitiesLock){ this.chunks.remove(index);
}
synchronized (entitiesLock) {
this.chunkEntities.remove(index); this.chunkEntities.remove(index);
} }