Fix file loaders not getting interrupted on level close
This commit is contained in:
+8
-2
@@ -1,6 +1,9 @@
|
||||
package com.seibel.lod.core.dataObjects.fullData;
|
||||
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.seibel.lod.core.dataObjects.fullData.sources.FullDataSource;
|
||||
import com.seibel.lod.core.dataObjects.transformers.FullToColumnTransformer;
|
||||
import com.seibel.lod.core.level.IDhClientLevel;
|
||||
import com.seibel.lod.core.level.IDhLevel;
|
||||
import com.seibel.lod.core.file.fullDatafile.FullDataMetaFile;
|
||||
|
||||
@@ -52,8 +55,11 @@ public abstract class AbstractFullDataSourceLoader
|
||||
loaderRegistry.put(clazz, this);
|
||||
}
|
||||
|
||||
/** Can return null as meaning the requirement is not met */
|
||||
public abstract IFullDataSource loadData(FullDataMetaFile dataFile, InputStream data, IDhLevel level) throws IOException;
|
||||
/**
|
||||
* Can return null if any of the requirements aren't met.
|
||||
* @throws InterruptedException if the loader thread is interrupted, generally happens when the level is shutting down
|
||||
*/
|
||||
public abstract IFullDataSource loadData(FullDataMetaFile dataFile, InputStream data, IDhLevel level) throws IOException, InterruptedException;
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ public class FullDataLoader extends AbstractFullDataSourceLoader
|
||||
}
|
||||
|
||||
@Override
|
||||
public IFullDataSource loadData(FullDataMetaFile dataFile, InputStream data, IDhLevel level) throws IOException
|
||||
public IFullDataSource loadData(FullDataMetaFile dataFile, InputStream data, IDhLevel level) throws IOException, InterruptedException
|
||||
{
|
||||
//TODO: Add decompressor here
|
||||
return FullDataSource.loadData(dataFile, data, level);
|
||||
|
||||
+11
-2
@@ -1,5 +1,6 @@
|
||||
package com.seibel.lod.core.dataObjects.fullData;
|
||||
|
||||
import com.seibel.lod.core.dataObjects.transformers.FullToColumnTransformer;
|
||||
import com.seibel.lod.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.lod.core.wrapperInterfaces.IWrapperFactory;
|
||||
import com.seibel.lod.core.wrapperInterfaces.block.IBlockStateWrapper;
|
||||
@@ -71,7 +72,7 @@ public class FullDataPointIdMap
|
||||
}
|
||||
|
||||
/** Creates a new IdBiomeBlockStateMap from the given UTF formatted stream */
|
||||
public static FullDataPointIdMap deserialize(InputStream inputStream) throws IOException
|
||||
public static FullDataPointIdMap deserialize(InputStream inputStream) throws IOException, InterruptedException
|
||||
{
|
||||
DataInputStream dataStream = new DataInputStream(inputStream); // DO NOT CLOSE! It would close all related streams
|
||||
int entityCount = dataStream.readInt();
|
||||
@@ -136,11 +137,19 @@ public class FullDataPointIdMap
|
||||
|
||||
public String serialize() { return this.biome.serialize() + " " + this.blockState.serialize(); }
|
||||
|
||||
public static Entry deserialize(String str) throws IOException
|
||||
public static Entry deserialize(String str) throws IOException, InterruptedException
|
||||
{
|
||||
String[] stringArray = str.split(" ");
|
||||
if (stringArray.length != 2)
|
||||
{
|
||||
throw new IOException("Failed to deserialize BiomeBlockStateEntry");
|
||||
}
|
||||
|
||||
// necessary to prevent issues with deserializing objects after the level has been closed
|
||||
if (Thread.interrupted())
|
||||
{
|
||||
throw new InterruptedException(FullDataPointIdMap.class.getSimpleName()+" task interrupted.");
|
||||
}
|
||||
|
||||
IBiomeWrapper biome = WRAPPER_FACTORY.deserializeBiomeWrapper(stringArray[0]);
|
||||
IBlockStateWrapper blockState = WRAPPER_FACTORY.deserializeBlockStateWrapper(stringArray[1]);
|
||||
|
||||
+2
-1
@@ -14,7 +14,8 @@ public class SingleChunkFullDataLoader extends AbstractFullDataSourceLoader
|
||||
}
|
||||
|
||||
@Override
|
||||
public IFullDataSource loadData(FullDataMetaFile dataFile, InputStream data, IDhLevel level) throws IOException {
|
||||
public IFullDataSource loadData(FullDataMetaFile dataFile, InputStream data, IDhLevel level) throws IOException, InterruptedException
|
||||
{
|
||||
return SingleChunkFullDataSource.loadData(dataFile, data, level);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ public class SparseFullDataLoader extends AbstractFullDataSourceLoader
|
||||
}
|
||||
|
||||
@Override
|
||||
public IFullDataSource loadData(FullDataMetaFile dataFile, InputStream data, IDhLevel level) throws IOException
|
||||
public IFullDataSource loadData(FullDataMetaFile dataFile, InputStream data, IDhLevel level) throws IOException, InterruptedException
|
||||
{
|
||||
return SparseFullDataSource.loadData(dataFile, data, level);
|
||||
}
|
||||
|
||||
+1
-1
@@ -178,7 +178,7 @@ public class FullDataSource extends FullArrayView implements IFullDataSource
|
||||
}
|
||||
|
||||
|
||||
public static FullDataSource loadData(FullDataMetaFile dataFile, InputStream dataStream, IDhLevel level) throws IOException
|
||||
public static FullDataSource loadData(FullDataMetaFile dataFile, InputStream dataStream, IDhLevel level) throws IOException, InterruptedException
|
||||
{
|
||||
DataInputStream dos = new DataInputStream(dataStream); // DO NOT CLOSE
|
||||
{
|
||||
|
||||
+1
-1
@@ -119,7 +119,7 @@ public class SingleChunkFullDataSource extends FullArrayView implements IIncompl
|
||||
}
|
||||
|
||||
|
||||
public static SingleChunkFullDataSource loadData(FullDataMetaFile dataFile, InputStream dataStream, IDhLevel level) throws IOException
|
||||
public static SingleChunkFullDataSource loadData(FullDataMetaFile dataFile, InputStream dataStream, IDhLevel level) throws IOException, InterruptedException
|
||||
{
|
||||
DataInputStream dos = new DataInputStream(dataStream); // DO NOT CLOSE
|
||||
{
|
||||
|
||||
+1
-1
@@ -291,7 +291,7 @@ public class SparseFullDataSource implements IIncompleteFullDataSource
|
||||
}
|
||||
}
|
||||
|
||||
public static SparseFullDataSource loadData(FullDataMetaFile dataFile, InputStream dataStream, IDhLevel level) throws IOException
|
||||
public static SparseFullDataSource loadData(FullDataMetaFile dataFile, InputStream dataStream, IDhLevel level) throws IOException, InterruptedException
|
||||
{
|
||||
LodUtil.assertTrue(dataFile.pos.sectionDetailLevel > SPARSE_UNIT_DETAIL);
|
||||
LodUtil.assertTrue(dataFile.pos.sectionDetailLevel <= MAX_SECTION_DETAIL);
|
||||
|
||||
@@ -57,9 +57,7 @@ public class ColumnRenderLoader
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InterruptedException see {@link FullToColumnTransformer#transformFullDataToColumnData(IDhClientLevel, FullDataSource) FullToColumnTransformer#transformFullDataToColumnData} for documentation
|
||||
*/
|
||||
/** @throws InterruptedException see {@link FullToColumnTransformer#transformFullDataToColumnData(IDhClientLevel, FullDataSource) FullToColumnTransformer#transformFullDataToColumnData} for documentation */
|
||||
public ColumnRenderSource createRenderSource(IFullDataSource dataSource, IDhClientLevel level) throws InterruptedException
|
||||
{
|
||||
if (dataSource instanceof FullDataSource)
|
||||
|
||||
@@ -227,10 +227,16 @@ public class FullDataMetaFile extends AbstractMetaDataContainerFile
|
||||
{
|
||||
data = this.loader.loadData(this, inputStream, this.level);
|
||||
}
|
||||
catch (Exception e)
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (ex instanceof InterruptedException)
|
||||
{
|
||||
// LOGGER.warn(FullDataMetaFile.class.getSimpleName()+" loadOrGetCachedAsync interrupted.");
|
||||
return null;
|
||||
}
|
||||
|
||||
// can happen if there is a missing file or the file was incorrectly formatted
|
||||
throw new CompletionException(e);
|
||||
throw new CompletionException(ex);
|
||||
}
|
||||
|
||||
// Apply the write queue
|
||||
@@ -241,12 +247,26 @@ public class FullDataMetaFile extends AbstractMetaDataContainerFile
|
||||
data = this.handler.onDataFileLoaded(data, this.metaData, this::saveChanges, this::applyWriteQueue);
|
||||
return data;
|
||||
}, this.handler.getIOExecutor())
|
||||
.exceptionally((e) ->
|
||||
.exceptionally((ex) ->
|
||||
{
|
||||
LOGGER.error("Error loading file {}: ", this.file, e);
|
||||
if (ex instanceof InterruptedException)
|
||||
{
|
||||
//LOGGER.warn(FullDataMetaFile.class.getSimpleName()+" loadOrGetCachedAsync interrupted.");
|
||||
//future.completeExceptionally(ex); // this exception can be ignored
|
||||
return null;
|
||||
}
|
||||
else if (ex instanceof RejectedExecutionException)
|
||||
{
|
||||
//LOGGER.warn(FullDataMetaFile.class.getSimpleName()+" loadOrGetCachedAsync attempted to use a closed thread pool.");
|
||||
//future.completeExceptionally(ex); // this exception can be ignored
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
LOGGER.error("Error loading file {}: ", this.file, ex);
|
||||
this.data.set(null);
|
||||
|
||||
future.completeExceptionally(e);
|
||||
future.completeExceptionally(ex);
|
||||
return null; // the return value here doesn't matter
|
||||
})
|
||||
.whenComplete((dataSource, e) ->
|
||||
|
||||
+2
-1
@@ -4,6 +4,7 @@ import java.io.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.ClosedByInterruptException;
|
||||
import java.nio.channels.ClosedChannelException;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.file.FileAlreadyExistsException;
|
||||
import java.nio.file.Files;
|
||||
@@ -240,7 +241,7 @@ public abstract class AbstractMetaDataContainerFile
|
||||
//LOGGER.info("replaced file: "+this.file.toPath());
|
||||
}
|
||||
}
|
||||
catch (ClosedByInterruptException e)
|
||||
catch (ClosedChannelException e) // includes ClosedByInterruptException
|
||||
{
|
||||
// expected if the file handler is shut down, the exception can be ignored
|
||||
// LOGGER.warn(AbstractMetaDataContainerFile.class.getSimpleName()+" file writing interrupted.");
|
||||
|
||||
+11
-5
@@ -24,6 +24,7 @@ import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
|
||||
public class RenderSourceFileHandler implements ILodRenderSourceProvider
|
||||
{
|
||||
@@ -273,16 +274,16 @@ public class RenderSourceFileHandler implements ILodRenderSourceProvider
|
||||
|
||||
final WeakReference<ColumnRenderSource> renderSourceReference = new WeakReference<>(renderSource); // TODO why is this a week reference?
|
||||
CompletableFuture<IFullDataSource> fullDataSourceFuture = this.fullDataSourceProvider.read(renderSource.getSectionPos());
|
||||
fullDataSourceFuture = fullDataSourceFuture.thenApply((dataSource) ->
|
||||
fullDataSourceFuture = fullDataSourceFuture.thenApply((fullDataSource) ->
|
||||
{
|
||||
if (renderSourceReference.get() == null)
|
||||
{
|
||||
throw new UncheckedInterruptedException();
|
||||
}
|
||||
LodUtil.assertTrue(dataSource != null);
|
||||
return dataSource;
|
||||
}
|
||||
).exceptionally((ex) ->
|
||||
|
||||
// the fullDataSource can be null if the thread this was running on was interrupted
|
||||
return fullDataSource;
|
||||
}).exceptionally((ex) ->
|
||||
{
|
||||
LOGGER.error("Exception when getting data for updateCache()", ex);
|
||||
return null;
|
||||
@@ -296,6 +297,11 @@ public class RenderSourceFileHandler implements ILodRenderSourceProvider
|
||||
if (ex instanceof InterruptedException)
|
||||
{
|
||||
// expected if the transformer is shut down, the exception can be ignored
|
||||
// LOGGER.warn("RenderSource file transforming interrupted.");
|
||||
}
|
||||
else if (ex instanceof RejectedExecutionException || ex.getCause() instanceof RejectedExecutionException)
|
||||
{
|
||||
// expected if the transformer was already shut down, the exception can be ignored
|
||||
// LOGGER.warn("RenderSource file transforming interrupted.");
|
||||
}
|
||||
else if (!UncheckedInterruptedException.isThrowableInterruption(ex))
|
||||
|
||||
Reference in New Issue
Block a user