From 487ebe4fd53a5b9ec1f4c9fc5fd436a404a19b91 Mon Sep 17 00:00:00 2001 From: Sahib Pandori Date: Tue, 7 Apr 2020 20:13:55 -0700 Subject: [PATCH] Add Java API for rocksdb::CancelAllBackgroundWork() (#6657) Summary: Adding a Java API for rocksdb::CancelAllBackgroundWork() so that the user can call this (when required) before closing the DB. This is to **prevent the crashes when manual compaction is running and the user decides to close the DB**. Calling CancelAllBackgroundWork() seems to be the recommended way to make sure that it's safe to close the DB (according to RocksDB FAQ: https://github.com/facebook/rocksdb/wiki/RocksDB-FAQ#basic-readwrite). Pull Request resolved: https://github.com/facebook/rocksdb/pull/6657 Reviewed By: cheng-chang Differential Revision: D20896395 Pulled By: pdillinger fbshipit-source-id: 8a8208c10093db09bd35db9af362211897870d96 --- java/rocksjni/rocksjni.cc | 11 ++++ java/src/main/java/org/rocksdb/RocksDB.java | 13 +++++ .../test/java/org/rocksdb/RocksDBTest.java | 51 +++++++++++++++++++ 3 files changed, 75 insertions(+) diff --git a/java/rocksjni/rocksjni.cc b/java/rocksjni/rocksjni.cc index 84175913a..5ccda2670 100644 --- a/java/rocksjni/rocksjni.cc +++ b/java/rocksjni/rocksjni.cc @@ -2610,6 +2610,17 @@ jobjectArray Java_org_rocksdb_RocksDB_compactFiles( return ROCKSDB_NAMESPACE::JniUtil::toJavaStrings(env, &output_file_names); } +/* + * Class: org_rocksdb_RocksDB + * Method: cancelAllBackgroundWork + * Signature: (JZ)V + */ +void Java_org_rocksdb_RocksDB_cancelAllBackgroundWork( + JNIEnv*, jobject, jlong jdb_handle, jboolean jwait) { + auto* db = reinterpret_cast(jdb_handle); + rocksdb::CancelAllBackgroundWork(db, jwait); +} + /* * Class: org_rocksdb_RocksDB * Method: pauseBackgroundWork diff --git a/java/src/main/java/org/rocksdb/RocksDB.java b/java/src/main/java/org/rocksdb/RocksDB.java index 338324b13..05d9ca201 100644 --- a/java/src/main/java/org/rocksdb/RocksDB.java +++ b/java/src/main/java/org/rocksdb/RocksDB.java @@ -3479,6 +3479,17 @@ public class RocksDB extends RocksObject { compactionJobInfo == null ? 0 : compactionJobInfo.nativeHandle_)); } + /** + * This function will cancel all currently running background processes. + * + * @param wait if true, wait for all background work to be cancelled before + * returning. + * + */ + public void cancelAllBackgroundWork(boolean wait) { + cancelAllBackgroundWork(nativeHandle_, wait); + } + /** * This function will wait until all currently running background processes * finish. After it returns, no background process will be run until @@ -4457,6 +4468,8 @@ public class RocksDB extends RocksObject { final int outputLevel, final int outputPathId, final long compactionJobInfoHandle) throws RocksDBException; + private native void cancelAllBackgroundWork(final long handle, + final boolean wait); private native void pauseBackgroundWork(final long handle) throws RocksDBException; private native void continueBackgroundWork(final long handle) diff --git a/java/src/test/java/org/rocksdb/RocksDBTest.java b/java/src/test/java/org/rocksdb/RocksDBTest.java index b4d96ed43..f6acfaa64 100644 --- a/java/src/test/java/org/rocksdb/RocksDBTest.java +++ b/java/src/test/java/org/rocksdb/RocksDBTest.java @@ -1084,6 +1084,57 @@ public class RocksDBTest { } } + @Test + public void continueBackgroundWorkAfterCancelAllBackgroundWork() throws RocksDBException { + final int KEY_SIZE = 20; + final int VALUE_SIZE = 300; + try (final DBOptions opt = new DBOptions(). + setCreateIfMissing(true). + setCreateMissingColumnFamilies(true); + final ColumnFamilyOptions new_cf_opts = new ColumnFamilyOptions() + ) { + final List columnFamilyDescriptors = + Arrays.asList( + new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY), + new ColumnFamilyDescriptor("new_cf".getBytes(), new_cf_opts) + ); + + final List columnFamilyHandles = new ArrayList<>(); + // open the database + try (final RocksDB db = RocksDB.open(opt, + dbFolder.getRoot().getAbsolutePath(), + columnFamilyDescriptors, + columnFamilyHandles)) { + try { + db.cancelAllBackgroundWork(true); + try { + db.put(new byte[KEY_SIZE], new byte[VALUE_SIZE]); + db.flush(new FlushOptions().setWaitForFlush(true)); + fail("Expected RocksDBException to be thrown if we attempt to trigger a flush after" + + " all background work is cancelled."); + } catch (RocksDBException ignored) { } + } finally { + for (final ColumnFamilyHandle handle : columnFamilyHandles) { + handle.close(); + } + } + } + } + } + + @Test + public void cancelAllBackgroundWorkTwice() throws RocksDBException { + try (final Options options = new Options().setCreateIfMissing(true); + final RocksDB db = RocksDB.open(options, + dbFolder.getRoot().getAbsolutePath()) + ) { + // Cancel all background work synchronously + db.cancelAllBackgroundWork(true); + // Cancel all background work asynchronously + db.cancelAllBackgroundWork(false); + } + } + @Test public void pauseContinueBackgroundWork() throws RocksDBException { try (final Options options = new Options().setCreateIfMissing(true);