diff options
Diffstat (limited to 'patches/server/0140-Do-not-submit-profile-lookups-to-worldgen-threads.patch')
-rw-r--r-- | patches/server/0140-Do-not-submit-profile-lookups-to-worldgen-threads.patch | 77 |
1 files changed, 77 insertions, 0 deletions
diff --git a/patches/server/0140-Do-not-submit-profile-lookups-to-worldgen-threads.patch b/patches/server/0140-Do-not-submit-profile-lookups-to-worldgen-threads.patch new file mode 100644 index 0000000000..b2385e0d42 --- /dev/null +++ b/patches/server/0140-Do-not-submit-profile-lookups-to-worldgen-threads.patch @@ -0,0 +1,77 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf <[email protected]> +Date: Sun, 8 Aug 2021 16:26:46 -0700 +Subject: [PATCH] Do not submit profile lookups to worldgen threads + +They block. On network I/O. + +If enough tasks are submitted the server will eventually stall +out due to a sync load, as the worldgen threads will be +stalling on profile lookups. + +diff --git a/src/main/java/net/minecraft/Util.java b/src/main/java/net/minecraft/Util.java +index 168ab805ecc48dd55db90eb7fe1c56fda3f2776c..336a26733b5bf73455f8ec10347c1e08b8e866f7 100644 +--- a/src/main/java/net/minecraft/Util.java ++++ b/src/main/java/net/minecraft/Util.java +@@ -81,6 +81,22 @@ public class Util { + private static final AtomicInteger WORKER_COUNT = new AtomicInteger(1); + private static final ExecutorService BOOTSTRAP_EXECUTOR = makeExecutor("Bootstrap"); + private static final ExecutorService BACKGROUND_EXECUTOR = makeExecutor("Main"); ++ // Paper start - don't submit BLOCKING PROFILE LOOKUPS to the world gen thread ++ public static final ExecutorService PROFILE_EXECUTOR = Executors.newFixedThreadPool(2, new java.util.concurrent.ThreadFactory() { ++ ++ private final AtomicInteger count = new AtomicInteger(); ++ ++ @Override ++ public Thread newThread(Runnable run) { ++ Thread ret = new Thread(run); ++ ret.setName("Profile Lookup Executor #" + this.count.getAndIncrement()); ++ ret.setUncaughtExceptionHandler((Thread thread, Throwable throwable) -> { ++ LOGGER.error("Uncaught exception in thread " + thread.getName(), throwable); ++ }); ++ return ret; ++ } ++ }); ++ // Paper end - don't submit BLOCKING PROFILE LOOKUPS to the world gen thread + private static final ExecutorService IO_POOL = makeIoExecutor(); + private static final DateTimeFormatter FILENAME_DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH.mm.ss", Locale.ROOT); + public static TimeSource.NanoTimeSource timeSource = System::nanoTime; +diff --git a/src/main/java/net/minecraft/server/players/GameProfileCache.java b/src/main/java/net/minecraft/server/players/GameProfileCache.java +index 376845f5a25a348e76193fac5c047b0ba2fb080f..2a0cf0a8a79c09566c598197fc6f8c447d4bbd72 100644 +--- a/src/main/java/net/minecraft/server/players/GameProfileCache.java ++++ b/src/main/java/net/minecraft/server/players/GameProfileCache.java +@@ -181,7 +181,7 @@ public class GameProfileCache { + } else { + this.requests.put(username, CompletableFuture.supplyAsync(() -> { + return this.get(username); +- }, Util.backgroundExecutor()).whenCompleteAsync((optional, throwable) -> { ++ }, Util.PROFILE_EXECUTOR).whenCompleteAsync((optional, throwable) -> { // Paper - not a good idea to use BLOCKING OPERATIONS on the worldgen executor + this.requests.remove(username); + }, this.executor).whenCompleteAsync((optional, throwable) -> { + consumer.accept(optional); +diff --git a/src/main/java/net/minecraft/world/level/block/entity/SkullBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/SkullBlockEntity.java +index 0c7e29b589ab106013d979a20edc415b4b32a677..c5d5d90d10b30f30d1262367b3d75df43fbdb231 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/SkullBlockEntity.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/SkullBlockEntity.java +@@ -120,7 +120,7 @@ public class SkullBlockEntity extends BlockEntity { + public static void updateGameprofile(@Nullable GameProfile owner, Consumer<GameProfile> callback) { + if (owner != null && !StringUtil.isNullOrEmpty(owner.getName()) && (!owner.isComplete() || !owner.getProperties().containsKey("textures")) && profileCache != null && sessionService != null) { + profileCache.getAsync(owner.getName(), (profile) -> { +- Util.backgroundExecutor().execute(() -> { ++ Util.PROFILE_EXECUTOR.execute(() -> { // Paper - not a good idea to use BLOCKING OPERATIONS on the worldgen executor + Util.ifElse(profile, (profilex) -> { + Property property = Iterables.getFirst(profilex.getProperties().get("textures"), (Property)null); + if (property == null) { +diff --git a/src/main/java/org/bukkit/craftbukkit/profile/CraftPlayerProfile.java b/src/main/java/org/bukkit/craftbukkit/profile/CraftPlayerProfile.java +index 2d49bd6f3f017d43dfaa23cedf35040b64bcdcf8..9edc5e73819e0b55372f77c5e292eece74d837c7 100644 +--- a/src/main/java/org/bukkit/craftbukkit/profile/CraftPlayerProfile.java ++++ b/src/main/java/org/bukkit/craftbukkit/profile/CraftPlayerProfile.java +@@ -121,7 +121,7 @@ public final class CraftPlayerProfile implements PlayerProfile { + + @Override + public CompletableFuture<PlayerProfile> update() { +- return CompletableFuture.supplyAsync(this::getUpdatedProfile, Util.backgroundExecutor()); ++ return CompletableFuture.supplyAsync(this::getUpdatedProfile, Util.PROFILE_EXECUTOR); // Paper - not a good idea to use BLOCKING OPERATIONS on the worldgen executor + } + + private CraftPlayerProfile getUpdatedProfile() { |