diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderMetaDataFile.java b/core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderMetaDataFile.java index 15827e5a5..16b5b3641 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderMetaDataFile.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderMetaDataFile.java @@ -1,8 +1,6 @@ package com.seibel.distanthorizons.core.file.renderfile; import com.seibel.distanthorizons.core.dataObjects.fullData.accessor.ChunkSizedFullDataAccessor; -import com.seibel.distanthorizons.core.dataObjects.fullData.sources.CompleteFullDataSource; -import com.seibel.distanthorizons.core.dataObjects.fullData.sources.interfaces.IFullDataSource; import com.seibel.distanthorizons.core.file.metaData.AbstractMetaDataContainerFile; import com.seibel.distanthorizons.core.file.metaData.BaseMetaData; import com.seibel.distanthorizons.core.level.IDhLevel; @@ -134,7 +132,7 @@ public class RenderMetaDataFile extends AbstractMetaDataContainerFile implements }); } - public CompletableFuture flushAndSave(ExecutorService renderCacheThread) + public CompletableFuture flushAndSaveAsync(ExecutorService renderCacheThread) { if (!this.file.exists()) { diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderSourceFileHandler.java b/core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderSourceFileHandler.java index c3104615e..9870bc002 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderSourceFileHandler.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderSourceFileHandler.java @@ -1,10 +1,8 @@ package com.seibel.distanthorizons.core.file.renderfile; import com.google.common.collect.HashMultimap; -import com.google.common.collect.ImmutableList; import com.seibel.distanthorizons.core.dataObjects.fullData.accessor.ChunkSizedFullDataAccessor; import com.seibel.distanthorizons.core.dataObjects.fullData.sources.interfaces.IFullDataSource; -import com.seibel.distanthorizons.core.file.fullDatafile.FullDataMetaFile; import com.seibel.distanthorizons.core.file.structure.AbstractSaveStructure; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.pos.DhLodPos; @@ -26,7 +24,6 @@ import java.awt.*; import java.io.File; import java.io.IOException; import java.util.*; -import java.util.List; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicInteger; @@ -39,7 +36,7 @@ public class RenderSourceFileHandler implements ILodRenderSourceProvider private static final Logger LOGGER = DhLoggerBuilder.getLogger(); - private final ExecutorService fileHandlerThreadPool = ThreadUtil.makeSingleThreadPool("Render Source File Handler"); + private final ThreadPoolExecutor fileHandlerThreadPool; private final ConcurrentHashMap unloadedFiles = new ConcurrentHashMap<>(); private final ConcurrentHashMap filesBySectionPos = new ConcurrentHashMap<>(); @@ -47,10 +44,15 @@ public class RenderSourceFileHandler implements ILodRenderSourceProvider private final IDhClientLevel level; private final File saveDir; /** This is the lowest (highest numeric) detail level that this {@link RenderSourceFileHandler} is keeping track of. */ - AtomicInteger topDetailLevel = new AtomicInteger(6); + AtomicInteger topDetailLevel = new AtomicInteger(DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL); private final IFullDataSourceProvider fullDataSourceProvider; - - + + + + //=============// + // constructor // + //=============// + public RenderSourceFileHandler(IFullDataSourceProvider sourceProvider, IDhClientLevel level, AbstractSaveStructure saveStructure) { this.fullDataSourceProvider = sourceProvider; @@ -60,6 +62,8 @@ public class RenderSourceFileHandler implements ILodRenderSourceProvider { LOGGER.warn("Unable to create render data folder, file saving may fail."); } + this.fileHandlerThreadPool = ThreadUtil.makeSingleThreadPool("Render Source File Handler ["+this.level.getClientLevelWrapper().getDimensionType().getDimensionName()+"]"); + FileScanUtil.scanFiles(saveStructure, level.getLevelWrapper(), null, this); } @@ -356,7 +360,7 @@ public class RenderSourceFileHandler implements ILodRenderSourceProvider ArrayList> futures = new ArrayList<>(); for (RenderMetaDataFile metaFile : this.filesBySectionPos.values()) { - futures.add(metaFile.flushAndSave(this.fileHandlerThreadPool)); + futures.add(metaFile.flushAndSaveAsync(this.fileHandlerThreadPool)); } return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])) @@ -481,15 +485,43 @@ public class RenderSourceFileHandler implements ILodRenderSourceProvider // clearing / shutdown // //=====================// + /** closes the handler after any necessary saving has been completed */ + public CompletableFuture saveAndCloseAsync() + { + CompletableFuture shutdownFuture = this.flushAndSaveAsync(); + shutdownFuture.whenComplete((voidObj, ex) -> { this.close(); }); + + return shutdownFuture; + } + @Override public void close() { + LOGGER.info("Closing "+this.getClass().getSimpleName()+" with ["+this.filesBySectionPos.size()+"] files..."); + + // queue the file save futures ArrayList> futures = new ArrayList<>(); for (RenderMetaDataFile metaFile : this.filesBySectionPos.values()) { - futures.add(metaFile.flushAndSave(this.fileHandlerThreadPool)); + futures.add(metaFile.flushAndSaveAsync(this.fileHandlerThreadPool)); + } + + + // if the save futures didn't already complete, wait for them and then shut down the thread pool + CompletableFuture combinedFuture = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])); + combinedFuture.thenRun(() -> + { + LOGGER.info("Finished closing "+this.getClass().getSimpleName()+", ["+futures.size()+"] files were saved."); + this.fileHandlerThreadPool.shutdown(); + }); + + // if the save futures were already completed, the above "thenRun" won't fire, + // if the executor isn't currently running anything, shut it down + if (!this.fileHandlerThreadPool.isTerminated() && this.fileHandlerThreadPool.getActiveCount() == 0) + { + LOGGER.info("Finished closing "+this.getClass().getSimpleName()+", thread pool manually shut down due to file save futures already being completed."); + this.fileHandlerThreadPool.shutdown(); } - CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/ClientLevelModule.java b/core/src/main/java/com/seibel/distanthorizons/core/level/ClientLevelModule.java index aca68690e..7161422ab 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/level/ClientLevelModule.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/ClientLevelModule.java @@ -269,7 +269,7 @@ public class ClientLevelModule { this.renderer.close(); this.quadtree.close(); - return this.renderSourceFileHandler.flushAndSaveAsync(); + return this.renderSourceFileHandler.saveAndCloseAsync(); } }