diff options
Diffstat (limited to 'patches/server/0753-Do-not-copy-visible-chunks.patch')
-rw-r--r-- | patches/server/0753-Do-not-copy-visible-chunks.patch | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/patches/server/0753-Do-not-copy-visible-chunks.patch b/patches/server/0753-Do-not-copy-visible-chunks.patch new file mode 100644 index 0000000000..ba44aac258 --- /dev/null +++ b/patches/server/0753-Do-not-copy-visible-chunks.patch @@ -0,0 +1,227 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf <[email protected]> +Date: Sun, 21 Mar 2021 11:22:10 -0700 +Subject: [PATCH] Do not copy visible chunks + +For servers with a lot of chunk holders, copying for each +tickDistanceManager call can take up quite a bit in +the function. I saw approximately 1/3rd of the function +on the copy. + +diff --git a/src/main/java/com/destroystokyo/paper/PaperCommand.java b/src/main/java/com/destroystokyo/paper/PaperCommand.java +index 4d7575087947f3b199dd895cd9aa02a7d61768b1..315bd2408e4a45993c9b2572e0ab5260a70522ec 100644 +--- a/src/main/java/com/destroystokyo/paper/PaperCommand.java ++++ b/src/main/java/com/destroystokyo/paper/PaperCommand.java +@@ -476,7 +476,7 @@ public class PaperCommand extends Command { + int ticking = 0; + int entityTicking = 0; + +- for (ChunkHolder chunk : world.getChunkSource().chunkMap.updatingChunkMap.values()) { ++ for (ChunkHolder chunk : world.getChunkSource().chunkMap.updatingChunks.getUpdatingMap().values()) { // Paper - change updating chunks map + if (chunk.getFullChunkUnchecked() == null) { + continue; + } +diff --git a/src/main/java/net/minecraft/server/MCUtil.java b/src/main/java/net/minecraft/server/MCUtil.java +index 35949e9c15eb998aa89842d34d0999cd973590e0..15f0c85ba9f4f9666e94e67dde43eb2e945ecfbf 100644 +--- a/src/main/java/net/minecraft/server/MCUtil.java ++++ b/src/main/java/net/minecraft/server/MCUtil.java +@@ -619,7 +619,7 @@ public final class MCUtil { + + ServerLevel world = ((org.bukkit.craftbukkit.CraftWorld)bukkitWorld).getHandle(); + ChunkMap chunkMap = world.getChunkSource().chunkMap; +- Long2ObjectLinkedOpenHashMap<ChunkHolder> visibleChunks = chunkMap.visibleChunkMap; ++ Long2ObjectLinkedOpenHashMap<ChunkHolder> visibleChunks = chunkMap.updatingChunks.getVisibleMap(); // Paper + DistanceManager chunkMapDistance = chunkMap.distanceManager; + List<ChunkHolder> allChunks = new ArrayList<>(visibleChunks.values()); + List<ServerPlayer> players = world.players; +diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java +index 09bb6e14864af68e9833e171a33aa981f51c8569..53399b80e60872224ba6b77f41626b2beef236d2 100644 +--- a/src/main/java/net/minecraft/server/level/ChunkMap.java ++++ b/src/main/java/net/minecraft/server/level/ChunkMap.java +@@ -120,9 +120,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + private static final int MIN_VIEW_DISTANCE = 3; + public static final int MAX_VIEW_DISTANCE = 33; + public static final int MAX_CHUNK_DISTANCE = 33 + ChunkStatus.maxDistance(); ++ // Paper start - Don't copy ++ public final com.destroystokyo.paper.util.map.QueuedChangesMapLong2Object<ChunkHolder> updatingChunks = new com.destroystokyo.paper.util.map.QueuedChangesMapLong2Object<>(); ++ // Paper end - Don't copy + public static final int FORCED_TICKET_LEVEL = 31; +- public final Long2ObjectLinkedOpenHashMap<ChunkHolder> updatingChunkMap = new Long2ObjectLinkedOpenHashMap(); +- public volatile Long2ObjectLinkedOpenHashMap<ChunkHolder> visibleChunkMap; ++ // Paper - Don't copy + private final Long2ObjectLinkedOpenHashMap<ChunkHolder> pendingUnloads; + public final LongSet entitiesInLevel; + public final ServerLevel level; +@@ -299,7 +301,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + boolean unloadingPlayerChunk = false; // Paper - do not allow ticket level changes while unloading chunks + public ChunkMap(ServerLevel world, LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, StructureManager structureManager, Executor executor, BlockableEventLoop<Runnable> mainThreadExecutor, LightChunkGetter chunkProvider, ChunkGenerator chunkGenerator, ChunkProgressListener worldGenerationProgressListener, ChunkStatusUpdateListener chunkStatusChangeListener, Supplier<DimensionDataStorage> persistentStateManagerFactory, int viewDistance, boolean dsync) { + super(session.getDimensionPath(world.dimension()).resolve("region"), dataFixer, dsync); +- this.visibleChunkMap = this.updatingChunkMap.clone(); ++ // Paper - don't copy + this.pendingUnloads = new Long2ObjectLinkedOpenHashMap(); + this.entitiesInLevel = new LongOpenHashSet(); + this.toDrop = new LongOpenHashSet(); +@@ -516,12 +518,17 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + + @Nullable + public ChunkHolder getUpdatingChunkIfPresent(long pos) { +- return (ChunkHolder) this.updatingChunkMap.get(pos); ++ return this.updatingChunks.getUpdating(pos); // Paper - Don't copy + } + + @Nullable + public ChunkHolder getVisibleChunkIfPresent(long pos) { +- return (ChunkHolder) this.visibleChunkMap.get(pos); ++ // Paper start - Don't copy ++ if (Thread.currentThread() == this.level.thread) { ++ return this.updatingChunks.getVisible(pos); ++ } ++ return this.updatingChunks.getVisibleAsync(pos); ++ // Paper end - Don't copy + } + + protected IntSupplier getChunkQueueLevel(long pos) { +@@ -683,7 +690,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + // Paper end + } + +- this.updatingChunkMap.put(pos, holder); ++ this.updatingChunks.queueUpdate(pos, holder); // Paper - Don't copy + this.modified = true; + } + +@@ -763,7 +770,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + + protected void saveAllChunks(boolean flush) { + if (flush) { +- List<ChunkHolder> list = (List) this.visibleChunkMap.values().stream().filter(ChunkHolder::wasAccessibleSinceLastSave).peek(ChunkHolder::refreshAccessibility).collect(Collectors.toList()); ++ List<ChunkHolder> list = (List) this.updatingChunks.getVisibleValuesCopy().stream().filter(ChunkHolder::wasAccessibleSinceLastSave).peek(ChunkHolder::refreshAccessibility).collect(Collectors.toList()); // Paper + MutableBoolean mutableboolean = new MutableBoolean(); + + do { +@@ -794,7 +801,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + //this.flushWorker(); // Paper - nuke IOWorker + this.level.asyncChunkTaskManager.flush(); // Paper - flush to preserve behavior compat with pre-async behaviour + } else { +- this.visibleChunkMap.values().forEach(this::saveChunkIfNeeded); ++ this.updatingChunks.getVisibleValuesCopy().forEach(this::saveChunkIfNeeded); // Paper + } + + } +@@ -828,7 +835,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + while (longiterator.hasNext()) { // Spigot + long j = longiterator.nextLong(); + longiterator.remove(); // Spigot +- ChunkHolder playerchunk = (ChunkHolder) this.updatingChunkMap.remove(j); ++ ChunkHolder playerchunk = this.updatingChunks.queueRemove(j); // Paper - Don't copy + + if (playerchunk != null) { + this.pendingUnloads.put(j, playerchunk); +@@ -854,7 +861,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + } + + int l = 0; +- ObjectIterator objectiterator = this.visibleChunkMap.values().iterator(); ++ Iterator objectiterator = this.updatingChunks.getVisibleValuesCopy().iterator(); // Paper + + while (false && l < 20 && shouldKeepTicking.getAsBoolean() && objectiterator.hasNext()) { // Paper - incremental chunk and player saving + if (this.saveChunkIfNeeded((ChunkHolder) objectiterator.next())) { +@@ -933,7 +940,12 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + if (!this.modified) { + return false; + } else { +- this.visibleChunkMap = this.updatingChunkMap.clone(); ++ // Paper start - Don't copy ++ synchronized (this.updatingChunks) { ++ this.updatingChunks.performUpdates(); ++ } ++ // Paper end - Don't copy ++ + this.modified = false; + return true; + } +@@ -1411,7 +1423,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + + this.viewDistance = j; + this.distanceManager.updatePlayerTickets(this.viewDistance + 1); +- ObjectIterator objectiterator = this.updatingChunkMap.values().iterator(); ++ Iterator objectiterator = this.updatingChunks.getVisibleValuesCopy().iterator(); // Paper + + while (objectiterator.hasNext()) { + ChunkHolder playerchunk = (ChunkHolder) objectiterator.next(); +@@ -1454,7 +1466,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + } + + public int size() { +- return this.visibleChunkMap.size(); ++ return this.updatingChunks.getVisibleMap().size(); // Paper - Don't copy + } + + public DistanceManager getDistanceManager() { +@@ -1462,13 +1474,13 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + } + + protected Iterable<ChunkHolder> getChunks() { +- return Iterables.unmodifiableIterable(this.visibleChunkMap.values()); ++ return Iterables.unmodifiableIterable(this.updatingChunks.getVisibleValuesCopy()); // Paper + } + + void dumpChunks(Writer writer) throws IOException { + CsvOutput csvwriter = CsvOutput.builder().addColumn("x").addColumn("z").addColumn("level").addColumn("in_memory").addColumn("status").addColumn("full_status").addColumn("accessible_ready").addColumn("ticking_ready").addColumn("entity_ticking_ready").addColumn("ticket").addColumn("spawning").addColumn("block_entity_count").addColumn("ticking_ticket").addColumn("ticking_level").addColumn("block_ticks").addColumn("fluid_ticks").build(writer); + TickingTracker tickingtracker = this.distanceManager.tickingTracker(); +- ObjectBidirectionalIterator objectbidirectionaliterator = this.visibleChunkMap.long2ObjectEntrySet().iterator(); ++ ObjectBidirectionalIterator objectbidirectionaliterator = this.updatingChunks.getVisibleMap().clone().long2ObjectEntrySet().fastIterator(); // Paper + + while (objectbidirectionaliterator.hasNext()) { + Entry<ChunkHolder> entry = (Entry) objectbidirectionaliterator.next(); +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +index f7d94cb32a178247bbc5f59e5bc31e79f9fcdc4d..ac41bc23d2f7e16bbacdc9b33fcf6c0d706fa023 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +@@ -151,7 +151,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + @Override + public int getTileEntityCount() { + // We don't use the full world tile entity list, so we must iterate chunks +- Long2ObjectLinkedOpenHashMap<ChunkHolder> chunks = world.getChunkSource().chunkMap.visibleChunkMap; ++ Long2ObjectLinkedOpenHashMap<ChunkHolder> chunks = world.getChunkSource().chunkMap.updatingChunks.getVisibleMap(); // Paper - change updating chunks map + int size = 0; + for (ChunkHolder playerchunk : chunks.values()) { + net.minecraft.world.level.chunk.LevelChunk chunk = playerchunk.getTickingChunk(); +@@ -172,7 +172,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + public int getChunkCount() { + int ret = 0; + +- for (ChunkHolder chunkHolder : world.getChunkSource().chunkMap.visibleChunkMap.values()) { ++ for (ChunkHolder chunkHolder : world.getChunkSource().chunkMap.updatingChunks.getVisibleMap().values()) { // Paper - change updating chunks map + if (chunkHolder.getTickingChunk() != null) { + ++ret; + } +@@ -346,7 +346,18 @@ public class CraftWorld extends CraftRegionAccessor implements World { + + @Override + public Chunk[] getLoadedChunks() { +- Long2ObjectLinkedOpenHashMap<ChunkHolder> chunks = this.world.getChunkSource().chunkMap.visibleChunkMap; ++ // Paper start ++ if (Thread.currentThread() != world.getLevel().thread) { ++ // Paper start - change updating chunks map ++ Long2ObjectLinkedOpenHashMap<ChunkHolder> chunks; ++ synchronized (world.getChunkSource().chunkMap.updatingChunks) { ++ chunks = world.getChunkSource().chunkMap.updatingChunks.getVisibleMap().clone(); ++ } ++ return chunks.values().stream().map(ChunkHolder::getFullChunk).filter(Objects::nonNull).map(net.minecraft.world.level.chunk.LevelChunk::getBukkitChunk).toArray(Chunk[]::new); ++ // Paper end - change updating chunks map ++ } ++ // Paper end ++ Long2ObjectLinkedOpenHashMap<ChunkHolder> chunks = world.getChunkSource().chunkMap.updatingChunks.getVisibleMap(); // Paper - change updating chunks map + return chunks.values().stream().map(ChunkHolder::getFullChunk).filter(Objects::nonNull).map(net.minecraft.world.level.chunk.LevelChunk::getBukkitChunk).toArray(Chunk[]::new); + } + +@@ -422,7 +433,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + + @Override + public boolean refreshChunk(int x, int z) { +- ChunkHolder playerChunk = this.world.getChunkSource().chunkMap.visibleChunkMap.get(ChunkPos.asLong(x, z)); ++ ChunkHolder playerChunk = this.world.getChunkSource().chunkMap.updatingChunks.getVisibleMap().get(ChunkPos.asLong(x, z)); + if (playerChunk == null) return false; + + playerChunk.getTickingChunkFuture().thenAccept(either -> { |