diff --git a/Spigot-Server-Patches/Asynchronous-chunk-IO-and-loading.patch b/Spigot-Server-Patches/Asynchronous-chunk-IO-and-loading.patch index b6f6d9a5b7..86987deb7e 100644 --- a/Spigot-Server-Patches/Asynchronous-chunk-IO-and-loading.patch +++ b/Spigot-Server-Patches/Asynchronous-chunk-IO-and-loading.patch @@ -3,9 +3,6 @@ From: Spottedleaf Date: Sat, 13 Jul 2019 09:23:10 -0700 Subject: [PATCH] Asynchronous chunk IO and loading -THIS PATCH NEEDS RE-EVALUTING AND WILL LIKELY NOT WORK AS-IS RIGHT THIS SECOND -- Pending investigation of IOWorker changes (Will do this when not too tired) - This patch re-adds a file IO thread as well as shoving de-serializing chunk NBT data onto worker threads. This patch also will shove chunk data serialization onto the same worker threads when the chunk @@ -2826,7 +2823,7 @@ index 721021791..f7156acb8 100644 ; } diff --git a/src/main/java/net/minecraft/server/IChunkLoader.java b/src/main/java/net/minecraft/server/IChunkLoader.java -index 2f95174fc..1025e01d5 100644 +index 2f95174fc..134c76065 100644 --- a/src/main/java/net/minecraft/server/IChunkLoader.java +++ b/src/main/java/net/minecraft/server/IChunkLoader.java @@ -0,0 +0,0 @@ package net.minecraft.server; @@ -2840,8 +2837,11 @@ index 2f95174fc..1025e01d5 100644 import java.util.function.Supplier; import javax.annotation.Nullable; -@@ -0,0 +0,0 @@ public class IChunkLoader implements AutoCloseable { - private final IOWorker a; public IOWorker getIOWorker() { return a; } // Paper - OBFHELPER +-public class IChunkLoader implements AutoCloseable { ++public class IChunkLoader extends RegionFileCache implements AutoCloseable { + +- private final IOWorker a; public IOWorker getIOWorker() { return a; } // Paper - OBFHELPER ++// private final IOWorker a; public IOWorker getIOWorker() { return a; } // Paper - OBFHELPER - nuke IOWorker protected final DataFixer b; @Nullable - private PersistentStructureLegacy c; @@ -2850,8 +2850,13 @@ index 2f95174fc..1025e01d5 100644 + private final Object persistentDataLock = new Object(); // Paper public IChunkLoader(File file, DataFixer datafixer) { ++ super(file); this.b = datafixer; -@@ -0,0 +0,0 @@ public class IChunkLoader implements AutoCloseable { +- this.a = new IOWorker(new RegionFileCache(file), "chunk"); ++// this.a = new IOWorker(new RegionFileCache(file), "chunk"); // Paper - nuke IOWorker + } + + // CraftBukkit start private boolean check(ChunkProviderServer cps, int x, int z) throws IOException { ChunkCoordIntPair pos = new ChunkCoordIntPair(x, z); if (cps != null) { @@ -2898,13 +2903,25 @@ index 2f95174fc..1025e01d5 100644 } @@ -0,0 +0,0 @@ public class IChunkLoader implements AutoCloseable { - return this.a.a(chunkcoordintpair); + return nbttagcompound.hasKeyOfType("DataVersion", 99) ? nbttagcompound.getInt("DataVersion") : -1; } +- @Nullable +- public NBTTagCompound read(ChunkCoordIntPair chunkcoordintpair) throws IOException { +- return this.a.a(chunkcoordintpair); +- } +- - public void a(ChunkCoordIntPair chunkcoordintpair, NBTTagCompound nbttagcompound) { +- this.a.a(chunkcoordintpair, nbttagcompound); ++// Paper start - nuke IOWorker ++// @Nullable ++// public NBTTagCompound read(ChunkCoordIntPair chunkcoordintpair) throws IOException { ++// return this.a.a(chunkcoordintpair); ++// } ++// + public void a(ChunkCoordIntPair chunkcoordintpair, NBTTagCompound nbttagcompound) throws IOException { write(chunkcoordintpair, nbttagcompound); } // Paper OBFHELPER + public void write(ChunkCoordIntPair chunkcoordintpair, NBTTagCompound nbttagcompound) throws IOException { // Paper - OBFHELPER - (Switched around for safety) - this.a.a(chunkcoordintpair, nbttagcompound); ++ super.write(chunkcoordintpair, nbttagcompound); if (this.c != null) { - this.c.a(chunkcoordintpair.pair()); + synchronized (this.persistentDataLock) { // Paper - Async chunk loading @@ -2912,6 +2929,24 @@ index 2f95174fc..1025e01d5 100644 } } +- +- public void i() { +- this.a.a().join(); +- } +- +- public void close() throws IOException { +- this.a.close(); +- } ++// ++// public void i() { ++// this.a.a().join(); ++// } ++// ++// public void close() throws IOException { ++// this.a.close(); ++// } ++// Paper end + } diff --git a/src/main/java/net/minecraft/server/MCUtil.java b/src/main/java/net/minecraft/server/MCUtil.java index 25a87c2d3..c02c53b50 100644 --- a/src/main/java/net/minecraft/server/MCUtil.java @@ -2939,7 +2974,7 @@ index 8e15aba7f..edb3a6035 100644 public String getServerIp() { diff --git a/src/main/java/net/minecraft/server/NextTickListEntry.java b/src/main/java/net/minecraft/server/NextTickListEntry.java -index 8471920b8..04429a274 100644 +index e9c405fb5..33cfeabde 100644 --- a/src/main/java/net/minecraft/server/NextTickListEntry.java +++ b/src/main/java/net/minecraft/server/NextTickListEntry.java @@ -0,0 +0,0 @@ import java.util.Comparator; @@ -2999,7 +3034,7 @@ index 7a1578afa..0fb9c1e44 100644 completablefuture = (CompletableFuture) this.statusFutures.get(i); if (completablefuture != null) { diff --git a/src/main/java/net/minecraft/server/PlayerChunkMap.java b/src/main/java/net/minecraft/server/PlayerChunkMap.java -index 6a54ccb86..66bd402e9 100644 +index 6a54ccb86..fce37d0d6 100644 --- a/src/main/java/net/minecraft/server/PlayerChunkMap.java +++ b/src/main/java/net/minecraft/server/PlayerChunkMap.java @@ -0,0 +0,0 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { @@ -3068,11 +3103,12 @@ index 6a54ccb86..66bd402e9 100644 this.b(() -> { return true; }); +- this.i(); + this.world.asyncChunkTaskManager.flush(); // Paper - flush to preserve behavior compat with pre-async behaviour - this.i(); ++// this.i(); // Paper - nuke IOWorker PlayerChunkMap.LOGGER.info("ThreadedAnvilChunkStorage ({}): All chunks are saved", this.w.getName()); } else { -@@ -0,0 +0,0 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { + this.visibleChunks.values().stream().filter(PlayerChunk::hasBeenLoaded).forEach((playerchunk) -> { IChunkAccess ichunkaccess = (IChunkAccess) playerchunk.getChunkSave().getNow(null); // CraftBukkit - decompile error if (ichunkaccess instanceof ProtoChunkExtension || ichunkaccess instanceof Chunk) { @@ -3393,6 +3429,13 @@ index 6a54ccb86..66bd402e9 100644 public NBTTagCompound readChunkData(ChunkCoordIntPair chunkcoordintpair) throws IOException { // Paper - private -> public NBTTagCompound nbttagcompound = this.read(chunkcoordintpair); @@ -0,0 +0,0 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { + + // Paper start - chunk status cache "api" + public ChunkStatus getChunkStatusOnDiskIfCached(ChunkCoordIntPair chunkPos) { +- RegionFile regionFile = this.getIOWorker().getRegionFileCache().getRegionFileIfLoaded(chunkPos); ++ RegionFile regionFile = this.getRegionFileIfLoaded(chunkPos); + + return regionFile == null ? null : regionFile.getStatusIfCached(chunkPos.x, chunkPos.z); } public ChunkStatus getChunkStatusOnDisk(ChunkCoordIntPair chunkPos) throws IOException { @@ -3414,7 +3457,7 @@ index 6a54ccb86..66bd402e9 100644 } + // Paper end + synchronized (this) { // Paper - async io -+ RegionFile regionFile = this.getIOWorker().getRegionFileCache().getFile(chunkPos, false); ++ RegionFile regionFile = this.getFile(chunkPos, false); + + if (!regionFile.chunkExists(chunkPos)) { + return null; @@ -3442,7 +3485,7 @@ index 6a54ccb86..66bd402e9 100644 public void updateChunkStatusOnDisk(ChunkCoordIntPair chunkPos, @Nullable NBTTagCompound compound) throws IOException { - RegionFile regionFile = this.getIOWorker().getRegionFileCache().getFile(chunkPos, false); + synchronized (this) { -+ RegionFile regionFile = this.getIOWorker().getRegionFileCache().getFile(chunkPos, false); ++ RegionFile regionFile = this.getFile(chunkPos, false); - regionFile.setStatus(chunkPos.x, chunkPos.z, ChunkRegionLoader.getStatus(compound)); + regionFile.setStatus(chunkPos.x, chunkPos.z, ChunkRegionLoader.getStatus(compound)); @@ -3478,7 +3521,7 @@ index 6a54ccb86..66bd402e9 100644 + synchronized (world.getChunkProvider().playerChunkMap) { + net.minecraft.server.RegionFile file; + try { -+ file = world.getChunkProvider().playerChunkMap.getIOWorker().getRegionFileCache().getFile(chunkPos, false); ++ file = world.getChunkProvider().playerChunkMap.getFile(chunkPos, false); + } catch (IOException ex) { + throw new RuntimeException(ex); + } @@ -3499,9 +3542,18 @@ index 6a54ccb86..66bd402e9 100644 return this.m; } diff --git a/src/main/java/net/minecraft/server/RegionFile.java b/src/main/java/net/minecraft/server/RegionFile.java -index 7eb87c517..551e91869 100644 +index 7eb87c517..b252684c2 100644 --- a/src/main/java/net/minecraft/server/RegionFile.java +++ b/src/main/java/net/minecraft/server/RegionFile.java +@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable { + return (i + 4096 - 1) / 4096; + } + +- public boolean b(ChunkCoordIntPair chunkcoordintpair) { ++ public synchronized boolean b(ChunkCoordIntPair chunkcoordintpair) { // Paper - synchronized + int i = this.getOffset(chunkcoordintpair); + + if (i == 0) { @@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable { return chunkcoordintpair.j() + chunkcoordintpair.k() * 32; } @@ -3512,9 +3564,18 @@ index 7eb87c517..551e91869 100644 try { this.c(); diff --git a/src/main/java/net/minecraft/server/RegionFileCache.java b/src/main/java/net/minecraft/server/RegionFileCache.java -index 1a6be7c6d..9a0fdec47 100644 +index 1a6be7c6d..386f47dc8 100644 --- a/src/main/java/net/minecraft/server/RegionFileCache.java +++ b/src/main/java/net/minecraft/server/RegionFileCache.java +@@ -0,0 +0,0 @@ import java.io.File; + import java.io.IOException; + import javax.annotation.Nullable; + +-public final class RegionFileCache implements AutoCloseable { ++public class RegionFileCache implements AutoCloseable { // Paper - no final + + public final Long2ObjectLinkedOpenHashMap cache = new Long2ObjectLinkedOpenHashMap(); + private final File b; @@ -0,0 +0,0 @@ public final class RegionFileCache implements AutoCloseable { @@ -3524,6 +3585,21 @@ index 1a6be7c6d..9a0fdec47 100644 return this.cache.getAndMoveToFirst(ChunkCoordIntPair.pair(chunkcoordintpair.getRegionX(), chunkcoordintpair.getRegionZ())); } + // Paper end +- public RegionFile getFile(ChunkCoordIntPair chunkcoordintpair, boolean existingOnly) throws IOException { // CraftBukkit // Paper - private > public ++ public synchronized RegionFile getFile(ChunkCoordIntPair chunkcoordintpair, boolean existingOnly) throws IOException { // CraftBukkit // Paper - private > public, synchronize + long i = ChunkCoordIntPair.pair(chunkcoordintpair.getRegionX(), chunkcoordintpair.getRegionZ()); + RegionFile regionfile = (RegionFile) this.cache.getAndMoveToFirst(i); + +@@ -0,0 +0,0 @@ public final class RegionFileCache implements AutoCloseable { + // Paper end + } + +- public void close() throws IOException { ++ public synchronized void close() throws IOException { // Paper -> synchronized + ObjectIterator objectiterator = this.cache.values().iterator(); + + while (objectiterator.hasNext()) { @@ -0,0 +0,0 @@ public final class RegionFileCache implements AutoCloseable { } @@ -3534,19 +3610,35 @@ index 1a6be7c6d..9a0fdec47 100644 return regionfile != null ? regionfile.chunkExists(pos) : false; diff --git a/src/main/java/net/minecraft/server/RegionFileSection.java b/src/main/java/net/minecraft/server/RegionFileSection.java -index db9f0196b..e7ea04861 100644 +index db9f0196b..a6d8ef5eb 100644 --- a/src/main/java/net/minecraft/server/RegionFileSection.java +++ b/src/main/java/net/minecraft/server/RegionFileSection.java -@@ -0,0 +0,0 @@ public class RegionFileSection implements AutoC +@@ -0,0 +0,0 @@ import javax.annotation.Nullable; + import org.apache.logging.log4j.LogManager; + import org.apache.logging.log4j.Logger; + +-public class RegionFileSection implements AutoCloseable { ++public class RegionFileSection extends RegionFileCache implements AutoCloseable { // Paper - nuke IOWorker + private static final Logger LOGGER = LogManager.getLogger(); - private final IOWorker b; +- private final IOWorker b; ++// private final IOWorker b; private final Long2ObjectMap> c = new Long2ObjectOpenHashMap(); - private final LongLinkedOpenHashSet d = new LongLinkedOpenHashSet(); + protected final LongLinkedOpenHashSet d = new LongLinkedOpenHashSet(); // Paper - private -> protected private final BiFunction, R> e; private final Function f; private final DataFixer g; -@@ -0,0 +0,0 @@ public class RegionFileSection implements AutoC + private final DataFixTypes h; + + public RegionFileSection(File file, BiFunction, R> bifunction, Function function, DataFixer datafixer, DataFixTypes datafixtypes) { ++ super(file); // Paper - nuke IOWorker + this.e = bifunction; + this.f = function; + this.g = datafixer; + this.h = datafixtypes; +- this.b = new IOWorker(new RegionFileCache(file), file.getName()); ++// this.b = new IOWorker(new RegionFileCache(file), file.getName()); // Paper - nuke IOWorker } protected void a(BooleanSupplier booleansupplier) { @@ -3571,6 +3663,13 @@ index db9f0196b..e7ea04861 100644 } @Nullable + private NBTTagCompound c(ChunkCoordIntPair chunkcoordintpair) { + try { +- return this.b.a(chunkcoordintpair); ++ return this.read(chunkcoordintpair); // Paper - nuke IOWorker + } catch (IOException ioexception) { + RegionFileSection.LOGGER.error("Error reading chunk {} data from disk", chunkcoordintpair, ioexception); + return null; @@ -0,0 +0,0 @@ public class RegionFileSection implements AutoC } @@ -3580,7 +3679,11 @@ index db9f0196b..e7ea04861 100644 NBTBase nbtbase = (NBTBase) dynamic.getValue(); if (nbtbase instanceof NBTTagCompound) { -@@ -0,0 +0,0 @@ public class RegionFileSection implements AutoC +- this.b.a(chunkcoordintpair, (NBTTagCompound) nbtbase); ++ try { this.write(chunkcoordintpair, (NBTTagCompound) nbtbase); } catch (IOException ioexception) { RegionFileSection.LOGGER.error("Error writing data to disk", ioexception); } // Paper - nuke IOWorker // TODO make this write async + } else { + RegionFileSection.LOGGER.error("Expected compound tag, got {}", nbtbase); + } } @@ -3614,9 +3717,16 @@ index db9f0196b..e7ea04861 100644 return; } @@ -0,0 +0,0 @@ public class RegionFileSection implements AutoC - public void close() throws IOException { - this.b.close(); + } + +- public void close() throws IOException { +- this.b.close(); ++// Paper start - nuke IOWorker ++// public void close() throws IOException { ++// this.b.close(); ++// } ++// Paper end + + // Paper start - get data function + public NBTTagCompound getData(ChunkCoordIntPair chunkcoordintpair) { @@ -3632,7 +3742,7 @@ index db9f0196b..e7ea04861 100644 + } + } + return null; -+ } + } + // Paper end } diff --git a/src/main/java/net/minecraft/server/TicketType.java b/src/main/java/net/minecraft/server/TicketType.java @@ -3737,7 +3847,7 @@ index c999f8c9b..b59ef1a63 100644 HAS_SPACE(VillagePlaceRecord::d), IS_OCCUPIED(VillagePlaceRecord::e), ANY((villageplacerecord) -> { diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java -index 8ea9b34a1..fecbe7914 100644 +index 049d4ef4e..59b2fc629 100644 --- a/src/main/java/net/minecraft/server/WorldServer.java +++ b/src/main/java/net/minecraft/server/WorldServer.java @@ -0,0 +0,0 @@ public class WorldServer extends World { @@ -3762,7 +3872,7 @@ index 8ea9b34a1..fecbe7914 100644 + RegionFile file; + + try { -+ file = WorldServer.this.getChunkProvider().playerChunkMap.getVillagePlace().getRegionFile(new ChunkCoordIntPair(chunkX, chunkZ), false); ++ file = WorldServer.this.getChunkProvider().playerChunkMap.getVillagePlace().getFile(new ChunkCoordIntPair(chunkX, chunkZ), false); + } catch (java.io.IOException ex) { + throw new RuntimeException(ex); + } @@ -3797,7 +3907,7 @@ index 8ea9b34a1..fecbe7914 100644 + RegionFile file; + + try { -+ file = WorldServer.this.getChunkProvider().playerChunkMap.getRegionFile(new ChunkCoordIntPair(chunkX, chunkZ), false); ++ file = WorldServer.this.getChunkProvider().playerChunkMap.getFile(new ChunkCoordIntPair(chunkX, chunkZ), false); + } catch (java.io.IOException ex) { + throw new RuntimeException(ex); + }