Merge pull request #366 from fyrz/RocksJava-Backup-Restore-Improvements

[RocksJava] - BackupInfos & Restore-/BackupableDB enhancements
main
Yueh-Hsuan Chiang 10 years ago
commit c49dedbe04
  1. 67
      java/org/rocksdb/BackupInfo.java
  2. 38
      java/org/rocksdb/BackupableDB.java
  3. 29
      java/org/rocksdb/RestoreBackupableDB.java
  4. 64
      java/org/rocksdb/test/BackupableDBTest.java
  5. 32
      java/rocksjni/backupablejni.cc
  6. 1
      java/rocksjni/comparatorjnicallback.cc
  7. 45
      java/rocksjni/portal.h
  8. 18
      java/rocksjni/restorejni.cc

@ -0,0 +1,67 @@
// 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;
/**
* Instances of this class describe a Backup made by
* {@link org.rocksdb.BackupableDB}.
*/
public class BackupInfo {
/**
* Package private constructor used to create instances
* of BackupInfo by {@link org.rocksdb.BackupableDB} and
* {@link org.rocksdb.RestoreBackupableDB}.
*
* @param backupId id of backup
* @param timestamp timestamp of backup
* @param size size of backup
* @param numberFiles number of files related to this backup.
*/
BackupInfo(int backupId, long timestamp, long size,
int numberFiles) {
backupId_ = backupId;
timestamp_ = timestamp;
size_ = size;
numberFiles_ = numberFiles;
}
/**
*
* @return the backup id.
*/
public int backupId() {
return backupId_;
}
/**
*
* @return the timestamp of the backup.
*/
public long timestamp() {
return timestamp_;
}
/**
*
* @return the size of the backup
*/
public long size() {
return size_;
}
/**
*
* @return the number of files of this backup.
*/
public int numberFiles() {
return numberFiles_;
}
private int backupId_;
private long timestamp_;
private long size_;
private int numberFiles_;
}

@ -5,6 +5,8 @@
package org.rocksdb; package org.rocksdb;
import java.util.List;
/** /**
* A subclass of RocksDB which supports backup-related operations. * A subclass of RocksDB which supports backup-related operations.
* *
@ -43,8 +45,10 @@ public class BackupableDB extends RocksDB {
* *
* @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.
* @throws org.rocksdb.RocksDBException
*/ */
public void createNewBackup(boolean flushBeforeBackup) { public void createNewBackup(boolean flushBeforeBackup)
throws RocksDBException {
createNewBackup(nativeHandle_, flushBeforeBackup); createNewBackup(nativeHandle_, flushBeforeBackup);
} }
@ -52,11 +56,32 @@ public class BackupableDB extends RocksDB {
* Deletes old backups, keeping latest numBackupsToKeep alive. * Deletes old backups, keeping latest numBackupsToKeep alive.
* *
* @param numBackupsToKeep Number of latest backups to keep. * @param numBackupsToKeep Number of latest backups to keep.
* @throws org.rocksdb.RocksDBException
*/ */
public void purgeOldBackups(int numBackupsToKeep) { public void purgeOldBackups(int numBackupsToKeep)
throws RocksDBException {
purgeOldBackups(nativeHandle_, numBackupsToKeep); purgeOldBackups(nativeHandle_, numBackupsToKeep);
} }
/**
* Deletes a specific backup.
*
* @param backupId of backup to delete.
* @throws org.rocksdb.RocksDBException
*/
public void deleteBackup(int backupId) throws RocksDBException {
deleteBackup0(nativeHandle_, backupId);
}
/**
* Returns a list of {@link BackupInfo} instances, which describe
* already made backups.
*
* @return List of {@link BackupInfo} instances.
*/
public List<BackupInfo> getBackupInfos() {
return getBackupInfo(nativeHandle_);
}
/** /**
* Close the BackupableDB instance and release resource. * Close the BackupableDB instance and release resource.
@ -85,6 +110,11 @@ public class BackupableDB extends RocksDB {
} }
protected native void open(long rocksDBHandle, long backupDBOptionsHandle); protected native void open(long rocksDBHandle, long backupDBOptionsHandle);
protected native void createNewBackup(long handle, boolean flag); protected native void createNewBackup(long handle, boolean flag)
protected native void purgeOldBackups(long handle, int numBackupsToKeep); throws RocksDBException;
protected native void purgeOldBackups(long handle, int numBackupsToKeep)
throws RocksDBException;
private native void deleteBackup0(long nativeHandle, int backupId)
throws RocksDBException;
protected native List<BackupInfo> getBackupInfo(long handle);
} }

@ -5,6 +5,8 @@
package org.rocksdb; 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.
* *
@ -65,6 +67,7 @@ public class RestoreBackupableDB extends RocksObject {
* Deletes old backups, keeping latest numBackupsToKeep alive. * Deletes old backups, keeping latest numBackupsToKeep alive.
* *
* @param numBackupsToKeep of latest backups to keep * @param numBackupsToKeep of latest backups to keep
* @throws org.rocksdb.RocksDBException
*/ */
public void purgeOldBackups(int numBackupsToKeep) throws RocksDBException { public void purgeOldBackups(int numBackupsToKeep) throws RocksDBException {
purgeOldBackups0(nativeHandle_, numBackupsToKeep); purgeOldBackups0(nativeHandle_, numBackupsToKeep);
@ -74,11 +77,22 @@ public class RestoreBackupableDB extends RocksObject {
* Deletes a specific backup. * Deletes a specific backup.
* *
* @param backupId of backup to delete. * @param backupId of backup to delete.
* @throws org.rocksdb.RocksDBException
*/ */
public void deleteBackup(long backupId) throws RocksDBException { public void deleteBackup(int backupId) throws RocksDBException {
deleteBackup0(nativeHandle_, backupId); deleteBackup0(nativeHandle_, backupId);
} }
/**
* Returns a list of {@link BackupInfo} instances, which describe
* already made backups.
*
* @return List of {@link BackupInfo} instances.
*/
public List<BackupInfo> getBackupInfos() {
return getBackupInfo(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.
@ -90,10 +104,15 @@ public class RestoreBackupableDB extends RocksObject {
private native long newRestoreBackupableDB(long options); private native long newRestoreBackupableDB(long options);
private native void restoreDBFromBackup0(long nativeHandle, long backupId, private native void restoreDBFromBackup0(long nativeHandle, long backupId,
String dbDir, String walDir, long restoreOptions) throws RocksDBException; String dbDir, String walDir, long restoreOptions)
throws RocksDBException;
private native void restoreDBFromLatestBackup0(long nativeHandle, private native void restoreDBFromLatestBackup0(long nativeHandle,
String dbDir, String walDir, long restoreOptions) throws RocksDBException; String dbDir, String walDir, long restoreOptions)
private native void purgeOldBackups0(long nativeHandle, int numBackupsToKeep); throws RocksDBException;
private native void deleteBackup0(long nativeHandle, long backupId); private native void purgeOldBackups0(long nativeHandle, int numBackupsToKeep)
throws RocksDBException;
private native void deleteBackup0(long nativeHandle, int backupId)
throws RocksDBException;
protected native List<BackupInfo> getBackupInfo(long handle);
private native void dispose(long nativeHandle); private native void dispose(long nativeHandle);
} }

@ -7,6 +7,8 @@ package org.rocksdb.test;
import org.rocksdb.*; import org.rocksdb.*;
import java.util.List;
public class BackupableDBTest { public class BackupableDBTest {
static final String db_path = "/tmp/rocksdbjni_backupable_db_test"; static final String db_path = "/tmp/rocksdbjni_backupable_db_test";
static final String backup_path = "/tmp/rocksdbjni_backupable_db_backup_test"; static final String backup_path = "/tmp/rocksdbjni_backupable_db_backup_test";
@ -21,14 +23,34 @@ public class BackupableDBTest {
BackupableDBOptions bopt = new BackupableDBOptions(backup_path, false, BackupableDBOptions bopt = new BackupableDBOptions(backup_path, false,
true, false, true, 0, 0); true, false, true, 0, 0);
BackupableDB bdb = null; BackupableDB bdb = null;
List<BackupInfo> backupInfos;
List<BackupInfo> restoreInfos;
try { try {
bdb = BackupableDB.open(opt, bopt, db_path); bdb = BackupableDB.open(opt, bopt, db_path);
bdb.put("abc".getBytes(), "def".getBytes()); bdb.put("abc".getBytes(), "def".getBytes());
bdb.put("ghi".getBytes(), "jkl".getBytes()); bdb.put("ghi".getBytes(), "jkl".getBytes());
backupInfos = bdb.getBackupInfos();
assert(backupInfos.size() == 0);
bdb.createNewBackup(true); bdb.createNewBackup(true);
backupInfos = bdb.getBackupInfos();
assert(backupInfos.size() == 1);
// Retrieving backup infos twice shall not
// lead to different results
List<BackupInfo> tmpBackupInfo = bdb.getBackupInfos();
assert(tmpBackupInfo.get(0).backupId() ==
backupInfos.get(0).backupId());
assert(tmpBackupInfo.get(0).timestamp() ==
backupInfos.get(0).timestamp());
assert(tmpBackupInfo.get(0).size() ==
backupInfos.get(0).size());
assert(tmpBackupInfo.get(0).numberFiles() ==
backupInfos.get(0).numberFiles());
// delete record after backup // delete record after backup
bdb.remove("abc".getBytes()); bdb.remove("abc".getBytes());
byte[] value = bdb.get("abc".getBytes()); byte[] value = bdb.get("abc".getBytes());
@ -38,8 +60,26 @@ public class BackupableDBTest {
// restore from backup // restore from backup
RestoreOptions ropt = new RestoreOptions(false); RestoreOptions ropt = new RestoreOptions(false);
RestoreBackupableDB rdb = new RestoreBackupableDB(bopt); RestoreBackupableDB rdb = new RestoreBackupableDB(bopt);
// getting backup infos from restorable db should
// lead to the same infos as from backupable db
restoreInfos = rdb.getBackupInfos();
assert(restoreInfos.size() == backupInfos.size());
assert(restoreInfos.get(0).backupId() ==
backupInfos.get(0).backupId());
assert(restoreInfos.get(0).timestamp() ==
backupInfos.get(0).timestamp());
assert(restoreInfos.get(0).size() ==
backupInfos.get(0).size());
assert(restoreInfos.get(0).numberFiles() ==
backupInfos.get(0).numberFiles());
rdb.restoreDBFromLatestBackup(db_path, db_path, rdb.restoreDBFromLatestBackup(db_path, db_path,
ropt); ropt);
// do nothing because there is only one backup
rdb.purgeOldBackups(1);
restoreInfos = rdb.getBackupInfos();
assert(restoreInfos.size() == 1);
rdb.dispose(); rdb.dispose();
ropt.dispose(); ropt.dispose();
@ -48,6 +88,28 @@ public class BackupableDBTest {
value = bdb.get("abc".getBytes()); value = bdb.get("abc".getBytes());
assert(new String(value).equals("def")); assert(new String(value).equals("def"));
bdb.createNewBackup(false);
// after new backup there must be two backup infos
backupInfos = bdb.getBackupInfos();
assert(backupInfos.size() == 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();
assert(backupInfos.size() == 1);
bdb.createNewBackup(false);
bdb.createNewBackup(false);
bdb.createNewBackup(false);
backupInfos = bdb.getBackupInfos();
assert(backupInfos.size() == 4);
// purge everything and keep two
bdb.purgeOldBackups(2);
// backup infos need to be two
backupInfos = bdb.getBackupInfos();
assert(backupInfos.size() == 2);
assert(backupInfos.get(0).backupId() == 4);
assert(backupInfos.get(1).backupId() == 5);
System.out.println("Backup and restore test passed"); System.out.println("Backup and restore test passed");
} catch (RocksDBException e) { } catch (RocksDBException e) {
System.err.format("[ERROR]: %s%n", e); System.err.format("[ERROR]: %s%n", e);

@ -11,6 +11,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <jni.h> #include <jni.h>
#include <string> #include <string>
#include <vector>
#include "include/org_rocksdb_BackupableDB.h" #include "include/org_rocksdb_BackupableDB.h"
#include "include/org_rocksdb_BackupableDBOptions.h" #include "include/org_rocksdb_BackupableDBOptions.h"
@ -53,7 +54,7 @@ void Java_org_rocksdb_BackupableDB_createNewBackup(
* Signature: (JI)V * Signature: (JI)V
*/ */
void Java_org_rocksdb_BackupableDB_purgeOldBackups( void Java_org_rocksdb_BackupableDB_purgeOldBackups(
JNIEnv* env, jobject jbdb, jlong jhandle, jboolean jnumBackupsToKeep) { JNIEnv* env, jobject jbdb, jlong jhandle, jint jnumBackupsToKeep) {
rocksdb::Status s = rocksdb::Status s =
reinterpret_cast<rocksdb::BackupableDB*>(jhandle)-> reinterpret_cast<rocksdb::BackupableDB*>(jhandle)->
PurgeOldBackups(jnumBackupsToKeep); PurgeOldBackups(jnumBackupsToKeep);
@ -62,6 +63,35 @@ void Java_org_rocksdb_BackupableDB_purgeOldBackups(
} }
} }
/*
* Class: org_rocksdb_BackupableDB
* Method: deleteBackup0
* Signature: (JI)V
*/
void Java_org_rocksdb_BackupableDB_deleteBackup0(JNIEnv* env,
jobject jobj, jlong jhandle, jint jbackup_id) {
auto rdb = reinterpret_cast<rocksdb::BackupableDB*>(jhandle);
rocksdb::Status s = rdb->DeleteBackup(jbackup_id);
if (!s.ok()) {
rocksdb::RocksDBExceptionJni::ThrowNew(env, s);
}
}
/*
* Class: org_rocksdb_BackupableDB
* Method: getBackupInfo
* Signature: (J)Ljava/util/List;
*/
jobject Java_org_rocksdb_BackupableDB_getBackupInfo(
JNIEnv* env, jobject jbdb, jlong jhandle) {
std::vector<rocksdb::BackupInfo> backup_infos;
reinterpret_cast<rocksdb::BackupableDB*>(jhandle)->
GetBackupInfo(&backup_infos);
return rocksdb::BackupInfoListJni::getBackupInfo(env,
backup_infos);
}
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// BackupDBOptions // BackupDBOptions

@ -15,7 +15,6 @@ BaseComparatorJniCallback::BaseComparatorJniCallback(
const ComparatorJniCallbackOptions* copt) const ComparatorJniCallbackOptions* copt)
: mtx_compare(new port::Mutex(copt->use_adaptive_mutex)), : mtx_compare(new port::Mutex(copt->use_adaptive_mutex)),
mtx_findShortestSeparator(new port::Mutex(copt->use_adaptive_mutex)) { mtx_findShortestSeparator(new port::Mutex(copt->use_adaptive_mutex)) {
// Note: Comparator methods may be accessed by multiple threads, // Note: Comparator methods may be accessed by multiple threads,
// so we ref the jvm not the env // so we ref the jvm not the env
const jint rs = env->GetJavaVM(&m_jvm); const jint rs = env->GetJavaVM(&m_jvm);

@ -13,6 +13,7 @@
#include <jni.h> #include <jni.h>
#include <limits> #include <limits>
#include <string> #include <string>
#include <vector>
#include "rocksdb/db.h" #include "rocksdb/db.h"
#include "rocksdb/filter_policy.h" #include "rocksdb/filter_policy.h"
@ -591,6 +592,50 @@ class ListJni {
} }
}; };
class BackupInfoJni {
public:
// Get the java class id of org.rocksdb.BackupInfo.
static jclass getJClass(JNIEnv* env) {
jclass jclazz = env->FindClass("org/rocksdb/BackupInfo");
assert(jclazz != nullptr);
return jclazz;
}
static jobject construct0(JNIEnv* env, uint32_t backup_id, int64_t timestamp,
uint64_t size, uint32_t number_files) {
static jmethodID mid = env->GetMethodID(getJClass(env), "<init>",
"(IJJI)V");
assert(mid != nullptr);
return env->NewObject(getJClass(env), mid,
backup_id, timestamp, size, number_files);
}
};
class BackupInfoListJni {
public:
static jobject getBackupInfo(JNIEnv* env,
std::vector<BackupInfo> backup_infos) {
jclass jclazz = env->FindClass("java/util/ArrayList");
jmethodID mid = rocksdb::ListJni::getArrayListConstructorMethodId(
env, jclazz);
jobject jbackup_info_handle_list = env->NewObject(jclazz, mid,
backup_infos.size());
// insert in java list
for (std::vector<rocksdb::BackupInfo>::size_type i = 0;
i != backup_infos.size(); i++) {
rocksdb::BackupInfo backup_info = backup_infos[i];
jobject obj = rocksdb::BackupInfoJni::construct0(env,
backup_info.backup_id,
backup_info.timestamp,
backup_info.size,
backup_info.number_files);
env->CallBooleanMethod(jbackup_info_handle_list,
rocksdb::ListJni::getListAddMethodId(env), obj);
}
return jbackup_info_handle_list;
}
};
class JniUtil { class JniUtil {
public: public:
/** /**

@ -119,10 +119,10 @@ void Java_org_rocksdb_RestoreBackupableDB_purgeOldBackups0(JNIEnv* env,
/* /*
* Class: org_rocksdb_RestoreBackupableDB * Class: org_rocksdb_RestoreBackupableDB
* Method: deleteBackup0 * Method: deleteBackup0
* Signature: (JJ)V * Signature: (JI)V
*/ */
void Java_org_rocksdb_RestoreBackupableDB_deleteBackup0(JNIEnv* env, void Java_org_rocksdb_RestoreBackupableDB_deleteBackup0(JNIEnv* env,
jobject jobj, jlong jhandle, jlong jbackup_id) { jobject jobj, jlong jhandle, jint jbackup_id) {
auto rdb = reinterpret_cast<rocksdb::RestoreBackupableDB*>(jhandle); auto rdb = reinterpret_cast<rocksdb::RestoreBackupableDB*>(jhandle);
rocksdb::Status s = rdb->DeleteBackup(jbackup_id); rocksdb::Status s = rdb->DeleteBackup(jbackup_id);
@ -131,6 +131,20 @@ void Java_org_rocksdb_RestoreBackupableDB_deleteBackup0(JNIEnv* env,
} }
} }
/*
* Class: org_rocksdb_RestoreBackupableDB
* Method: getBackupInfo
* Signature: (J)Ljava/util/List;
*/
jobject Java_org_rocksdb_RestoreBackupableDB_getBackupInfo(
JNIEnv* env, jobject jbdb, jlong jhandle) {
std::vector<rocksdb::BackupInfo> backup_infos;
reinterpret_cast<rocksdb::RestoreBackupableDB*>(jhandle)->
GetBackupInfo(&backup_infos);
return rocksdb::BackupInfoListJni::getBackupInfo(env,
backup_infos);
}
/* /*
* Class: org_rocksdb_RestoreBackupableDB * Class: org_rocksdb_RestoreBackupableDB
* Method: dispose * Method: dispose

Loading…
Cancel
Save