diff --git a/patches/server/0003-Threaded-Regions.patch b/patches/server/0003-Threaded-Regions.patch index d56e12fab0..3232086225 100644 --- a/patches/server/0003-Threaded-Regions.patch +++ b/patches/server/0003-Threaded-Regions.patch @@ -1638,7 +1638,7 @@ index 15ee41452992714108efe53b708b5a4e1da7c1ff..5bef4f50082e56b89239cfd62dd74299 } diff --git a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkHolderManager.java b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkHolderManager.java -index 6bc7c6f16a1649fc9e24e7cf90fca401e5bd4875..30259130f23dc07288a7cbb33456b07bd11f0d56 100644 +index 6bc7c6f16a1649fc9e24e7cf90fca401e5bd4875..67bf841878eb8e3703782caeb16db4803d13f0d9 100644 --- a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkHolderManager.java +++ b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkHolderManager.java @@ -53,6 +53,14 @@ import java.util.concurrent.atomic.AtomicReference; @@ -1656,7 +1656,7 @@ index 6bc7c6f16a1649fc9e24e7cf90fca401e5bd4875..30259130f23dc07288a7cbb33456b07b public final class ChunkHolderManager { private static final Logger LOGGER = LogUtils.getClassLogger(); -@@ -112,27 +120,92 @@ public final class ChunkHolderManager { +@@ -112,27 +120,83 @@ public final class ChunkHolderManager { private final ChunkTaskScheduler taskScheduler; private long currentTick; @@ -1666,15 +1666,6 @@ index 6bc7c6f16a1649fc9e24e7cf90fca401e5bd4875..30259130f23dc07288a7cbb33456b07b - return 0; + // Folia start - region threading + public static final class HolderManagerRegionData { -+ /* -+ * This region data is a bit of a mess, because it is part global state and part region state. -+ * Typically for region state we do not need to worry about threading concerns because it is only -+ * accessed by the current region when ticking. But since this contains state ( -+ * tickets, and removeTickToChunkExpireTicketCount) that can be written to by any thread holding the -+ * ticket lock, the merge logic is complicated as merging only holds the region lock. So, Folia has modified -+ * the add and remove ticket functions to acquire the region lock if the current region does not own the target -+ * position. -+ */ + private final ArrayDeque pendingFullLoadUpdate = new ArrayDeque<>(); + private final ObjectRBTreeSet autoSaveQueue = new ObjectRBTreeSet<>((final NewChunkHolder c1, final NewChunkHolder c2) -> { + if (c1 == c2) { @@ -1716,9 +1707,7 @@ index 6bc7c6f16a1649fc9e24e7cf90fca401e5bd4875..30259130f23dc07288a7cbb33456b07b + for (final NewChunkHolder fullLoadUpdate : this.pendingFullLoadUpdate) { + final int regionCoordinateX = fullLoadUpdate.chunkX >> chunkToRegionShift; + final int regionCoordinateZ = fullLoadUpdate.chunkZ >> chunkToRegionShift; - -- if (saveTickCompare != 0) { -- return saveTickCompare; ++ + final HolderManagerRegionData data = regionToData.get(CoordinateUtils.getChunkKey(regionCoordinateX, regionCoordinateZ)); + if (data != null) { + data.pendingFullLoadUpdate.add(fullLoadUpdate); @@ -1728,7 +1717,9 @@ index 6bc7c6f16a1649fc9e24e7cf90fca401e5bd4875..30259130f23dc07288a7cbb33456b07b + for (final NewChunkHolder autoSave : this.autoSaveQueue) { + final int regionCoordinateX = autoSave.chunkX >> chunkToRegionShift; + final int regionCoordinateZ = autoSave.chunkZ >> chunkToRegionShift; -+ + +- if (saveTickCompare != 0) { +- return saveTickCompare; + final HolderManagerRegionData data = regionToData.get(CoordinateUtils.getChunkKey(regionCoordinateX, regionCoordinateZ)); + if (data != null) { + data.autoSaveQueue.add(autoSave); @@ -1762,7 +1753,7 @@ index 6bc7c6f16a1649fc9e24e7cf90fca401e5bd4875..30259130f23dc07288a7cbb33456b07b public ChunkHolderManager(final ServerLevel world, final ChunkTaskScheduler taskScheduler) { this.world = world; -@@ -167,8 +240,13 @@ public final class ChunkHolderManager { +@@ -167,8 +231,13 @@ public final class ChunkHolderManager { } public void close(final boolean save, final boolean halt) { @@ -1777,7 +1768,7 @@ index 6bc7c6f16a1649fc9e24e7cf90fca401e5bd4875..30259130f23dc07288a7cbb33456b07b LOGGER.info("Waiting 60s for chunk system to halt for world '" + this.world.getWorld().getName() + "'"); if (!this.taskScheduler.halt(true, TimeUnit.SECONDS.toNanos(60L))) { LOGGER.warn("Failed to halt world generation/loading tasks for world '" + this.world.getWorld().getName() + "'"); -@@ -178,9 +256,10 @@ public final class ChunkHolderManager { +@@ -178,9 +247,10 @@ public final class ChunkHolderManager { } if (save) { @@ -1789,7 +1780,7 @@ index 6bc7c6f16a1649fc9e24e7cf90fca401e5bd4875..30259130f23dc07288a7cbb33456b07b if (this.world.chunkDataControllerNew.hasTasks() || this.world.entityDataControllerNew.hasTasks() || this.world.poiDataControllerNew.hasTasks()) { RegionFileIOThread.flush(); } -@@ -201,27 +280,34 @@ public final class ChunkHolderManager { +@@ -201,27 +271,34 @@ public final class ChunkHolderManager { } catch (final IOException ex) { LOGGER.error("Failed to close poi regionfile cache for world '" + this.world.getWorld().getName() + "'", ex); } @@ -1831,7 +1822,7 @@ index 6bc7c6f16a1649fc9e24e7cf90fca401e5bd4875..30259130f23dc07288a7cbb33456b07b holder.lastAutoSave = currentTick; if (holder.save(false, false) != null) { -@@ -235,15 +321,38 @@ public final class ChunkHolderManager { +@@ -235,15 +312,38 @@ public final class ChunkHolderManager { for (final NewChunkHolder holder : reschedule) { if (holder.getChunkStatus().isOrAfter(FullChunkStatus.FULL)) { @@ -1873,7 +1864,7 @@ index 6bc7c6f16a1649fc9e24e7cf90fca401e5bd4875..30259130f23dc07288a7cbb33456b07b LOGGER.info("Saving all chunkholders for world '" + this.world.getWorld().getName() + "'"); } -@@ -251,7 +360,7 @@ public final class ChunkHolderManager { +@@ -251,7 +351,7 @@ public final class ChunkHolderManager { int saved = 0; @@ -1882,7 +1873,7 @@ index 6bc7c6f16a1649fc9e24e7cf90fca401e5bd4875..30259130f23dc07288a7cbb33456b07b long lastLog = start; boolean needsFlush = false; final int flushInterval = 50; -@@ -262,6 +371,12 @@ public final class ChunkHolderManager { +@@ -262,6 +362,12 @@ public final class ChunkHolderManager { for (int i = 0, len = holders.size(); i < len; ++i) { final NewChunkHolder holder = holders.get(i); @@ -1895,7 +1886,7 @@ index 6bc7c6f16a1649fc9e24e7cf90fca401e5bd4875..30259130f23dc07288a7cbb33456b07b try { final NewChunkHolder.SaveStat saveStat = holder.save(shutdown, false); if (saveStat != null) { -@@ -294,7 +409,7 @@ public final class ChunkHolderManager { +@@ -294,7 +400,7 @@ public final class ChunkHolderManager { } } } @@ -1904,7 +1895,7 @@ index 6bc7c6f16a1649fc9e24e7cf90fca401e5bd4875..30259130f23dc07288a7cbb33456b07b RegionFileIOThread.flush(); if (this.world.paperConfig().chunks.flushRegionsOnSave) { try { -@@ -707,6 +822,13 @@ public final class ChunkHolderManager { +@@ -707,6 +813,13 @@ public final class ChunkHolderManager { } public void tick() { @@ -1918,7 +1909,7 @@ index 6bc7c6f16a1649fc9e24e7cf90fca401e5bd4875..30259130f23dc07288a7cbb33456b07b final int sectionShift = this.world.getRegionChunkShift(); final Predicate> expireNow = (final Ticket ticket) -> { -@@ -716,12 +838,12 @@ public final class ChunkHolderManager { +@@ -716,12 +829,12 @@ public final class ChunkHolderManager { return --ticket.removeDelay <= 0L; }; @@ -1936,7 +1927,7 @@ index 6bc7c6f16a1649fc9e24e7cf90fca401e5bd4875..30259130f23dc07288a7cbb33456b07b continue; } -@@ -1024,19 +1146,51 @@ public final class ChunkHolderManager { +@@ -1024,19 +1137,51 @@ public final class ChunkHolderManager { if (changedFullStatus.isEmpty()) { return; } @@ -2000,7 +1991,7 @@ index 6bc7c6f16a1649fc9e24e7cf90fca401e5bd4875..30259130f23dc07288a7cbb33456b07b } } } -@@ -1044,8 +1198,9 @@ public final class ChunkHolderManager { +@@ -1044,8 +1189,9 @@ public final class ChunkHolderManager { private void removeChunkHolder(final NewChunkHolder holder) { holder.killed = true; holder.vanillaChunkHolder.onChunkRemove(); @@ -2011,7 +2002,7 @@ index 6bc7c6f16a1649fc9e24e7cf90fca401e5bd4875..30259130f23dc07288a7cbb33456b07b synchronized (this.chunkHolders) { this.chunkHolders.remove(CoordinateUtils.getChunkKey(holder.chunkX, holder.chunkZ)); } -@@ -1059,7 +1214,7 @@ public final class ChunkHolderManager { +@@ -1059,7 +1205,7 @@ public final class ChunkHolderManager { throw new IllegalStateException("Cannot unload chunks recursively"); } final int sectionShift = this.unloadQueue.coordinateShift; // sectionShift <= lock shift @@ -2020,7 +2011,7 @@ index 6bc7c6f16a1649fc9e24e7cf90fca401e5bd4875..30259130f23dc07288a7cbb33456b07b int unloadCountTentative = 0; for (final ChunkQueue.SectionToUnload sectionRef : unloadSectionsForRegion) { final ChunkQueue.UnloadSection section -@@ -1372,7 +1527,13 @@ public final class ChunkHolderManager { +@@ -1372,7 +1518,13 @@ public final class ChunkHolderManager { // only call on tick thread protected final boolean processPendingFullUpdate() { @@ -2035,7 +2026,7 @@ index 6bc7c6f16a1649fc9e24e7cf90fca401e5bd4875..30259130f23dc07288a7cbb33456b07b boolean ret = false; -@@ -1383,9 +1544,7 @@ public final class ChunkHolderManager { +@@ -1383,9 +1535,7 @@ public final class ChunkHolderManager { ret |= holder.handleFullStatusChange(changedFullStatus); if (!changedFullStatus.isEmpty()) { @@ -2046,7 +2037,7 @@ index 6bc7c6f16a1649fc9e24e7cf90fca401e5bd4875..30259130f23dc07288a7cbb33456b07b changedFullStatus.clear(); } } -@@ -1399,7 +1558,7 @@ public final class ChunkHolderManager { +@@ -1399,7 +1549,7 @@ public final class ChunkHolderManager { private JsonObject getDebugJsonNoLock() { final JsonObject ret = new JsonObject(); @@ -10075,7 +10066,7 @@ index 3e2d5dcd62775b6ed7c0ce0ba51a71b635b1d644..98fb69a9adeb6eaab199aec127692acb // CraftBukkit start - SPIGOT-5477, MC-142590 } else if (MinecraftServer.getServer().hasStopped() || (listener instanceof ServerCommonPacketListenerImpl && ((ServerCommonPacketListenerImpl) listener).processedDisconnect)) { diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 680919045310be7e50e2d503a23d265f2e9b2bc6..0330f180ef8fed3091b69758cea64d742a4dc0ac 100644 +index 680919045310be7e50e2d503a23d265f2e9b2bc6..11eb550cba3a8eee1deb2f00e5514863e255ea07 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -203,7 +203,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { return worldserver + " " + worldserver.dimension().location(); -@@ -1711,7 +1792,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0 && io.papermc.paper.threadedregions.RegionizedServer.getCurrentTick() % autosavePeriod == 0; // Folia - region threading @@ -1428,7 +1424,7 @@ index b912a5d6737cf8bd74617225ca0837e6e97b7206..b73699a08a368e6305759438c00066b0 try { this.isSaving = true; if (playerSaveInterval > 0) { -@@ -1663,6 +1676,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { // Folia - region threading entityplayer.connection.suspendFlushing(); -@@ -1793,12 +1808,14 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop