add pre-shutdown action to be executed inside ChronicleHashCloseOnExitHook.

This is useful when we want to do an orderly shutdown.
For example: To carry out graceful shutdown and explicitly control when a ChronicleHash
is closed, a pre-shutdown action can be a wait on a CountDownLatch that would be released
appropriately.
This commit is contained in:
udaysagar2177
2018-09-21 00:36:04 -07:00
parent ccb6577c3d
commit 9eed0e3265
9 changed files with 105 additions and 11 deletions
@@ -32,6 +32,7 @@ import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
/**
* Base interface for {@link ChronicleMapBuilder} and {@link ChronicleSetBuilder}, i. e. defines
@@ -745,6 +746,22 @@ public interface ChronicleHashBuilder<K, H extends ChronicleHash<K, ?, ?, ?>,
File file, boolean sameBuilderConfigAndLibraryVersion,
ChronicleHashCorruption.Listener corruptionListener) throws IOException;
/**
* A {@link ChronicleHash} created using this builder is closed using a JVM shutdown hook.
* This method lets you perform an action before the {@link ChronicleHash} is closed.
* <p>
* <p>The registered action is not executed when JVM is running and a
* {@link ChronicleHash#close()} is explicitly called.
* <p>
* <p>Example usage of this call: To carry out a graceful shutdown and explicitly
* control when the {@link ChronicleHash} is closed, the action can be a wait on a
* {@link CountDownLatch} that would be released appropriately.
*
* @param preShutdownAction action to run before closing the {@link ChronicleHash} in a
* JVM shutdown hook.
*/
void setPreShutdownAction(Runnable preShutdownAction);
/**
* @deprecated don't use private API in the client code
*/
@@ -90,4 +90,12 @@ public interface ChronicleHashBuilderPrivateAPI<K, RO> {
void removedEntryCleanupTimeout(long removedEntryCleanupTimeout, TimeUnit unit);
void remoteOperations(RO remoteOperations);
/**
* Provides registered action to be executed before closing a {@link ChronicleHash} in a JVM
* shutdown hook.
*
* @return registered pre-shutdown action.
*/
Runnable getPreShutdownAction();
}
@@ -60,6 +60,20 @@ final class ChronicleHashCloseOnExitHook {
// close later added maps first
orderedMaps.descendingMap().values().forEach(h -> {
try {
Runnable preShutdownAction = h.getPreShutdownAction();
if (preShutdownAction != null) {
try {
preShutdownAction.run();
} catch (Throwable throwable) {
try {
LOG.error("Error running pre-shutdown action for " + h.toIdentityString() +
" :", throwable);
} catch (Throwable t2) {
throwable.addSuppressed(t2);
throwable.printStackTrace();
}
}
}
h.close();
} catch (Throwable throwable) {
try {
@@ -125,6 +125,7 @@ public abstract class VanillaChronicleHash<K,
public transient CompactOffHeapLinearHashTable hashLookup;
public transient Identity identity;
protected int log2TiersInBulk;
private Runnable preShutdownAction;
/////////////////////////////////////////////////
// Bytes Store (essentially, the base address) and serialization-dependent offsets
protected transient BytesStore bs;
@@ -208,6 +209,8 @@ public abstract class VanillaChronicleHash<K,
tierBulkSizeInBytes = computeTierBulkBytesSize(tiersInBulk);
checksumEntries = privateAPI.checksumEntries();
preShutdownAction = privateAPI.getPreShutdownAction();
}
public static IOException throwRecoveryOrReturnIOException(
@@ -230,6 +233,10 @@ public abstract class VanillaChronicleHash<K,
initTransients();
}
public Runnable getPreShutdownAction() {
return preShutdownAction;
}
protected void readMarshallableFields(@NotNull WireIn wireIn) {
dataFileVersion = wireIn.read(() -> "dataFileVersion").text();
@@ -181,6 +181,7 @@ public final class ChronicleMapBuilder<K, V> implements
MapMethods<K, V, ?> methods = DefaultSpi.mapMethods();
MapEntryOperations<K, V, ?> entryOperations = mapEntryOperations();
MapRemoteOperations<K, V, ?> remoteOperations = mapRemoteOperations();
Runnable preShutdownAction;
private String name;
// not final because of cloning
private ChronicleMapBuilderPrivateAPI<K, V> privateAPI =
@@ -1587,6 +1588,11 @@ public final class ChronicleMapBuilder<K, V> implements
corruptionListener);
}
@Override
public void setPreShutdownAction(Runnable preShutdownAction) {
this.preShutdownAction = preShutdownAction;
}
@Override
public ChronicleMap<K, V> create() {
// clone() to make this builder instance thread-safe, because createWithoutFile() method
@@ -116,4 +116,9 @@ class ChronicleMapBuilderPrivateAPI<K, V>
public void remoteOperations(MapRemoteOperations<K, V, ?> remoteOperations) {
b.remoteOperations(remoteOperations);
}
@Override
public Runnable getPreShutdownAction() {
return b.preShutdownAction;
}
}
@@ -353,6 +353,11 @@ public final class ChronicleSetBuilder<K>
return new SetFromMap<>((VanillaChronicleMap<K, DummyValue, ?>) map);
}
@Override
public void setPreShutdownAction(Runnable preShutdownAction) {
chronicleMapBuilder.setPreShutdownAction(preShutdownAction);
}
/**
* @deprecated don't use private API in the client code
*/
@@ -134,4 +134,9 @@ class ChronicleSetBuilderPrivateAPI<K>
}
});
}
@Override
public Runnable getPreShutdownAction() {
return mapB.getPreShutdownAction();
}
}