aboutsummaryrefslogtreecommitdiffhomepage
path: root/patches/server/0753-Do-not-copy-visible-chunks.patch
diff options
context:
space:
mode:
Diffstat (limited to 'patches/server/0753-Do-not-copy-visible-chunks.patch')
-rw-r--r--patches/server/0753-Do-not-copy-visible-chunks.patch227
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 -> {