mirror of https://github.com/facebook/rocksdb.git
Merge pull request #404 from fyrz/RocksJava-Backup-Restore-3.8
[RocksJava] Update BackupableDB and RestoreBackupableDB to 3.8.0.
This commit is contained in:
commit
4f882924dd
|
@ -47,7 +47,8 @@ ifeq ($(PLATFORM), OS_MACOSX)
|
||||||
ROCKSDB_JAR = rocksdbjni-$(ROCKSDB_MAJOR).$(ROCKSDB_MINOR).$(ROCKSDB_PATCH)-osx.jar
|
ROCKSDB_JAR = rocksdbjni-$(ROCKSDB_MAJOR).$(ROCKSDB_MINOR).$(ROCKSDB_PATCH)-osx.jar
|
||||||
endif
|
endif
|
||||||
|
|
||||||
JAVA_TESTS = org.rocksdb.test.BackupableDBTest\
|
JAVA_TESTS = org.rocksdb.test.BackupableDBOptionsTest\
|
||||||
|
org.rocksdb.test.BackupableDBTest\
|
||||||
org.rocksdb.test.BlockBasedTableConfigTest\
|
org.rocksdb.test.BlockBasedTableConfigTest\
|
||||||
org.rocksdb.test.ColumnFamilyOptionsTest\
|
org.rocksdb.test.ColumnFamilyOptionsTest\
|
||||||
org.rocksdb.test.ColumnFamilyTest\
|
org.rocksdb.test.ColumnFamilyTest\
|
||||||
|
|
|
@ -8,21 +8,23 @@ package org.rocksdb;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A subclass of RocksDB which supports backup-related operations.
|
* <p>A subclass of RocksDB which supports
|
||||||
|
* backup-related operations.</p>
|
||||||
*
|
*
|
||||||
* @see org.rocksdb.BackupableDBOptions
|
* @see org.rocksdb.BackupableDBOptions
|
||||||
*/
|
*/
|
||||||
public class BackupableDB extends RocksDB {
|
public class BackupableDB extends RocksDB {
|
||||||
/**
|
/**
|
||||||
* Open a {@code BackupableDB} under the specified path.
|
* <p>Open a {@code BackupableDB} under the specified path.
|
||||||
* Note that the backup path should be set properly in the
|
* Note that the backup path should be set properly in the
|
||||||
* input BackupableDBOptions.
|
* input BackupableDBOptions.</p>
|
||||||
*
|
*
|
||||||
* @param opt {@link org.rocksdb.Options} to set for the database.
|
* @param opt {@link org.rocksdb.Options} to set for the database.
|
||||||
* @param bopt {@link org.rocksdb.BackupableDBOptions} to use.
|
* @param bopt {@link org.rocksdb.BackupableDBOptions} to use.
|
||||||
* @param db_path Path to store data to. The path for storing the backup should be
|
* @param db_path Path to store data to. The path for storing the backup should be
|
||||||
* specified in the {@link org.rocksdb.BackupableDBOptions}.
|
* specified in the {@link org.rocksdb.BackupableDBOptions}.
|
||||||
* @return BackupableDB reference to the opened database.
|
*
|
||||||
|
* @return {@link BackupableDB} reference to the opened database.
|
||||||
*
|
*
|
||||||
* @throws RocksDBException thrown if error happens in underlying
|
* @throws RocksDBException thrown if error happens in underlying
|
||||||
* native library.
|
* native library.
|
||||||
|
@ -43,8 +45,8 @@ public class BackupableDB extends RocksDB {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Captures the state of the database in the latest backup.
|
* <p>Captures the state of the database in the latest backup.
|
||||||
* Note that this function is not thread-safe.
|
* Note that this function is not thread-safe.</p>
|
||||||
*
|
*
|
||||||
* @param flushBeforeBackup if true, then all data will be flushed
|
* @param flushBeforeBackup if true, then all data will be flushed
|
||||||
* before creating backup.
|
* before creating backup.
|
||||||
|
@ -54,11 +56,12 @@ public class BackupableDB extends RocksDB {
|
||||||
*/
|
*/
|
||||||
public void createNewBackup(boolean flushBeforeBackup)
|
public void createNewBackup(boolean flushBeforeBackup)
|
||||||
throws RocksDBException {
|
throws RocksDBException {
|
||||||
|
assert(isInitialized());
|
||||||
createNewBackup(nativeHandle_, flushBeforeBackup);
|
createNewBackup(nativeHandle_, flushBeforeBackup);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes old backups, keeping latest numBackupsToKeep alive.
|
* <p>Deletes old backups, keeping latest numBackupsToKeep alive.</p>
|
||||||
*
|
*
|
||||||
* @param numBackupsToKeep Number of latest backups to keep.
|
* @param numBackupsToKeep Number of latest backups to keep.
|
||||||
*
|
*
|
||||||
|
@ -67,11 +70,12 @@ public class BackupableDB extends RocksDB {
|
||||||
*/
|
*/
|
||||||
public void purgeOldBackups(int numBackupsToKeep)
|
public void purgeOldBackups(int numBackupsToKeep)
|
||||||
throws RocksDBException {
|
throws RocksDBException {
|
||||||
|
assert(isInitialized());
|
||||||
purgeOldBackups(nativeHandle_, numBackupsToKeep);
|
purgeOldBackups(nativeHandle_, numBackupsToKeep);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes a specific backup.
|
* <p>Deletes a specific backup.</p>
|
||||||
*
|
*
|
||||||
* @param backupId of backup to delete.
|
* @param backupId of backup to delete.
|
||||||
*
|
*
|
||||||
|
@ -79,25 +83,54 @@ public class BackupableDB extends RocksDB {
|
||||||
* native library.
|
* native library.
|
||||||
*/
|
*/
|
||||||
public void deleteBackup(int backupId) throws RocksDBException {
|
public void deleteBackup(int backupId) throws RocksDBException {
|
||||||
|
assert(isInitialized());
|
||||||
deleteBackup0(nativeHandle_, backupId);
|
deleteBackup0(nativeHandle_, backupId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of {@link BackupInfo} instances, which describe
|
* <p>Returns a list of {@link BackupInfo} instances, which describe
|
||||||
* already made backups.
|
* already made backups.</p>
|
||||||
*
|
*
|
||||||
* @return List of {@link BackupInfo} instances.
|
* @return List of {@link BackupInfo} instances.
|
||||||
*/
|
*/
|
||||||
public List<BackupInfo> getBackupInfos() {
|
public List<BackupInfo> getBackupInfos() {
|
||||||
|
assert(isInitialized());
|
||||||
return getBackupInfo(nativeHandle_);
|
return getBackupInfo(nativeHandle_);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Close the BackupableDB instance and release resource.
|
* <p>Returns a list of corrupted backup ids. If there
|
||||||
|
* is no corrupted backup the method will return an
|
||||||
|
* empty list.</p>
|
||||||
*
|
*
|
||||||
* Internally, BackupableDB owns the {@code rocksdb::DB} pointer to its associated
|
* @return array of backup ids as int ids.
|
||||||
* {@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.
|
public int[] getCorruptedBackups() {
|
||||||
|
assert(isInitialized());
|
||||||
|
return getCorruptedBackups(nativeHandle_);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>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.</p>
|
||||||
|
*
|
||||||
|
* @throws RocksDBException thrown if error happens in underlying
|
||||||
|
* native library.
|
||||||
|
*/
|
||||||
|
public void garbageCollect() throws RocksDBException {
|
||||||
|
assert(isInitialized());
|
||||||
|
garbageCollect(nativeHandle_);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Close the BackupableDB instance and release resource.</p>
|
||||||
|
*
|
||||||
|
* <p>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.</p>
|
||||||
*/
|
*/
|
||||||
@Override public synchronized void close() {
|
@Override public synchronized void close() {
|
||||||
if (isInitialized()) {
|
if (isInitialized()) {
|
||||||
|
@ -106,8 +139,9 @@ public class BackupableDB extends RocksDB {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A protected construction that will be used in the static factory
|
* <p>A protected construction that will be used in the static
|
||||||
* method {@link #open(Options, BackupableDBOptions, String)}.
|
* factory method {@link #open(Options, BackupableDBOptions, String)}.
|
||||||
|
* </p>
|
||||||
*/
|
*/
|
||||||
protected BackupableDB() {
|
protected BackupableDB() {
|
||||||
super();
|
super();
|
||||||
|
@ -126,4 +160,7 @@ public class BackupableDB extends RocksDB {
|
||||||
private native void deleteBackup0(long nativeHandle, int backupId)
|
private native void deleteBackup0(long nativeHandle, int backupId)
|
||||||
throws RocksDBException;
|
throws RocksDBException;
|
||||||
protected native List<BackupInfo> getBackupInfo(long handle);
|
protected native List<BackupInfo> getBackupInfo(long handle);
|
||||||
|
private native int[] getCorruptedBackups(long handle);
|
||||||
|
private native void garbageCollect(long handle)
|
||||||
|
throws RocksDBException;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,57 +5,38 @@
|
||||||
|
|
||||||
package org.rocksdb;
|
package org.rocksdb;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BackupableDBOptions to control the behavior of a backupable database.
|
* <p>BackupableDBOptions to control the behavior of a backupable database.
|
||||||
* It will be used during the creation of a {@link org.rocksdb.BackupableDB}.
|
* It will be used during the creation of a {@link org.rocksdb.BackupableDB}.
|
||||||
*
|
* </p>
|
||||||
* Note that dispose() must be called before an Options instance
|
* <p>Note that dispose() must be called before an Options instance
|
||||||
* become out-of-scope to release the allocated memory in c++.
|
* become out-of-scope to release the allocated memory in c++.</p>
|
||||||
*
|
*
|
||||||
* @see org.rocksdb.BackupableDB
|
* @see org.rocksdb.BackupableDB
|
||||||
*/
|
*/
|
||||||
public class BackupableDBOptions extends RocksObject {
|
public class BackupableDBOptions extends RocksObject {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BackupableDBOptions constructor
|
* <p>BackupableDBOptions constructor.</p>
|
||||||
*
|
*
|
||||||
* @param path Where to keep the backup files. Has to be different than db name.
|
* @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"}
|
||||||
* @param shareTableFiles If {@code share_table_files == true}, backup will assume
|
* @throws java.lang.IllegalArgumentException if illegal path is used.
|
||||||
* 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
|
|
||||||
* @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
|
|
||||||
* @param destroyOldData If true, it will delete whatever backups there are already.
|
|
||||||
* Default: false
|
|
||||||
* @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
|
|
||||||
*/
|
*/
|
||||||
public BackupableDBOptions(String path, boolean shareTableFiles, boolean sync,
|
public BackupableDBOptions(String path) {
|
||||||
boolean destroyOldData, boolean backupLogFiles, long backupRateLimit,
|
|
||||||
long restoreRateLimit) {
|
|
||||||
super();
|
super();
|
||||||
|
File backupPath = path == null ? null : new File(path);
|
||||||
backupRateLimit = (backupRateLimit <= 0) ? 0 : backupRateLimit;
|
if (backupPath == null || !backupPath.isDirectory() || !backupPath.canWrite()) {
|
||||||
restoreRateLimit = (restoreRateLimit <= 0) ? 0 : restoreRateLimit;
|
throw new IllegalArgumentException("Illegal path provided.");
|
||||||
|
}
|
||||||
newBackupableDBOptions(path, shareTableFiles, sync, destroyOldData,
|
newBackupableDBOptions(path);
|
||||||
backupLogFiles, backupRateLimit, restoreRateLimit);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the path to the BackupableDB directory.
|
* <p>Returns the path to the BackupableDB directory.</p>
|
||||||
*
|
*
|
||||||
* @return the path to the BackupableDB directory.
|
* @return the path to the BackupableDB directory.
|
||||||
*/
|
*/
|
||||||
|
@ -64,18 +45,227 @@ public class BackupableDBOptions extends RocksObject {
|
||||||
return backupDir(nativeHandle_);
|
return backupDir(nativeHandle_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Share table files between backups.</p>
|
||||||
|
*
|
||||||
|
* @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.
|
||||||
|
*
|
||||||
|
* <p>Default: true</p>
|
||||||
|
*
|
||||||
|
* @return instance of current BackupableDBOptions.
|
||||||
|
*/
|
||||||
|
public BackupableDBOptions setShareTableFiles(boolean shareTableFiles) {
|
||||||
|
assert(isInitialized());
|
||||||
|
setShareTableFiles(nativeHandle_, shareTableFiles);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Share table files between backups.</p>
|
||||||
|
*
|
||||||
|
* @return boolean value indicating if SST files will be shared between
|
||||||
|
* backups.
|
||||||
|
*/
|
||||||
|
public boolean shareTableFiles() {
|
||||||
|
assert(isInitialized());
|
||||||
|
return shareTableFiles(nativeHandle_);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Set synchronous backups.</p>
|
||||||
|
*
|
||||||
|
* @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.
|
||||||
|
*
|
||||||
|
* <p>Default: true</p>
|
||||||
|
*
|
||||||
|
* @return instance of current BackupableDBOptions.
|
||||||
|
*/
|
||||||
|
public BackupableDBOptions setSync(boolean sync) {
|
||||||
|
assert(isInitialized());
|
||||||
|
setSync(nativeHandle_, sync);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Are synchronous backups activated.</p>
|
||||||
|
*
|
||||||
|
* @return boolean value if synchronous backups are configured.
|
||||||
|
*/
|
||||||
|
public boolean sync() {
|
||||||
|
assert(isInitialized());
|
||||||
|
return sync(nativeHandle_);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Set if old data will be destroyed.</p>
|
||||||
|
*
|
||||||
|
* @param destroyOldData If true, it will delete whatever backups there are already.
|
||||||
|
*
|
||||||
|
* <p>Default: false</p>
|
||||||
|
*
|
||||||
|
* @return instance of current BackupableDBOptions.
|
||||||
|
*/
|
||||||
|
public BackupableDBOptions setDestroyOldData(boolean destroyOldData) {
|
||||||
|
assert(isInitialized());
|
||||||
|
setDestroyOldData(nativeHandle_, destroyOldData);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Returns if old data will be destroyed will performing new backups.</p>
|
||||||
|
*
|
||||||
|
* @return boolean value indicating if old data will be destroyed.
|
||||||
|
*/
|
||||||
|
public boolean destroyOldData() {
|
||||||
|
assert(isInitialized());
|
||||||
|
return destroyOldData(nativeHandle_);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Set if log files shall be persisted.</p>
|
||||||
|
*
|
||||||
|
* @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.
|
||||||
|
*
|
||||||
|
* <p>Default: true</p>
|
||||||
|
*
|
||||||
|
* @return instance of current BackupableDBOptions.
|
||||||
|
*/
|
||||||
|
public BackupableDBOptions setBackupLogFiles(boolean backupLogFiles) {
|
||||||
|
assert(isInitialized());
|
||||||
|
setBackupLogFiles(nativeHandle_, backupLogFiles);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Return information if log files shall be persisted.</p>
|
||||||
|
*
|
||||||
|
* @return boolean value indicating if log files will be persisted.
|
||||||
|
*/
|
||||||
|
public boolean backupLogFiles() {
|
||||||
|
assert(isInitialized());
|
||||||
|
return backupLogFiles(nativeHandle_);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Set backup rate limit.</p>
|
||||||
|
*
|
||||||
|
* @param backupRateLimit Max bytes that can be transferred in a second during backup.
|
||||||
|
* If 0 or negative, then go as fast as you can.
|
||||||
|
*
|
||||||
|
* <p>Default: 0</p>
|
||||||
|
*
|
||||||
|
* @return instance of current BackupableDBOptions.
|
||||||
|
*/
|
||||||
|
public BackupableDBOptions setBackupRateLimit(long backupRateLimit) {
|
||||||
|
assert(isInitialized());
|
||||||
|
backupRateLimit = (backupRateLimit <= 0) ? 0 : backupRateLimit;
|
||||||
|
setBackupRateLimit(nativeHandle_, backupRateLimit);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Return backup rate limit which described the max bytes that can be transferred in a
|
||||||
|
* second during backup.</p>
|
||||||
|
*
|
||||||
|
* @return numerical value describing the backup transfer limit in bytes per second.
|
||||||
|
*/
|
||||||
|
public long backupRateLimit() {
|
||||||
|
assert(isInitialized());
|
||||||
|
return backupRateLimit(nativeHandle_);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Set restore rate limit.</p>
|
||||||
|
*
|
||||||
|
* @param restoreRateLimit Max bytes that can be transferred in a second during restore.
|
||||||
|
* If 0 or negative, then go as fast as you can.
|
||||||
|
*
|
||||||
|
* <p>Default: 0</p>
|
||||||
|
*
|
||||||
|
* @return instance of current BackupableDBOptions.
|
||||||
|
*/
|
||||||
|
public BackupableDBOptions setRestoreRateLimit(long restoreRateLimit) {
|
||||||
|
assert(isInitialized());
|
||||||
|
restoreRateLimit = (restoreRateLimit <= 0) ? 0 : restoreRateLimit;
|
||||||
|
setRestoreRateLimit(nativeHandle_, restoreRateLimit);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Return restore rate limit which described the max bytes that can be transferred in a
|
||||||
|
* second during restore.</p>
|
||||||
|
*
|
||||||
|
* @return numerical value describing the restore transfer limit in bytes per second.
|
||||||
|
*/
|
||||||
|
public long restoreRateLimit() {
|
||||||
|
assert(isInitialized());
|
||||||
|
return restoreRateLimit(nativeHandle_);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>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)</p>
|
||||||
|
*
|
||||||
|
* @param shareFilesWithChecksum boolean value indicating if SST files are stored
|
||||||
|
* using the triple (file name, crc32, file length) and not its name.
|
||||||
|
*
|
||||||
|
* <p>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*</p>
|
||||||
|
*
|
||||||
|
* <p>Default: false</p>
|
||||||
|
*
|
||||||
|
* @return instance of current BackupableDBOptions.
|
||||||
|
*/
|
||||||
|
public BackupableDBOptions setShareFilesWithChecksum(
|
||||||
|
boolean shareFilesWithChecksum) {
|
||||||
|
assert(isInitialized());
|
||||||
|
setShareFilesWithChecksum(nativeHandle_, shareFilesWithChecksum);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Return of share files with checksum is active.</p>
|
||||||
|
*
|
||||||
|
* @return boolean value indicating if share files with checksum
|
||||||
|
* is active.
|
||||||
|
*/
|
||||||
|
public boolean shareFilesWithChecksum() {
|
||||||
|
assert(isInitialized());
|
||||||
|
return shareFilesWithChecksum(nativeHandle_);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Release the memory allocated for the current instance
|
* Release the memory allocated for the current instance
|
||||||
* in the c++ side.
|
* in the c++ side.
|
||||||
*/
|
*/
|
||||||
@Override protected void disposeInternal() {
|
@Override protected void disposeInternal() {
|
||||||
assert(isInitialized());
|
|
||||||
disposeInternal(nativeHandle_);
|
disposeInternal(nativeHandle_);
|
||||||
}
|
}
|
||||||
|
|
||||||
private native void newBackupableDBOptions(String path,
|
private native void newBackupableDBOptions(String path);
|
||||||
boolean shareTableFiles, boolean sync, boolean destroyOldData,
|
|
||||||
boolean backupLogFiles, long backupRateLimit, long restoreRateLimit);
|
|
||||||
private native String backupDir(long handle);
|
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);
|
private native void disposeInternal(long handle);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,15 +8,17 @@ package org.rocksdb;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class is used to access information about backups and restore from them.
|
* <p>This class is used to access information about backups and
|
||||||
|
* restore from them.</p>
|
||||||
*
|
*
|
||||||
* Note that dispose() must be called before this instance become out-of-scope
|
* <p>Note: {@code dispose()} must be called before this instance
|
||||||
* to release the allocated memory in c++.
|
* become out-of-scope to release the allocated
|
||||||
|
* memory in c++.</p>
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class RestoreBackupableDB extends RocksObject {
|
public class RestoreBackupableDB extends RocksObject {
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* <p>Construct new estoreBackupableDB instance.</p>
|
||||||
*
|
*
|
||||||
* @param options {@link org.rocksdb.BackupableDBOptions} instance
|
* @param options {@link org.rocksdb.BackupableDBOptions} instance
|
||||||
*/
|
*/
|
||||||
|
@ -26,16 +28,18 @@ public class RestoreBackupableDB extends RocksObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Restore from backup with backup_id
|
* <p>Restore from backup with backup_id.</p>
|
||||||
* 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.
|
* <p><strong>Important</strong>: If options_.share_table_files == true
|
||||||
* If you add new data to the DB and try creating a new backup now, the
|
* and you restore DB from some backup that is not the latest, and you
|
||||||
* database will diverge from backups 4 and 5 and the new backup will fail.
|
* start creating new backups from the new DB, they will probably
|
||||||
* If you want to create new backup, you will first have to delete backups 4
|
* fail.</p>
|
||||||
* and 5.
|
*
|
||||||
|
* <p><strong>Example</strong>: 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.</p>
|
||||||
*
|
*
|
||||||
* @param backupId id pointing to backup
|
* @param backupId id pointing to backup
|
||||||
* @param dbDir database directory to restore to
|
* @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,
|
public void restoreDBFromBackup(long backupId, String dbDir, String walDir,
|
||||||
RestoreOptions restoreOptions) throws RocksDBException {
|
RestoreOptions restoreOptions) throws RocksDBException {
|
||||||
|
assert(isInitialized());
|
||||||
restoreDBFromBackup0(nativeHandle_, backupId, dbDir, walDir,
|
restoreDBFromBackup0(nativeHandle_, backupId, dbDir, walDir,
|
||||||
restoreOptions.nativeHandle_);
|
restoreOptions.nativeHandle_);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Restore from the latest backup.
|
* <p>Restore from the latest backup.</p>
|
||||||
*
|
*
|
||||||
* @param dbDir database directory to restore to
|
* @param dbDir database directory to restore to
|
||||||
* @param walDir directory where wal files are located
|
* @param walDir directory where wal files are located
|
||||||
|
@ -63,12 +68,13 @@ public class RestoreBackupableDB extends RocksObject {
|
||||||
*/
|
*/
|
||||||
public void restoreDBFromLatestBackup(String dbDir, String walDir,
|
public void restoreDBFromLatestBackup(String dbDir, String walDir,
|
||||||
RestoreOptions restoreOptions) throws RocksDBException {
|
RestoreOptions restoreOptions) throws RocksDBException {
|
||||||
|
assert(isInitialized());
|
||||||
restoreDBFromLatestBackup0(nativeHandle_, dbDir, walDir,
|
restoreDBFromLatestBackup0(nativeHandle_, dbDir, walDir,
|
||||||
restoreOptions.nativeHandle_);
|
restoreOptions.nativeHandle_);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes old backups, keeping latest numBackupsToKeep alive.
|
* <p>Deletes old backups, keeping latest numBackupsToKeep alive.</p>
|
||||||
*
|
*
|
||||||
* @param numBackupsToKeep of latest backups to keep
|
* @param numBackupsToKeep of latest backups to keep
|
||||||
*
|
*
|
||||||
|
@ -76,11 +82,12 @@ public class RestoreBackupableDB extends RocksObject {
|
||||||
* native library.
|
* native library.
|
||||||
*/
|
*/
|
||||||
public void purgeOldBackups(int numBackupsToKeep) throws RocksDBException {
|
public void purgeOldBackups(int numBackupsToKeep) throws RocksDBException {
|
||||||
|
assert(isInitialized());
|
||||||
purgeOldBackups0(nativeHandle_, numBackupsToKeep);
|
purgeOldBackups0(nativeHandle_, numBackupsToKeep);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes a specific backup.
|
* <p>Deletes a specific backup.</p>
|
||||||
*
|
*
|
||||||
* @param backupId of backup to delete.
|
* @param backupId of backup to delete.
|
||||||
*
|
*
|
||||||
|
@ -88,25 +95,51 @@ public class RestoreBackupableDB extends RocksObject {
|
||||||
* native library.
|
* native library.
|
||||||
*/
|
*/
|
||||||
public void deleteBackup(int backupId) throws RocksDBException {
|
public void deleteBackup(int backupId) throws RocksDBException {
|
||||||
|
assert(isInitialized());
|
||||||
deleteBackup0(nativeHandle_, backupId);
|
deleteBackup0(nativeHandle_, backupId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of {@link BackupInfo} instances, which describe
|
* <p>Returns a list of {@link BackupInfo} instances, which describe
|
||||||
* already made backups.
|
* already made backups.</p>
|
||||||
*
|
*
|
||||||
* @return List of {@link BackupInfo} instances.
|
* @return List of {@link BackupInfo} instances.
|
||||||
*/
|
*/
|
||||||
public List<BackupInfo> getBackupInfos() {
|
public List<BackupInfo> getBackupInfos() {
|
||||||
|
assert(isInitialized());
|
||||||
return getBackupInfo(nativeHandle_);
|
return getBackupInfo(nativeHandle_);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Release the memory allocated for the current instance
|
* <p>Returns a list of corrupted backup ids. If there
|
||||||
* in the c++ side.
|
* is no corrupted backup the method will return an
|
||||||
|
* empty list.</p>
|
||||||
|
*
|
||||||
|
* @return array of backup ids as int ids.
|
||||||
|
*/
|
||||||
|
public int[] getCorruptedBackups() {
|
||||||
|
assert(isInitialized());
|
||||||
|
return getCorruptedBackups(nativeHandle_);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>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.</p>
|
||||||
|
*
|
||||||
|
* @throws RocksDBException thrown if error happens in underlying
|
||||||
|
* native library.
|
||||||
|
*/
|
||||||
|
public void garbageCollect() throws RocksDBException {
|
||||||
|
assert(isInitialized());
|
||||||
|
garbageCollect(nativeHandle_);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Release the memory allocated for the current instance
|
||||||
|
* in the c++ side.</p>
|
||||||
*/
|
*/
|
||||||
@Override public synchronized void disposeInternal() {
|
@Override public synchronized void disposeInternal() {
|
||||||
assert(isInitialized());
|
|
||||||
dispose(nativeHandle_);
|
dispose(nativeHandle_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,6 +154,9 @@ public class RestoreBackupableDB extends RocksObject {
|
||||||
throws RocksDBException;
|
throws RocksDBException;
|
||||||
private native void deleteBackup0(long nativeHandle, int backupId)
|
private native void deleteBackup0(long nativeHandle, int backupId)
|
||||||
throws RocksDBException;
|
throws RocksDBException;
|
||||||
protected native List<BackupInfo> getBackupInfo(long handle);
|
private native List<BackupInfo> getBackupInfo(long handle);
|
||||||
|
private native int[] getCorruptedBackups(long handle);
|
||||||
|
private native void garbageCollect(long handle)
|
||||||
|
throws RocksDBException;
|
||||||
private native void dispose(long nativeHandle);
|
private native void dispose(long nativeHandle);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,138 +28,387 @@ public class BackupableDBTest {
|
||||||
public TemporaryFolder backupFolder = new TemporaryFolder();
|
public TemporaryFolder backupFolder = new TemporaryFolder();
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void backupableDb() throws RocksDBException {
|
public void backupDb() throws RocksDBException {
|
||||||
Options opt = null;
|
Options opt = null;
|
||||||
BackupableDBOptions bopt = null;
|
BackupableDBOptions bopt = null;
|
||||||
BackupableDB bdb = null;
|
BackupableDB bdb = null;
|
||||||
RestoreOptions ropt = null;
|
|
||||||
RestoreBackupableDB rdb = null;
|
|
||||||
try {
|
try {
|
||||||
opt = new Options();
|
opt = new Options().setCreateIfMissing(true);
|
||||||
opt.setCreateIfMissing(true);
|
|
||||||
|
|
||||||
bopt = new BackupableDBOptions(
|
bopt = new BackupableDBOptions(
|
||||||
backupFolder.getRoot().getAbsolutePath(), false,
|
backupFolder.getRoot().getAbsolutePath());
|
||||||
true, false, true, 0, 0);
|
|
||||||
assertThat(bopt.backupDir()).isEqualTo(
|
assertThat(bopt.backupDir()).isEqualTo(
|
||||||
backupFolder.getRoot().getAbsolutePath());
|
backupFolder.getRoot().getAbsolutePath());
|
||||||
|
// Open empty database.
|
||||||
List<BackupInfo> backupInfos;
|
|
||||||
List<BackupInfo> restoreInfos;
|
|
||||||
|
|
||||||
bdb = BackupableDB.open(opt, bopt,
|
bdb = BackupableDB.open(opt, bopt,
|
||||||
dbFolder.getRoot().getAbsolutePath());
|
dbFolder.getRoot().getAbsolutePath());
|
||||||
bdb.put("abc".getBytes(), "def".getBytes());
|
// Fill database with some test values
|
||||||
bdb.put("ghi".getBytes(), "jkl".getBytes());
|
prepareDatabase(bdb);
|
||||||
|
// Create two backups
|
||||||
backupInfos = bdb.getBackupInfos();
|
bdb.createNewBackup(false);
|
||||||
assertThat(backupInfos.size()).
|
|
||||||
isEqualTo(0);
|
|
||||||
|
|
||||||
bdb.createNewBackup(true);
|
bdb.createNewBackup(true);
|
||||||
backupInfos = bdb.getBackupInfos();
|
verifyNumberOfValidBackups(bdb, 2);
|
||||||
assertThat(backupInfos.size()).
|
|
||||||
isEqualTo(1);
|
|
||||||
|
|
||||||
// Retrieving backup infos twice shall not
|
|
||||||
// lead to different results
|
|
||||||
List<BackupInfo> 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();
|
|
||||||
bdb.close();
|
|
||||||
|
|
||||||
// restore from backup
|
|
||||||
ropt = new RestoreOptions(false);
|
|
||||||
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(
|
|
||||||
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
|
|
||||||
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);
|
|
||||||
} finally {
|
} finally {
|
||||||
if (opt != null) {
|
if (bdb != null) {
|
||||||
opt.dispose();
|
bdb.close();
|
||||||
}
|
}
|
||||||
if (bopt != null) {
|
if (bopt != null) {
|
||||||
bopt.dispose();
|
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());
|
||||||
|
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> backupInfo =
|
||||||
|
verifyNumberOfValidBackups(bdb, 2);
|
||||||
|
// Delete the first backup
|
||||||
|
bdb.deleteBackup(backupInfo.get(0).backupId());
|
||||||
|
List<BackupInfo> newBackupInfo =
|
||||||
|
verifyNumberOfValidBackups(bdb, 1);
|
||||||
|
// The second backup must remain.
|
||||||
|
assertThat(newBackupInfo.get(0).backupId()).
|
||||||
|
isEqualTo(backupInfo.get(1).backupId());
|
||||||
|
} finally {
|
||||||
if (bdb != null) {
|
if (bdb != null) {
|
||||||
bdb.close();
|
bdb.close();
|
||||||
}
|
}
|
||||||
if (ropt != null) {
|
if (bopt != null) {
|
||||||
ropt.dispose();
|
bopt.dispose();
|
||||||
|
}
|
||||||
|
if (opt != null) {
|
||||||
|
opt.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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> 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<BackupInfo> 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) {
|
if (rdb != null) {
|
||||||
rdb.dispose();
|
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());
|
||||||
|
// 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> backupInfo =
|
||||||
|
verifyNumberOfValidBackups(bdb, 4);
|
||||||
|
// Delete everything except the latest backup
|
||||||
|
bdb.purgeOldBackups(1);
|
||||||
|
List<BackupInfo> 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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);
|
||||||
|
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);
|
||||||
|
verifyNumberOfValidBackups(rdb, 2);
|
||||||
|
// restore db from latest backup
|
||||||
|
rdb.restoreDBFromLatestBackup(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("V2");
|
||||||
|
assertThat(new String(bdb.get("key2".getBytes()))).endsWith("V2");
|
||||||
|
} finally {
|
||||||
|
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> 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 (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<BackupInfo> verifyNumberOfValidBackups(BackupableDB bdb,
|
||||||
|
int expectedNumberOfBackups) throws RocksDBException {
|
||||||
|
// Verify that backups exist
|
||||||
|
assertThat(bdb.getCorruptedBackups().length).
|
||||||
|
isEqualTo(0);
|
||||||
|
bdb.garbageCollect();
|
||||||
|
List<BackupInfo> 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<BackupInfo> verifyNumberOfValidBackups(
|
||||||
|
RestoreBackupableDB rdb, int expectedNumberOfBackups)
|
||||||
|
throws RocksDBException {
|
||||||
|
// Verify that backups exist
|
||||||
|
assertThat(rdb.getCorruptedBackups().length).
|
||||||
|
isEqualTo(0);
|
||||||
|
rdb.garbageCollect();
|
||||||
|
List<BackupInfo> 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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -92,6 +92,45 @@ jobject Java_org_rocksdb_BackupableDB_getBackupInfo(
|
||||||
backup_infos);
|
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<rocksdb::BackupID> backup_ids;
|
||||||
|
reinterpret_cast<rocksdb::BackupableDB*>(jhandle)->
|
||||||
|
GetCorruptedBackups(&backup_ids);
|
||||||
|
// store backupids in int array
|
||||||
|
const int kIdSize = backup_ids.size();
|
||||||
|
int int_backup_ids[kIdSize];
|
||||||
|
for (std::vector<rocksdb::BackupID>::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<rocksdb::BackupableDB*>(jhandle);
|
||||||
|
rocksdb::Status s = db->GarbageCollect();
|
||||||
|
|
||||||
|
if (!s.ok()) {
|
||||||
|
rocksdb::RocksDBExceptionJni::ThrowNew(env, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// BackupDBOptions
|
// BackupDBOptions
|
||||||
|
|
||||||
|
@ -101,20 +140,10 @@ jobject Java_org_rocksdb_BackupableDB_getBackupInfo(
|
||||||
* Signature: (Ljava/lang/String;)V
|
* Signature: (Ljava/lang/String;)V
|
||||||
*/
|
*/
|
||||||
void Java_org_rocksdb_BackupableDBOptions_newBackupableDBOptions(
|
void Java_org_rocksdb_BackupableDBOptions_newBackupableDBOptions(
|
||||||
JNIEnv* env, jobject jobj, jstring jpath, jboolean jshare_table_files,
|
JNIEnv* env, jobject jobj, jstring jpath) {
|
||||||
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;
|
|
||||||
|
|
||||||
const char* cpath = env->GetStringUTFChars(jpath, 0);
|
const char* cpath = env->GetStringUTFChars(jpath, 0);
|
||||||
|
auto bopt = new rocksdb::BackupableDBOptions(cpath);
|
||||||
auto bopt = new rocksdb::BackupableDBOptions(cpath, nullptr,
|
|
||||||
jshare_table_files, nullptr, jsync, jdestroy_old_data, jbackup_log_files,
|
|
||||||
jbackup_rate_limit, jrestore_rate_limit);
|
|
||||||
|
|
||||||
env->ReleaseStringUTFChars(jpath, cpath);
|
env->ReleaseStringUTFChars(jpath, cpath);
|
||||||
|
|
||||||
rocksdb::BackupableDBOptionsJni::setHandle(env, jobj, bopt);
|
rocksdb::BackupableDBOptionsJni::setHandle(env, jobj, bopt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,6 +158,160 @@ jstring Java_org_rocksdb_BackupableDBOptions_backupDir(
|
||||||
return env->NewStringUTF(bopt->backup_dir.c_str());
|
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<rocksdb::BackupableDBOptions*>(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<rocksdb::BackupableDBOptions*>(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<rocksdb::BackupableDBOptions*>(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<rocksdb::BackupableDBOptions*>(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<rocksdb::BackupableDBOptions*>(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<rocksdb::BackupableDBOptions*>(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<rocksdb::BackupableDBOptions*>(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<rocksdb::BackupableDBOptions*>(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<rocksdb::BackupableDBOptions*>(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<rocksdb::BackupableDBOptions*>(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<rocksdb::BackupableDBOptions*>(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<rocksdb::BackupableDBOptions*>(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<rocksdb::BackupableDBOptions*>(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<rocksdb::BackupableDBOptions*>(jhandle);
|
||||||
|
return bopt->share_files_with_checksum;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Class: org_rocksdb_BackupableDBOptions
|
* Class: org_rocksdb_BackupableDBOptions
|
||||||
* Method: disposeInternal
|
* Method: disposeInternal
|
||||||
|
@ -139,6 +322,5 @@ void Java_org_rocksdb_BackupableDBOptions_disposeInternal(
|
||||||
auto bopt = reinterpret_cast<rocksdb::BackupableDBOptions*>(jhandle);
|
auto bopt = reinterpret_cast<rocksdb::BackupableDBOptions*>(jhandle);
|
||||||
assert(bopt);
|
assert(bopt);
|
||||||
delete bopt;
|
delete bopt;
|
||||||
|
|
||||||
rocksdb::BackupableDBOptionsJni::setHandle(env, jopt, nullptr);
|
rocksdb::BackupableDBOptionsJni::setHandle(env, jopt, nullptr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -145,6 +145,46 @@ jobject Java_org_rocksdb_RestoreBackupableDB_getBackupInfo(
|
||||||
backup_infos);
|
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<rocksdb::BackupID> backup_ids;
|
||||||
|
reinterpret_cast<rocksdb::RestoreBackupableDB*>(jhandle)->
|
||||||
|
GetCorruptedBackups(&backup_ids);
|
||||||
|
// store backupids in int array
|
||||||
|
const int kIdSize = backup_ids.size();
|
||||||
|
int int_backup_ids[kIdSize];
|
||||||
|
for (std::vector<rocksdb::BackupID>::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<rocksdb::RestoreBackupableDB*>(
|
||||||
|
jhandle);
|
||||||
|
rocksdb::Status s = db->GarbageCollect();
|
||||||
|
|
||||||
|
if (!s.ok()) {
|
||||||
|
rocksdb::RocksDBExceptionJni::ThrowNew(env, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Class: org_rocksdb_RestoreBackupableDB
|
* Class: org_rocksdb_RestoreBackupableDB
|
||||||
* Method: dispose
|
* Method: dispose
|
||||||
|
|
Loading…
Reference in New Issue