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