mirror of
https://github.com/PaperMC/Paper.git
synced 2025-08-01 12:42:05 -07:00
Improvements to Async Chunks
If a chunk load comes in on a chunk load or gen thread, execute it synchronously on that thread instead of enqueueing it. It doesn't make sense to enqueue it as that thread is then going to future.join() it and block until it's ready anyways. This opens risk to a deadlock if every load or gen thread is waiting on a recursive chunk but it will never finish because all of the threads are waiting.
This commit is contained in:
@@ -904,7 +904,7 @@ index 98d182fdb8..487d98eb1b 100644
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/PaperAsyncChunkProvider.java b/src/main/java/net/minecraft/server/PaperAsyncChunkProvider.java
|
||||
new file mode 100644
|
||||
index 0000000000..2dfa59b204
|
||||
index 0000000000..4fc5fad09e
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/net/minecraft/server/PaperAsyncChunkProvider.java
|
||||
@@ -0,0 +0,0 @@
|
||||
@@ -965,6 +965,8 @@ index 0000000000..2dfa59b204
|
||||
+ private final Long2ObjectMap<PendingChunk> pendingChunks = Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap<>());
|
||||
+ private final ConcurrentLinkedQueue<Runnable> mainThreadQueue = new ConcurrentLinkedQueue<>();
|
||||
+ private final IAsyncTaskHandler asyncHandler;
|
||||
+ private final ThreadLocal<Boolean> isChunkThread = ThreadLocal.withInitial(() -> false);
|
||||
+ private final ThreadLocal<Boolean> isChunkGenThread = ThreadLocal.withInitial(() -> false);
|
||||
+
|
||||
+ private final WorldServer world;
|
||||
+ private final IChunkLoader chunkLoader;
|
||||
@@ -1069,6 +1071,9 @@ index 0000000000..2dfa59b204
|
||||
+ // Listen for when result is ready
|
||||
+ final CompletableFuture<Chunk> future = new CompletableFuture<>();
|
||||
+ PendingChunkRequest request = pending.addListener(future, gen);
|
||||
+ if (isChunkThread.get()) {
|
||||
+ pending.loadTask.run();
|
||||
+ }
|
||||
+
|
||||
+ if (isBlockingMain && pending.hasFinished) {
|
||||
+ processChunkLoads();
|
||||
@@ -1248,6 +1253,11 @@ index 0000000000..2dfa59b204
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private Chunk generateChunkExecutor() {
|
||||
+ isChunkThread.set(true);
|
||||
+ isChunkGenThread.set(true);
|
||||
+ return generateChunk();
|
||||
+ }
|
||||
+ private Chunk generateChunk() {
|
||||
+ synchronized (this) {
|
||||
+ if (requests.get() <= 0) {
|
||||
@@ -1405,8 +1415,16 @@ index 0000000000..2dfa59b204
|
||||
+ if (loadTask == null) {
|
||||
+ // Take care of a race condition in that a request could be cancelled after the synchronize
|
||||
+ // on pendingChunks, but before a listener is added, which would erase these pending tasks.
|
||||
+ genTask = generationExecutor.createPendingTask(this::generateChunk, taskPriority);
|
||||
+ loadTask = EXECUTOR.submitTask(this, taskPriority);
|
||||
+ if (shouldGenSync) {
|
||||
+ genTask = generationExecutor.createPendingTask(this::generateChunk, taskPriority);
|
||||
+ } else {
|
||||
+ genTask = generationExecutor.createPendingTask(this::generateChunkExecutor, taskPriority);
|
||||
+ }
|
||||
+ loadTask = EXECUTOR.createPendingTask(this, taskPriority);
|
||||
+ if (!isChunkThread.get()) {
|
||||
+ // We will execute it outside of the synchronized context immediately after
|
||||
+ EXECUTOR.submitTask(loadTask);
|
||||
+ }
|
||||
+ }
|
||||
+ return new PendingChunkRequest(this, gen);
|
||||
+ }
|
||||
@@ -1414,6 +1432,7 @@ index 0000000000..2dfa59b204
|
||||
+
|
||||
+ @Override
|
||||
+ public void run() {
|
||||
+ isChunkThread.set(true);
|
||||
+ try {
|
||||
+ if (!loadFinished(loadChunk(x, z))) {
|
||||
+ return;
|
||||
@@ -1435,7 +1454,13 @@ index 0000000000..2dfa59b204
|
||||
+ mainThreadQueue.notify();
|
||||
+ }
|
||||
+ } else {
|
||||
+ generationExecutor.submitTask(genTask);
|
||||
+ if (isChunkGenThread.get()) {
|
||||
+ // ideally we should never run into 1 chunk generating another chunk...
|
||||
+ // but if we do, let's apply same solution
|
||||
+ genTask.run();
|
||||
+ } else {
|
||||
+ generationExecutor.submitTask(genTask);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
|
Reference in New Issue
Block a user