From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: MrHua269 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{ +}