/** * Triggers an asynchronous snapshot of the keyed state backend from RocksDB. This snapshot can be * canceled and is also stopped when the backend is closed through {@link #dispose()}. For each * backend, this method must always be called by the same thread. * * @param checkpointId The Id of the checkpoint. * @param timestamp The timestamp of the checkpoint. * @param streamFactory The factory that we can use for writing our state to streams. * @return Future to the state handle of the snapshot data. * @throws Exception */ @Override public RunnableFuture<KeyGroupsStateHandle> snapshot( final long checkpointId, final long timestamp, final CheckpointStreamFactory streamFactory) throws Exception { long startTime = System.currentTimeMillis(); final RocksDBSnapshotOperation snapshotOperation = new RocksDBSnapshotOperation(this, streamFactory); // hold the db lock while operation on the db to guard us against async db disposal synchronized (asyncSnapshotLock) { if (kvStateInformation.isEmpty()) { LOG.info( "Asynchronous RocksDB snapshot performed on empty keyed state at " + timestamp + " . Returning null."); return new DoneFuture<>(null); } if (db != null) { snapshotOperation.takeDBSnapShot(checkpointId, timestamp); } else { throw new IOException("RocksDB closed."); } } // implementation of the async IO operation, based on FutureTask AbstractAsyncIOCallable< KeyGroupsStateHandle, CheckpointStreamFactory.CheckpointStateOutputStream> ioCallable = new AbstractAsyncIOCallable< KeyGroupsStateHandle, CheckpointStreamFactory.CheckpointStateOutputStream>() { @Override public CheckpointStreamFactory.CheckpointStateOutputStream openIOHandle() throws Exception { snapshotOperation.openCheckpointStream(); return snapshotOperation.getOutStream(); } @Override public KeyGroupsStateHandle performOperation() throws Exception { long startTime = System.currentTimeMillis(); synchronized (asyncSnapshotLock) { try { // hold the db lock while operation on the db to guard us against async db // disposal if (db == null) { throw new IOException("RocksDB closed."); } snapshotOperation.writeDBSnapshot(); } finally { snapshotOperation.closeCheckpointStream(); } } LOG.info( "Asynchronous RocksDB snapshot (" + streamFactory + ", asynchronous part) in thread " + Thread.currentThread() + " took " + (System.currentTimeMillis() - startTime) + " ms."); return snapshotOperation.getSnapshotResultStateHandle(); } private void releaseSnapshotOperationResources(boolean canceled) { // hold the db lock while operation on the db to guard us against async db disposal synchronized (asyncSnapshotLock) { snapshotOperation.releaseSnapshotResources(canceled); } } @Override public void done(boolean canceled) { releaseSnapshotOperationResources(canceled); } }; LOG.info( "Asynchronous RocksDB snapshot (" + streamFactory + ", synchronous part) in thread " + Thread.currentThread() + " took " + (System.currentTimeMillis() - startTime) + " ms."); return AsyncStoppableTaskWithCallback.from(ioCallable); }