From e4bac5f81acfbe0a5986519c0b2976525d710ed7 Mon Sep 17 00:00:00 2001 From: KennyTV Date: Fri, 24 Apr 2020 13:27:29 +0200 Subject: [PATCH] Improve shutdown of executor loader and mappings cache Previously, the shutdown check would only happen once all futures were removed, as in a player joined that had to check the remaining protocols. Now, the check will be done regularly once the plugin has fully been enabled and has the option to delay the shutdown until set on again (i.e. with ViaBackwards) --- .../java/us/myles/ViaVersion/ViaManager.java | 8 +++++ .../api/data/MappingDataLoader.java | 2 ++ .../api/protocol/ProtocolRegistry.java | 35 +++++++++++++++---- 3 files changed, 38 insertions(+), 7 deletions(-) diff --git a/common/src/main/java/us/myles/ViaVersion/ViaManager.java b/common/src/main/java/us/myles/ViaVersion/ViaManager.java index 370885753..4b901cba0 100644 --- a/common/src/main/java/us/myles/ViaVersion/ViaManager.java +++ b/common/src/main/java/us/myles/ViaVersion/ViaManager.java @@ -2,6 +2,7 @@ package us.myles.ViaVersion; import us.myles.ViaVersion.api.Via; import us.myles.ViaVersion.api.data.UserConnection; +import us.myles.ViaVersion.api.platform.TaskId; import us.myles.ViaVersion.api.platform.ViaConnectionManager; import us.myles.ViaVersion.api.platform.ViaInjector; import us.myles.ViaVersion.api.platform.ViaPlatform; @@ -27,6 +28,7 @@ public class ViaManager { private final ViaCommandHandler commandHandler; private final ViaPlatformLoader loader; private final Set subPlatforms = new HashSet<>(); + private TaskId mappingLoadingTask; private boolean debug; public ViaManager(ViaPlatform platform, ViaInjector injector, ViaCommandHandler commandHandler, ViaPlatformLoader loader) { @@ -86,6 +88,12 @@ public class ViaManager { // Load Platform loader.load(); // Common tasks + mappingLoadingTask = Via.getPlatform().runRepeatingSync(() -> { + if (ProtocolRegistry.checkForMappingCompletion()) { + platform.cancelTask(mappingLoadingTask); + mappingLoadingTask = null; + } + }, 10L); if (ProtocolRegistry.SERVER_PROTOCOL < ProtocolVersion.v1_9.getId()) { if (Via.getConfig().isSimulatePlayerTick()) { Via.getPlatform().runRepeatingSync(new ViaIdleThread(), 1L); diff --git a/common/src/main/java/us/myles/ViaVersion/api/data/MappingDataLoader.java b/common/src/main/java/us/myles/ViaVersion/api/data/MappingDataLoader.java index e2371aebf..651bcc2d8 100644 --- a/common/src/main/java/us/myles/ViaVersion/api/data/MappingDataLoader.java +++ b/common/src/main/java/us/myles/ViaVersion/api/data/MappingDataLoader.java @@ -6,6 +6,7 @@ import com.google.gson.JsonIOException; import com.google.gson.JsonObject; import com.google.gson.JsonSyntaxException; import us.myles.ViaVersion.api.Via; +import us.myles.ViaVersion.api.protocol.ProtocolRegistry; import us.myles.ViaVersion.util.GsonUtil; import java.io.File; @@ -33,6 +34,7 @@ public class MappingDataLoader { public static void enableMappingsCache() { cacheJsonMappings = true; + ProtocolRegistry.setKeepExecutorLoaded(true); } /** diff --git a/common/src/main/java/us/myles/ViaVersion/api/protocol/ProtocolRegistry.java b/common/src/main/java/us/myles/ViaVersion/api/protocol/ProtocolRegistry.java index 184d2526f..29111251b 100644 --- a/common/src/main/java/us/myles/ViaVersion/api/protocol/ProtocolRegistry.java +++ b/common/src/main/java/us/myles/ViaVersion/api/protocol/ProtocolRegistry.java @@ -61,6 +61,7 @@ public class ProtocolRegistry { private static Map, CompletableFuture> mappingLoaderFutures = new HashMap<>(); private static ThreadPoolExecutor mappingLoaderExecutor; private static boolean mappingsLoaded; + private static boolean keepExecutorLoaded; static { mappingLoaderExecutor = new ThreadPoolExecutor(5, 16, 45L, TimeUnit.SECONDS, new SynchronousQueue<>()); @@ -70,11 +71,10 @@ public class ProtocolRegistry { registerBaseProtocol(BASE_PROTOCOL, Range.lessThan(Integer.MIN_VALUE)); registerBaseProtocol(new BaseProtocol1_7(), Range.all()); - // Register built in protocols registerProtocol(new Protocol1_9To1_8(), ProtocolVersion.v1_9, ProtocolVersion.v1_8); registerProtocol(new Protocol1_9_1To1_9(), Arrays.asList(ProtocolVersion.v1_9_1.getId(), ProtocolVersion.v1_9_2.getId()), ProtocolVersion.v1_9.getId()); registerProtocol(new Protocol1_9_3To1_9_1_2(), ProtocolVersion.v1_9_3, ProtocolVersion.v1_9_2); - // Only supported for 1.9.4 server to 1.9 (nothing else) + registerProtocol(new Protocol1_9To1_9_1(), ProtocolVersion.v1_9, ProtocolVersion.v1_9_2); registerProtocol(new Protocol1_9_1_2To1_9_3_4(), Arrays.asList(ProtocolVersion.v1_9_1.getId(), ProtocolVersion.v1_9_2.getId()), ProtocolVersion.v1_9_3.getId()); registerProtocol(new Protocol1_10To1_9_3_4(), ProtocolVersion.v1_10, ProtocolVersion.v1_9_3); @@ -320,15 +320,26 @@ public class ProtocolRegistry { if (future == null) return; future.get(); + } + /** + * Shuts down the executor and uncaches mappings if all futures have been completed. + * + * @return true if the executor has now been shut down + */ + public static boolean checkForMappingCompletion() { synchronized (MAPPING_LOADER_LOCK) { - if (mappingsLoaded) return; + if (mappingsLoaded || keepExecutorLoaded) return false; - // Remove only after execution to block other potential threads - mappingLoaderFutures.remove(protocolClass); - if (mappingLoaderFutures.isEmpty()) { - shutdownLoaderExecutor(); + for (CompletableFuture future : mappingLoaderFutures.values()) { + // Return if any future hasn't completed yet + if (!future.isDone()) { + return false; + } } + + shutdownLoaderExecutor(); + return true; } } @@ -336,6 +347,7 @@ public class ProtocolRegistry { mappingsLoaded = true; mappingLoaderExecutor.shutdown(); mappingLoaderExecutor = null; + mappingLoaderFutures.clear(); mappingLoaderFutures = null; if (MappingDataLoader.isCacheJsonMappings()) { MappingDataLoader.getMappingsCache().clear(); @@ -355,4 +367,13 @@ public class ProtocolRegistry { return mappingLoaderFutures.get(protocolClass); } } + + /** + * If set to true, the executor and mappings will stay loaded, even if all current futures have been completed. + * + * @param keepExecutorLoaded whether to keep the executor and mappings loaded, even if all current futures have been completed + */ + public static void setKeepExecutorLoaded(boolean keepExecutorLoaded) { + ProtocolRegistry.keepExecutorLoaded = keepExecutorLoaded; + } }