278 lines
13 KiB
Diff
278 lines
13 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: MrHua269 <wangxyper@163.com>
|
|
Date: Wed, 18 Sep 2024 23:10:47 +0800
|
|
Subject: [PATCH] Add experimental config for folia scheduling issue fixing
|
|
|
|
|
|
diff --git a/src/main/java/io/papermc/paper/threadedregions/RegionizedTaskQueue.java b/src/main/java/io/papermc/paper/threadedregions/RegionizedTaskQueue.java
|
|
index a1e1782d87403ca8934d37361be7ba66ddba133f..8177cd855c7529ab0740877045835c00d13f4fcc 100644
|
|
--- a/src/main/java/io/papermc/paper/threadedregions/RegionizedTaskQueue.java
|
|
+++ b/src/main/java/io/papermc/paper/threadedregions/RegionizedTaskQueue.java
|
|
@@ -48,8 +48,29 @@ public final class RegionizedTaskQueue {
|
|
|
|
public PrioritisedExecutor.PrioritisedTask queueChunkTask(final ServerLevel world, final int chunkX, final int chunkZ,
|
|
final Runnable run, final PrioritisedExecutor.Priority priority) {
|
|
- final PrioritisedExecutor.PrioritisedTask ret = this.createChunkTask(world, chunkX, chunkZ, run, priority);
|
|
- ret.queue();
|
|
+ PrioritisedExecutor.PrioritisedTask ret = new PrioritisedQueue.ChunkBasedPriorityTask(world.taskQueueRegionData, chunkX, chunkZ, true, run, priority, me.earthme.luminol.config.modules.experiment.FoliaTaskQueueFixConfig.enabled); // Luminol
|
|
+ // Luminol start
|
|
+ if (!me.earthme.luminol.config.modules.experiment.FoliaTaskQueueFixConfig.enabled){
|
|
+ ret.queue();
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ for (;;) {
|
|
+ boolean result;
|
|
+
|
|
+ try {
|
|
+ result = ret.queue();
|
|
+ }catch (me.earthme.luminol.utils.TaskCancelledException ignored) {
|
|
+ result = true;
|
|
+ }
|
|
+
|
|
+ if (result) {
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ ret = new PrioritisedQueue.ChunkBasedPriorityTask(world.taskQueueRegionData, chunkX, chunkZ, true, run, priority, me.earthme.luminol.config.modules.experiment.FoliaTaskQueueFixConfig.enabled);
|
|
+ }
|
|
+ // Luminol end
|
|
return ret;
|
|
}
|
|
|
|
@@ -60,8 +81,29 @@ public final class RegionizedTaskQueue {
|
|
|
|
public PrioritisedExecutor.PrioritisedTask queueTickTaskQueue(final ServerLevel world, final int chunkX, final int chunkZ,
|
|
final Runnable run, final PrioritisedExecutor.Priority priority) {
|
|
- final PrioritisedExecutor.PrioritisedTask ret = this.createTickTaskQueue(world, chunkX, chunkZ, run, priority);
|
|
- ret.queue();
|
|
+ PrioritisedExecutor.PrioritisedTask ret = new PrioritisedQueue.ChunkBasedPriorityTask(world.taskQueueRegionData, chunkX, chunkZ, false, run, priority, me.earthme.luminol.config.modules.experiment.FoliaTaskQueueFixConfig.enabled); // Luminol
|
|
+ // Luminol start
|
|
+ if (!me.earthme.luminol.config.modules.experiment.FoliaTaskQueueFixConfig.enabled){
|
|
+ ret.queue();
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ for (;;) {
|
|
+ boolean result;
|
|
+
|
|
+ try {
|
|
+ result = ret.queue();
|
|
+ }catch (me.earthme.luminol.utils.TaskCancelledException ignored) {
|
|
+ result = true;
|
|
+ }
|
|
+
|
|
+ if (result) {
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ ret = new PrioritisedQueue.ChunkBasedPriorityTask(world.taskQueueRegionData, chunkX, chunkZ, false, run, priority, me.earthme.luminol.config.modules.experiment.FoliaTaskQueueFixConfig.enabled);
|
|
+ }
|
|
+ // Luminol end
|
|
return ret;
|
|
}
|
|
|
|
@@ -136,6 +178,81 @@ public final class RegionizedTaskQueue {
|
|
}
|
|
}
|
|
|
|
+ // Luminol start - Try fixing scheduling
|
|
+ private final java.util.concurrent.locks.Lock referenceCountersLock = new java.util.concurrent.locks.ReentrantLock(true);
|
|
+
|
|
+ private void luminolReplaced$decrementReference(final AtomicLong reference, final long coord) {
|
|
+ final int chunkX = CoordinateUtils.getChunkX(coord);
|
|
+ final int chunkZ = CoordinateUtils.getChunkZ(coord);
|
|
+
|
|
+ this.referenceCountersLock.lock();
|
|
+ boolean shouldRemove = false;
|
|
+ try {
|
|
+ final long val = reference.decrementAndGet();
|
|
+ if (val == 0L) {
|
|
+ shouldRemove = this.referenceCounters.remove(coord, reference) == reference;
|
|
+ } else if (val < 0L) {
|
|
+ throw new IllegalStateException("Reference count < 0: " + val);
|
|
+ }
|
|
+ }finally {
|
|
+ this.referenceCountersLock.unlock();
|
|
+ }
|
|
+
|
|
+ if (shouldRemove) {
|
|
+ final ca.spottedleaf.concurrentutil.lock.ReentrantAreaLock.Node ticketLock = this.world.moonrise$getChunkTaskScheduler().chunkHolderManager.ticketLockArea.lock(chunkX, chunkZ);
|
|
+ try {
|
|
+ WorldRegionTaskData.this.removeTicket(coord);
|
|
+ } finally {
|
|
+ this.world.moonrise$getChunkTaskScheduler().chunkHolderManager.ticketLockArea.unlock(ticketLock);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private AtomicLong luminolReplaced$incrementReference(final long coord){
|
|
+ final AtomicLong result;
|
|
+
|
|
+ final int chunkX = CoordinateUtils.getChunkX(coord);
|
|
+ final int chunkZ = CoordinateUtils.getChunkZ(coord);
|
|
+
|
|
+ final boolean processTicketUpdates;
|
|
+
|
|
+ final AtomicLong replace = new AtomicLong(1L);
|
|
+ boolean addTicket = false;
|
|
+
|
|
+ this.referenceCountersLock.lock();
|
|
+ try {
|
|
+ final AtomicLong valueInMap = this.referenceCounters.putIfAbsent(coord, replace);
|
|
+
|
|
+ if (valueInMap == null) {
|
|
+ result = replace;
|
|
+ addTicket = true;
|
|
+ processTicketUpdates = true;
|
|
+ }else {
|
|
+ processTicketUpdates = false;
|
|
+ valueInMap.getAndIncrement();
|
|
+ result = valueInMap;
|
|
+ }
|
|
+ }finally {
|
|
+ this.referenceCountersLock.unlock();
|
|
+ }
|
|
+
|
|
+ final ca.spottedleaf.concurrentutil.lock.ReentrantAreaLock.Node ticketLock = this.world.moonrise$getChunkTaskScheduler().chunkHolderManager.ticketLockArea.lock(chunkX, chunkZ);
|
|
+ try {
|
|
+ if (addTicket) {
|
|
+ this.addTicket(coord);
|
|
+ }
|
|
+ } finally {
|
|
+ this.world.moonrise$getChunkTaskScheduler().chunkHolderManager.ticketLockArea.unlock(ticketLock);
|
|
+ }
|
|
+
|
|
+ if (processTicketUpdates) {
|
|
+ this.processTicketUpdates(coord);
|
|
+ }
|
|
+
|
|
+ return result;
|
|
+ }
|
|
+ // Luminol end
|
|
+
|
|
private AtomicLong incrementReference(final long coord) {
|
|
final AtomicLong ret = this.referenceCounters.get(coord);
|
|
if (ret != null) {
|
|
@@ -428,7 +545,13 @@ public final class RegionizedTaskQueue {
|
|
try {
|
|
task.executeInternal();
|
|
} finally {
|
|
- task.world.decrementReference(referenceCounter, task.sectionLowerLeftCoord);
|
|
+ // Luminol start - Try fixing schedule
|
|
+ if (me.earthme.luminol.config.modules.experiment.FoliaTaskQueueFixConfig.enabled) {
|
|
+ task.world.luminolReplaced$decrementReference(referenceCounter, task.sectionLowerLeftCoord);
|
|
+ }else {
|
|
+ task.world.decrementReference(referenceCounter, task.sectionLowerLeftCoord);
|
|
+ }
|
|
+ // Luminol end
|
|
}
|
|
|
|
return true;
|
|
@@ -449,6 +572,13 @@ public final class RegionizedTaskQueue {
|
|
private Runnable run;
|
|
private volatile PrioritisedExecutor.Priority priority;
|
|
private static final VarHandle PRIORITY_HANDLE = ConcurrentUtil.getVarHandle(ChunkBasedPriorityTask.class, "priority", PrioritisedExecutor.Priority.class);
|
|
+ private boolean softThrowWhenCancelled = false; // Luminol
|
|
+
|
|
+ ChunkBasedPriorityTask(final WorldRegionTaskData world, final int chunkX, final int chunkZ, final boolean isChunkTask,
|
|
+ final Runnable run, final PrioritisedExecutor.Priority priority, boolean sft) { // Luminol
|
|
+ this(world, chunkX, chunkZ, isChunkTask, run, priority);
|
|
+ this.softThrowWhenCancelled = sft;
|
|
+ }
|
|
|
|
ChunkBasedPriorityTask(final WorldRegionTaskData world, final int chunkX, final int chunkZ, final boolean isChunkTask,
|
|
final Runnable run, final PrioritisedExecutor.Priority priority) {
|
|
@@ -533,7 +663,13 @@ public final class RegionizedTaskQueue {
|
|
}
|
|
} finally {
|
|
if (curr != REFERENCE_COUNTER_NOT_SET) {
|
|
- this.world.decrementReference(curr, this.sectionLowerLeftCoord);
|
|
+ // Luminol start - Try fixing scheduling
|
|
+ if (me.earthme.luminol.config.modules.experiment.FoliaTaskQueueFixConfig.enabled) {
|
|
+ this.world.luminolReplaced$decrementReference(curr, this.sectionLowerLeftCoord);
|
|
+ }else {
|
|
+ this.world.decrementReference(curr, this.sectionLowerLeftCoord);
|
|
+ }
|
|
+ // Luminol end
|
|
}
|
|
}
|
|
|
|
@@ -547,10 +683,16 @@ public final class RegionizedTaskQueue {
|
|
return false;
|
|
}
|
|
|
|
- final AtomicLong referenceCounter = this.world.incrementReference(this.sectionLowerLeftCoord);
|
|
+ final AtomicLong referenceCounter = me.earthme.luminol.config.modules.experiment.FoliaTaskQueueFixConfig.enabled ? this.world.luminolReplaced$incrementReference(this.sectionLowerLeftCoord) : this.world.incrementReference(this.sectionLowerLeftCoord);
|
|
if (this.compareAndExchangeReferenceCounter(REFERENCE_COUNTER_NOT_SET, referenceCounter) != REFERENCE_COUNTER_NOT_SET) {
|
|
// we don't expect race conditions here, so it is OK if we have to needlessly reference count
|
|
- this.world.decrementReference(referenceCounter, this.sectionLowerLeftCoord);
|
|
+ // Luminol start - Try fixing scheduling
|
|
+ if (me.earthme.luminol.config.modules.experiment.FoliaTaskQueueFixConfig.enabled) {
|
|
+ this.world.luminolReplaced$decrementReference(referenceCounter, this.sectionLowerLeftCoord);
|
|
+ }else {
|
|
+ this.world.decrementReference(referenceCounter, this.sectionLowerLeftCoord);
|
|
+ }
|
|
+ // Luminol end
|
|
return false;
|
|
}
|
|
|
|
@@ -574,6 +716,11 @@ public final class RegionizedTaskQueue {
|
|
// the task never could be polled from the queue, so we return false
|
|
// don't decrement reference count, as we were certainly cancelled by another thread, which
|
|
// will decrement the reference count
|
|
+ // Luminol start
|
|
+ if (this.softThrowWhenCancelled) {
|
|
+ throw new me.earthme.luminol.utils.TaskCancelledException();
|
|
+ }
|
|
+ // Luminol end
|
|
return false;
|
|
}
|
|
|
|
@@ -584,6 +731,9 @@ public final class RegionizedTaskQueue {
|
|
// we were cancelled
|
|
// don't decrement reference count, as we were certainly cancelled by another thread, which
|
|
// will decrement the reference count
|
|
+ if (this.softThrowWhenCancelled) {
|
|
+ throw new me.earthme.luminol.utils.TaskCancelledException();
|
|
+ }
|
|
return false;
|
|
}
|
|
|
|
diff --git a/src/main/java/me/earthme/luminol/config/modules/experiment/FoliaTaskQueueFixConfig.java b/src/main/java/me/earthme/luminol/config/modules/experiment/FoliaTaskQueueFixConfig.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..47e0339ecb0d96010c41e739c66f3d024aad95eb
|
|
--- /dev/null
|
|
+++ b/src/main/java/me/earthme/luminol/config/modules/experiment/FoliaTaskQueueFixConfig.java
|
|
@@ -0,0 +1,20 @@
|
|
+package me.earthme.luminol.config.modules.experiment;
|
|
+
|
|
+import me.earthme.luminol.config.ConfigInfo;
|
|
+import me.earthme.luminol.config.EnumConfigCategory;
|
|
+import me.earthme.luminol.config.IConfigModule;
|
|
+
|
|
+public class FoliaTaskQueueFixConfig implements IConfigModule {
|
|
+ @ConfigInfo(baseName = "enabled")
|
|
+ public static boolean enabled = false;
|
|
+
|
|
+ @Override
|
|
+ public EnumConfigCategory getCategory() {
|
|
+ return EnumConfigCategory.EXPERIMENT;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public String getBaseName() {
|
|
+ return "queue_until_task_queued";
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/me/earthme/luminol/utils/TaskCancelledException.java b/src/main/java/me/earthme/luminol/utils/TaskCancelledException.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..c7b55489f4d3a57320b0963e45cd1c87e6c0ec88
|
|
--- /dev/null
|
|
+++ b/src/main/java/me/earthme/luminol/utils/TaskCancelledException.java
|
|
@@ -0,0 +1,4 @@
|
|
+package me.earthme.luminol.utils;
|
|
+
|
|
+public class TaskCancelledException extends RuntimeException{
|
|
+}
|