Returns a list of corrupted backup ids. If there
+ * is no corrupted backup the method will return an
+ * empty list.
+ *
+ * @return array of backup ids as int ids.
+ */
+ public int[] getCorruptedBackups() {
+ assert(isInitialized());
+ return getCorruptedBackups(nativeHandle_);
+ }
+
+ /**
+ * Will delete all the files we don't need anymore. It will
+ * do the full scan of the files/ directory and delete all the
+ * files that are not referenced.
+ *
+ * @throws RocksDBException thrown if error happens in underlying
+ * native library.
+ */
+ public void garbageCollect() throws RocksDBException {
+ assert(isInitialized());
+ garbageCollect(nativeHandle_);
+ }
+
+ /**
+ * Close the BackupableDB instance and release resource.
*
- * Internally, BackupableDB owns the {@code rocksdb::DB} pointer to its associated
- * {@link org.rocksdb.RocksDB}. The release of that RocksDB pointer is handled in the destructor
- * of the c++ {@code rocksdb::BackupableDB} and should be transparent to Java developers.
+ * Internally, {@link BackupableDB} owns the {@code rocksdb::DB}
+ * pointer to its associated {@link org.rocksdb.RocksDB}.
+ * The release of that RocksDB pointer is handled in the destructor
+ * of the c++ {@code rocksdb::BackupableDB} and should be transparent
+ * to Java developers.
*/
@Override public synchronized void close() {
if (isInitialized()) {
@@ -106,8 +139,9 @@ public class BackupableDB extends RocksDB {
}
/**
- * A protected construction that will be used in the static factory
- * method {@link #open(Options, BackupableDBOptions, String)}.
+ * A protected construction that will be used in the static
+ * factory method {@link #open(Options, BackupableDBOptions, String)}.
+ *
*/
protected BackupableDB() {
super();
@@ -126,4 +160,7 @@ public class BackupableDB extends RocksDB {
private native void deleteBackup0(long nativeHandle, int backupId)
throws RocksDBException;
protected native List getBackupInfo(long handle);
+ private native int[] getCorruptedBackups(long handle);
+ private native void garbageCollect(long handle)
+ throws RocksDBException;
}
diff --git a/java/org/rocksdb/BackupableDBOptions.java b/java/org/rocksdb/BackupableDBOptions.java
index 07751a64d..ab532f282 100644
--- a/java/org/rocksdb/BackupableDBOptions.java
+++ b/java/org/rocksdb/BackupableDBOptions.java
@@ -5,63 +5,242 @@
package org.rocksdb;
+import java.io.File;
+import java.nio.file.Path;
+
/**
- * BackupableDBOptions to control the behavior of a backupable database.
+ * BackupableDBOptions to control the behavior of a backupable database.
* It will be used during the creation of a {@link org.rocksdb.BackupableDB}.
- *
- * Note that dispose() must be called before an Options instance
- * become out-of-scope to release the allocated memory in c++.
+ *
+ * Note that dispose() must be called before an Options instance
+ * become out-of-scope to release the allocated memory in c++.
*
* @see org.rocksdb.BackupableDB
*/
public class BackupableDBOptions extends RocksObject {
/**
- * BackupableDBOptions constructor
+ * BackupableDBOptions constructor.
*
* @param path Where to keep the backup files. Has to be different than db name.
- * Best to set this to {@code db name_ + "/backups"}
+ * Best to set this to {@code db name_ + "/backups"}
+ * @throws java.lang.IllegalArgumentException if illegal path is used.
+ */
+ public BackupableDBOptions(String path) {
+ super();
+ File backupPath = path == null ? null : new File(path);
+ if (backupPath == null || !backupPath.isDirectory() || !backupPath.canWrite()) {
+ throw new IllegalArgumentException("Illegal path provided.");
+ }
+ newBackupableDBOptions(path);
+ }
+
+ /**
+ * Returns the path to the BackupableDB directory.
+ *
+ * @return the path to the BackupableDB directory.
+ */
+ public String backupDir() {
+ assert(isInitialized());
+ return backupDir(nativeHandle_);
+ }
+
+ /**
+ * Share table files between backups.
+ *
* @param shareTableFiles If {@code share_table_files == true}, backup will assume
* that table files with same name have the same contents. This enables incremental
* backups and avoids unnecessary data copies. If {@code share_table_files == false},
* each backup will be on its own and will not share any data with other backups.
- * Default: true
+ *
+ * Default: true
+ *
+ * @return instance of current BackupableDBOptions.
+ */
+ public BackupableDBOptions setShareTableFiles(boolean shareTableFiles) {
+ assert(isInitialized());
+ setShareTableFiles(nativeHandle_, shareTableFiles);
+ return this;
+ }
+
+ /**
+ * Share table files between backups.
+ *
+ * @return boolean value indicating if SST files will be shared between
+ * backups.
+ */
+ public boolean shareTableFiles() {
+ assert(isInitialized());
+ return shareTableFiles(nativeHandle_);
+ }
+
+ /**
+ * Set synchronous backups.
+ *
* @param sync If {@code sync == true}, we can guarantee you'll get consistent backup
* even on a machine crash/reboot. Backup process is slower with sync enabled.
* If {@code sync == false}, we don't guarantee anything on machine reboot.
* However,chances are some of the backups are consistent.
- * Default: true
+ *
+ * Default: true
+ *
+ * @return instance of current BackupableDBOptions.
+ */
+ public BackupableDBOptions setSync(boolean sync) {
+ assert(isInitialized());
+ setSync(nativeHandle_, sync);
+ return this;
+ }
+
+ /**
+ * Are synchronous backups activated.
+ *
+ * @return boolean value if synchronous backups are configured.
+ */
+ public boolean sync() {
+ assert(isInitialized());
+ return sync(nativeHandle_);
+ }
+
+ /**
+ * Set if old data will be destroyed.
+ *
* @param destroyOldData If true, it will delete whatever backups there are already.
- * Default: false
+ *
+ * Default: false
+ *
+ * @return instance of current BackupableDBOptions.
+ */
+ public BackupableDBOptions setDestroyOldData(boolean destroyOldData) {
+ assert(isInitialized());
+ setDestroyOldData(nativeHandle_, destroyOldData);
+ return this;
+ }
+
+ /**
+ * Returns if old data will be destroyed will performing new backups.
+ *
+ * @return boolean value indicating if old data will be destroyed.
+ */
+ public boolean destroyOldData() {
+ assert(isInitialized());
+ return destroyOldData(nativeHandle_);
+ }
+
+ /**
+ * Set if log files shall be persisted.
+ *
* @param backupLogFiles If false, we won't backup log files. This option can be
* useful for backing up in-memory databases where log file are persisted,but table
* files are in memory.
- * Default: true
- * @param backupRateLimit Max bytes that can be transferred in a second during backup.
- * If 0 or negative, then go as fast as you can. Default: 0
- * @param restoreRateLimit Max bytes that can be transferred in a second during restore.
- * If 0 or negative, then go as fast as you can. Default: 0
+ *
+ * Default: true
+ *
+ * @return instance of current BackupableDBOptions.
*/
- public BackupableDBOptions(String path, boolean shareTableFiles, boolean sync,
- boolean destroyOldData, boolean backupLogFiles, long backupRateLimit,
- long restoreRateLimit) {
- super();
+ public BackupableDBOptions setBackupLogFiles(boolean backupLogFiles) {
+ assert(isInitialized());
+ setBackupLogFiles(nativeHandle_, backupLogFiles);
+ return this;
+ }
+
+ /**
+ * Return information if log files shall be persisted.
+ *
+ * @return boolean value indicating if log files will be persisted.
+ */
+ public boolean backupLogFiles() {
+ assert(isInitialized());
+ return backupLogFiles(nativeHandle_);
+ }
+ /**
+ * Set backup rate limit.
+ *
+ * @param backupRateLimit Max bytes that can be transferred in a second during backup.
+ * If 0 or negative, then go as fast as you can.
+ *
+ * Default: 0
+ *
+ * @return instance of current BackupableDBOptions.
+ */
+ public BackupableDBOptions setBackupRateLimit(long backupRateLimit) {
+ assert(isInitialized());
backupRateLimit = (backupRateLimit <= 0) ? 0 : backupRateLimit;
+ setBackupRateLimit(nativeHandle_, backupRateLimit);
+ return this;
+ }
+
+ /**
+ * Return backup rate limit which described the max bytes that can be transferred in a
+ * second during backup.
+ *
+ * @return numerical value describing the backup transfer limit in bytes per second.
+ */
+ public long backupRateLimit() {
+ assert(isInitialized());
+ return backupRateLimit(nativeHandle_);
+ }
+
+ /**
+ * Set restore rate limit.
+ *
+ * @param restoreRateLimit Max bytes that can be transferred in a second during restore.
+ * If 0 or negative, then go as fast as you can.
+ *
+ * Default: 0
+ *
+ * @return instance of current BackupableDBOptions.
+ */
+ public BackupableDBOptions setRestoreRateLimit(long restoreRateLimit) {
+ assert(isInitialized());
restoreRateLimit = (restoreRateLimit <= 0) ? 0 : restoreRateLimit;
+ setRestoreRateLimit(nativeHandle_, restoreRateLimit);
+ return this;
+ }
+
+ /**
+ * Return restore rate limit which described the max bytes that can be transferred in a
+ * second during restore.
+ *
+ * @return numerical value describing the restore transfer limit in bytes per second.
+ */
+ public long restoreRateLimit() {
+ assert(isInitialized());
+ return restoreRateLimit(nativeHandle_);
+ }
- newBackupableDBOptions(path, shareTableFiles, sync, destroyOldData,
- backupLogFiles, backupRateLimit, restoreRateLimit);
+ /**
+ * Only used if share_table_files is set to true. If true, will consider that
+ * backups can come from different databases, hence a sst is not uniquely
+ * identified by its name, but by the triple (file name, crc32, file length)
+ *
+ * @param shareFilesWithChecksum boolean value indicating if SST files are stored
+ * using the triple (file name, crc32, file length) and not its name.
+ *
+ * Note: this is an experimental option, and you'll need to set it manually
+ * turn it on only if you know what you're doing*
+ *
+ * Default: false
+ *
+ * @return instance of current BackupableDBOptions.
+ */
+ public BackupableDBOptions setShareFilesWithChecksum(
+ boolean shareFilesWithChecksum) {
+ assert(isInitialized());
+ setShareFilesWithChecksum(nativeHandle_, shareFilesWithChecksum);
+ return this;
}
/**
- * Returns the path to the BackupableDB directory.
+ * Return of share files with checksum is active.
*
- * @return the path to the BackupableDB directory.
+ * @return boolean value indicating if share files with checksum
+ * is active.
*/
- public String backupDir() {
+ public boolean shareFilesWithChecksum() {
assert(isInitialized());
- return backupDir(nativeHandle_);
+ return shareFilesWithChecksum(nativeHandle_);
}
/**
@@ -69,13 +248,24 @@ public class BackupableDBOptions extends RocksObject {
* in the c++ side.
*/
@Override protected void disposeInternal() {
- assert(isInitialized());
disposeInternal(nativeHandle_);
}
- private native void newBackupableDBOptions(String path,
- boolean shareTableFiles, boolean sync, boolean destroyOldData,
- boolean backupLogFiles, long backupRateLimit, long restoreRateLimit);
+ private native void newBackupableDBOptions(String path);
private native String backupDir(long handle);
+ private native void setShareTableFiles(long handle, boolean flag);
+ private native boolean shareTableFiles(long handle);
+ private native void setSync(long handle, boolean flag);
+ private native boolean sync(long handle);
+ private native void setDestroyOldData(long handle, boolean flag);
+ private native boolean destroyOldData(long handle);
+ private native void setBackupLogFiles(long handle, boolean flag);
+ private native boolean backupLogFiles(long handle);
+ private native void setBackupRateLimit(long handle, long rateLimit);
+ private native long backupRateLimit(long handle);
+ private native void setRestoreRateLimit(long handle, long rateLimit);
+ private native long restoreRateLimit(long handle);
+ private native void setShareFilesWithChecksum(long handle, boolean flag);
+ private native boolean shareFilesWithChecksum(long handle);
private native void disposeInternal(long handle);
}
diff --git a/java/org/rocksdb/RestoreBackupableDB.java b/java/org/rocksdb/RestoreBackupableDB.java
index ffbc2e011..e29628815 100644
--- a/java/org/rocksdb/RestoreBackupableDB.java
+++ b/java/org/rocksdb/RestoreBackupableDB.java
@@ -8,15 +8,17 @@ package org.rocksdb;
import java.util.List;
/**
- * This class is used to access information about backups and restore from them.
+ * This class is used to access information about backups and
+ * restore from them.
*
- * Note that dispose() must be called before this instance become out-of-scope
- * to release the allocated memory in c++.
+ * Note: {@code dispose()} must be called before this instance
+ * become out-of-scope to release the allocated
+ * memory in c++.
*
*/
public class RestoreBackupableDB extends RocksObject {
/**
- * Constructor
+ * Construct new estoreBackupableDB instance.
*
* @param options {@link org.rocksdb.BackupableDBOptions} instance
*/
@@ -26,16 +28,18 @@ public class RestoreBackupableDB extends RocksObject {
}
/**
- * Restore from backup with backup_id
- * IMPORTANT -- if options_.share_table_files == true and you restore DB
- * from some backup that is not the latest, and you start creating new
- * backups from the new DB, they will probably fail.
+ * Restore from backup with backup_id.
*
- * Example: Let's say you have backups 1, 2, 3, 4, 5 and you restore 3.
- * If you add new data to the DB and try creating a new backup now, the
- * database will diverge from backups 4 and 5 and the new backup will fail.
- * If you want to create new backup, you will first have to delete backups 4
- * and 5.
+ * Important: If options_.share_table_files == true
+ * and you restore DB from some backup that is not the latest, and you
+ * start creating new backups from the new DB, they will probably
+ * fail.
+ *
+ * Example: Let's say you have backups 1, 2, 3, 4, 5
+ * and you restore 3. If you add new data to the DB and try creating a new
+ * backup now, the database will diverge from backups 4 and 5 and the new
+ * backup will fail. If you want to create new backup, you will first have
+ * to delete backups 4 and 5.
*
* @param backupId id pointing to backup
* @param dbDir database directory to restore to
@@ -47,12 +51,13 @@ public class RestoreBackupableDB extends RocksObject {
*/
public void restoreDBFromBackup(long backupId, String dbDir, String walDir,
RestoreOptions restoreOptions) throws RocksDBException {
+ assert(isInitialized());
restoreDBFromBackup0(nativeHandle_, backupId, dbDir, walDir,
restoreOptions.nativeHandle_);
}
/**
- * Restore from the latest backup.
+ * Restore from the latest backup.
*
* @param dbDir database directory to restore to
* @param walDir directory where wal files are located
@@ -63,12 +68,13 @@ public class RestoreBackupableDB extends RocksObject {
*/
public void restoreDBFromLatestBackup(String dbDir, String walDir,
RestoreOptions restoreOptions) throws RocksDBException {
+ assert(isInitialized());
restoreDBFromLatestBackup0(nativeHandle_, dbDir, walDir,
restoreOptions.nativeHandle_);
}
/**
- * Deletes old backups, keeping latest numBackupsToKeep alive.
+ * Deletes old backups, keeping latest numBackupsToKeep alive.
*
* @param numBackupsToKeep of latest backups to keep
*
@@ -76,11 +82,12 @@ public class RestoreBackupableDB extends RocksObject {
* native library.
*/
public void purgeOldBackups(int numBackupsToKeep) throws RocksDBException {
+ assert(isInitialized());
purgeOldBackups0(nativeHandle_, numBackupsToKeep);
}
/**
- * Deletes a specific backup.
+ * Deletes a specific backup.
*
* @param backupId of backup to delete.
*
@@ -88,25 +95,51 @@ public class RestoreBackupableDB extends RocksObject {
* native library.
*/
public void deleteBackup(int backupId) throws RocksDBException {
+ assert(isInitialized());
deleteBackup0(nativeHandle_, backupId);
}
/**
- * Returns a list of {@link BackupInfo} instances, which describe
- * already made backups.
+ * Returns a list of {@link BackupInfo} instances, which describe
+ * already made backups.
*
* @return List of {@link BackupInfo} instances.
*/
public List getBackupInfos() {
+ assert(isInitialized());
return getBackupInfo(nativeHandle_);
}
/**
- * Release the memory allocated for the current instance
- * in the c++ side.
+ * Returns a list of corrupted backup ids. If there
+ * is no corrupted backup the method will return an
+ * empty list.
+ *
+ * @return array of backup ids as int ids.
*/
- @Override public synchronized void disposeInternal() {
+ public int[] getCorruptedBackups() {
+ assert(isInitialized());
+ return getCorruptedBackups(nativeHandle_);
+ }
+
+ /**
+ * Will delete all the files we don't need anymore. It will
+ * do the full scan of the files/ directory and delete all the
+ * files that are not referenced.
+ *
+ * @throws RocksDBException thrown if error happens in underlying
+ * native library.
+ */
+ public void garbageCollect() throws RocksDBException {
assert(isInitialized());
+ garbageCollect(nativeHandle_);
+ }
+
+ /**
+ * Release the memory allocated for the current instance
+ * in the c++ side.
+ */
+ @Override public synchronized void disposeInternal() {
dispose(nativeHandle_);
}
@@ -121,6 +154,9 @@ public class RestoreBackupableDB extends RocksObject {
throws RocksDBException;
private native void deleteBackup0(long nativeHandle, int backupId)
throws RocksDBException;
- protected native List getBackupInfo(long handle);
+ private native List getBackupInfo(long handle);
+ private native int[] getCorruptedBackups(long handle);
+ private native void garbageCollect(long handle)
+ throws RocksDBException;
private native void dispose(long nativeHandle);
}
diff --git a/java/org/rocksdb/test/BackupableDBOptionsTest.java b/java/org/rocksdb/test/BackupableDBOptionsTest.java
new file mode 100644
index 000000000..b7bdc0011
--- /dev/null
+++ b/java/org/rocksdb/test/BackupableDBOptionsTest.java
@@ -0,0 +1,284 @@
+// Copyright (c) 2014, Facebook, Inc. All rights reserved.
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree. An additional grant
+// of patent rights can be found in the PATENTS file in the same directory.
+
+package org.rocksdb.test;
+
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.rocksdb.BackupableDBOptions;
+
+import java.util.Random;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class BackupableDBOptionsTest {
+
+ private final static String ARBITRARY_PATH = "/tmp";
+
+ @ClassRule
+ public static final RocksMemoryResource rocksMemoryResource =
+ new RocksMemoryResource();
+
+ @Rule
+ public ExpectedException exception = ExpectedException.none();
+
+ public static final Random rand = PlatformRandomHelper.
+ getPlatformSpecificRandomFactory();
+
+ @Test
+ public void backupDir() {
+ BackupableDBOptions backupableDBOptions = null;
+ try {
+ backupableDBOptions = new BackupableDBOptions(ARBITRARY_PATH);
+ assertThat(backupableDBOptions.backupDir()).
+ isEqualTo(ARBITRARY_PATH);
+ } finally {
+ if (backupableDBOptions != null) {
+ backupableDBOptions.dispose();
+ }
+ }
+ }
+
+ @Test
+ public void shareTableFiles() {
+ BackupableDBOptions backupableDBOptions = null;
+ try {
+ backupableDBOptions = new BackupableDBOptions(ARBITRARY_PATH);
+ boolean value = rand.nextBoolean();
+ backupableDBOptions.setShareTableFiles(value);
+ assertThat(backupableDBOptions.shareTableFiles()).
+ isEqualTo(value);
+ } finally {
+ if (backupableDBOptions != null) {
+ backupableDBOptions.dispose();
+ }
+ }
+ }
+
+ @Test
+ public void sync() {
+ BackupableDBOptions backupableDBOptions = null;
+ try {
+ backupableDBOptions = new BackupableDBOptions(ARBITRARY_PATH);
+ boolean value = rand.nextBoolean();
+ backupableDBOptions.setSync(value);
+ assertThat(backupableDBOptions.sync()).isEqualTo(value);
+ } finally {
+ if (backupableDBOptions != null) {
+ backupableDBOptions.dispose();
+ }
+ }
+ }
+
+ @Test
+ public void destroyOldData() {
+ BackupableDBOptions backupableDBOptions = null;
+ try {
+ backupableDBOptions = new BackupableDBOptions(ARBITRARY_PATH);
+ boolean value = rand.nextBoolean();
+ backupableDBOptions.setDestroyOldData(value);
+ assertThat(backupableDBOptions.destroyOldData()).
+ isEqualTo(value);
+ } finally {
+ if (backupableDBOptions != null) {
+ backupableDBOptions.dispose();
+ }
+ }
+ }
+
+ @Test
+ public void backupLogFiles() {
+ BackupableDBOptions backupableDBOptions = null;
+ try {
+ backupableDBOptions = new BackupableDBOptions(ARBITRARY_PATH);
+ boolean value = rand.nextBoolean();
+ backupableDBOptions.setBackupLogFiles(value);
+ assertThat(backupableDBOptions.backupLogFiles()).
+ isEqualTo(value);
+ } finally {
+ if (backupableDBOptions != null) {
+ backupableDBOptions.dispose();
+ }
+ }
+ }
+
+ @Test
+ public void backupRateLimit() {
+ BackupableDBOptions backupableDBOptions = null;
+ try {
+ backupableDBOptions = new BackupableDBOptions(ARBITRARY_PATH);
+ long value = Math.abs(rand.nextLong());
+ backupableDBOptions.setBackupRateLimit(value);
+ assertThat(backupableDBOptions.backupRateLimit()).
+ isEqualTo(value);
+ // negative will be mapped to 0
+ backupableDBOptions.setBackupRateLimit(-1);
+ assertThat(backupableDBOptions.backupRateLimit()).
+ isEqualTo(0);
+ } finally {
+ if (backupableDBOptions != null) {
+ backupableDBOptions.dispose();
+ }
+ }
+ }
+
+ @Test
+ public void restoreRateLimit() {
+ BackupableDBOptions backupableDBOptions = null;
+ try {
+ backupableDBOptions = new BackupableDBOptions(ARBITRARY_PATH);
+ long value = Math.abs(rand.nextLong());
+ backupableDBOptions.setRestoreRateLimit(value);
+ assertThat(backupableDBOptions.restoreRateLimit()).
+ isEqualTo(value);
+ // negative will be mapped to 0
+ backupableDBOptions.setRestoreRateLimit(-1);
+ assertThat(backupableDBOptions.restoreRateLimit()).
+ isEqualTo(0);
+ } finally {
+ if (backupableDBOptions != null) {
+ backupableDBOptions.dispose();
+ }
+ }
+ }
+
+ @Test
+ public void shareFilesWithChecksum() {
+ BackupableDBOptions backupableDBOptions = null;
+ try {
+ backupableDBOptions = new BackupableDBOptions(ARBITRARY_PATH);
+ boolean value = rand.nextBoolean();
+ backupableDBOptions.setShareFilesWithChecksum(value);
+ assertThat(backupableDBOptions.shareFilesWithChecksum()).
+ isEqualTo(value);
+ } finally {
+ if (backupableDBOptions != null) {
+ backupableDBOptions.dispose();
+ }
+ }
+ }
+
+ @Test
+ public void failBackupDirIsNull() {
+ exception.expect(IllegalArgumentException.class);
+ new BackupableDBOptions(null);
+ }
+
+ @Test
+ public void failBackupDirIfDisposed(){
+ BackupableDBOptions options = setupUninitializedBackupableDBOptions(
+ exception);
+ options.backupDir();
+ }
+
+ @Test
+ public void failSetShareTableFilesIfDisposed(){
+ BackupableDBOptions options = setupUninitializedBackupableDBOptions(
+ exception);
+ options.setShareTableFiles(true);
+ }
+
+ @Test
+ public void failShareTableFilesIfDisposed(){
+ BackupableDBOptions options = setupUninitializedBackupableDBOptions(
+ exception);
+ options.shareTableFiles();
+ }
+
+ @Test
+ public void failSetSyncIfDisposed(){
+ BackupableDBOptions options = setupUninitializedBackupableDBOptions(
+ exception);
+ options.setSync(true);
+ }
+
+ @Test
+ public void failSyncIfDisposed(){
+ BackupableDBOptions options = setupUninitializedBackupableDBOptions(
+ exception);
+ options.sync();
+ }
+
+ @Test
+ public void failSetDestroyOldDataIfDisposed(){
+ BackupableDBOptions options = setupUninitializedBackupableDBOptions(
+ exception);
+ options.setDestroyOldData(true);
+ }
+
+ @Test
+ public void failDestroyOldDataIfDisposed(){
+ BackupableDBOptions options = setupUninitializedBackupableDBOptions(
+ exception);
+ options.destroyOldData();
+ }
+
+ @Test
+ public void failSetBackupLogFilesIfDisposed(){
+ BackupableDBOptions options = setupUninitializedBackupableDBOptions(
+ exception);
+ options.setBackupLogFiles(true);
+ }
+
+ @Test
+ public void failBackupLogFilesIfDisposed(){
+ BackupableDBOptions options = setupUninitializedBackupableDBOptions(
+ exception);
+ options.backupLogFiles();
+ }
+
+ @Test
+ public void failSetBackupRateLimitIfDisposed(){
+ BackupableDBOptions options = setupUninitializedBackupableDBOptions(
+ exception);
+ options.setBackupRateLimit(1);
+ }
+
+ @Test
+ public void failBackupRateLimitIfDisposed(){
+ BackupableDBOptions options = setupUninitializedBackupableDBOptions(
+ exception);
+ options.backupRateLimit();
+ }
+
+ @Test
+ public void failSetRestoreRateLimitIfDisposed(){
+ BackupableDBOptions options = setupUninitializedBackupableDBOptions(
+ exception);
+ options.setRestoreRateLimit(1);
+ }
+
+ @Test
+ public void failRestoreRateLimitIfDisposed(){
+ BackupableDBOptions options = setupUninitializedBackupableDBOptions(
+ exception);
+ options.restoreRateLimit();
+ }
+
+ @Test
+ public void failSetShareFilesWithChecksumIfDisposed(){
+ BackupableDBOptions options = setupUninitializedBackupableDBOptions(
+ exception);
+ options.setShareFilesWithChecksum(true);
+ }
+
+ @Test
+ public void failShareFilesWithChecksumIfDisposed(){
+ BackupableDBOptions options = setupUninitializedBackupableDBOptions(
+ exception);
+ options.shareFilesWithChecksum();
+ }
+
+ private BackupableDBOptions setupUninitializedBackupableDBOptions(
+ ExpectedException exception) {
+ BackupableDBOptions backupableDBOptions =
+ new BackupableDBOptions(ARBITRARY_PATH);
+ backupableDBOptions.dispose();
+ exception.expect(AssertionError.class);
+ return backupableDBOptions;
+ }
+}
diff --git a/java/org/rocksdb/test/BackupableDBTest.java b/java/org/rocksdb/test/BackupableDBTest.java
index 55a707687..3da519418 100644
--- a/java/org/rocksdb/test/BackupableDBTest.java
+++ b/java/org/rocksdb/test/BackupableDBTest.java
@@ -28,138 +28,387 @@ public class BackupableDBTest {
public TemporaryFolder backupFolder = new TemporaryFolder();
@Test
- public void backupableDb() throws RocksDBException {
+ public void backupDb() throws RocksDBException {
Options opt = null;
BackupableDBOptions bopt = null;
BackupableDB bdb = null;
- RestoreOptions ropt = null;
- RestoreBackupableDB rdb = null;
try {
- opt = new Options();
- opt.setCreateIfMissing(true);
+ opt = new Options().setCreateIfMissing(true);
+ bopt = new BackupableDBOptions(
+ backupFolder.getRoot().getAbsolutePath());
+ assertThat(bopt.backupDir()).isEqualTo(
+ backupFolder.getRoot().getAbsolutePath());
+ // Open empty database.
+ bdb = BackupableDB.open(opt, bopt,
+ dbFolder.getRoot().getAbsolutePath());
+ // Fill database with some test values
+ prepareDatabase(bdb);
+ // Create two backups
+ bdb.createNewBackup(false);
+ bdb.createNewBackup(true);
+ verifyNumberOfValidBackups(bdb, 2);
+ } finally {
+ if (bdb != null) {
+ bdb.close();
+ }
+ if (bopt != null) {
+ bopt.dispose();
+ }
+ if (opt != null) {
+ opt.dispose();
+ }
+ }
+ }
+ @Test
+ public void deleteBackup() throws RocksDBException {
+ Options opt = null;
+ BackupableDBOptions bopt = null;
+ BackupableDB bdb = null;
+ try {
+ opt = new Options().setCreateIfMissing(true);
bopt = new BackupableDBOptions(
- backupFolder.getRoot().getAbsolutePath(), false,
- true, false, true, 0, 0);
+ backupFolder.getRoot().getAbsolutePath());
assertThat(bopt.backupDir()).isEqualTo(
backupFolder.getRoot().getAbsolutePath());
+ // Open empty database.
+ bdb = BackupableDB.open(opt, bopt,
+ dbFolder.getRoot().getAbsolutePath());
+ // Fill database with some test values
+ prepareDatabase(bdb);
+ // Create two backups
+ bdb.createNewBackup(false);
+ bdb.createNewBackup(true);
+ List backupInfo =
+ verifyNumberOfValidBackups(bdb, 2);
+ // Delete the first backup
+ bdb.deleteBackup(backupInfo.get(0).backupId());
+ List newBackupInfo =
+ verifyNumberOfValidBackups(bdb, 1);
+ // The second backup must remain.
+ assertThat(newBackupInfo.get(0).backupId()).
+ isEqualTo(backupInfo.get(1).backupId());
+ } finally {
+ if (bdb != null) {
+ bdb.close();
+ }
+ if (bopt != null) {
+ bopt.dispose();
+ }
+ if (opt != null) {
+ opt.dispose();
+ }
+ }
+ }
- List backupInfos;
- List restoreInfos;
+ @Test
+ public void deleteBackupWithRestoreBackupableDB()
+ throws RocksDBException {
+ Options opt = null;
+ BackupableDBOptions bopt = null;
+ BackupableDB bdb = null;
+ RestoreBackupableDB rdb = null;
+ try {
+ opt = new Options().setCreateIfMissing(true);
+ bopt = new BackupableDBOptions(
+ backupFolder.getRoot().getAbsolutePath());
+ assertThat(bopt.backupDir()).isEqualTo(
+ backupFolder.getRoot().getAbsolutePath());
+ // Open empty database.
+ bdb = BackupableDB.open(opt, bopt,
+ dbFolder.getRoot().getAbsolutePath());
+ // Fill database with some test values
+ prepareDatabase(bdb);
+ // Create two backups
+ bdb.createNewBackup(false);
+ bdb.createNewBackup(true);
+ List backupInfo =
+ verifyNumberOfValidBackups(bdb, 2);
+ // init RestoreBackupableDB
+ rdb = new RestoreBackupableDB(bopt);
+ // Delete the first backup
+ rdb.deleteBackup(backupInfo.get(0).backupId());
+ // Fetch backup info using RestoreBackupableDB
+ List newBackupInfo = verifyNumberOfValidBackups(rdb, 1);
+ // The second backup must remain.
+ assertThat(newBackupInfo.get(0).backupId()).
+ isEqualTo(backupInfo.get(1).backupId());
+ } finally {
+ if (bdb != null) {
+ bdb.close();
+ }
+ if (rdb != null) {
+ rdb.dispose();
+ }
+ if (bopt != null) {
+ bopt.dispose();
+ }
+ if (opt != null) {
+ opt.dispose();
+ }
+ }
+ }
+ @Test
+ public void purgeOldBackups() throws RocksDBException {
+ Options opt = null;
+ BackupableDBOptions bopt = null;
+ BackupableDB bdb = null;
+ try {
+ opt = new Options().setCreateIfMissing(true);
+ bopt = new BackupableDBOptions(
+ backupFolder.getRoot().getAbsolutePath());
+ assertThat(bopt.backupDir()).isEqualTo(
+ backupFolder.getRoot().getAbsolutePath());
+ // Open empty database.
bdb = BackupableDB.open(opt, bopt,
dbFolder.getRoot().getAbsolutePath());
- bdb.put("abc".getBytes(), "def".getBytes());
- bdb.put("ghi".getBytes(), "jkl".getBytes());
+ // Fill database with some test values
+ prepareDatabase(bdb);
+ // Create two backups
+ bdb.createNewBackup(false);
+ bdb.createNewBackup(true);
+ bdb.createNewBackup(true);
+ bdb.createNewBackup(true);
+ List backupInfo =
+ verifyNumberOfValidBackups(bdb, 4);
+ // Delete everything except the latest backup
+ bdb.purgeOldBackups(1);
+ List newBackupInfo =
+ verifyNumberOfValidBackups(bdb, 1);
+ // The latest backup must remain.
+ assertThat(newBackupInfo.get(0).backupId()).
+ isEqualTo(backupInfo.get(3).backupId());
+ } finally {
+ if (bdb != null) {
+ bdb.close();
+ }
+ if (bopt != null) {
+ bopt.dispose();
+ }
+ if (opt != null) {
+ opt.dispose();
+ }
+ }
+ }
- backupInfos = bdb.getBackupInfos();
- assertThat(backupInfos.size()).
- isEqualTo(0);
+ @Test
+ public void purgeOldBackupsWithRestoreBackupableDb()
+ throws RocksDBException {
+ Options opt = null;
+ BackupableDBOptions bopt = null;
+ BackupableDB bdb = null;
+ RestoreBackupableDB rdb = null;
+ try {
+ opt = new Options().setCreateIfMissing(true);
+ bopt = new BackupableDBOptions(
+ backupFolder.getRoot().getAbsolutePath());
+ assertThat(bopt.backupDir()).isEqualTo(
+ backupFolder.getRoot().getAbsolutePath());
+ // Open empty database.
+ bdb = BackupableDB.open(opt, bopt,
+ dbFolder.getRoot().getAbsolutePath());
+ // Fill database with some test values
+ prepareDatabase(bdb);
+ // Create two backups
+ bdb.createNewBackup(false);
+ bdb.createNewBackup(true);
+ bdb.createNewBackup(true);
+ bdb.createNewBackup(true);
+ verifyNumberOfValidBackups(bdb, 4);
+ // init RestoreBackupableDB
+ rdb = new RestoreBackupableDB(bopt);
+ // the same number of backups must
+ // exist using RestoreBackupableDB.
+ verifyNumberOfValidBackups(rdb, 4);
+ rdb.purgeOldBackups(1);
+ verifyNumberOfValidBackups(rdb, 1);
+ } finally {
+ if (bdb != null) {
+ bdb.close();
+ }
+ if (rdb != null) {
+ rdb.dispose();
+ }
+ if (bopt != null) {
+ bopt.dispose();
+ }
+ if (opt != null) {
+ opt.dispose();
+ }
+ }
+ }
+ @Test
+ public void restoreLatestBackup()
+ throws RocksDBException {
+ Options opt = null;
+ BackupableDBOptions bopt = null;
+ BackupableDB bdb = null;
+ RestoreBackupableDB rdb = null;
+ try {
+ opt = new Options().setCreateIfMissing(true);
+ bopt = new BackupableDBOptions(
+ backupFolder.getRoot().getAbsolutePath());
+ assertThat(bopt.backupDir()).isEqualTo(
+ backupFolder.getRoot().getAbsolutePath());
+ // Open empty database.
+ bdb = BackupableDB.open(opt, bopt,
+ dbFolder.getRoot().getAbsolutePath());
+ // Fill database with some test values
+ prepareDatabase(bdb);
+ bdb.createNewBackup(true);
+ verifyNumberOfValidBackups(bdb, 1);
+ bdb.put("key1".getBytes(), "valueV2".getBytes());
+ bdb.put("key2".getBytes(), "valueV2".getBytes());
bdb.createNewBackup(true);
- backupInfos = bdb.getBackupInfos();
- assertThat(backupInfos.size()).
- isEqualTo(1);
-
- // Retrieving backup infos twice shall not
- // lead to different results
- List tmpBackupInfo = bdb.getBackupInfos();
- assertThat(tmpBackupInfo.get(0).backupId()).
- isEqualTo(backupInfos.get(0).backupId());
- assertThat(tmpBackupInfo.get(0).timestamp()).
- isEqualTo(backupInfos.get(0).timestamp());
- assertThat(tmpBackupInfo.get(0).size()).
- isEqualTo(backupInfos.get(0).size());
- assertThat(tmpBackupInfo.get(0).numberFiles()).
- isEqualTo(backupInfos.get(0).numberFiles());
-
- // delete record after backup
- bdb.remove("abc".getBytes());
- byte[] value = bdb.get("abc".getBytes());
- assertThat(value).isNull();
+ verifyNumberOfValidBackups(bdb, 2);
+ bdb.put("key1".getBytes(), "valueV3".getBytes());
+ bdb.put("key2".getBytes(), "valueV3".getBytes());
+ assertThat(new String(bdb.get("key1".getBytes()))).endsWith("V3");
+ assertThat(new String(bdb.get("key2".getBytes()))).endsWith("V3");
bdb.close();
- // restore from backup
- ropt = new RestoreOptions(false);
+ // init RestoreBackupableDB
rdb = new RestoreBackupableDB(bopt);
-
- // getting backup infos from restorable db should
- // lead to the same infos as from backupable db
- restoreInfos = rdb.getBackupInfos();
- assertThat(restoreInfos.size()).
- isEqualTo(backupInfos.size());
- assertThat(restoreInfos.get(0).backupId()).
- isEqualTo(backupInfos.get(0).backupId());
- assertThat(restoreInfos.get(0).timestamp()).
- isEqualTo(backupInfos.get(0).timestamp());
- assertThat(restoreInfos.get(0).size()).
- isEqualTo(backupInfos.get(0).size());
- assertThat(restoreInfos.get(0).numberFiles()).
- isEqualTo(backupInfos.get(0).numberFiles());
-
- rdb.restoreDBFromLatestBackup(
+ verifyNumberOfValidBackups(rdb, 2);
+ // restore db from latest backup
+ rdb.restoreDBFromLatestBackup(dbFolder.getRoot().getAbsolutePath(),
dbFolder.getRoot().getAbsolutePath(),
- dbFolder.getRoot().getAbsolutePath(),
- ropt);
- // do nothing because there is only one backup
- rdb.purgeOldBackups(1);
- restoreInfos = rdb.getBackupInfos();
- assertThat(restoreInfos.size()).
- isEqualTo(1);
- rdb.dispose();
- ropt.dispose();
-
- // verify that backed up data contains deleted record
+ new RestoreOptions(false));
+ // Open database again.
bdb = BackupableDB.open(opt, bopt,
dbFolder.getRoot().getAbsolutePath());
- value = bdb.get("abc".getBytes());
- assertThat(new String(value)).
- isEqualTo("def");
-
- bdb.createNewBackup(false);
- // after new backup there must be two backup infos
- backupInfos = bdb.getBackupInfos();
- assertThat(backupInfos.size()).
- isEqualTo(2);
- // deleting the backup must be possible using the
- // id provided by backup infos
- bdb.deleteBackup(backupInfos.get(1).backupId());
- // after deletion there should only be one info
- backupInfos = bdb.getBackupInfos();
- assertThat(backupInfos.size()).
- isEqualTo(1);
- bdb.createNewBackup(false);
- bdb.createNewBackup(false);
- bdb.createNewBackup(false);
- backupInfos = bdb.getBackupInfos();
- assertThat(backupInfos.size()).
- isEqualTo(4);
- // purge everything and keep two
- bdb.purgeOldBackups(2);
- // backup infos need to be two
- backupInfos = bdb.getBackupInfos();
- assertThat(backupInfos.size()).
- isEqualTo(2);
- assertThat(backupInfos.get(0).backupId()).
- isEqualTo(4);
- assertThat(backupInfos.get(1).backupId()).
- isEqualTo(5);
+ // Values must have suffix V2 because of restoring latest backup.
+ assertThat(new String(bdb.get("key1".getBytes()))).endsWith("V2");
+ assertThat(new String(bdb.get("key2".getBytes()))).endsWith("V2");
} finally {
- if (opt != null) {
- opt.dispose();
+ if (bdb != null) {
+ bdb.close();
+ }
+ if (rdb != null) {
+ rdb.dispose();
}
if (bopt != null) {
bopt.dispose();
}
+ if (opt != null) {
+ opt.dispose();
+ }
+ }
+ }
+
+ @Test
+ public void restoreFromBackup()
+ throws RocksDBException {
+ Options opt = null;
+ BackupableDBOptions bopt = null;
+ BackupableDB bdb = null;
+ RestoreBackupableDB rdb = null;
+ try {
+ opt = new Options().setCreateIfMissing(true);
+ bopt = new BackupableDBOptions(
+ backupFolder.getRoot().getAbsolutePath());
+ assertThat(bopt.backupDir()).isEqualTo(
+ backupFolder.getRoot().getAbsolutePath());
+ // Open empty database.
+ bdb = BackupableDB.open(opt, bopt,
+ dbFolder.getRoot().getAbsolutePath());
+ // Fill database with some test values
+ prepareDatabase(bdb);
+ bdb.createNewBackup(true);
+ verifyNumberOfValidBackups(bdb, 1);
+ bdb.put("key1".getBytes(), "valueV2".getBytes());
+ bdb.put("key2".getBytes(), "valueV2".getBytes());
+ bdb.createNewBackup(true);
+ verifyNumberOfValidBackups(bdb, 2);
+ bdb.put("key1".getBytes(), "valueV3".getBytes());
+ bdb.put("key2".getBytes(), "valueV3".getBytes());
+ assertThat(new String(bdb.get("key1".getBytes()))).endsWith("V3");
+ assertThat(new String(bdb.get("key2".getBytes()))).endsWith("V3");
+ bdb.close();
+
+ // init RestoreBackupableDB
+ rdb = new RestoreBackupableDB(bopt);
+ List backupInfo = verifyNumberOfValidBackups(rdb, 2);
+ // restore db from first backup
+ rdb.restoreDBFromBackup(backupInfo.get(0).backupId(),
+ dbFolder.getRoot().getAbsolutePath(),
+ dbFolder.getRoot().getAbsolutePath(),
+ new RestoreOptions(false));
+ // Open database again.
+ bdb = BackupableDB.open(opt, bopt,
+ dbFolder.getRoot().getAbsolutePath());
+ // Values must have suffix V2 because of restoring latest backup.
+ assertThat(new String(bdb.get("key1".getBytes()))).endsWith("V1");
+ assertThat(new String(bdb.get("key2".getBytes()))).endsWith("V1");
+ } finally {
if (bdb != null) {
bdb.close();
}
- if (ropt != null) {
- ropt.dispose();
- }
if (rdb != null) {
rdb.dispose();
}
+ if (bopt != null) {
+ bopt.dispose();
+ }
+ if (opt != null) {
+ opt.dispose();
+ }
}
}
+
+ /**
+ * Verify backups.
+ *
+ * @param bdb {@link BackupableDB} instance.
+ * @param expectedNumberOfBackups numerical value
+ * @throws RocksDBException thrown if an error occurs within the native
+ * part of the library.
+ */
+ private List verifyNumberOfValidBackups(BackupableDB bdb,
+ int expectedNumberOfBackups) throws RocksDBException {
+ // Verify that backups exist
+ assertThat(bdb.getCorruptedBackups().length).
+ isEqualTo(0);
+ bdb.garbageCollect();
+ List backupInfo = bdb.getBackupInfos();
+ assertThat(backupInfo.size()).
+ isEqualTo(expectedNumberOfBackups);
+ return backupInfo;
+ }
+
+ /**
+ * Verify backups.
+ *
+ * @param rdb {@link RestoreBackupableDB} instance.
+ * @param expectedNumberOfBackups numerical value
+ * @throws RocksDBException thrown if an error occurs within the native
+ * part of the library.
+ */
+ private List verifyNumberOfValidBackups(
+ RestoreBackupableDB rdb, int expectedNumberOfBackups)
+ throws RocksDBException {
+ // Verify that backups exist
+ assertThat(rdb.getCorruptedBackups().length).
+ isEqualTo(0);
+ rdb.garbageCollect();
+ List backupInfo = rdb.getBackupInfos();
+ assertThat(backupInfo.size()).
+ isEqualTo(expectedNumberOfBackups);
+ return backupInfo;
+ }
+
+ /**
+ * Fill database with some test values.
+ *
+ * @param db {@link RocksDB} instance.
+ * @throws RocksDBException thrown if an error occurs within the native
+ * part of the library.
+ */
+ private void prepareDatabase(RocksDB db)
+ throws RocksDBException {
+ db.put("key1".getBytes(), "valueV1".getBytes());
+ db.put("key2".getBytes(), "valueV1".getBytes());
+ }
}
diff --git a/java/rocksjni/backupablejni.cc b/java/rocksjni/backupablejni.cc
index 609cbd73e..83c641370 100644
--- a/java/rocksjni/backupablejni.cc
+++ b/java/rocksjni/backupablejni.cc
@@ -92,6 +92,45 @@ jobject Java_org_rocksdb_BackupableDB_getBackupInfo(
backup_infos);
}
+/*
+ * Class: org_rocksdb_BackupableDB
+ * Method: getCorruptedBackups
+ * Signature: (J)[I;
+ */
+jintArray Java_org_rocksdb_BackupableDB_getCorruptedBackups(
+ JNIEnv* env, jobject jbdb, jlong jhandle) {
+ std::vector backup_ids;
+ reinterpret_cast(jhandle)->
+ GetCorruptedBackups(&backup_ids);
+ // store backupids in int array
+ const int kIdSize = backup_ids.size();
+ int int_backup_ids[kIdSize];
+ for (std::vector::size_type i = 0;
+ i != backup_ids.size(); i++) {
+ int_backup_ids[i] = backup_ids[i];
+ }
+ // Store ints in java array
+ jintArray ret_backup_ids;
+ ret_backup_ids = env->NewIntArray(kIdSize);
+ env->SetIntArrayRegion(ret_backup_ids, 0, kIdSize, int_backup_ids);
+ return ret_backup_ids;
+}
+
+/*
+ * Class: org_rocksdb_BackupableDB
+ * Method: garbageCollect
+ * Signature: (J)V
+ */
+void Java_org_rocksdb_BackupableDB_garbageCollect(JNIEnv* env,
+ jobject jobj, jlong jhandle) {
+ auto db = reinterpret_cast(jhandle);
+ rocksdb::Status s = db->GarbageCollect();
+
+ if (!s.ok()) {
+ rocksdb::RocksDBExceptionJni::ThrowNew(env, s);
+ }
+}
+
///////////////////////////////////////////////////////////////////////////
// BackupDBOptions
@@ -101,20 +140,10 @@ jobject Java_org_rocksdb_BackupableDB_getBackupInfo(
* Signature: (Ljava/lang/String;)V
*/
void Java_org_rocksdb_BackupableDBOptions_newBackupableDBOptions(
- JNIEnv* env, jobject jobj, jstring jpath, jboolean jshare_table_files,
- jboolean jsync, jboolean jdestroy_old_data, jboolean jbackup_log_files,
- jlong jbackup_rate_limit, jlong jrestore_rate_limit) {
- jbackup_rate_limit = (jbackup_rate_limit <= 0) ? 0 : jbackup_rate_limit;
- jrestore_rate_limit = (jrestore_rate_limit <= 0) ? 0 : jrestore_rate_limit;
-
+ JNIEnv* env, jobject jobj, jstring jpath) {
const char* cpath = env->GetStringUTFChars(jpath, 0);
-
- auto bopt = new rocksdb::BackupableDBOptions(cpath, nullptr,
- jshare_table_files, nullptr, jsync, jdestroy_old_data, jbackup_log_files,
- jbackup_rate_limit, jrestore_rate_limit);
-
+ auto bopt = new rocksdb::BackupableDBOptions(cpath);
env->ReleaseStringUTFChars(jpath, cpath);
-
rocksdb::BackupableDBOptionsJni::setHandle(env, jobj, bopt);
}
@@ -129,6 +158,160 @@ jstring Java_org_rocksdb_BackupableDBOptions_backupDir(
return env->NewStringUTF(bopt->backup_dir.c_str());
}
+/*
+ * Class: org_rocksdb_BackupableDBOptions
+ * Method: setShareTableFiles
+ * Signature: (JZ)V
+ */
+void Java_org_rocksdb_BackupableDBOptions_setShareTableFiles(
+ JNIEnv* env, jobject jobj, jlong jhandle, jboolean flag) {
+ auto bopt = reinterpret_cast(jhandle);
+ bopt->share_table_files = flag;
+}
+
+/*
+ * Class: org_rocksdb_BackupableDBOptions
+ * Method: shareTableFiles
+ * Signature: (J)Z
+ */
+jboolean Java_org_rocksdb_BackupableDBOptions_shareTableFiles(
+ JNIEnv* env, jobject jobj, jlong jhandle) {
+ auto bopt = reinterpret_cast(jhandle);
+ return bopt->share_table_files;
+}
+
+/*
+ * Class: org_rocksdb_BackupableDBOptions
+ * Method: setSync
+ * Signature: (JZ)V
+ */
+void Java_org_rocksdb_BackupableDBOptions_setSync(
+ JNIEnv* env, jobject jobj, jlong jhandle, jboolean flag) {
+ auto bopt = reinterpret_cast(jhandle);
+ bopt->sync = flag;
+}
+
+/*
+ * Class: org_rocksdb_BackupableDBOptions
+ * Method: sync
+ * Signature: (J)Z
+ */
+jboolean Java_org_rocksdb_BackupableDBOptions_sync(
+ JNIEnv* env, jobject jobj, jlong jhandle) {
+ auto bopt = reinterpret_cast(jhandle);
+ return bopt->sync;
+}
+
+/*
+ * Class: org_rocksdb_BackupableDBOptions
+ * Method: setDestroyOldData
+ * Signature: (JZ)V
+ */
+void Java_org_rocksdb_BackupableDBOptions_setDestroyOldData(
+ JNIEnv* env, jobject jobj, jlong jhandle, jboolean flag) {
+ auto bopt = reinterpret_cast(jhandle);
+ bopt->destroy_old_data = flag;
+}
+
+/*
+ * Class: org_rocksdb_BackupableDBOptions
+ * Method: destroyOldData
+ * Signature: (J)Z
+ */
+jboolean Java_org_rocksdb_BackupableDBOptions_destroyOldData(
+ JNIEnv* env, jobject jobj, jlong jhandle) {
+ auto bopt = reinterpret_cast(jhandle);
+ return bopt->destroy_old_data;
+}
+
+/*
+ * Class: org_rocksdb_BackupableDBOptions
+ * Method: setBackupLogFiles
+ * Signature: (JZ)V
+ */
+void Java_org_rocksdb_BackupableDBOptions_setBackupLogFiles(
+ JNIEnv* env, jobject jobj, jlong jhandle, jboolean flag) {
+ auto bopt = reinterpret_cast(jhandle);
+ bopt->backup_log_files = flag;
+}
+
+/*
+ * Class: org_rocksdb_BackupableDBOptions
+ * Method: backupLogFiles
+ * Signature: (J)Z
+ */
+jboolean Java_org_rocksdb_BackupableDBOptions_backupLogFiles(
+ JNIEnv* env, jobject jobj, jlong jhandle) {
+ auto bopt = reinterpret_cast(jhandle);
+ return bopt->backup_log_files;
+}
+
+/*
+ * Class: org_rocksdb_BackupableDBOptions
+ * Method: setBackupRateLimit
+ * Signature: (JJ)V
+ */
+void Java_org_rocksdb_BackupableDBOptions_setBackupRateLimit(
+ JNIEnv* env, jobject jobj, jlong jhandle, jlong jbackup_rate_limit) {
+ auto bopt = reinterpret_cast(jhandle);
+ bopt->backup_rate_limit = jbackup_rate_limit;
+}
+
+/*
+ * Class: org_rocksdb_BackupableDBOptions
+ * Method: backupRateLimit
+ * Signature: (J)J
+ */
+jlong Java_org_rocksdb_BackupableDBOptions_backupRateLimit(
+ JNIEnv* env, jobject jobj, jlong jhandle) {
+ auto bopt = reinterpret_cast(jhandle);
+ return bopt->backup_rate_limit;
+}
+
+/*
+ * Class: org_rocksdb_BackupableDBOptions
+ * Method: setRestoreRateLimit
+ * Signature: (JJ)V
+ */
+void Java_org_rocksdb_BackupableDBOptions_setRestoreRateLimit(
+ JNIEnv* env, jobject jobj, jlong jhandle, jlong jrestore_rate_limit) {
+ auto bopt = reinterpret_cast(jhandle);
+ bopt->restore_rate_limit = jrestore_rate_limit;
+}
+
+/*
+ * Class: org_rocksdb_BackupableDBOptions
+ * Method: restoreRateLimit
+ * Signature: (J)J
+ */
+jlong Java_org_rocksdb_BackupableDBOptions_restoreRateLimit(
+ JNIEnv* env, jobject jobj, jlong jhandle) {
+ auto bopt = reinterpret_cast(jhandle);
+ return bopt->restore_rate_limit;
+}
+
+/*
+ * Class: org_rocksdb_BackupableDBOptions
+ * Method: setShareFilesWithChecksum
+ * Signature: (JZ)V
+ */
+void Java_org_rocksdb_BackupableDBOptions_setShareFilesWithChecksum(
+ JNIEnv* env, jobject jobj, jlong jhandle, jboolean flag) {
+ auto bopt = reinterpret_cast(jhandle);
+ bopt->share_files_with_checksum = flag;
+}
+
+/*
+ * Class: org_rocksdb_BackupableDBOptions
+ * Method: shareFilesWithChecksum
+ * Signature: (J)Z
+ */
+jboolean Java_org_rocksdb_BackupableDBOptions_shareFilesWithChecksum(
+ JNIEnv* env, jobject jobj, jlong jhandle) {
+ auto bopt = reinterpret_cast(jhandle);
+ return bopt->share_files_with_checksum;
+}
+
/*
* Class: org_rocksdb_BackupableDBOptions
* Method: disposeInternal
@@ -139,6 +322,5 @@ void Java_org_rocksdb_BackupableDBOptions_disposeInternal(
auto bopt = reinterpret_cast(jhandle);
assert(bopt);
delete bopt;
-
rocksdb::BackupableDBOptionsJni::setHandle(env, jopt, nullptr);
}
diff --git a/java/rocksjni/restorejni.cc b/java/rocksjni/restorejni.cc
index 4fe813d09..ad8749758 100644
--- a/java/rocksjni/restorejni.cc
+++ b/java/rocksjni/restorejni.cc
@@ -145,6 +145,46 @@ jobject Java_org_rocksdb_RestoreBackupableDB_getBackupInfo(
backup_infos);
}
+/*
+ * Class: org_rocksdb_RestoreBackupableDB
+ * Method: getCorruptedBackups
+ * Signature: (J)[I;
+ */
+jintArray Java_org_rocksdb_RestoreBackupableDB_getCorruptedBackups(
+ JNIEnv* env, jobject jbdb, jlong jhandle) {
+ std::vector backup_ids;
+ reinterpret_cast(jhandle)->
+ GetCorruptedBackups(&backup_ids);
+ // store backupids in int array
+ const int kIdSize = backup_ids.size();
+ int int_backup_ids[kIdSize];
+ for (std::vector::size_type i = 0;
+ i != backup_ids.size(); i++) {
+ int_backup_ids[i] = backup_ids[i];
+ }
+ // Store ints in java array
+ jintArray ret_backup_ids;
+ ret_backup_ids = env->NewIntArray(kIdSize);
+ env->SetIntArrayRegion(ret_backup_ids, 0, kIdSize, int_backup_ids);
+ return ret_backup_ids;
+}
+
+/*
+ * Class: org_rocksdb_RestoreBackupableDB
+ * Method: garbageCollect
+ * Signature: (J)V
+ */
+void Java_org_rocksdb_RestoreBackupableDB_garbageCollect(
+ JNIEnv* env, jobject jobj, jlong jhandle) {
+ auto db = reinterpret_cast(
+ jhandle);
+ rocksdb::Status s = db->GarbageCollect();
+
+ if (!s.ok()) {
+ rocksdb::RocksDBExceptionJni::ThrowNew(env, s);
+ }
+}
+
/*
* Class: org_rocksdb_RestoreBackupableDB
* Method: dispose