From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: wangxyper Date: Wed, 11 Jan 2023 10:10:12 +0800 Subject: [PATCH] Hearse: Add worker command Original license: MIT Original project: https://github.com/NaturalCodeClub/HearseRewrite diff --git a/src/main/java/co/earthme/hearse/Hearse.java b/src/main/java/co/earthme/hearse/Hearse.java new file mode 100644 index 0000000000000000000000000000000000000000..79116449c221e0748e938f40366af03f93a4ab9f --- /dev/null +++ b/src/main/java/co/earthme/hearse/Hearse.java @@ -0,0 +1,25 @@ +package co.earthme.hearse; + +import co.earthme.hearse.commands.WorkerCommand; +import co.earthme.hearse.server.ServerEntityTickHook; +import co.earthme.hearse.workers.WorkerThreadPoolManager; +import net.minecraft.server.MinecraftServer; + +public class Hearse { + private static final WorkerThreadPoolManager workerManager = new WorkerThreadPoolManager(); + + public static void initAll(){ + HearseConfig.init(); + ServerEntityTickHook.init(); + MinecraftServer.getServer().server.getCommandMap().register("workers","hearse",new WorkerCommand()); + } + + public static void onServerStop(){ + HearseConfig.save(); + workerManager.shutdownAllNow(); + } + + public static WorkerThreadPoolManager getWorkerManager() { + return workerManager; + } +} diff --git a/src/main/java/co/earthme/hearse/commands/WorkerCommand.java b/src/main/java/co/earthme/hearse/commands/WorkerCommand.java new file mode 100644 index 0000000000000000000000000000000000000000..9bf8e0bdfed9a30a302c6369a727e8bb394b4670 --- /dev/null +++ b/src/main/java/co/earthme/hearse/commands/WorkerCommand.java @@ -0,0 +1,72 @@ +package co.earthme.hearse.commands; + +import co.earthme.hearse.Hearse; +import co.earthme.hearse.concurrent.WorkerThreadPoolExecutor; +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.jetbrains.annotations.NotNull; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class WorkerCommand extends Command { + public WorkerCommand() { + super("workers"); + this.setPermission("hearse.commands.workers"); + this.setDescription("You can see or edit the server workers by using this command"); + this.setUsage("/workers "); + } + + @Override + public @NotNull List tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) throws IllegalArgumentException { + final List ret = new ArrayList<>(); + if (args.length == 1){ + ret.add("status"); + ret.add("setThreadCount"); + ret.add("forceStop"); + } + if (args.length == 2){ + for (Map.Entry entry : Hearse.getWorkerManager().getManagedWorkers().entrySet()){ + ret.add(entry.getKey()); + } + } + return ret; + } + + @Override + public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) { + if (args.length >= 2){ + final String action = args[0]; + final String workerName = args[1]; + final WorkerThreadPoolExecutor searchedWorker = Hearse.getWorkerManager().getTargetWorker(workerName); + if (searchedWorker == null){ + sender.sendMessage(ChatColor.RED+"Target worker not found!"); + return true; + } + switch (action){ + case "status": + sender.sendMessage(ChatColor.GREEN+"Worker: "+workerName+" Status:"+ searchedWorker); + break; + case "setThreadCount": + if (args.length == 3){ + try { + searchedWorker.setCorePoolSize(Integer.parseInt(args[2])); + sender.sendMessage(ChatColor.GREEN+"Finished!"); + }catch (NumberFormatException e){ + sender.sendMessage(ChatColor.RED+"Please supply a integer!"); + } + }else{ + sender.sendMessage(ChatColor.RED+"Please supply a integer!"); + } + break; + case "forceStop": + searchedWorker.shutdownNow(); + sender.sendMessage(ChatColor.YELLOW+"Worker "+workerName+" has been stopped!"); + break; + } + return true; + } + return false; + } +} diff --git a/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java b/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java index cf7ee6fda90fa0f6827dc2d1c584151e3b99fb38..18c1f6ee4d4fc422fb2aa41483ce145d34fa39b1 100644 --- a/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java +++ b/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java @@ -1,14 +1,13 @@ package co.earthme.hearse.server; +import co.earthme.hearse.Hearse; import co.earthme.hearse.HearseConfig; -import co.earthme.hearse.concurrent.WorkerThread; import co.earthme.hearse.concurrent.WorkerThreadFactory; import co.earthme.hearse.concurrent.WorkerThreadPoolExecutor; import co.earthme.hearse.concurrent.threadfactory.DefaultWorkerFactory; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; - import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; @@ -27,14 +26,6 @@ public class ServerEntityTickHook { worker.execute(task); } - public static void onServerStop() throws InterruptedException { - if (!asyncEntityEnabled){ - return; - } - worker.shutdown(); - while (!worker.awaitTermination(100,TimeUnit.MILLISECONDS)); - } - public static void init(){ boolean asyncEntityEnabled1 = HearseConfig.getBoolean("optimizations.enable-async-entity",true); final int workerCount = HearseConfig.getInt("workers.async-entity-worker-count",Runtime.getRuntime().availableProcessors()); @@ -47,6 +38,7 @@ public class ServerEntityTickHook { new LinkedBlockingQueue<>(), defFactory ); + Hearse.getWorkerManager().addWorker("entity",worker); } asyncEntityEnabled = asyncEntityEnabled1; } diff --git a/src/main/java/co/earthme/hearse/workers/WorkerThreadPoolManager.java b/src/main/java/co/earthme/hearse/workers/WorkerThreadPoolManager.java new file mode 100644 index 0000000000000000000000000000000000000000..90dd97491c0313bee031b81aa43fe6df3dda5b4f --- /dev/null +++ b/src/main/java/co/earthme/hearse/workers/WorkerThreadPoolManager.java @@ -0,0 +1,84 @@ +package co.earthme.hearse.workers; + +import co.earthme.hearse.concurrent.WorkerThreadPoolExecutor; +import com.google.common.collect.Maps; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +public class WorkerThreadPoolManager { + private final Map managedWorkers = Maps.newConcurrentMap(); + + public void addWorker(String bound,WorkerThreadPoolExecutor worker){ + this.managedWorkers.put(bound,worker); + } + + public void shutdownAll() throws InterruptedException { + for (WorkerThreadPoolExecutor worker : this.managedWorkers.values()){ + worker.shutdown(); + while (worker.awaitTermination(100, TimeUnit.MILLISECONDS)) {} + } + } + + public Map getManagedWorkers() { + return Maps.newHashMap(this.managedWorkers); + } + + public WorkerThreadPoolExecutor getTargetWorker(String bound){ + return this.managedWorkers.get(bound); + } + + public Map> shutdownAllNow(){ + final Map> ret = Maps.newHashMap(); + for (Map.Entry entry : this.managedWorkers.entrySet()){ + final String workerName = entry.getKey(); + final WorkerThreadPoolExecutor worker = entry.getValue(); + try { + final List taskNotRunned = worker.shutdownNow(); + while (worker.awaitTermination(1,TimeUnit.MILLISECONDS)){ + + } + ret.put(workerName,taskNotRunned); + }catch (Exception e){ + e.printStackTrace(); + } + } + return ret; + } + + public Map> shutdownAllNow(long timeOutCount){ + final Map> ret = Maps.newHashMap(); + for (Map.Entry entry : this.managedWorkers.entrySet()){ + final String workerName = entry.getKey(); + final WorkerThreadPoolExecutor worker = entry.getValue(); + try { + long timeCounter = timeOutCount; + final List taskNotRunned = worker.shutdownNow(); + while (worker.awaitTermination(1,TimeUnit.MILLISECONDS)){ + if (timeCounter == 0){ + break; + } + timeCounter--; + } + ret.put(workerName,taskNotRunned); + }catch (Exception e){ + e.printStackTrace(); + } + } + return ret; + } + + public void shutdownAll(long singleWorkerAwaitTimeOutCount) throws InterruptedException { + long counter = singleWorkerAwaitTimeOutCount; + for (WorkerThreadPoolExecutor worker : this.managedWorkers.values()){ + worker.shutdown(); + while (worker.awaitTermination(1, TimeUnit.MILLISECONDS)) { + if (counter == 0){ + break; + } + counter--; + } + counter = singleWorkerAwaitTimeOutCount; + } + } +} diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java index 9c4811a9936f819e201b93e13519abf10d02ac8e..fe47aff8654283aa6a17a36226aa9fc7f18f9886 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -1,5 +1,6 @@ package net.minecraft.server; +import co.earthme.hearse.Hearse; import co.earthme.hearse.HearseConfig; import co.earthme.hearse.server.ServerEntityTickHook; import com.google.common.base.Splitter; @@ -399,8 +400,6 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop