diff --git a/core/src/main/java/com/seibel/lod/core/api/internal/SharedApi.java b/core/src/main/java/com/seibel/lod/core/api/internal/SharedApi.java index 4fc94cd65..78da9dfce 100644 --- a/core/src/main/java/com/seibel/lod/core/api/internal/SharedApi.java +++ b/core/src/main/java/com/seibel/lod/core/api/internal/SharedApi.java @@ -1,7 +1,9 @@ package com.seibel.lod.core.api.internal; import com.seibel.lod.core.Initializer; +import com.seibel.lod.core.dataObjects.render.bufferBuilding.ColumnRenderBufferBuilder; import com.seibel.lod.core.dataObjects.transformers.DataRenderTransformer; +import com.seibel.lod.core.file.fullDatafile.FullDataFileHandler; import com.seibel.lod.core.world.*; import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftSharedWrapper; @@ -29,10 +31,14 @@ public class SharedApi if (currentWorld == null) { DataRenderTransformer.shutdownExecutorService(); + FullDataFileHandler.shutdownExecutorService(); + ColumnRenderBufferBuilder.shutdownExecutorService(); } else { DataRenderTransformer.setupExecutorService(); + FullDataFileHandler.setupExecutorService(); + ColumnRenderBufferBuilder.setupExecutorService(); } } diff --git a/core/src/main/java/com/seibel/lod/core/dataObjects/render/bufferBuilding/ColumnRenderBufferBuilder.java b/core/src/main/java/com/seibel/lod/core/dataObjects/render/bufferBuilding/ColumnRenderBufferBuilder.java index b3ca39f18..891220284 100644 --- a/core/src/main/java/com/seibel/lod/core/dataObjects/render/bufferBuilding/ColumnRenderBufferBuilder.java +++ b/core/src/main/java/com/seibel/lod/core/dataObjects/render/bufferBuilding/ColumnRenderBufferBuilder.java @@ -4,8 +4,10 @@ import com.seibel.lod.api.enums.config.EGpuUploadMethod; import com.seibel.lod.api.enums.rendering.EDebugMode; import com.seibel.lod.api.enums.rendering.EGLProxyContext; import com.seibel.lod.core.config.Config; +import com.seibel.lod.core.config.listeners.ConfigChangeListener; import com.seibel.lod.core.dataObjects.render.ColumnRenderSource; import com.seibel.lod.core.dataObjects.render.columnViews.ColumnArrayView; +import com.seibel.lod.core.dataObjects.transformers.DataRenderTransformer; import com.seibel.lod.core.enums.ELodDirection; import com.seibel.lod.core.level.IDhClientLevel; import com.seibel.lod.core.logging.ConfigBasedLogger; @@ -13,7 +15,6 @@ import com.seibel.lod.core.logging.DhLoggerBuilder; import com.seibel.lod.core.pos.DhBlockPos; import com.seibel.lod.core.render.glObject.GLProxy; import com.seibel.lod.core.render.glObject.buffer.GLVertexBuffer; -import com.seibel.lod.core.util.LodUtil; import com.seibel.lod.core.util.RenderDataPointUtil; import com.seibel.lod.core.util.ThreadUtil; import com.seibel.lod.core.util.objects.Reference; @@ -37,11 +38,13 @@ public class ColumnRenderBufferBuilder () -> Config.Client.Advanced.Debugging.DebugSwitch.logRendererBufferEvent.get()); private static final Logger LOGGER = DhLoggerBuilder.getLogger(); - //TODO: Make the pool change thread count after the config value is changed - public static final ExecutorService BUFFER_BUILDER_THREADS = ThreadUtil.makeThreadPool(Config.Client.Advanced.Threading.numberOfBufferBuilderThreads.get(), "BufferBuilder"); - public static final ExecutorService BUFFER_UPLOADER = ThreadUtil.makeSingleThreadPool("ColumnBufferUploader"); - // TODO this should probably be based on the number of builder threads - public static final int MAX_CONCURRENT_CALL = 8; + + public static ExecutorService bufferUploaderThreadPool = ThreadUtil.makeSingleThreadPool("ColumnBufferUploader"); + public static ExecutorService bufferBuilderThreadPool; + private static ConfigChangeListener configListener; + + public static final int MAX_NUMBER_OF_CONCURRENT_CALLS_PER_THREAD = 3; + public static int maxNumberOfConcurrentCalls = MAX_NUMBER_OF_CONCURRENT_CALLS_PER_THREAD; @@ -50,7 +53,6 @@ public class ColumnRenderBufferBuilder // vbo building // //==============// - /// TODO this is static, it should be moved to its own class to prevent confusion /** @return null if busy */ public static CompletableFuture buildBuffers(IDhClientLevel clientLevel, Reference renderBufferRef, ColumnRenderSource renderSource, ColumnRenderSource[] adjData) { @@ -90,7 +92,7 @@ public class ColumnRenderBufferBuilder throw e3; } - }, BUFFER_BUILDER_THREADS) + }, bufferBuilderThreadPool) .thenApplyAsync((quadBuilder) -> { try @@ -134,7 +136,7 @@ public class ColumnRenderBufferBuilder throw e3; } }, - BUFFER_UPLOADER).handle((columnRenderBuffer, ex) -> + bufferUploaderThreadPool).handle((columnRenderBuffer, ex) -> { //LOGGER.info("RenderRegion endBuild @ {}", renderSource.sectionPos); if (ex != null) @@ -356,6 +358,50 @@ public class ColumnRenderBufferBuilder + //==========================// + // executor handler methods // + //==========================// + + /** + * Creates a new executor.
+ * Does nothing if an executor already exists. + */ + public static void setupExecutorService() + { + // static setup + if (configListener == null) + { + configListener = new ConfigChangeListener<>(Config.Client.Advanced.Threading.numberOfBufferBuilderThreads, (threadCount) -> { setThreadPoolSize(threadCount); }); + } + + + if (bufferBuilderThreadPool == null || bufferBuilderThreadPool.isTerminated()) + { + LOGGER.info("Starting "+ ColumnRenderBufferBuilder.class.getSimpleName()); + setThreadPoolSize(Config.Client.Advanced.Threading.numberOfBufferBuilderThreads.get()); + } + } + public static void setThreadPoolSize(int threadPoolSize) + { + bufferBuilderThreadPool = ThreadUtil.makeThreadPool(threadPoolSize, "BufferBuilder"); + maxNumberOfConcurrentCalls = threadPoolSize * MAX_NUMBER_OF_CONCURRENT_CALLS_PER_THREAD; + } + + /** + * Stops any executing tasks and destroys the executor.
+ * Does nothing if the executor isn't running. + */ + public static void shutdownExecutorService() + { + if (bufferBuilderThreadPool != null) + { + LOGGER.info("Stopping "+ColumnRenderBufferBuilder.class.getSimpleName()); + bufferBuilderThreadPool.shutdownNow(); + } + } + + + //=========// // getters // //=========// @@ -363,10 +409,10 @@ public class ColumnRenderBufferBuilder // TODO move static methods to their own class to avoid confusion private static long getCurrentJobsCount() { - long jobs = ((ThreadPoolExecutor) BUFFER_BUILDER_THREADS).getQueue().stream().filter(runnable -> !((Future) runnable).isDone()).count(); - jobs += ((ThreadPoolExecutor) BUFFER_UPLOADER).getQueue().stream().filter(runnable -> !((Future) runnable).isDone()).count(); + long jobs = ((ThreadPoolExecutor) bufferBuilderThreadPool).getQueue().stream().filter(runnable -> !((Future) runnable).isDone()).count(); + jobs += ((ThreadPoolExecutor) bufferUploaderThreadPool).getQueue().stream().filter(runnable -> !((Future) runnable).isDone()).count(); return jobs; } - public static boolean isBusy() { return getCurrentJobsCount() > MAX_CONCURRENT_CALL; } + public static boolean isBusy() { return getCurrentJobsCount() > maxNumberOfConcurrentCalls; } } diff --git a/core/src/main/java/com/seibel/lod/core/dataObjects/transformers/DataRenderTransformer.java b/core/src/main/java/com/seibel/lod/core/dataObjects/transformers/DataRenderTransformer.java index 1e56c1b28..82f3a9c4f 100644 --- a/core/src/main/java/com/seibel/lod/core/dataObjects/transformers/DataRenderTransformer.java +++ b/core/src/main/java/com/seibel/lod/core/dataObjects/transformers/DataRenderTransformer.java @@ -1,10 +1,12 @@ package com.seibel.lod.core.dataObjects.transformers; import com.seibel.lod.core.config.Config; +import com.seibel.lod.core.config.listeners.ConfigChangeListener; import com.seibel.lod.core.dataObjects.fullData.sources.interfaces.IFullDataSource; import com.seibel.lod.core.dataObjects.render.ColumnRenderLoader; import com.seibel.lod.core.dataObjects.render.ColumnRenderSource; import com.seibel.lod.core.dependencyInjection.SingletonInjector; +import com.seibel.lod.core.file.fullDatafile.FullDataFileHandler; import com.seibel.lod.core.level.IDhClientLevel; import com.seibel.lod.core.logging.DhLoggerBuilder; import com.seibel.lod.core.util.ThreadUtil; @@ -20,7 +22,8 @@ public class DataRenderTransformer private static final Logger LOGGER = DhLoggerBuilder.getLogger(); private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class); - private static ExecutorService transformerThreads = null; + private static ExecutorService transformerThreadPool = null; + private static ConfigChangeListener configListener; @@ -30,12 +33,12 @@ public class DataRenderTransformer public static CompletableFuture transformDataSourceAsync(IFullDataSource fullDataSource, IDhClientLevel level) { - return CompletableFuture.supplyAsync(() -> transform(fullDataSource, level), transformerThreads); + return CompletableFuture.supplyAsync(() -> transform(fullDataSource, level), transformerThreadPool); } public static CompletableFuture transformDataSourceAsync(CompletableFuture fullDataSourceFuture, IDhClientLevel level) { - return fullDataSourceFuture.thenApplyAsync((fullDataSource) -> transform(fullDataSource, level), transformerThreads); + return fullDataSourceFuture.thenApplyAsync((fullDataSource) -> transform(fullDataSource, level), transformerThreadPool); } private static ColumnRenderSource transform(IFullDataSource fullDataSource, IDhClientLevel level) @@ -72,13 +75,20 @@ public class DataRenderTransformer */ public static void setupExecutorService() { - if (transformerThreads == null || transformerThreads.isTerminated()) + // static setup + if (configListener == null) + { + configListener = new ConfigChangeListener<>(Config.Client.Advanced.Threading.numberOfDataConverterThreads, (threadCount) -> { setThreadPoolSize(threadCount); }); + } + + + if (transformerThreadPool == null || transformerThreadPool.isTerminated()) { LOGGER.info("Starting "+DataRenderTransformer.class.getSimpleName()); - // TODO change when the config is modified - transformerThreads = ThreadUtil.makeThreadPool(Config.Client.Advanced.Threading.numberOfDataConverterThreads.get(), "Data/Render Transformer"); + setThreadPoolSize(Config.Client.Advanced.Threading.numberOfDataConverterThreads.get()); } } + public static void setThreadPoolSize(int threadPoolSize) { transformerThreadPool = ThreadUtil.makeThreadPool(threadPoolSize, "Data/Render Transformer"); } /** * Stops any executing tasks and destroys the executor.
@@ -86,10 +96,10 @@ public class DataRenderTransformer */ public static void shutdownExecutorService() { - if (transformerThreads != null) + if (transformerThreadPool != null) { LOGGER.info("Stopping "+DataRenderTransformer.class.getSimpleName()); - transformerThreads.shutdownNow(); + transformerThreadPool.shutdownNow(); } } diff --git a/core/src/main/java/com/seibel/lod/core/file/fullDatafile/FullDataFileHandler.java b/core/src/main/java/com/seibel/lod/core/file/fullDatafile/FullDataFileHandler.java index 5ef378373..75e307a0e 100644 --- a/core/src/main/java/com/seibel/lod/core/file/fullDatafile/FullDataFileHandler.java +++ b/core/src/main/java/com/seibel/lod/core/file/fullDatafile/FullDataFileHandler.java @@ -9,6 +9,7 @@ import com.seibel.lod.core.dataObjects.fullData.sources.*; import com.seibel.lod.core.dataObjects.fullData.sources.CompleteFullDataSource; import com.seibel.lod.core.dataObjects.fullData.sources.interfaces.IFullDataSource; import com.seibel.lod.core.dataObjects.fullData.sources.interfaces.IIncompleteFullDataSource; +import com.seibel.lod.core.dataObjects.transformers.DataRenderTransformer; import com.seibel.lod.core.util.FileUtil; import com.seibel.lod.core.file.metaData.BaseMetaData; import com.seibel.lod.core.level.IDhLevel; @@ -34,8 +35,8 @@ public class FullDataFileHandler implements IFullDataSourceProvider { private static final Logger LOGGER = DhLoggerBuilder.getLogger(); - protected ExecutorService fileHandlerThreadPool; - protected final ConfigChangeListener configListener; + protected static ExecutorService fileHandlerThreadPool; + protected static ConfigChangeListener configListener; protected final ConcurrentHashMap fileBySectionPos = new ConcurrentHashMap<>(); protected final IDhLevel level; @@ -47,11 +48,6 @@ public class FullDataFileHandler implements IFullDataSourceProvider public FullDataFileHandler(IDhLevel level, File saveRootDir) { - configListener = new ConfigChangeListener<>(Config.Client.Advanced.Threading.numberOfFileHandlerThreads, (threadCount) -> { this.setThreadPoolSize(threadCount); }); - - int threadPoolSize = Config.Client.Advanced.Threading.numberOfFileHandlerThreads.get(); - this.setThreadPoolSize(threadPoolSize); - this.saveDir = saveRootDir; this.level = level; } @@ -433,7 +429,7 @@ public class FullDataFileHandler implements IFullDataSourceProvider @Override public CompletableFuture onDataFileRefresh(IFullDataSource source, BaseMetaData metaData, Function updater, Consumer onUpdated) { - if (this.fileHandlerThreadPool.isTerminated()) + if (fileHandlerThreadPool.isTerminated()) { return CompletableFuture.completedFuture(source); } @@ -462,26 +458,65 @@ public class FullDataFileHandler implements IFullDataSourceProvider onUpdated.accept(sourceLocal); } return sourceLocal; - }, this.fileHandlerThreadPool); + }, fileHandlerThreadPool); } @Override public File computeDataFilePath(DhSectionPos pos) { return new File(this.saveDir, pos.serialize() + ".lod"); } - @Override - public ExecutorService getIOExecutor() { return this.fileHandlerThreadPool; } - public void setThreadPoolSize(int threadPoolSize) { fileHandlerThreadPool = ThreadUtil.makeThreadPool(threadPoolSize, FullDataFileHandler.class.getSimpleName()+"Thread"); } + + //==========================// + // executor handler methods // + //==========================// + + /** + * Creates a new executor.
+ * Does nothing if an executor already exists. + */ + public static void setupExecutorService() + { + // static setup + if (configListener == null) + { + configListener = new ConfigChangeListener<>(Config.Client.Advanced.Threading.numberOfFileHandlerThreads, (threadCount) -> { setThreadPoolSize(threadCount); }); + } + + + if (fileHandlerThreadPool == null || fileHandlerThreadPool.isTerminated()) + { + LOGGER.info("Starting "+FullDataFileHandler.class.getSimpleName()); + setThreadPoolSize(Config.Client.Advanced.Threading.numberOfFileHandlerThreads.get()); + } + } + public static void setThreadPoolSize(int threadPoolSize) { fileHandlerThreadPool = ThreadUtil.makeThreadPool(threadPoolSize, FullDataFileHandler.class.getSimpleName()+"Thread"); } + + /** + * Stops any executing tasks and destroys the executor.
+ * Does nothing if the executor isn't running. + */ + public static void shutdownExecutorService() + { + if (fileHandlerThreadPool != null) + { + LOGGER.info("Stopping "+ FullDataFileHandler.class.getSimpleName()); + fileHandlerThreadPool.shutdownNow(); + } + } + + @Override + public ExecutorService getIOExecutor() { return fileHandlerThreadPool; } + + + + //=========// + // cleanup // + //=========// @Override public void close() { FullDataMetaFile.debugPhantomLifeCycleCheck(); - - configListener.close(); - - // stop any existing file tasks - this.fileHandlerThreadPool.shutdownNow(); } }