mirror of
https://github.com/Winds-Studio/Leaf.git
synced 2025-12-19 15:09:25 +00:00
Some fixes for failed to shutdown if some async are disabled
This commit is contained in:
@@ -12,8 +12,17 @@ import java.util.concurrent.TimeUnit;
|
|||||||
|
|
||||||
public class AsyncPlayerDataSaving {
|
public class AsyncPlayerDataSaving {
|
||||||
|
|
||||||
public static final ExecutorService IO_POOL = new ThreadPoolExecutor(
|
public static ExecutorService IO_POOL = null;
|
||||||
1, 1, 0L, TimeUnit.MILLISECONDS,
|
|
||||||
|
private AsyncPlayerDataSaving() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void init() {
|
||||||
|
if (IO_POOL == null) {
|
||||||
|
IO_POOL = new ThreadPoolExecutor(
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
0L, TimeUnit.MILLISECONDS,
|
||||||
new LinkedBlockingQueue<>(),
|
new LinkedBlockingQueue<>(),
|
||||||
new com.google.common.util.concurrent.ThreadFactoryBuilder()
|
new com.google.common.util.concurrent.ThreadFactoryBuilder()
|
||||||
.setPriority(Thread.NORM_PRIORITY - 2)
|
.setPriority(Thread.NORM_PRIORITY - 2)
|
||||||
@@ -22,8 +31,9 @@ public class AsyncPlayerDataSaving {
|
|||||||
.build(),
|
.build(),
|
||||||
new ThreadPoolExecutor.DiscardPolicy()
|
new ThreadPoolExecutor.DiscardPolicy()
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
private AsyncPlayerDataSaving() {
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Optional<Future<?>> submit(Runnable runnable) {
|
public static Optional<Future<?>> submit(Runnable runnable) {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import org.dreeam.leaf.async.tracker.MultithreadedTracker;
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class ShutdownExecutors {
|
public class ShutdownExecutors {
|
||||||
|
|
||||||
public static final Logger LOGGER = LogManager.getLogger("Leaf");
|
public static final Logger LOGGER = LogManager.getLogger("Leaf");
|
||||||
|
|
||||||
public static void shutdown(MinecraftServer server) {
|
public static void shutdown(MinecraftServer server) {
|
||||||
@@ -48,11 +49,11 @@ public class ShutdownExecutors {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AsyncPathProcessor.pathProcessingExecutor != null) {
|
if (AsyncPathProcessor.PATH_PROCESSING_EXECUTOR != null) {
|
||||||
LOGGER.info("Waiting for mob pathfinding executor to shutdown...");
|
LOGGER.info("Waiting for mob pathfinding executor to shutdown...");
|
||||||
AsyncPathProcessor.pathProcessingExecutor.shutdown();
|
AsyncPathProcessor.PATH_PROCESSING_EXECUTOR.shutdown();
|
||||||
try {
|
try {
|
||||||
AsyncPathProcessor.pathProcessingExecutor.awaitTermination(10L, TimeUnit.SECONDS);
|
AsyncPathProcessor.PATH_PROCESSING_EXECUTOR.awaitTermination(10L, TimeUnit.SECONDS);
|
||||||
} catch (InterruptedException ignored) {
|
} catch (InterruptedException ignored) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.dreeam.leaf.async.path;
|
package org.dreeam.leaf.async.path;
|
||||||
|
|
||||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||||
|
import net.minecraft.Util;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.world.level.pathfinder.Path;
|
import net.minecraft.world.level.pathfinder.Path;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
@@ -15,6 +16,7 @@ import java.util.concurrent.BlockingQueue;
|
|||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
import java.util.concurrent.RejectedExecutionHandler;
|
import java.util.concurrent.RejectedExecutionHandler;
|
||||||
|
import java.util.concurrent.ThreadFactory;
|
||||||
import java.util.concurrent.ThreadPoolExecutor;
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
@@ -28,49 +30,25 @@ public class AsyncPathProcessor {
|
|||||||
private static final String THREAD_PREFIX = "Leaf Async Pathfinding";
|
private static final String THREAD_PREFIX = "Leaf Async Pathfinding";
|
||||||
private static final Logger LOGGER = LogManager.getLogger(THREAD_PREFIX);
|
private static final Logger LOGGER = LogManager.getLogger(THREAD_PREFIX);
|
||||||
private static long lastWarnMillis = System.currentTimeMillis();
|
private static long lastWarnMillis = System.currentTimeMillis();
|
||||||
public static final ThreadPoolExecutor pathProcessingExecutor = new ThreadPoolExecutor(
|
public static ThreadPoolExecutor PATH_PROCESSING_EXECUTOR = null;
|
||||||
1,
|
|
||||||
AsyncPathfinding.asyncPathfindingMaxThreads,
|
public static void init() {
|
||||||
AsyncPathfinding.asyncPathfindingKeepalive, TimeUnit.SECONDS,
|
if (PATH_PROCESSING_EXECUTOR == null) {
|
||||||
|
PATH_PROCESSING_EXECUTOR = new ThreadPoolExecutor(
|
||||||
|
getCorePoolSize(),
|
||||||
|
getMaxPoolSize(),
|
||||||
|
getKeepAliveTime(), TimeUnit.SECONDS,
|
||||||
getQueueImpl(),
|
getQueueImpl(),
|
||||||
new ThreadFactoryBuilder()
|
getThreadFactory(),
|
||||||
.setNameFormat(THREAD_PREFIX + " Thread - %d")
|
getRejectedPolicy()
|
||||||
.setPriority(Thread.NORM_PRIORITY - 2)
|
|
||||||
.build(),
|
|
||||||
new RejectedTaskHandler()
|
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
private static class RejectedTaskHandler implements RejectedExecutionHandler {
|
throw new IllegalStateException();
|
||||||
@Override
|
|
||||||
public void rejectedExecution(Runnable rejectedTask, ThreadPoolExecutor executor) {
|
|
||||||
BlockingQueue<Runnable> workQueue = executor.getQueue();
|
|
||||||
if (!executor.isShutdown()) {
|
|
||||||
switch (AsyncPathfinding.asyncPathfindingRejectPolicy) {
|
|
||||||
case FLUSH_ALL -> {
|
|
||||||
if (!workQueue.isEmpty()) {
|
|
||||||
List<Runnable> pendingTasks = new ArrayList<>(workQueue.size());
|
|
||||||
|
|
||||||
workQueue.drainTo(pendingTasks);
|
|
||||||
|
|
||||||
for (Runnable pendingTask : pendingTasks) {
|
|
||||||
pendingTask.run();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rejectedTask.run();
|
|
||||||
}
|
|
||||||
case CALLER_RUNS -> rejectedTask.run();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (System.currentTimeMillis() - lastWarnMillis > 30000L) {
|
|
||||||
LOGGER.warn("Async pathfinding processor is busy! Pathfinding tasks will be treated as policy defined in config. Increasing max-threads in Leaf config may help.");
|
|
||||||
lastWarnMillis = System.currentTimeMillis();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static CompletableFuture<Void> queue(@NotNull AsyncPath path) {
|
protected static CompletableFuture<Void> queue(@NotNull AsyncPath path) {
|
||||||
return CompletableFuture.runAsync(path::process, pathProcessingExecutor)
|
return CompletableFuture.runAsync(path::process, PATH_PROCESSING_EXECUTOR)
|
||||||
.orTimeout(60L, TimeUnit.SECONDS)
|
.orTimeout(60L, TimeUnit.SECONDS)
|
||||||
.exceptionally(throwable -> {
|
.exceptionally(throwable -> {
|
||||||
if (throwable instanceof TimeoutException e) {
|
if (throwable instanceof TimeoutException e) {
|
||||||
@@ -98,9 +76,57 @@ public class AsyncPathProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int getCorePoolSize() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getMaxPoolSize() {
|
||||||
|
return AsyncPathfinding.asyncPathfindingMaxThreads;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long getKeepAliveTime() {
|
||||||
|
return AsyncPathfinding.asyncPathfindingKeepalive;
|
||||||
|
}
|
||||||
|
|
||||||
private static BlockingQueue<Runnable> getQueueImpl() {
|
private static BlockingQueue<Runnable> getQueueImpl() {
|
||||||
final int queueCapacity = AsyncPathfinding.asyncPathfindingQueueSize;
|
final int queueCapacity = AsyncPathfinding.asyncPathfindingQueueSize;
|
||||||
|
|
||||||
return new LinkedBlockingQueue<>(queueCapacity);
|
return new LinkedBlockingQueue<>(queueCapacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static @NotNull ThreadFactory getThreadFactory() {
|
||||||
|
return new ThreadFactoryBuilder()
|
||||||
|
.setNameFormat(THREAD_PREFIX + " Thread - %d")
|
||||||
|
.setPriority(Thread.NORM_PRIORITY - 2)
|
||||||
|
.setUncaughtExceptionHandler(Util::onThreadException)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static @NotNull RejectedExecutionHandler getRejectedPolicy() {
|
||||||
|
return (Runnable rejectedTask, ThreadPoolExecutor executor) -> {
|
||||||
|
BlockingQueue<Runnable> workQueue = executor.getQueue();
|
||||||
|
if (!executor.isShutdown()) {
|
||||||
|
switch (AsyncPathfinding.asyncPathfindingRejectPolicy) {
|
||||||
|
case FLUSH_ALL -> {
|
||||||
|
if (!workQueue.isEmpty()) {
|
||||||
|
List<Runnable> pendingTasks = new ArrayList<>(workQueue.size());
|
||||||
|
|
||||||
|
workQueue.drainTo(pendingTasks);
|
||||||
|
|
||||||
|
for (Runnable pendingTask : pendingTasks) {
|
||||||
|
pendingTask.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rejectedTask.run();
|
||||||
|
}
|
||||||
|
case CALLER_RUNS -> rejectedTask.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (System.currentTimeMillis() - lastWarnMillis > 30000L) {
|
||||||
|
LOGGER.warn("Async pathfinding processor is busy! Pathfinding tasks will be treated as policy defined in config. Increasing max-threads in Leaf config may help.");
|
||||||
|
lastWarnMillis = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,5 +60,9 @@ public class AsyncPathfinding extends ConfigModules {
|
|||||||
? PathfindTaskRejectPolicy.FLUSH_ALL.toString()
|
? PathfindTaskRejectPolicy.FLUSH_ALL.toString()
|
||||||
: PathfindTaskRejectPolicy.CALLER_RUNS.toString())
|
: PathfindTaskRejectPolicy.CALLER_RUNS.toString())
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (enabled) {
|
||||||
|
org.dreeam.leaf.async.path.AsyncPathProcessor.init();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,5 +19,9 @@ public class AsyncPlayerDataSave extends ConfigModules {
|
|||||||
异步保存玩家数据.""");
|
异步保存玩家数据.""");
|
||||||
|
|
||||||
enabled = config.getBoolean(getBasePath() + ".enabled", enabled);
|
enabled = config.getBoolean(getBasePath() + ".enabled", enabled);
|
||||||
|
|
||||||
|
if (enabled) {
|
||||||
|
org.dreeam.leaf.async.AsyncPlayerDataSaving.init();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ public class MultithreadedTracker extends ConfigModules {
|
|||||||
|
|
||||||
if (asyncEntityTrackerQueueSize <= 0)
|
if (asyncEntityTrackerQueueSize <= 0)
|
||||||
asyncEntityTrackerQueueSize = asyncEntityTrackerMaxThreads * 384;
|
asyncEntityTrackerQueueSize = asyncEntityTrackerMaxThreads * 384;
|
||||||
|
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
org.dreeam.leaf.async.tracker.MultithreadedTracker.init();
|
org.dreeam.leaf.async.tracker.MultithreadedTracker.init();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user