From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: NanaChiyo0721 Date: Wed, 29 Jul 2026 18:39:56 +0800 Subject: [PATCH] RegionizedTaskQueue queue TTL optimization diff --git a/io/papermc/paper/threadedregions/RegionizedTaskQueue.java b/io/papermc/paper/threadedregions/RegionizedTaskQueue.java index 037697e6364c73057b1fbac354bd78d8bf35bc7b..0e88bc2776615f8e3e1e6a05c5ffb8f791d49917 100644 --- a/io/papermc/paper/threadedregions/RegionizedTaskQueue.java +++ b/io/papermc/paper/threadedregions/RegionizedTaskQueue.java @@ -23,6 +23,7 @@ import java.util.concurrent.atomic.AtomicLong; public final class RegionizedTaskQueue { private static final TicketType TASK_QUEUE_TICKET = ChunkSystemTicketType.create("task_queue_ticket", Long::compareTo); + private static final long QUEUE_MAX_TTL_TICKS = 5L; // Shiroha - RegionizedTaskQueue queue TTL optimization public PrioritisedExecutor.PrioritisedTask createChunkTask(final ServerLevel world, final int chunkX, final int chunkZ, final Runnable run) { @@ -155,6 +156,58 @@ public final class RegionizedTaskQueue { } } + // Shiroha start - RegionizedTaskQueue queue TTL optimization + public void tickQueueReferenceTTL() { + final ThreadedRegionizer.ThreadedRegion currentRegion + = io.papermc.paper.threadedregions.TickRegionScheduler.getCurrentRegion(); + if (currentRegion == null) { + return; + } + + final ReferenceCountData[] toRemoveTicket = new ReferenceCountData[1]; + + for (ConcurrentChainedLong2ReferenceHashTable.TableEntry counterEntry : this.referenceCounters.entrySet()) { + final long coord = counterEntry.getKey(); + final ReferenceCountData counterData = counterEntry.getValue(); + + // only tick for our region + if (currentRegion == this.world.regioniser.getRegionAtUnsynchronised(CoordinateUtils.getChunkX(coord), CoordinateUtils.getChunkZ(coord))) { + long curr = counterData.referenceTTL.get(); + // successfully decreased ttl + if (curr == (curr = counterData.referenceTTL.compareAndExchange(curr, curr - 1))) { + if (counterData.referenceCount.get() != 0L) { + // still has reference, pump back + counterData.referenceTTL.set(QUEUE_MAX_TTL_TICKS); + continue; + } + + // dead + if (curr <= 0) { + // parsed from decrementReference + this.referenceCounters.computeIfPresent(coord, (final long keyInMap, final ReferenceCountData valueInMap) -> { + // might be increased again + if (valueInMap.referenceCount.get() != 0L) { + valueInMap.referenceTTL.set(QUEUE_MAX_TTL_TICKS); // still has reference, pump back + return valueInMap; // directly, the ttl was already charged in add logic + } + + // note: valueInMap may not be referenceCountData + toRemoveTicket[0] = valueInMap; + + return null; + }); + + if (toRemoveTicket[0] != null) { + this.removeTicket(coord, toRemoveTicket[0].id); + toRemoveTicket[0] = null; + } + } + } + } + } + } + // Shiroha end - RegionizedTaskQueue queue TTL optimization + private void decrementReference(final ReferenceCountData referenceCountData, final long coord) { if (!referenceCountData.decreaseReferenceCount()) { return; @@ -212,9 +265,10 @@ public final class RegionizedTaskQueue { private final long id = ID_GENERATOR.getAndIncrement(); public final AtomicLong referenceCount = new AtomicLong(1L); + public final AtomicLong referenceTTL = new AtomicLong(QUEUE_MAX_TTL_TICKS); // Shiroha - RegionizedTaskQueue queue TTL optimization public volatile boolean addedTicket; - // returns false if reference count is 0, otherwise increments ref count + // returns false if reference count or ttl is 0, otherwise increments ref count // Shiroha - RegionizedTaskQueue queue TTL optimization public boolean addCount() { int failures = 0; for (long curr = this.referenceCount.get();;) { @@ -227,6 +281,27 @@ public final class RegionizedTaskQueue { } if (curr == (curr = this.referenceCount.compareAndExchange(curr, curr + 1L))) { + // Shiroha start - RegionizedTaskQueue queue TTL optimization + // now force charge back the ttl to max + int ttlFailures = 0; + for (long currTTL = this.referenceTTL.get();;) { + for (int i = 0; i < ttlFailures; i++) { + Thread.onSpinWait(); + } + + // add failed, rollback (ttl reached) + if (currTTL <= 0) { + this.referenceCount.decrementAndGet(); // revert the addition + return false; + } + + if (currTTL == (currTTL = this.referenceTTL.compareAndExchange(currTTL, QUEUE_MAX_TTL_TICKS))) { + break; + } + + ++ttlFailures; + } + // Shiroha end - RegionizedTaskQueue queue TTL optimization return true; } @@ -234,11 +309,11 @@ public final class RegionizedTaskQueue { } } - // returns true if new reference count is 0 + // returns true if new reference count and ttl is 0 // Shiroha - RegionizedTaskQueue queue TTL optimization public boolean decreaseReferenceCount() { final long res = this.referenceCount.decrementAndGet(); if (res >= 0L) { - return res == 0L; + return res == 0L && this.referenceTTL.get() <= 0L; // Shiroha - RegionizedTaskQueue queue TTL optimization } else { throw new IllegalStateException("Negative reference count"); } diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java index d4cb160e285a807597523de840a4d1c4f9fced27..a7100db6d1ce6434cd9ecfdff554a4ebcfde1e66 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java @@ -1736,6 +1736,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop