[Java] Add a basic binding and test for BackupableDB and StackableDB.

Summary:
Add a skeleton binding and test for BackupableDB which shows that BackupableDB
and RocksDB can share the same JNI calls.

Test Plan:
make rocksdbjava
make jtest

Reviewers: haobo, ankgup87, sdong, dhruba

Reviewed By: haobo

CC: leveldb

Differential Revision: https://reviews.facebook.net/D17793
This commit is contained in:
Yueh-Hsuan Chiang 2014-04-17 17:28:51 -07:00
parent 651792251a
commit bb6fd15a6e
9 changed files with 315 additions and 13 deletions

View File

@ -422,7 +422,7 @@ ldb: tools/ldb.o $(LIBOBJECTS)
# ---------------------------------------------------------------------------
# Jni stuff
# ---------------------------------------------------------------------------
JNI_NATIVE_SOURCES = ./java/rocksjni/rocksjni.cc ./java/rocksjni/options.cc ./java/rocksjni/write_batch.cc
JNI_NATIVE_SOURCES = ./java/rocksjni/*.cc
JAVA_INCLUDE = -I/usr/lib/jvm/java-openjdk/include/ -I/usr/lib/jvm/java-openjdk/include/linux
ROCKSDBJNILIB = ./java/librocksdbjni.so

View File

@ -1,4 +1,4 @@
NATIVE_JAVA_CLASSES = org.rocksdb.RocksDB org.rocksdb.Options org.rocksdb.WriteBatch org.rocksdb.WriteBatchInternal org.rocksdb.WriteBatchTest org.rocksdb.WriteOptions
NATIVE_JAVA_CLASSES = org.rocksdb.RocksDB org.rocksdb.Options org.rocksdb.WriteBatch org.rocksdb.WriteBatchInternal org.rocksdb.WriteBatchTest org.rocksdb.WriteOptions org.rocksdb.BackupableDB org.rocksdb.BackupableDBOptions
NATIVE_INCLUDE = ./include
ROCKSDB_JAR = rocksdbjni.jar
@ -21,7 +21,9 @@ sample: java
@rm -rf /tmp/rocksdbjni_not_found
test: java
javac org/rocksdb/test/*.java
java -ea -Djava.library.path=.:../ -cp "$(ROCKSDB_JAR):.:./*" org.rocksdb.WriteBatchTest
java -ea -Djava.library.path=.:../ -cp "$(ROCKSDB_JAR):.:./*" org.rocksdb.test.BackupableDBTest
db_bench: java
javac org/rocksdb/benchmark/*.java

View File

@ -0,0 +1,84 @@
// 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;
/**
* A subclass of RocksDB which supports backup-related operations.
*
* @see BackupableDBOptions
*/
public class BackupableDB extends RocksDB {
/**
* Open a BackupableDB under the specified path.
* Note that the backup path should be set properly in the
* input BackupableDBOptions.
*
* @param opt options for db.
* @param bopt backup related options.
* @param the db path for storing data. The path for storing
* backup should be specified in the BackupableDBOptions.
* @return reference to the opened BackupableDB.
*/
public static BackupableDB open(
Options opt, BackupableDBOptions bopt, String db_path)
throws RocksDBException {
// since BackupableDB c++ will handle the life cycle of
// the returned RocksDB of RocksDB.open(), here we store
// it as a BackupableDB member variable to avoid GC.
BackupableDB bdb = new BackupableDB(RocksDB.open(opt, db_path));
bdb.open(bdb.db_.nativeHandle_, bopt.nativeHandle_);
return bdb;
}
/**
* Captures the state of the database in the latest backup.
* Note that this function is not thread-safe.
*
* @param flushBeforeBackup if true, then all data will be flushed
* before creating backup.
*/
public void createNewBackup(boolean flushBeforeBackup) {
createNewBackup(nativeHandle_, flushBeforeBackup);
}
/**
* Close the BackupableDB instance and release resource.
*
* Internally, BackupableDB owns the rocksdb::DB pointer to its
* associated RocksDB. The release of that RocksDB pointer is
* handled in the destructor of the c++ rocksdb::BackupableDB and
* should be transparent to Java developers.
*/
@Override public synchronized void close() {
if (isOpened()) {
super.close0();
}
}
/**
* A protected construction that will be used in the static factory
* method BackupableDB.open().
*/
protected BackupableDB(RocksDB db) {
super();
db_ = db;
}
@Override protected void finalize() {
close();
}
private boolean isOpened() {
return nativeHandle_ != 0;
}
protected native void open(long rocksDBHandle, long backupDBOptionsHandle);
protected native void createNewBackup(long handle, boolean flag);
private final RocksDB db_;
}

View File

@ -0,0 +1,52 @@
// 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;
/**
* BackupableDBOptions to control the behavior of a backupable database.
* It will be used during the creation of a BackupableDB.
*
* Note that dispose() must be called before an Options instance
* become out-of-scope to release the allocated memory in c++.
*/
public class BackupableDBOptions {
public BackupableDBOptions(String path) {
newBackupableDBOptions(path);
}
/**
* Returns the path to the BackupableDB directory.
*
* @return the path to the BackupableDB directory.
*/
public String backupDir() {
assert(isInitialized());
return backupDir(nativeHandle_);
}
/**
* Release the memory allocated for the current instance
* in the c++ side.
*/
public synchronized void dispose() {
if (isInitialized()) {
dispose(nativeHandle_);
}
}
@Override protected void finalize() {
dispose();
}
boolean isInitialized() {
return nativeHandle_ != 0;
}
private native void newBackupableDBOptions(String path);
private native String backupDir(long handle);
private native void dispose(long handle);
long nativeHandle_;
}

View File

@ -228,6 +228,10 @@ public class Options {
}
}
@Override protected void finalize() {
dispose();
}
private boolean isInitialized() {
return (nativeHandle_ != 0);
}

View File

@ -145,33 +145,33 @@ public class RocksDB {
/**
* Private constructor.
*/
private RocksDB() {
protected RocksDB() {
nativeHandle_ = 0;
}
// native methods
private native void open(
protected native void open(
long optionsHandle, long cacheSize, String path) throws RocksDBException;
private native void put(
protected native void put(
long handle, byte[] key, int keyLen,
byte[] value, int valueLen) throws RocksDBException;
private native void put(
protected native void put(
long handle, long writeOptHandle,
byte[] key, int keyLen,
byte[] value, int valueLen) throws RocksDBException;
private native void write(
protected native void write(
long writeOptHandle, long batchHandle) throws RocksDBException;
private native int get(
protected native int get(
long handle, byte[] key, int keyLen,
byte[] value, int valueLen) throws RocksDBException;
private native byte[] get(
protected native byte[] get(
long handle, byte[] key, int keyLen) throws RocksDBException;
private native void remove(
protected native void remove(
long handle, byte[] key, int keyLen) throws RocksDBException;
private native void remove(
protected native void remove(
long handle, long writeOptHandle,
byte[] key, int keyLen) throws RocksDBException;
private native void close0();
protected native void close0();
private long nativeHandle_;
protected long nativeHandle_;
}

View File

@ -0,0 +1,41 @@
// 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.rocksdb.*;
public class BackupableDBTest {
static final String db_path = "/tmp/backupablejni_db";
static final String backup_path = "/tmp/backupablejni_db_backup";
static {
System.loadLibrary("rocksdbjni");
}
public static void main(String[] args) {
Options opt = new Options();
opt.setCreateIfMissing(true);
BackupableDBOptions bopt = new BackupableDBOptions(backup_path);
BackupableDB bdb = null;
try {
bdb = BackupableDB.open(opt, bopt, db_path);
bdb.put("hello".getBytes(), "BackupableDB".getBytes());
bdb.createNewBackup(true);
byte[] value = bdb.get("hello".getBytes());
assert(new String(value).equals("BackupableDB"));
} catch (RocksDBException e) {
System.err.format("[ERROR]: %s%n", e);
e.printStackTrace();
} finally {
opt.dispose();
bopt.dispose();
if (bdb != null) {
bdb.close();
}
}
}
}

View File

@ -0,0 +1,85 @@
// 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.
//
// This file implements the "bridge" between Java and C++ and enables
// calling c++ rocksdb::DB methods from Java side.
#include <stdio.h>
#include <stdlib.h>
#include <jni.h>
#include <string>
#include "include/org_rocksdb_BackupableDB.h"
#include "include/org_rocksdb_BackupableDBOptions.h"
#include "rocksjni/portal.h"
#include "utilities/backupable_db.h"
/*
* Class: org_rocksdb_BackupableDB
* Method: open
* Signature: (JJ)V
*/
void Java_org_rocksdb_BackupableDB_open(
JNIEnv* env, jobject jbdb, jlong jdb_handle, jlong jopt_handle) {
auto db = reinterpret_cast<rocksdb::DB*>(jdb_handle);
auto opt = reinterpret_cast<rocksdb::BackupableDBOptions*>(jopt_handle);
auto bdb = new rocksdb::BackupableDB(db, *opt);
// as BackupableDB extends RocksDB on the java side, we can reuse
// the RocksDB portal here.
rocksdb::RocksDBJni::setHandle(env, jbdb, bdb);
}
/*
* Class: org_rocksdb_BackupableDB
* Method: createNewBackup
* Signature: (JZ)V
*/
void Java_org_rocksdb_BackupableDB_createNewBackup(
JNIEnv* env, jobject jbdb, jlong jhandle, jboolean jflag) {
reinterpret_cast<rocksdb::BackupableDB*>(jhandle)->CreateNewBackup(jflag);
}
///////////////////////////////////////////////////////////////////////////
// BackupDBOptions
/*
* Class: org_rocksdb_BackupableDBOptions
* Method: newBackupableDBOptions
* Signature: (Ljava/lang/String;)V
*/
void Java_org_rocksdb_BackupableDBOptions_newBackupableDBOptions(
JNIEnv* env, jobject jobj, jstring jpath) {
const char* cpath = env->GetStringUTFChars(jpath, 0);
auto bopt = new rocksdb::BackupableDBOptions(cpath);
env->ReleaseStringUTFChars(jpath, cpath);
rocksdb::BackupableDBOptionsJni::setHandle(env, jobj, bopt);
}
/*
* Class: org_rocksdb_BackupableDBOptions
* Method: backupDir
* Signature: (J)Ljava/lang/String;
*/
jstring Java_org_rocksdb_BackupableDBOptions_backupDir(
JNIEnv* env, jobject jopt, jlong jhandle, jstring jpath) {
auto bopt = reinterpret_cast<rocksdb::BackupableDBOptions*>(jhandle);
return env->NewStringUTF(bopt->backup_dir.c_str());
}
/*
* Class: org_rocksdb_BackupableDBOptions
* Method: dispose
* Signature: (J)V
*/
void Java_org_rocksdb_BackupableDBOptions_dispose(
JNIEnv* env, jobject jopt, jlong jhandle) {
auto bopt = reinterpret_cast<rocksdb::BackupableDBOptions*>(jhandle);
assert(bopt);
delete bopt;
rocksdb::BackupableDBOptionsJni::setHandle(env, jopt, nullptr);
}

View File

@ -12,6 +12,7 @@
#include <jni.h>
#include "rocksdb/db.h"
#include "utilities/backupable_db.h"
namespace rocksdb {
@ -170,5 +171,38 @@ class WriteBatchJni {
reinterpret_cast<jlong>(wb));
}
};
class BackupableDBOptionsJni {
public:
// Get the java class id of org.rocksdb.BackupableDBOptions.
static jclass getJClass(JNIEnv* env) {
static jclass jclazz = env->FindClass("org/rocksdb/BackupableDBOptions");
assert(jclazz != nullptr);
return jclazz;
}
// Get the field id of the member variable of org.rocksdb.BackupableDBOptions
// that stores the pointer to rocksdb::BackupableDBOptions
static jfieldID getHandleFieldID(JNIEnv* env) {
static jfieldID fid = env->GetFieldID(
getJClass(env), "nativeHandle_", "J");
assert(fid != nullptr);
return fid;
}
// Get the pointer to rocksdb::BackupableDBOptions
static rocksdb::BackupableDBOptions* getHandle(JNIEnv* env, jobject jobj) {
return reinterpret_cast<rocksdb::BackupableDBOptions*>(
env->GetLongField(jobj, getHandleFieldID(env)));
}
// Pass the rocksdb::BackupableDBOptions pointer to the java side.
static void setHandle(
JNIEnv* env, jobject jobj, rocksdb::BackupableDBOptions* op) {
env->SetLongField(
jobj, getHandleFieldID(env),
reinterpret_cast<jlong>(op));
}
};
} // namespace rocksdb
#endif // JAVA_ROCKSJNI_PORTAL_H_