Summary: RocksDB supports two ways of saving snapshots. In memory and on disk. The later was added with this pull request to RocksJava. Test Plan: Reviewers: Subscribers:main
parent
274ba62707
commit
fcc2dfd9f9
@ -0,0 +1,65 @@ |
|||||||
|
// 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. |
||||||
|
*/ |
||||||
|
public static Checkpoint create(RocksDB db) { |
||||||
|
if (db == null || !db.isInitialized()) { |
||||||
|
throw new IllegalArgumentException( |
||||||
|
"RocksDB instance needs to be initialized."); |
||||||
|
} |
||||||
|
Checkpoint checkpoint = new Checkpoint( |
||||||
|
newCheckpoint(db.nativeHandle_)); |
||||||
|
checkpoint.db_ = 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(long handle) { |
||||||
|
super(); |
||||||
|
nativeHandle_ = handle; |
||||||
|
} |
||||||
|
|
||||||
|
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; |
||||||
|
} |
@ -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 = IllegalArgumentException.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(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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); |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue