From 1291aa829a3ac95ef1db5fb3f12fa61f0c354906 Mon Sep 17 00:00:00 2001 From: Octavia Togami Date: Sat, 21 Aug 2021 20:45:40 -0700 Subject: [PATCH] Replace ThreadLocal with ConcurrentHashMap in CommandSourceStack (#6325) This object is created so often that it likely creates problems with the ThreadLocalMap because the weak references can't be cleaned up fast enough. This has manifest as lag seemingly caused by WorldEdit: https://github.com/EngineHub/WorldEdit/issues/1668 --- ...-Vanilla-Command-permission-checking.patch | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/patches/server/Thread-Safe-Vanilla-Command-permission-checking.patch b/patches/server/Thread-Safe-Vanilla-Command-permission-checking.patch index 807d3f1593..0ba62f8040 100644 --- a/patches/server/Thread-Safe-Vanilla-Command-permission-checking.patch +++ b/patches/server/Thread-Safe-Vanilla-Command-permission-checking.patch @@ -17,11 +17,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (source instanceof CommandSourceStack) { try { - ((CommandSourceStack) source).currentCommand = this; -+ ((CommandSourceStack) source).currentCommand.set(this); // Paper ++ ((CommandSourceStack) source).currentCommand.put(Thread.currentThread(), this); // Paper return this.requirement.test(source); } finally { - ((CommandSourceStack) source).currentCommand = null; -+ ((CommandSourceStack) source).currentCommand.set(null); // Paper ++ ((CommandSourceStack) source).currentCommand.remove(Thread.currentThread()); // Paper } } // CraftBukkit end @@ -29,12 +29,23 @@ diff --git a/src/main/java/net/minecraft/commands/CommandSourceStack.java b/src/ index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/commands/CommandSourceStack.java +++ b/src/main/java/net/minecraft/commands/CommandSourceStack.java +@@ -0,0 +0,0 @@ import com.mojang.brigadier.suggestion.Suggestions; + import com.mojang.brigadier.suggestion.SuggestionsBuilder; + import java.util.Collection; + import java.util.Iterator; ++import java.util.Map; + import java.util.Set; + import java.util.concurrent.CompletableFuture; ++import java.util.concurrent.ConcurrentHashMap; + import java.util.function.BinaryOperator; + import java.util.stream.Stream; + import javax.annotation.Nullable; @@ -0,0 +0,0 @@ public class CommandSourceStack implements SharedSuggestionProvider, com.destroy private final ResultConsumer consumer; private final EntityAnchorArgument.Anchor anchor; private final Vec2 rotation; - public volatile CommandNode currentCommand; // CraftBukkit -+ public ThreadLocal currentCommand = new ThreadLocal<>(); // CraftBukkit // Paper ++ public Map currentCommand = new ConcurrentHashMap<>(); // CraftBukkit // Paper public CommandSourceStack(CommandSource output, Vec3 pos, Vec2 rot, ServerLevel world, int level, String name, Component displayName, MinecraftServer server, @Nullable Entity entity) { this(output, pos, rot, world, level, name, displayName, server, entity, false, (commandcontext, flag, j) -> { @@ -44,7 +55,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // CraftBukkit start - CommandNode currentCommand = this.currentCommand; + // Paper start - fix concurrency issue -+ CommandNode currentCommand = this.currentCommand.get(); ++ CommandNode currentCommand = this.currentCommand.get(Thread.currentThread()); if (currentCommand != null) { return this.hasPermission(level, org.bukkit.craftbukkit.command.VanillaCommandWrapper.getPermission(currentCommand)); + // Paper end