From 5e1a37f1e3c7d96e222876e5f3d5d61200774b83 Mon Sep 17 00:00:00 2001 From: Arbousier1 Date: Sat, 18 Jul 2026 11:27:16 +0800 Subject: [PATCH] perf(runtime): cache Folia global and region scheduler instances MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit globalRegionScheduler() and regionScheduler() previously invoked a reflective method lookup on plugin.getServer() on every call. On Folia, these return stable singleton schedulers that do not change for the lifetime of the server. Cache the resolved scheduler in a volatile field on first successful lookup so subsequent calls skip the reflective invokeNoArgs path entirely. In the benchmark Folia burst (84 tasks), this eliminates 19 reflective scheduler lookups per invocation (4 runGlobal + 16 runRegion, minus the first call each that populates the cache). On Paper, where these methods do not exist and invokeNoArgs returns null, the cache stays empty and the behavior is unchanged — null is never cached so the lookup still runs each time, preserving the existing fallback-to-BukkitScheduler semantics. entityScheduler(Entity) is not cached because the target entity varies per call and there is no stable key to cache on. --- .../mahjong/runtime/ServerScheduler.java | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/main/java/top/ellan/mahjong/runtime/ServerScheduler.java b/src/main/java/top/ellan/mahjong/runtime/ServerScheduler.java index 7a984b0..602917e 100644 --- a/src/main/java/top/ellan/mahjong/runtime/ServerScheduler.java +++ b/src/main/java/top/ellan/mahjong/runtime/ServerScheduler.java @@ -90,6 +90,8 @@ public boolean isCancelled() { }; private final Plugin plugin; + private volatile Object cachedGlobalRegionScheduler; + private volatile Object cachedRegionScheduler; public ServerScheduler(Plugin plugin) { this.plugin = Objects.requireNonNull(plugin, "plugin"); @@ -313,11 +315,27 @@ public PluginTask removeEntity(Entity entity, long delayTicks) { } private Object globalRegionScheduler() { - return this.invokeNoArgs(this.plugin.getServer(), GET_GLOBAL_REGION_SCHEDULER); + Object cached = this.cachedGlobalRegionScheduler; + if (cached != null) { + return cached; + } + Object resolved = this.invokeNoArgs(this.plugin.getServer(), GET_GLOBAL_REGION_SCHEDULER); + if (resolved != null) { + this.cachedGlobalRegionScheduler = resolved; + } + return resolved; } private Object regionScheduler() { - return this.invokeNoArgs(this.plugin.getServer(), GET_REGION_SCHEDULER); + Object cached = this.cachedRegionScheduler; + if (cached != null) { + return cached; + } + Object resolved = this.invokeNoArgs(this.plugin.getServer(), GET_REGION_SCHEDULER); + if (resolved != null) { + this.cachedRegionScheduler = resolved; + } + return resolved; } private Object entityScheduler(Entity entity) {