Nuke IOWorker, make stuff compile (#2733)

* remove removed patch cause its not removed anymore

* Nuke IOWorker, oh, and also make it compile

* synchronize writes properly

* Remove note about IOWorker
This commit is contained in:
MiniDigger 2019-12-13 14:46:45 +01:00 committed by Shane Freeder
parent 4565495711
commit bd93836d4c
2 changed files with 151 additions and 420 deletions

View File

@ -1,11 +1,8 @@
From 867219c4f28a3b9b5ea9dfe010569d45b620f1e1 Mon Sep 17 00:00:00 2001
From 783755ca4f609df8e98ca724b6efa576e29bd117 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
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,10 +2823,10 @@ 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
@@ -3,6 +3,10 @@ package net.minecraft.server;
@@ -3,37 +3,49 @@ package net.minecraft.server;
import com.mojang.datafixers.DataFixer;
import java.io.File;
import java.io.IOException;
@ -2840,8 +2837,11 @@ index 2f95174fc..1025e01d5 100644
import java.util.function.Supplier;
import javax.annotation.Nullable;
@@ -11,7 +15,9 @@ 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;
@@ -22,18 +28,23 @@ 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) {
@ -2883,7 +2888,7 @@ index 2f95174fc..1025e01d5 100644
ChunkStatus status = ChunkStatus.a(level.getString("Status"));
if (status != null && status.b(ChunkStatus.FEATURES)) {
@@ -64,11 +75,13 @@ public class IChunkLoader implements AutoCloseable {
@@ -64,11 +76,13 @@ public class IChunkLoader implements AutoCloseable {
if (i < 1493) {
nbttagcompound = GameProfileSerializer.a(this.b, DataFixTypes.CHUNK, nbttagcompound, i, 1493);
if (nbttagcompound.getCompound("Level").getBoolean("hasLegacyStructureData")) {
@ -2897,14 +2902,26 @@ index 2f95174fc..1025e01d5 100644
}
}
@@ -89,10 +102,12 @@ public class IChunkLoader implements AutoCloseable {
return this.a.a(chunkcoordintpair);
@@ -84,24 +98,28 @@ public class IChunkLoader implements AutoCloseable {
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
@@ -4,7 +4,7 @@ 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
@@ -63,7 +63,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
@ -3064,15 +3099,16 @@ index 6a54ccb86..66bd402e9 100644
mutableboolean.setTrue();
});
} while (mutableboolean.isTrue());
@@ -354,6 +355,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
@@ -354,18 +355,20 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
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 {
@@ -361,11 +363,12 @@ 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) {
@ -3392,7 +3428,14 @@ index 6a54ccb86..66bd402e9 100644
@Nullable
public NBTTagCompound readChunkData(ChunkCoordIntPair chunkcoordintpair) throws IOException { // Paper - private -> public
NBTTagCompound nbttagcompound = this.read(chunkcoordintpair);
@@ -927,27 +1087,47 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
@@ -921,33 +1081,53 @@ 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
@@ -218,7 +218,7 @@ 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) {
@@ -373,7 +373,7 @@ public class RegionFile implements AutoCloseable {
return chunkcoordintpair.j() + chunkcoordintpair.k() * 32;
}
@ -3512,10 +3564,19 @@ 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
@@ -20,7 +20,7 @@ public final class RegionFileCache implements AutoCloseable {
@@ -9,7 +9,7 @@ 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<RegionFile> cache = new Long2ObjectLinkedOpenHashMap();
private final File b;
@@ -20,12 +20,12 @@ public final class RegionFileCache implements AutoCloseable {
// Paper start
@ -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);
@@ -126,7 +126,7 @@ 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()) {
@@ -138,7 +138,7 @@ 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
@@ -25,7 +25,7 @@ public class RegionFileSection<R extends MinecraftSerializable> implements AutoC
@@ -20,28 +20,29 @@ import javax.annotation.Nullable;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
-public class RegionFileSection<R extends MinecraftSerializable> implements AutoCloseable {
+public class RegionFileSection<R extends MinecraftSerializable> 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<Optional<R>> c = new Long2ObjectOpenHashMap();
- private final LongLinkedOpenHashSet d = new LongLinkedOpenHashSet();
+ protected final LongLinkedOpenHashSet d = new LongLinkedOpenHashSet(); // Paper - private -> protected
private final BiFunction<Runnable, Dynamic<?>, R> e;
private final Function<Runnable, R> f;
private final DataFixer g;
@@ -40,8 +40,8 @@ public class RegionFileSection<R extends MinecraftSerializable> implements AutoC
private final DataFixTypes h;
public RegionFileSection(File file, BiFunction<Runnable, Dynamic<?>, R> bifunction, Function<Runnable, R> 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) {
@ -3557,7 +3649,7 @@ index db9f0196b..e7ea04861 100644
this.d(chunkcoordintpair);
}
@@ -95,7 +95,12 @@ public class RegionFileSection<R extends MinecraftSerializable> implements AutoC
@@ -95,13 +96,18 @@ public class RegionFileSection<R extends MinecraftSerializable> implements AutoC
}
private void b(ChunkCoordIntPair chunkcoordintpair) {
@ -3571,7 +3663,14 @@ index db9f0196b..e7ea04861 100644
}
@Nullable
@@ -143,7 +148,7 @@ public class RegionFileSection<R extends MinecraftSerializable> implements AutoC
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;
@@ -143,17 +149,31 @@ public class RegionFileSection<R extends MinecraftSerializable> implements AutoC
}
private void d(ChunkCoordIntPair chunkcoordintpair) {
@ -3580,7 +3679,11 @@ index db9f0196b..e7ea04861 100644
NBTBase nbtbase = (NBTBase) dynamic.getValue();
if (nbtbase instanceof NBTTagCompound) {
@@ -154,6 +159,20 @@ public class RegionFileSection<R extends MinecraftSerializable> 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);
}
}
@ -3601,7 +3704,7 @@ index db9f0196b..e7ea04861 100644
private <T> Dynamic<T> a(ChunkCoordIntPair chunkcoordintpair, DynamicOps<T> dynamicops) {
Map<T, T> map = Maps.newHashMap();
@@ -190,9 +209,9 @@ public class RegionFileSection<R extends MinecraftSerializable> implements AutoC
@@ -190,9 +210,9 @@ public class RegionFileSection<R extends MinecraftSerializable> implements AutoC
public void a(ChunkCoordIntPair chunkcoordintpair) {
if (!this.d.isEmpty()) {
for (int i = 0; i < 16; ++i) {
@ -3613,10 +3716,17 @@ index db9f0196b..e7ea04861 100644
this.d(chunkcoordintpair);
return;
}
@@ -204,4 +223,21 @@ public class RegionFileSection<R extends MinecraftSerializable> implements AutoC
public void close() throws IOException {
this.b.close();
@@ -201,7 +221,26 @@ public class RegionFileSection<R extends MinecraftSerializable> implements AutoC
}
- 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
@@ -81,6 +81,79 @@ 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);
+ }
@ -3920,5 +4030,5 @@ index a1d93200e..6ca0ebfde 100644
log.log( Level.SEVERE, "------------------------------" );
//
--
2.24.1
2.17.1

View File

@ -1,379 +0,0 @@
From 14f4011c2f16754e3f39826237f4822c3b6446b1 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Sat, 15 Jun 2019 08:54:33 -0700
Subject: [PATCH] Fix World#isChunkGenerated calls
Optimize World#loadChunk() too
This patch also adds a chunk status cache on region files (note that
its only purpose is to cache the status on DISK)
diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java
index 8689e0f9f..56761afdf 100644
--- a/src/main/java/net/minecraft/server/ChunkProviderServer.java
+++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java
@@ -28,7 +28,7 @@ public class ChunkProviderServer extends IChunkProvider {
private final WorldServer world;
private final Thread serverThread;
private final LightEngineThreaded lightEngine;
- private final ChunkProviderServer.a serverThreadQueue;
+ public final ChunkProviderServer.a serverThreadQueue; // Paper private -> public
public final PlayerChunkMap playerChunkMap;
private final WorldPersistentData worldPersistentData;
private long lastTickTime;
@@ -109,6 +109,21 @@ public class ChunkProviderServer extends IChunkProvider {
return playerChunk.getFullChunk();
}
+
+ @Nullable
+ public IChunkAccess getChunkAtImmediately(int x, int z) {
+ long k = ChunkCoordIntPair.pair(x, z);
+
+ // Note: Bypass cache to make this MT-Safe
+
+ PlayerChunk playerChunk = this.getChunk(k);
+ if (playerChunk == null) {
+ return null;
+ }
+
+ return playerChunk.getAvailableChunkNow();
+
+ }
// Paper end
@Nullable
diff --git a/src/main/java/net/minecraft/server/ChunkRegionLoader.java b/src/main/java/net/minecraft/server/ChunkRegionLoader.java
index e778c2e85..73f93e494 100644
--- a/src/main/java/net/minecraft/server/ChunkRegionLoader.java
+++ b/src/main/java/net/minecraft/server/ChunkRegionLoader.java
@@ -410,6 +410,17 @@ public class ChunkRegionLoader {
return nbttagcompound;
}
+ // Paper start
+ public static ChunkStatus getStatus(NBTTagCompound compound) {
+ if (compound == null) {
+ return null;
+ }
+
+ // Note: Copied from below
+ return ChunkStatus.getStatus(compound.getCompound("Level").getString("Status"));
+ }
+ // Paper end
+
public static ChunkStatus.Type a(@Nullable NBTTagCompound nbttagcompound) {
if (nbttagcompound != null) {
ChunkStatus chunkstatus = ChunkStatus.a(nbttagcompound.getCompound("Level").getString("Status"));
diff --git a/src/main/java/net/minecraft/server/ChunkStatus.java b/src/main/java/net/minecraft/server/ChunkStatus.java
index dd1822d6f..e324989b4 100644
--- a/src/main/java/net/minecraft/server/ChunkStatus.java
+++ b/src/main/java/net/minecraft/server/ChunkStatus.java
@@ -176,6 +176,7 @@ public class ChunkStatus {
return this.s;
}
+ public ChunkStatus getPreviousStatus() { return this.e(); } // Paper - OBFHELPER
public ChunkStatus e() {
return this.u;
}
@@ -196,6 +197,17 @@ public class ChunkStatus {
return this.y;
}
+ // Paper start
+ public static ChunkStatus getStatus(String name) {
+ try {
+ // We need this otherwise we return EMPTY for invalid names
+ MinecraftKey key = new MinecraftKey(name);
+ return IRegistry.CHUNK_STATUS.getOptional(key).orElse(null);
+ } catch (Exception ex) {
+ return null; // invalid name
+ }
+ }
+ // Paper end
public static ChunkStatus a(String s) {
return (ChunkStatus) IRegistry.CHUNK_STATUS.get(MinecraftKey.a(s));
}
diff --git a/src/main/java/net/minecraft/server/PlayerChunk.java b/src/main/java/net/minecraft/server/PlayerChunk.java
index 14a176d61..98590e233 100644
--- a/src/main/java/net/minecraft/server/PlayerChunk.java
+++ b/src/main/java/net/minecraft/server/PlayerChunk.java
@@ -70,6 +70,19 @@ public class PlayerChunk {
Either<IChunkAccess, PlayerChunk.Failure> either = (Either<IChunkAccess, PlayerChunk.Failure>) statusFuture.getNow(null);
return either == null ? null : (Chunk) either.left().orElse(null);
}
+
+ public IChunkAccess getAvailableChunkNow() {
+ // TODO can we just getStatusFuture(EMPTY)?
+ for (ChunkStatus curr = ChunkStatus.FULL, next = curr.getPreviousStatus(); curr != next; curr = next, next = next.getPreviousStatus()) {
+ CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> future = this.getStatusFutureUnchecked(curr);
+ Either<IChunkAccess, PlayerChunk.Failure> either = future.getNow(null);
+ if (either == null || !either.left().isPresent()) {
+ continue;
+ }
+ return either.left().get();
+ }
+ return null;
+ }
// Paper end
public CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> getStatusFutureUnchecked(ChunkStatus chunkstatus) {
diff --git a/src/main/java/net/minecraft/server/PlayerChunkMap.java b/src/main/java/net/minecraft/server/PlayerChunkMap.java
index 6f1e48ba4..eb49e9021 100644
--- a/src/main/java/net/minecraft/server/PlayerChunkMap.java
+++ b/src/main/java/net/minecraft/server/PlayerChunkMap.java
@@ -897,11 +897,61 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
}
@Nullable
- private NBTTagCompound readChunkData(ChunkCoordIntPair chunkcoordintpair) throws IOException {
+ public NBTTagCompound readChunkData(ChunkCoordIntPair chunkcoordintpair) throws IOException { // Paper - private -> public
NBTTagCompound nbttagcompound = this.read(chunkcoordintpair);
- return nbttagcompound == null ? null : this.getChunkData(this.world.getWorldProvider().getDimensionManager(), this.m, nbttagcompound, chunkcoordintpair, world); // CraftBukkit
+ // Paper start - Cache chunk status on disk
+ if (nbttagcompound == null) {
+ return null;
+ }
+
+ nbttagcompound = this.getChunkData(this.world.getWorldProvider().getDimensionManager(), this.m, nbttagcompound, chunkcoordintpair, world); // CraftBukkit
+ if (nbttagcompound == null) {
+ return null;
+ }
+
+ this.updateChunkStatusOnDisk(chunkcoordintpair, nbttagcompound);
+
+ return nbttagcompound;
+ // Paper end
+ }
+
+ // Paper start - chunk status cache "api"
+ public ChunkStatus getChunkStatusOnDiskIfCached(ChunkCoordIntPair chunkPos) {
+ RegionFile regionFile = this.getRegionFileIfLoaded(chunkPos);
+
+ return regionFile == null ? null : regionFile.getStatusIfCached(chunkPos.x, chunkPos.z);
+ }
+
+ public ChunkStatus getChunkStatusOnDisk(ChunkCoordIntPair chunkPos) throws IOException {
+ RegionFile regionFile = this.getRegionFile(chunkPos, false);
+
+ if (!regionFile.chunkExists(chunkPos)) {
+ return null;
+ }
+
+ ChunkStatus status = regionFile.getStatusIfCached(chunkPos.x, chunkPos.z);
+
+ if (status != null) {
+ return status;
+ }
+
+ this.readChunkData(chunkPos);
+
+ return regionFile.getStatusIfCached(chunkPos.x, chunkPos.z);
+ }
+
+ public void updateChunkStatusOnDisk(ChunkCoordIntPair chunkPos, @Nullable NBTTagCompound compound) throws IOException {
+ RegionFile regionFile = this.getRegionFile(chunkPos, false);
+
+ regionFile.setStatus(chunkPos.x, chunkPos.z, ChunkRegionLoader.getStatus(compound));
+ }
+
+ public IChunkAccess getUnloadingChunk(int chunkX, int chunkZ) {
+ PlayerChunk chunkHolder = this.pendingUnload.get(ChunkCoordIntPair.pair(chunkX, chunkZ));
+ return chunkHolder == null ? null : chunkHolder.getAvailableChunkNow();
}
+ // Paper end
boolean isOutsideOfRange(ChunkCoordIntPair chunkcoordintpair) {
// Spigot start
diff --git a/src/main/java/net/minecraft/server/RegionFile.java b/src/main/java/net/minecraft/server/RegionFile.java
index ccc3d6c7a..b487e8060 100644
--- a/src/main/java/net/minecraft/server/RegionFile.java
+++ b/src/main/java/net/minecraft/server/RegionFile.java
@@ -31,6 +31,30 @@ public class RegionFile implements AutoCloseable {
private final int[] d = new int[1024]; private final int[] timestamps = d; // Paper - OBFHELPER
private final List<Boolean> e; // PAIL freeSectors
+ // Paper start - Cache chunk status
+ private final ChunkStatus[] statuses = new ChunkStatus[32 * 32];
+
+ private boolean closed;
+
+ // invoked on write/read
+ public void setStatus(int x, int z, ChunkStatus status) {
+ if (this.closed) {
+ // We've used an invalid region file.
+ throw new IllegalStateException("RegionFile is closed");
+ }
+ this.statuses[this.getChunkLocation(new ChunkCoordIntPair(x, z))] = status;
+ }
+
+ public ChunkStatus getStatusIfCached(int x, int z) {
+ if (this.closed) {
+ // We've used an invalid region file.
+ throw new IllegalStateException("RegionFile is closed");
+ }
+ final int location = this.getChunkLocation(new ChunkCoordIntPair(x, z));
+ return this.statuses[location];
+ }
+ // Paper end
+
public RegionFile(File file) throws IOException {
this.b = new RandomAccessFile(file, "rw");
this.file = file; // Spigot // Paper - We need this earlier
@@ -291,6 +315,7 @@ public class RegionFile implements AutoCloseable {
return this.c[this.f(chunkcoordintpair)];
}
+ public final boolean chunkExists(ChunkCoordIntPair chunkPos) { return this.d(chunkPos); } // Paper - OBFHELPER
public boolean d(ChunkCoordIntPair chunkcoordintpair) {
return this.getOffset(chunkcoordintpair) != 0;
}
@@ -304,6 +329,7 @@ public class RegionFile implements AutoCloseable {
this.c[j] = i; // Spigot - move this to after the write
}
+ private final int getChunkLocation(ChunkCoordIntPair chunkcoordintpair) { return this.f(chunkcoordintpair); } // Paper - OBFHELPER
private int f(ChunkCoordIntPair chunkcoordintpair) {
return chunkcoordintpair.j() + chunkcoordintpair.k() * 32;
}
@@ -318,6 +344,7 @@ public class RegionFile implements AutoCloseable {
}
public void close() throws IOException {
+ this.closed = true; // Paper
this.b.close();
}
diff --git a/src/main/java/net/minecraft/server/RegionFileCache.java b/src/main/java/net/minecraft/server/RegionFileCache.java
index 6f34d8aea..d2b328945 100644
--- a/src/main/java/net/minecraft/server/RegionFileCache.java
+++ b/src/main/java/net/minecraft/server/RegionFileCache.java
@@ -47,6 +47,12 @@ public abstract class RegionFileCache implements AutoCloseable {
// Paper start
}
+ // Paper start
+ public RegionFile getRegionFileIfLoaded(ChunkCoordIntPair chunkcoordintpair) {
+ return this.cache.getAndMoveToFirst(ChunkCoordIntPair.pair(chunkcoordintpair.getRegionX(), chunkcoordintpair.getRegionZ()));
+ }
+ // Paper end
+
public RegionFile getRegionFile(ChunkCoordIntPair chunkcoordintpair, boolean existingOnly) throws IOException { return this.a(chunkcoordintpair, existingOnly); } // Paper - OBFHELPER
private RegionFile a(ChunkCoordIntPair chunkcoordintpair, boolean existingOnly) throws IOException { // CraftBukkit
long i = ChunkCoordIntPair.pair(chunkcoordintpair.getRegionX(), chunkcoordintpair.getRegionZ());
@@ -110,6 +116,7 @@ public abstract class RegionFileCache implements AutoCloseable {
try {
NBTCompressedStreamTools.writeNBT(nbttagcompound, out);
out.close();
+ regionfile.setStatus(chunk.x, chunk.z, ChunkRegionLoader.getStatus(nbttagcompound)); // Paper - cache status on disk
regionfile.setOversized(chunkX, chunkZ, false);
} catch (RegionFile.ChunkTooLargeException ignored) {
printOversizedLog("ChunkTooLarge! Someone is trying to duplicate.", regionfile.file, chunkX, chunkZ);
@@ -127,6 +134,7 @@ public abstract class RegionFileCache implements AutoCloseable {
if (SIZE_THRESHOLD == OVERZEALOUS_THRESHOLD) {
resetFilterThresholds();
}
+ regionfile.setStatus(chunk.x, chunk.z, ChunkRegionLoader.getStatus(nbttagcompound)); // Paper - cache status on disk
} catch (RegionFile.ChunkTooLargeException e) {
printOversizedLog("ChunkTooLarge even after reduction. Trying in overzealous mode.", regionfile.file, chunkX, chunkZ);
// Eek, major fail. We have retry logic, so reduce threshholds and fall back
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
index e42bd2638..2227de3bf 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
@@ -18,6 +18,7 @@ import java.util.Objects;
import java.util.Random;
import java.util.Set;
import java.util.UUID;
+import java.util.concurrent.CompletableFuture;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
@@ -408,8 +409,22 @@ public class CraftWorld implements World {
@Override
public boolean isChunkGenerated(int x, int z) {
+ // Paper start - Fix this method
+ if (!Bukkit.isPrimaryThread()) {
+ return CompletableFuture.supplyAsync(() -> {
+ return CraftWorld.this.isChunkGenerated(x, z);
+ }, world.getChunkProvider().serverThreadQueue).join();
+ }
+ IChunkAccess chunk = world.getChunkProvider().getChunkAtImmediately(x, z);
+ if (chunk == null) {
+ chunk = world.getChunkProvider().playerChunkMap.getUnloadingChunk(x, z);
+ }
+ if (chunk != null) {
+ return chunk instanceof ProtoChunkExtension || chunk instanceof net.minecraft.server.Chunk;
+ }
try {
- return world.getChunkProvider().getChunkAtIfCachedImmediately(x, z) != null || world.getChunkProvider().playerChunkMap.chunkExists(new ChunkCoordIntPair(x, z)); // Paper
+ return world.getChunkProvider().playerChunkMap.getChunkStatusOnDisk(new ChunkCoordIntPair(x, z)) == ChunkStatus.FULL;
+ // Paper end
} catch (IOException ex) {
throw new RuntimeException(ex);
}
@@ -521,20 +536,49 @@ public class CraftWorld implements World {
@Override
public boolean loadChunk(int x, int z, boolean generate) {
org.spigotmc.AsyncCatcher.catchOp("chunk load"); // Spigot
- IChunkAccess chunk = world.getChunkProvider().getChunkAt(x, z, generate || isChunkGenerated(x, z) ? ChunkStatus.FULL : ChunkStatus.EMPTY, true); // Paper
+ // Paper start - Optimize this method
+ ChunkCoordIntPair chunkPos = new ChunkCoordIntPair(x, z);
- // If generate = false, but the chunk already exists, we will get this back.
- if (chunk instanceof ProtoChunkExtension) {
- // We then cycle through again to get the full chunk immediately, rather than after the ticket addition
- chunk = world.getChunkProvider().getChunkAt(x, z, ChunkStatus.FULL, true);
- }
+ if (!generate) {
- if (chunk instanceof net.minecraft.server.Chunk) {
- world.getChunkProvider().addTicket(TicketType.PLUGIN, new ChunkCoordIntPair(x, z), 1, Unit.INSTANCE);
- return true;
+ IChunkAccess immediate = world.getChunkProvider().getChunkAtImmediately(x, z);
+ if (immediate == null) {
+ immediate = world.getChunkProvider().playerChunkMap.getUnloadingChunk(x, z);
+ }
+ if (immediate != null) {
+ if (!(immediate instanceof ProtoChunkExtension) && !(immediate instanceof net.minecraft.server.Chunk)) {
+ return false; // not full status
+ }
+ world.getChunkProvider().addTicket(TicketType.PLUGIN, chunkPos, 1, Unit.INSTANCE);
+ world.getChunkAt(x, z); // make sure we're at ticket level 32 or lower
+ return true;
+ }
+
+ net.minecraft.server.RegionFile file;
+ try {
+ file = world.getChunkProvider().playerChunkMap.getRegionFile(chunkPos, false);
+ } catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+
+ ChunkStatus status = file.getStatusIfCached(x, z);
+ if (!file.chunkExists(chunkPos) || (status != null && status != ChunkStatus.FULL)) {
+ return false;
+ }
+
+ IChunkAccess chunk = world.getChunkProvider().getChunkAt(x, z, ChunkStatus.EMPTY, true);
+ if (!(chunk instanceof ProtoChunkExtension) && !(chunk instanceof net.minecraft.server.Chunk)) {
+ return false;
+ }
+
+ // fall through to load
+ // we do this so we do not re-read the chunk data on disk
}
- return false;
+ world.getChunkProvider().addTicket(TicketType.PLUGIN, chunkPos, 1, Unit.INSTANCE);
+ world.getChunkProvider().getChunkAt(x, z, ChunkStatus.FULL, true);
+ return true;
+ // Paper end
}
@Override
--
2.24.0