Merge pull request #398 from fyrz/RocksJava-CreateCheckPoint

[RocksJava] Support for stored snapshots
This commit is contained in:
Yueh-Hsuan Chiang 2014-11-26 11:40:41 -08:00
commit b8136a7d27
4 changed files with 236 additions and 0 deletions

View file

@ -4,6 +4,7 @@ NATIVE_JAVA_CLASSES = org.rocksdb.AbstractComparator\
org.rocksdb.BackupableDBOptions\
org.rocksdb.BlockBasedTableConfig\
org.rocksdb.BloomFilter\
org.rocksdb.Checkpoint\
org.rocksdb.ColumnFamilyHandle\
org.rocksdb.ColumnFamilyOptions\
org.rocksdb.Comparator\
@ -50,6 +51,7 @@ endif
JAVA_TESTS = org.rocksdb.test.BackupableDBOptionsTest\
org.rocksdb.test.BackupableDBTest\
org.rocksdb.test.BlockBasedTableConfigTest\
org.rocksdb.test.CheckPointTest\
org.rocksdb.test.ColumnFamilyOptionsTest\
org.rocksdb.test.ColumnFamilyTest\
org.rocksdb.test.ComparatorOptionsTest\

View file

@ -0,0 +1,72 @@
// 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;
/**
* Provides Checkpoint functionality. Checkpoints
* provide persistent snapshots of RocksDB databases.
*/
public class Checkpoint extends RocksObject {
/**
* Creates a Checkpoint object to be used for creating open-able
* snapshots.
*
* @param db {@link RocksDB} instance.
* @return a Checkpoint instance.
*
* @throws java.lang.IllegalArgumentException if {@link RocksDB}
* instance is null.
* @throws java.lang.IllegalStateException if {@link RocksDB}
* instance is not initialized.
*/
public static Checkpoint create(RocksDB db) {
if (db == null) {
throw new IllegalArgumentException(
"RocksDB instance shall not be null.");
} else if (!db.isInitialized()) {
throw new IllegalStateException(
"RocksDB instance must be initialized.");
}
Checkpoint checkpoint = new Checkpoint(db);
return checkpoint;
}
/**
* <p>Builds an open-able snapshot of RocksDB on the same disk, which
* accepts an output directory on the same disk, and under the directory
* (1) hard-linked SST files pointing to existing live SST files
* (2) a copied manifest files and other files</p>
*
* @param checkpointPath path to the folder where the snapshot is going
* to be stored.
* @throws RocksDBException thrown if an error occurs within the native
* part of the library.
*/
public void createCheckpoint(String checkpointPath)
throws RocksDBException {
createCheckpoint(nativeHandle_, checkpointPath);
}
@Override
protected void disposeInternal() {
disposeInternal(nativeHandle_);
}
private Checkpoint(RocksDB db) {
super();
nativeHandle_ = newCheckpoint(db.nativeHandle_);
db_ = db;
}
RocksDB db_;
private static native long newCheckpoint(long dbHandle);
private native void disposeInternal(long handle);
private native void createCheckpoint(long handle, String checkpointPath)
throws RocksDBException;
}

View file

@ -0,0 +1,101 @@
package org.rocksdb.test;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.rocksdb.Checkpoint;
import org.rocksdb.Options;
import org.rocksdb.RocksDB;
import org.rocksdb.RocksDBException;
import static org.assertj.core.api.Assertions.assertThat;
public class CheckPointTest {
@ClassRule
public static final RocksMemoryResource rocksMemoryResource =
new RocksMemoryResource();
@Rule
public TemporaryFolder dbFolder = new TemporaryFolder();
@Rule
public TemporaryFolder checkpointFolder = new TemporaryFolder();
@Test
public void checkPoint() throws RocksDBException {
RocksDB db = null;
Options options = null;
Checkpoint checkpoint = null;
try {
options = new Options().
setCreateIfMissing(true);
db = RocksDB.open(options,
dbFolder.getRoot().getAbsolutePath());
db.put("key".getBytes(), "value".getBytes());
checkpoint = Checkpoint.create(db);
checkpoint.createCheckpoint(checkpointFolder.
getRoot().getAbsolutePath() + "/snapshot1");
db.put("key2".getBytes(), "value2".getBytes());
checkpoint.createCheckpoint(checkpointFolder.
getRoot().getAbsolutePath() + "/snapshot2");
db.close();
db = RocksDB.open(options,
checkpointFolder.getRoot().getAbsolutePath() +
"/snapshot1");
assertThat(new String(db.get("key".getBytes()))).
isEqualTo("value");
assertThat(db.get("key2".getBytes())).isNull();
db.close();
db = RocksDB.open(options,
checkpointFolder.getRoot().getAbsolutePath() +
"/snapshot2");
assertThat(new String(db.get("key".getBytes()))).
isEqualTo("value");
assertThat(new String(db.get("key2".getBytes()))).
isEqualTo("value2");
} finally {
if (db != null) {
db.close();
}
if (options != null) {
options.dispose();
}
if (checkpoint != null) {
checkpoint.dispose();
}
}
}
@Test(expected = IllegalArgumentException.class)
public void failIfDbIsNull() {
Checkpoint.create(null);
}
@Test(expected = IllegalStateException.class)
public void failIfDbNotInitialized() throws RocksDBException {
RocksDB db = RocksDB.open(dbFolder.getRoot().getAbsolutePath());
db.dispose();
Checkpoint.create(db);
}
@Test(expected = RocksDBException.class)
public void failWithIllegalPath() throws RocksDBException {
RocksDB db = null;
Checkpoint checkpoint = null;
try {
db = RocksDB.open(dbFolder.getRoot().getAbsolutePath());
checkpoint = Checkpoint.create(db);
checkpoint.createCheckpoint("/Z:///:\\C:\\TZ/-");
} finally {
if (db != null) {
db.close();
}
if (checkpoint != null) {
checkpoint.dispose();
}
}
}
}

View file

@ -0,0 +1,61 @@
// 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::Checkpoint methods from Java side.
#include <stdio.h>
#include <stdlib.h>
#include <jni.h>
#include <string>
#include "include/org_rocksdb_Checkpoint.h"
#include "rocksjni/portal.h"
#include "rocksdb/db.h"
#include "rocksdb/utilities/checkpoint.h"
/*
* Class: org_rocksdb_Checkpoint
* Method: newCheckpoint
* Signature: (J)J
*/
jlong Java_org_rocksdb_Checkpoint_newCheckpoint(JNIEnv* env,
jclass jclazz, jlong jdb_handle) {
auto db = reinterpret_cast<rocksdb::DB*>(jdb_handle);
rocksdb::Checkpoint* checkpoint;
rocksdb::Checkpoint::Create(db, &checkpoint);
return reinterpret_cast<jlong>(checkpoint);
}
/*
* Class: org_rocksdb_Checkpoint
* Method: dispose
* Signature: (J)V
*/
void Java_org_rocksdb_Checkpoint_disposeInternal(JNIEnv* env, jobject jobj,
jlong jhandle) {
auto checkpoint = reinterpret_cast<rocksdb::Checkpoint*>(jhandle);
assert(checkpoint);
delete checkpoint;
}
/*
* Class: org_rocksdb_Checkpoint
* Method: createCheckpoint
* Signature: (JLjava/lang/String;)V
*/
void Java_org_rocksdb_Checkpoint_createCheckpoint(
JNIEnv* env, jobject jobj, jlong jcheckpoint_handle,
jstring jcheckpoint_path) {
auto checkpoint = reinterpret_cast<rocksdb::Checkpoint*>(
jcheckpoint_handle);
const char* checkpoint_path = env->GetStringUTFChars(
jcheckpoint_path, 0);
rocksdb::Status s = checkpoint->CreateCheckpoint(
checkpoint_path);
env->ReleaseStringUTFChars(jcheckpoint_path, checkpoint_path);
if (!s.ok()) {
rocksdb::RocksDBExceptionJni::ThrowNew(env, s);
}
}