Skip to content

Commit

Permalink
Simplify resource closing with IOUtils.
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisvest committed Oct 4, 2018
1 parent aa821f3 commit f2564a4
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 93 deletions.
98 changes: 46 additions & 52 deletions community/io/src/main/java/org/neo4j/io/IOUtils.java
Expand Up @@ -21,10 +21,8 @@


import java.io.IOException; import java.io.IOException;
import java.io.UncheckedIOException; import java.io.UncheckedIOException;
import java.lang.reflect.Constructor;
import java.util.Collection; import java.util.Collection;

import java.util.function.BiFunction;
import org.neo4j.helpers.Exceptions;


/** /**
* IO helper methods. * IO helper methods.
Expand All @@ -40,12 +38,12 @@ private IOUtils()
* *
* @param closeables the closeables to close * @param closeables the closeables to close
* @param <T> the type of closeable * @param <T> the type of closeable
* @throws IOException * @throws IOException if an exception was thrown by one of the close methods.
* @see #closeAll(AutoCloseable[]) * @see #closeAll(AutoCloseable[])
*/ */
public static <T extends AutoCloseable> void closeAll( Collection<T> closeables ) throws IOException public static <T extends AutoCloseable> void closeAll( Collection<T> closeables ) throws IOException
{ {
closeAll( closeables.toArray( new AutoCloseable[0] ) ); close( IOException::new, closeables.toArray( new AutoCloseable[0] ) );
} }


/** /**
Expand Down Expand Up @@ -77,13 +75,7 @@ public static <T extends AutoCloseable> void closeAllUnchecked( T... closeables
*/ */
public static <T extends AutoCloseable> void closeAllSilently( Collection<T> closeables ) public static <T extends AutoCloseable> void closeAllSilently( Collection<T> closeables )
{ {
try close( ( msg, cause ) -> null, closeables.toArray( new AutoCloseable[0] ) );
{
closeAll( closeables );
}
catch ( IOException ignored )
{
}
} }


/** /**
Expand All @@ -94,12 +86,12 @@ public static <T extends AutoCloseable> void closeAllSilently( Collection<T> clo
* *
* @param closeables the closeables to close * @param closeables the closeables to close
* @param <T> the type of closeable * @param <T> the type of closeable
* @throws IOException * @throws IOException if an exception was thrown by one of the close methods.
*/ */
@SafeVarargs @SafeVarargs
public static <T extends AutoCloseable> void closeAll( T... closeables ) throws IOException public static <T extends AutoCloseable> void closeAll( T... closeables ) throws IOException
{ {
closeAll( IOException.class, closeables ); close( IOException::new, closeables );
} }


/** /**
Expand All @@ -111,64 +103,66 @@ public static <T extends AutoCloseable> void closeAll( T... closeables ) throws
@SafeVarargs @SafeVarargs
public static <T extends AutoCloseable> void closeAllSilently( T... closeables ) public static <T extends AutoCloseable> void closeAllSilently( T... closeables )
{ {
try close( ( msg, cause ) -> null, closeables );
{
closeAll( closeables );
}
catch ( IOException ignored )
{
}
} }


/** /**
* Close all given closeables and if something goes wrong throw exception of the given type. * Close all ofthe given closeables, and if something goes wrong, use the given constructor to create a {@link Throwable} instance with the specific cause
* Exception class should have a public constructor that accepts {@link String} and {@link Throwable} like * attached. The remaining closeables will still be closed, in that case, and if they in turn throw any exceptions then these will be attached as
* {@link RuntimeException#RuntimeException(String, Throwable)} * suppressed exceptions.
* *
* @param throwableClass exception type to throw in case of failure * @param constructor The function used to construct the parent throwable that will have the first thrown exception attached as a cause, and any
* @param closeables the closeables to close * remaining exceptions attached as suppressed exceptions. If this function returns {@code null}, then the exception is ignored.
* @param <T> the type of closeable * @param closeables an iterator of all the things to close, in order.
* @param <E> the type of exception * @param <T> the type of things to close.
* @param <E> the type of the parent exception.
* @throws E when any {@link AutoCloseable#close()} throws exception
*/
public static <T extends AutoCloseable, E extends Throwable> void close( BiFunction<String,Throwable,E> constructor, Collection<T> closeables ) throws E
{
close( constructor, closeables.toArray( new AutoCloseable[0] ) );
}

/**
* Close all ofthe given closeables, and if something goes wrong, use the given constructor to create a {@link Throwable} instance with the specific cause
* attached. The remaining closeables will still be closed, in that case, and if they in turn throw any exceptions then these will be attached as
* suppressed exceptions.
*
* @param constructor The function used to construct the parent throwable that will have the first thrown exception attached as a cause, and any
* remaining exceptions attached as suppressed exceptions. If this function returns {@code null}, then the exception is ignored.
* @param closeables all the things to close, in order.
* @param <T> the type of things to close.
* @param <E> the type of the parent exception.
* @throws E when any {@link AutoCloseable#close()} throws exception * @throws E when any {@link AutoCloseable#close()} throws exception
*/ */
@SafeVarargs @SafeVarargs
public static <T extends AutoCloseable, E extends Throwable> void closeAll( Class<E> throwableClass, public static <T extends AutoCloseable, E extends Throwable> void close( BiFunction<String,Throwable,E> constructor, T... closeables ) throws E
T... closeables ) throws E
{ {
Throwable closeThrowable = null; E closeThrowable = null;
for ( T closeable : closeables ) for ( T closeable : closeables )
{ {
if ( closeable != null ) try
{ {
try if ( closeable != null )
{ {
closeable.close(); closeable.close();
} }
catch ( Throwable t ) }
catch ( Exception e )
{
if ( closeThrowable == null )
{
closeThrowable = constructor.apply( "Exception closing multiple resources.", e );
}
else
{ {
closeThrowable = Exceptions.chain( closeThrowable, t ); closeThrowable.addSuppressed( e );
} }
} }
} }
if ( closeThrowable != null ) if ( closeThrowable != null )
{ {
throw newThrowable( throwableClass, "Exception closing multiple resources", closeThrowable ); throw closeThrowable;
}
}

private static <E extends Throwable> E newThrowable( Class<E> throwableClass, String message, Throwable cause )
{
try
{
Constructor<E> constructor = throwableClass.getConstructor( String.class, Throwable.class );
return constructor.newInstance( message, cause );
}
catch ( Throwable t )
{
RuntimeException runtimeException = new RuntimeException(
"Unable to create exception to throw. Original message: " + message, t );
runtimeException.addSuppressed( cause );
throw runtimeException;
} }
} }
} }
8 changes: 8 additions & 0 deletions community/io/src/test/java/org/neo4j/io/IOUtilsTest.java
Expand Up @@ -68,4 +68,12 @@ public void closeAllAndRethrowException() throws Exception
IOUtils.closeAll( goodClosable1, faultyClosable, goodClosable2 ); IOUtils.closeAll( goodClosable1, faultyClosable, goodClosable2 );
} }


@Test
public void closeMustIgnoreNullResources() throws Exception
{
AutoCloseable a = () -> {};
AutoCloseable b = null;
AutoCloseable c = () -> {};
IOUtils.close( IOException::new, a, b, c );
}
} }
Expand Up @@ -21,7 +21,7 @@


public class AuxiliaryTransactionStateCloseException extends RuntimeException public class AuxiliaryTransactionStateCloseException extends RuntimeException
{ {
public AuxiliaryTransactionStateCloseException( String message, Exception cause ) public AuxiliaryTransactionStateCloseException( String message, Throwable cause )
{ {
super( message, cause ); super( message, cause );
} }
Expand Down
Expand Up @@ -63,7 +63,7 @@ public final void closeAllCloseableResources()
Collection<AutoCloseable> resourcesToClose = closeableResources; Collection<AutoCloseable> resourcesToClose = closeableResources;
closeableResources = null; closeableResources = null;


IOUtils.closeAll( ResourceCloseFailureException.class, resourcesToClose.toArray( new AutoCloseable[0] ) ); IOUtils.close( ResourceCloseFailureException::new, resourcesToClose.toArray( new AutoCloseable[0] ) );
} }
} }
} }
Expand Up @@ -36,7 +36,7 @@


public class KernelAuxTransactionStateManager implements AuxiliaryTransactionStateManager public class KernelAuxTransactionStateManager implements AuxiliaryTransactionStateManager
{ {
private volatile CopyOnWriteHashMap<Object, AuxiliaryTransactionStateProvider> providers; private volatile CopyOnWriteHashMap<Object,AuxiliaryTransactionStateProvider> providers;


public KernelAuxTransactionStateManager() public KernelAuxTransactionStateManager()
{ {
Expand All @@ -63,12 +63,12 @@ public AuxiliaryTransactionStateHolder openStateHolder()


private static class AuxStateHolder implements AuxiliaryTransactionStateHolder, Function<Object,AuxiliaryTransactionState> private static class AuxStateHolder implements AuxiliaryTransactionStateHolder, Function<Object,AuxiliaryTransactionState>
{ {
private final Map<Object, AuxiliaryTransactionStateProvider> providers; private final Map<Object,AuxiliaryTransactionStateProvider> providers;
private final Map<Object, AuxiliaryTransactionState> openedStates; private final Map<Object,AuxiliaryTransactionState> openedStates;


AuxStateHolder( Map<Object,AuxiliaryTransactionStateProvider> providers ) AuxStateHolder( Map<Object,AuxiliaryTransactionStateProvider> providers )
{ {
this.providers = providers; this.providers = providers;
openedStates = new HashMap<>(); openedStates = new HashMap<>();
} }


Expand Down Expand Up @@ -121,25 +121,8 @@ public void extractCommands( Collection<StorageCommand> extractedCommands ) thro
@Override @Override
public void close() throws AuxiliaryTransactionStateCloseException public void close() throws AuxiliaryTransactionStateCloseException
{ {
AuxiliaryTransactionStateCloseException exception = null; IOUtils.close( ( msg, cause ) -> new AuxiliaryTransactionStateCloseException( "Failure when closing auxiliary transaction state.", cause ),
for ( AuxiliaryTransactionState state : openedStates.values() ) openedStates.values() );
{
try
{
state.close();
}
catch ( Exception e )
{
if ( exception == null )
{
exception = new AuxiliaryTransactionStateCloseException( "Failure when closing auxiliary transaction state.", e );
}
else
{
exception.addSuppressed( e );
}
}
}
} }
} }
} }
Expand Up @@ -35,10 +35,10 @@
/** /**
* This class filters acceptNode() calls from an index progressor, to assert that exact entries returned from the * This class filters acceptNode() calls from an index progressor, to assert that exact entries returned from the
* progressor really match the exact property values. See also org.neo4j.kernel.impl.api.LookupFilter. * progressor really match the exact property values. See also org.neo4j.kernel.impl.api.LookupFilter.
* * <p>
* It works by acting as a man-in-the-middle between outer {@link NodeValueClient client} and inner {@link IndexProgressor}. * It works by acting as a man-in-the-middle between outer {@link NodeValueClient client} and inner {@link IndexProgressor}.
* Interaction goes like: * Interaction goes like:
* * <p>
* Initialize: * Initialize:
* <pre><code> * <pre><code>
* client * client
Expand All @@ -47,7 +47,7 @@
* filter <- initialize(progressor) -- progressor * filter <- initialize(progressor) -- progressor
* client <- initialize(filter) -- filter * client <- initialize(filter) -- filter
* </code></pre> * </code></pre>
* * <p>
* Progress: * Progress:
* <pre><code> * <pre><code>
* client -- next() -> filter * client -- next() -> filter
Expand All @@ -61,7 +61,7 @@
* -- :true -> filter -- :true -> progressor * -- :true -> filter -- :true -> progressor
* client <---------------------------------------------- * client <----------------------------------------------
* </code></pre> * </code></pre>
* * <p>
* Close: * Close:
* <pre><code> * <pre><code>
* client -- close() -> filter * client -- close() -> filter
Expand All @@ -78,9 +78,7 @@ class NodeValueClientFilter implements NodeValueClient, IndexProgressor
private final org.neo4j.internal.kernel.api.Read read; private final org.neo4j.internal.kernel.api.Read read;
private IndexProgressor progressor; private IndexProgressor progressor;


NodeValueClientFilter( NodeValueClientFilter( NodeValueClient target, NodeCursor node, PropertyCursor property, Read read, IndexQuery... filters )
NodeValueClient target,
NodeCursor node, PropertyCursor property, Read read, IndexQuery... filters )
{ {
this.target = target; this.target = target;
this.node = node; this.node = node;
Expand All @@ -90,11 +88,7 @@ class NodeValueClientFilter implements NodeValueClient, IndexProgressor
} }


@Override @Override
public void initialize( IndexDescriptor descriptor, public void initialize( IndexDescriptor descriptor, IndexProgressor progressor, IndexQuery[] query, IndexOrder indexOrder, boolean needsValues )
IndexProgressor progressor,
IndexQuery[] query,
IndexOrder indexOrder,
boolean needsValues )
{ {
this.progressor = progressor; this.progressor = progressor;
target.initialize( descriptor, this, query, indexOrder, needsValues ); target.initialize( descriptor, this, query, indexOrder, needsValues );
Expand Down Expand Up @@ -193,6 +187,6 @@ public boolean next()
@Override @Override
public void close() public void close()
{ {
IOUtils.closeAll( RuntimeException.class, node, property, progressor ); IOUtils.close( RuntimeException::new, node, property, progressor );
} }
} }
Expand Up @@ -735,9 +735,9 @@ public void close()
Resource resourceToClose = closeableResource; Resource resourceToClose = closeableResource;
closeableResource = null; closeableResource = null;


IOUtils.closeAll( ResourceCloseFailureException.class, IOUtils.close( ResourceCloseFailureException::new,
() -> resourceTracker.unregisterCloseableResource( resourceToClose ), () -> resourceTracker.unregisterCloseableResource( resourceToClose ),
resourceToClose::close ); resourceToClose );
} }
} }


Expand Down
Expand Up @@ -47,7 +47,7 @@ <T extends AutoCloseable> T add( T closeable )
@Override @Override
public void close() public void close()
{ {
IOUtils.closeAll( RuntimeException.class, closeables.toArray( new AutoCloseable[closeables.size()] ) ); IOUtils.close( RuntimeException::new, closeables );
} }


@Override @Override
Expand Down

0 comments on commit f2564a4

Please sign in to comment.