[RocksJava] - BackupInfos & Restore-/BackupableDB enhancements

Summary:
- BackupableDB deleteBackup method
- BackupableDB purgeOldBackups bugfix
- BackupInfos now available in Restorable-/BackupableDB
- Extended BackupableDBTest to cover more of the currently implemented functionality.

Test Plan:
make rocksdbjava
make jtest

Differential Revision: https://reviews.facebook.net/D27027
main
fyrz 10 years ago
parent eb357af58c
commit 7e12ae5a21
  1. 67
      java/org/rocksdb/BackupInfo.java
  2. 38
      java/org/rocksdb/BackupableDB.java
  3. 27
      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. 14
      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;
import java.util.List;
/**
* 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
* before creating backup.
* @throws org.rocksdb.RocksDBException
*/
public void createNewBackup(boolean flushBeforeBackup) {
public void createNewBackup(boolean flushBeforeBackup)
throws RocksDBException {
createNewBackup(nativeHandle_, flushBeforeBackup);
}
@ -52,11 +56,32 @@ public class BackupableDB extends RocksDB {
* Deletes old backups, keeping latest numBackupsToKeep alive.
*
* @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);
}
/**
* Deletes a specific backup.
*
* @param backupId of backup to delete.
* @throws org.rocksdb.RocksDBException
*/
public void deleteBackup(long 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.
@ -85,6 +110,11 @@ public class BackupableDB extends RocksDB {
}
protected native void open(long rocksDBHandle, long backupDBOptionsHandle);
protected native void createNewBackup(long handle, boolean flag);
protected native void purgeOldBackups(long handle, int numBackupsToKeep);
protected native void createNewBackup(long handle, boolean flag)
throws RocksDBException;
protected native void purgeOldBackups(long handle, int numBackupsToKeep)
throws RocksDBException;
private native void deleteBackup0(long nativeHandle, long backupId)
throws RocksDBException;
protected native List<BackupInfo> getBackupInfo(long handle);
}

@ -5,6 +5,8 @@
package org.rocksdb;
import java.util.List;
/**
* 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.
*
* @param numBackupsToKeep of latest backups to keep
* @throws org.rocksdb.RocksDBException
*/
public void purgeOldBackups(int numBackupsToKeep) throws RocksDBException {
purgeOldBackups0(nativeHandle_, numBackupsToKeep);
@ -74,11 +77,22 @@ public class RestoreBackupableDB extends RocksObject {
* Deletes a specific backup.
*
* @param backupId of backup to delete.
* @throws org.rocksdb.RocksDBException
*/
public void deleteBackup(long 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_);
}
/**
* Release the memory allocated for the current instance
* in the c++ side.
@ -90,10 +104,15 @@ public class RestoreBackupableDB extends RocksObject {
private native long newRestoreBackupableDB(long options);
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,
String dbDir, String walDir, long restoreOptions) throws RocksDBException;
private native void purgeOldBackups0(long nativeHandle, int numBackupsToKeep);
private native void deleteBackup0(long nativeHandle, long backupId);
String dbDir, String walDir, long restoreOptions)
throws RocksDBException;
private native void purgeOldBackups0(long nativeHandle, int numBackupsToKeep)
throws RocksDBException;
private native void deleteBackup0(long nativeHandle, long backupId)
throws RocksDBException;
protected native List<BackupInfo> getBackupInfo(long handle);
private native void dispose(long nativeHandle);
}

@ -7,6 +7,8 @@ package org.rocksdb.test;
import org.rocksdb.*;
import java.util.List;
public class BackupableDBTest {
static final String db_path = "/tmp/rocksdbjni_backupable_db_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,
true, false, true, 0, 0);
BackupableDB bdb = null;
List<BackupInfo> backupInfos;
List<BackupInfo> restoreInfos;
try {
bdb = BackupableDB.open(opt, bopt, db_path);
bdb.put("abc".getBytes(), "def".getBytes());
bdb.put("ghi".getBytes(), "jkl".getBytes());
backupInfos = bdb.getBackupInfos();
assert(backupInfos.size() == 0);
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
bdb.remove("abc".getBytes());
byte[] value = bdb.get("abc".getBytes());
@ -38,8 +60,26 @@ public class BackupableDBTest {
// restore from backup
RestoreOptions ropt = new RestoreOptions(false);
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,
ropt);
// do nothing because there is only one backup
rdb.purgeOldBackups(1);
restoreInfos = rdb.getBackupInfos();
assert(restoreInfos.size() == 1);
rdb.dispose();
ropt.dispose();
@ -48,6 +88,28 @@ public class BackupableDBTest {
value = bdb.get("abc".getBytes());
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");
} catch (RocksDBException e) {
System.err.format("[ERROR]: %s%n", e);

@ -11,6 +11,7 @@
#include <stdlib.h>
#include <jni.h>
#include <string>
#include <vector>
#include "include/org_rocksdb_BackupableDB.h"
#include "include/org_rocksdb_BackupableDBOptions.h"
@ -53,7 +54,7 @@ void Java_org_rocksdb_BackupableDB_createNewBackup(
* Signature: (JI)V
*/
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 =
reinterpret_cast<rocksdb::BackupableDB*>(jhandle)->
PurgeOldBackups(jnumBackupsToKeep);
@ -62,6 +63,35 @@ void Java_org_rocksdb_BackupableDB_purgeOldBackups(
}
}
/*
* Class: org_rocksdb_BackupableDB
* Method: deleteBackup0
* Signature: (JJ)V
*/
void Java_org_rocksdb_BackupableDB_deleteBackup0(JNIEnv* env,
jobject jobj, jlong jhandle, jlong 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

@ -15,7 +15,6 @@ BaseComparatorJniCallback::BaseComparatorJniCallback(
const ComparatorJniCallbackOptions* copt)
: mtx_compare(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,
// so we ref the jvm not the env
const jint rs = env->GetJavaVM(&m_jvm);

@ -13,6 +13,7 @@
#include <jni.h>
#include <limits>
#include <string>
#include <vector>
#include "rocksdb/db.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 {
public:
/**

@ -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
* Method: dispose

Loading…
Cancel
Save