From 7941af6fec88a5d2df1b1b2867f69dd5aa39cd3c Mon Sep 17 00:00:00 2001 From: Shane Freeder Date: Sun, 28 Oct 2018 14:40:30 +0000 Subject: [PATCH] Process chunks blocking main urgently (#1627) A chunk load on the main thread will be added to the high priority queue, however, due to existing work on this queue, there was no guarantee that the load would occur within a reasonable amount of time, potentially causing a server to crash while waiting for a chunk in the queue In order to counteract this, a new urgent priority has been added, allowing us to prioritize these tasks over standard chunk gen/loading (#1625 #1615 #1575 #1558 (and probably more)) --- .../Async-Chunk-Loading-and-Generation.patch | 73 +++++++++++++++---- 1 file changed, 58 insertions(+), 15 deletions(-) diff --git a/Spigot-Server-Patches/Async-Chunk-Loading-and-Generation.patch b/Spigot-Server-Patches/Async-Chunk-Loading-and-Generation.patch index 70e95e7ccc..5aea1ec159 100644 --- a/Spigot-Server-Patches/Async-Chunk-Loading-and-Generation.patch +++ b/Spigot-Server-Patches/Async-Chunk-Loading-and-Generation.patch @@ -106,7 +106,7 @@ index b703e0848..77d35ac99 100644 } diff --git a/src/main/java/com/destroystokyo/paper/util/PriorityQueuedExecutor.java b/src/main/java/com/destroystokyo/paper/util/PriorityQueuedExecutor.java new file mode 100644 -index 000000000..5c77b6e8e +index 000000000..e589aa356 --- /dev/null +++ b/src/main/java/com/destroystokyo/paper/util/PriorityQueuedExecutor.java @@ -0,0 +0,0 @@ @@ -136,6 +136,7 @@ index 000000000..5c77b6e8e + */ +@SuppressWarnings({"WeakerAccess", "UnusedReturnValue", "unused"}) +public class PriorityQueuedExecutor extends AbstractExecutorService { ++ private final ConcurrentLinkedQueue urgent = new ConcurrentLinkedQueue<>(); + private final ConcurrentLinkedQueue high = new ConcurrentLinkedQueue<>(); + private final ConcurrentLinkedQueue normal = new ConcurrentLinkedQueue<>(); + private final RejectionHandler handler; @@ -264,7 +265,11 @@ index 000000000..5c77b6e8e + } + + private Runnable getTask() { -+ Runnable run = high.poll(); ++ Runnable run = urgent.poll(); ++ if (run != null) { ++ return run; ++ } ++ run = high.poll(); + if (run != null) { + return run; + } @@ -300,7 +305,7 @@ index 000000000..5c77b6e8e + } + + public enum Priority { -+ NORMAL, HIGH ++ NORMAL, HIGH, URGENT + } + + public class PendingTask implements Runnable { @@ -339,8 +344,18 @@ index 000000000..5c77b6e8e + } + + public void bumpPriority() { -+ if (!priority.compareAndSet(Priority.NORMAL.ordinal(), Priority.HIGH.ordinal())) { -+ return; ++ bumpPriority(Priority.HIGH); ++ } ++ ++ public void bumpPriority(Priority newPriority) { ++ for (;;) { ++ int current = this.priority.get(); ++ if (current >= newPriority.ordinal()) { ++ return; ++ } ++ if (priority.compareAndSet(current, newPriority.ordinal())) { ++ break; ++ } + } + + if (this.executor == null) { @@ -362,7 +377,9 @@ index 000000000..5c77b6e8e + return; + } + if (this.submitted.compareAndSet(submitted, priority)) { -+ if (priority == Priority.HIGH.ordinal()) { ++ if (priority == Priority.URGENT.ordinal()) { ++ urgent.add(this); ++ } else if (priority == Priority.HIGH.ordinal()) { + high.add(this); + } else { + normal.add(this); @@ -1014,7 +1031,7 @@ index 763130b03..67722440f 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 000000000..5823917a6 +index 000000000..c334462f2 --- /dev/null +++ b/src/main/java/net/minecraft/server/PaperAsyncChunkProvider.java @@ -0,0 +0,0 @@ @@ -1114,6 +1131,18 @@ index 000000000..5823917a6 + } + } + ++ private static Priority calculatePriority(boolean isBlockingMain, boolean priority) { ++ if (isBlockingMain) { ++ return Priority.URGENT; ++ } ++ ++ if (priority) { ++ return Priority.HIGH; ++ } ++ ++ return Priority.NORMAL; ++ } ++ + private boolean processChunkLoads() { + Runnable run; + boolean hadLoad = false; @@ -1128,7 +1157,7 @@ index 000000000..5823917a6 + public void bumpPriority(ChunkCoordIntPair coords) { + PendingChunk pending = pendingChunks.get(coords.asLong()); + if (pending != null) { -+ pending.bumpPriority(); ++ pending.bumpPriority(Priority.HIGH); + } + } + @@ -1165,16 +1194,18 @@ index 000000000..5823917a6 + synchronized (pendingChunks) { + PendingChunk pendingChunk = pendingChunks.get(key); + if (pendingChunk == null) { -+ pending = new PendingChunk(x, z, key, gen, priority || isBlockingMain); ++ pending = new PendingChunk(x, z, key, gen, calculatePriority(isBlockingMain, priority)); + pendingChunks.put(key, pending); + } else if (pendingChunk.hasFinished && gen && !pendingChunk.canGenerate && pendingChunk.chunk == null) { + // need to overwrite the old -+ pending = new PendingChunk(x, z, key, true, priority || isBlockingMain); ++ pending = new PendingChunk(x, z, key, true, calculatePriority(isBlockingMain, priority)); + pendingChunks.put(key, pending); + } else { + pending = pendingChunk; -+ if (priority || isBlockingMain) { -+ pending.bumpPriority(); ++ ++ Priority newPriority = calculatePriority(isBlockingMain, priority); ++ if (pending.taskPriority != newPriority) { ++ pending.bumpPriority(newPriority); + } + } + } @@ -1347,6 +1378,14 @@ index 000000000..5823917a6 + taskPriority = priority ? Priority.HIGH : Priority.NORMAL; + } + ++ PendingChunk(int x, int z, long key, boolean canGenerate, Priority taskPriority) { ++ this.x = x; ++ this.z = z; ++ this.key = key; ++ this.canGenerate = canGenerate; ++ this.taskPriority = taskPriority; ++ } ++ + private synchronized void setStatus(PendingStatus status) { + this.status = status; + } @@ -1575,14 +1614,18 @@ index 000000000..5823917a6 + } + + void bumpPriority() { -+ this.taskPriority = Priority.HIGH; ++ bumpPriority(Priority.HIGH); ++ } ++ ++ void bumpPriority(Priority newPriority) { ++ this.taskPriority = newPriority; + PriorityQueuedExecutor.PendingTask loadTask = this.loadTask; + PriorityQueuedExecutor.PendingTask genTask = this.genTask; + if (loadTask != null) { -+ loadTask.bumpPriority(); ++ loadTask.bumpPriority(newPriority); + } + if (genTask != null) { -+ genTask.bumpPriority(); ++ genTask.bumpPriority(newPriority); + } + } +