mirror of
https://github.com/facebook/rocksdb.git
synced 2026-07-07 22:55:23 +08:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8969445642 | |||
| 250d2a6791 | |||
| 68d69899a1 | |||
| b4fc156fb8 | |||
| 34ccab0210 | |||
| 4f51078c44 | |||
| 2c3ceec5a3 | |||
| 5ae32b86ac | |||
| 9e9192c8c6 | |||
| b04c5d4277 | |||
| 8d47fc7199 |
@@ -602,6 +602,7 @@ set(SOURCES
|
||||
utilities/leveldb_options/leveldb_options.cc
|
||||
utilities/lua/rocks_lua_compaction_filter.cc
|
||||
utilities/memory/memory_util.cc
|
||||
utilities/merge_operators/bytesxor.cc
|
||||
utilities/merge_operators/max.cc
|
||||
utilities/merge_operators/put.cc
|
||||
utilities/merge_operators/string_append/stringappend.cc
|
||||
|
||||
+11
-1
@@ -1,11 +1,21 @@
|
||||
# Rocksdb Change Log
|
||||
## Unreleased
|
||||
## 5.12.2 (3/23/2018)
|
||||
### Bug Fixes
|
||||
* Fsync after writing global seq number to the ingestion file in ExternalSstFileIngestionJob.
|
||||
|
||||
### Java API Changes
|
||||
* Add `BlockBasedTableConfig.setBlockCache` to allow sharing a block cache across DB instances.
|
||||
|
||||
## 5.12.1 (3/16/2018)
|
||||
### Public API Change
|
||||
* RocksDBOptionsParser::Parse()'s `ignore_unknown_options` argument will only be effective if the option file shows it is generated using a higher version of RocksDB than the current version.
|
||||
|
||||
### New Features
|
||||
* Avoid unnecessarily flushing in `CompactRange()` when the range specified by the user does not overlap unflushed memtables.
|
||||
|
||||
### Bug Fixes
|
||||
* Fix WAL corruption caused by race condition between user write thread and backup/checkpoint thread.
|
||||
|
||||
## 5.12.0 (2/14/2018)
|
||||
### Public API Change
|
||||
* Iterator::SeekForPrev is now a pure virtual method. This is to prevent user who implement the Iterator interface fail to implement SeekForPrev by mistake.
|
||||
|
||||
@@ -242,6 +242,7 @@ cpp_library(
|
||||
"utilities/leveldb_options/leveldb_options.cc",
|
||||
"utilities/lua/rocks_lua_compaction_filter.cc",
|
||||
"utilities/memory/memory_util.cc",
|
||||
"utilities/merge_operators/bytesxor.cc",
|
||||
"utilities/merge_operators/max.cc",
|
||||
"utilities/merge_operators/put.cc",
|
||||
"utilities/merge_operators/string_append/stringappend.cc",
|
||||
|
||||
@@ -509,6 +509,9 @@ Status ExternalSstFileIngestionJob::AssignGlobalSeqnoForIngestedFile(
|
||||
std::string seqno_val;
|
||||
PutFixed64(&seqno_val, seqno);
|
||||
status = rwfile->Write(file_to_ingest->global_seqno_offset, seqno_val);
|
||||
if (status.ok()) {
|
||||
status = rwfile->Fsync();
|
||||
}
|
||||
if (status.ok()) {
|
||||
file_to_ingest->assigned_seqno = seqno;
|
||||
}
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
#pragma once
|
||||
|
||||
#define ROCKSDB_MAJOR 5
|
||||
#define ROCKSDB_MINOR 10
|
||||
#define ROCKSDB_PATCH 0
|
||||
#define ROCKSDB_MINOR 12
|
||||
#define ROCKSDB_PATCH 2
|
||||
|
||||
// Do not use these. We made the mistake of declaring macros starting with
|
||||
// double underscore. Now we have to live with our choice. We'll deprecate these
|
||||
|
||||
@@ -24,6 +24,7 @@ set(JNI_NATIVE_SOURCES
|
||||
rocksjni/lru_cache.cc
|
||||
rocksjni/memtablejni.cc
|
||||
rocksjni/merge_operator.cc
|
||||
rocksjni/native_comparator_wrapper_test.cc
|
||||
rocksjni/options.cc
|
||||
rocksjni/options_util.cc
|
||||
rocksjni/ratelimiterjni.cc
|
||||
@@ -87,6 +88,8 @@ set(NATIVE_JAVA_CLASSES
|
||||
org.rocksdb.LRUCache
|
||||
org.rocksdb.MemTableConfig
|
||||
org.rocksdb.MergeOperator
|
||||
org.rocksdb.NativeComparatorWrapper
|
||||
org.rocksdb.NativeComparatorWrapperTest.NativeStringComparatorWrapper
|
||||
org.rocksdb.NativeLibraryLoader
|
||||
org.rocksdb.Options
|
||||
org.rocksdb.OptionsUtil
|
||||
@@ -122,6 +125,8 @@ set(NATIVE_JAVA_CLASSES
|
||||
org.rocksdb.WriteBatchTestInternalHelper
|
||||
org.rocksdb.WriteBatchWithIndex
|
||||
org.rocksdb.WriteOptions
|
||||
org.rocksdb.util.CapturingWriteBatchHandler
|
||||
org.rocksdb.util.WriteBatchGetter
|
||||
)
|
||||
|
||||
include(FindJava)
|
||||
@@ -177,6 +182,7 @@ add_jar(
|
||||
src/main/java/org/rocksdb/CompactionStyle.java
|
||||
src/main/java/org/rocksdb/Comparator.java
|
||||
src/main/java/org/rocksdb/ComparatorOptions.java
|
||||
src/main/java/org/rocksdb/ComparatorType.java
|
||||
src/main/java/org/rocksdb/CompressionOptions.java
|
||||
src/main/java/org/rocksdb/CompressionType.java
|
||||
src/main/java/org/rocksdb/DBOptions.java
|
||||
@@ -203,6 +209,7 @@ add_jar(
|
||||
src/main/java/org/rocksdb/MergeOperator.java
|
||||
src/main/java/org/rocksdb/MutableColumnFamilyOptions.java
|
||||
src/main/java/org/rocksdb/MutableColumnFamilyOptionsInterface.java
|
||||
src/main/java/org/rocksdb/NativeComparatorWrapper.java
|
||||
src/main/java/org/rocksdb/NativeLibraryLoader.java
|
||||
src/main/java/org/rocksdb/Options.java
|
||||
src/main/java/org/rocksdb/OptionsUtil.java
|
||||
@@ -244,11 +251,14 @@ add_jar(
|
||||
src/main/java/org/rocksdb/WriteOptions.java
|
||||
src/test/java/org/rocksdb/BackupEngineTest.java
|
||||
src/test/java/org/rocksdb/IngestExternalFileOptionsTest.java
|
||||
src/test/java/org/rocksdb/NativeComparatorWrapperTest.java
|
||||
src/test/java/org/rocksdb/PlatformRandomHelper.java
|
||||
src/test/java/org/rocksdb/RocksDBExceptionTest.java
|
||||
src/test/java/org/rocksdb/RocksMemoryResource.java
|
||||
src/test/java/org/rocksdb/SnapshotTest.java
|
||||
src/test/java/org/rocksdb/WriteBatchTest.java
|
||||
src/test/java/org/rocksdb/util/CapturingWriteBatchHandler.java
|
||||
src/test/java/org/rocksdb/util/WriteBatchGetter.java
|
||||
INCLUDE_JARS ${JAVA_TESTCLASSPATH}
|
||||
)
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
NATIVE_JAVA_CLASSES = org.rocksdb.AbstractCompactionFilter\
|
||||
org.rocksdb.AbstractCompactionFilterFactory\
|
||||
org.rocksdb.AbstractSlice\
|
||||
org.rocksdb.AbstractTransactionNotifier\
|
||||
org.rocksdb.BackupEngine\
|
||||
org.rocksdb.BackupableDBOptions\
|
||||
org.rocksdb.BlockBasedTableConfig\
|
||||
@@ -29,6 +30,9 @@ NATIVE_JAVA_CLASSES = org.rocksdb.AbstractCompactionFilter\
|
||||
org.rocksdb.Logger\
|
||||
org.rocksdb.LRUCache\
|
||||
org.rocksdb.MergeOperator\
|
||||
org.rocksdb.NativeComparatorWrapper\
|
||||
org.rocksdb.OptimisticTransactionDB\
|
||||
org.rocksdb.OptimisticTransactionOptions\
|
||||
org.rocksdb.Options\
|
||||
org.rocksdb.OptionsUtil\
|
||||
org.rocksdb.PlainTableConfig\
|
||||
@@ -45,6 +49,10 @@ NATIVE_JAVA_CLASSES = org.rocksdb.AbstractCompactionFilter\
|
||||
org.rocksdb.Slice\
|
||||
org.rocksdb.SstFileWriter\
|
||||
org.rocksdb.Statistics\
|
||||
org.rocksdb.Transaction\
|
||||
org.rocksdb.TransactionDB\
|
||||
org.rocksdb.TransactionDBOptions\
|
||||
org.rocksdb.TransactionOptions\
|
||||
org.rocksdb.TransactionLogIterator\
|
||||
org.rocksdb.TtlDB\
|
||||
org.rocksdb.VectorMemTableConfig\
|
||||
@@ -57,6 +65,7 @@ NATIVE_JAVA_CLASSES = org.rocksdb.AbstractCompactionFilter\
|
||||
org.rocksdb.WBWIRocksIterator
|
||||
|
||||
NATIVE_JAVA_TEST_CLASSES = org.rocksdb.RocksDBExceptionTest\
|
||||
org.rocksdb.NativeComparatorWrapperTest.NativeStringComparatorWrapper\
|
||||
org.rocksdb.WriteBatchTest\
|
||||
org.rocksdb.WriteBatchTestInternalHelper
|
||||
|
||||
@@ -104,7 +113,11 @@ JAVA_TESTS = org.rocksdb.BackupableDBOptionsTest\
|
||||
org.rocksdb.MergeTest\
|
||||
org.rocksdb.MixedOptionsTest\
|
||||
org.rocksdb.MutableColumnFamilyOptionsTest\
|
||||
org.rocksdb.NativeComparatorWrapperTest\
|
||||
org.rocksdb.NativeLibraryLoaderTest\
|
||||
org.rocksdb.OptimisticTransactionTest\
|
||||
org.rocksdb.OptimisticTransactionDBTest\
|
||||
org.rocksdb.OptimisticTransactionOptionsTest\
|
||||
org.rocksdb.OptionsUtilTest\
|
||||
org.rocksdb.OptionsTest\
|
||||
org.rocksdb.PlainTableConfigTest\
|
||||
@@ -120,6 +133,10 @@ JAVA_TESTS = org.rocksdb.BackupableDBOptionsTest\
|
||||
org.rocksdb.SliceTest\
|
||||
org.rocksdb.SnapshotTest\
|
||||
org.rocksdb.SstFileWriterTest\
|
||||
org.rocksdb.TransactionTest\
|
||||
org.rocksdb.TransactionDBTest\
|
||||
org.rocksdb.TransactionOptionsTest\
|
||||
org.rocksdb.TransactionDBOptionsTest\
|
||||
org.rocksdb.TransactionLogIteratorTest\
|
||||
org.rocksdb.TtlDBTest\
|
||||
org.rocksdb.StatisticsTest\
|
||||
@@ -209,6 +226,20 @@ column_family_sample: java
|
||||
java $(JAVA_ARGS) -Djava.library.path=target -cp $(MAIN_CLASSES):$(SAMPLES_MAIN_CLASSES) RocksDBColumnFamilySample /tmp/rocksdbjni
|
||||
$(AM_V_at)@rm -rf /tmp/rocksdbjni
|
||||
|
||||
transaction_sample: java
|
||||
$(AM_V_GEN)mkdir -p $(SAMPLES_MAIN_CLASSES)
|
||||
$(AM_V_at)javac -cp $(MAIN_CLASSES) -d $(SAMPLES_MAIN_CLASSES) $(SAMPLES_MAIN_SRC)/TransactionSample.java
|
||||
$(AM_V_at)@rm -rf /tmp/rocksdbjni
|
||||
java -ea -Xcheck:jni -Djava.library.path=target -cp $(MAIN_CLASSES):$(SAMPLES_MAIN_CLASSES) TransactionSample /tmp/rocksdbjni
|
||||
$(AM_V_at)@rm -rf /tmp/rocksdbjni
|
||||
|
||||
optimistic_transaction_sample: java
|
||||
$(AM_V_GEN)mkdir -p $(SAMPLES_MAIN_CLASSES)
|
||||
$(AM_V_at)javac -cp $(MAIN_CLASSES) -d $(SAMPLES_MAIN_CLASSES) $(SAMPLES_MAIN_SRC)/OptimisticTransactionSample.java
|
||||
$(AM_V_at)@rm -rf /tmp/rocksdbjni
|
||||
java -ea -Xcheck:jni -Djava.library.path=target -cp $(MAIN_CLASSES):$(SAMPLES_MAIN_CLASSES) OptimisticTransactionSample /tmp/rocksdbjni
|
||||
$(AM_V_at)@rm -rf /tmp/rocksdbjni
|
||||
|
||||
resolve_test_deps:
|
||||
test -d "$(JAVA_TEST_LIBDIR)" || mkdir -p "$(JAVA_TEST_LIBDIR)"
|
||||
test -s "$(JAVA_JUNIT_JAR)" || cp $(MVN_LOCAL)/junit/junit/4.12/junit-4.12.jar $(JAVA_TEST_LIBDIR) || curl -k -L -o $(JAVA_JUNIT_JAR) $(SEARCH_REPO_URL)junit/junit/4.12/junit-4.12.jar
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
//
|
||||
// This file implements the "bridge" between Java and C++ and enables
|
||||
// calling c++ rocksdb::Iterator methods from Java side.
|
||||
// This file implements the "bridge" between Java and C++ for
|
||||
// rocksdb::ColumnFamilyHandle.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -13,14 +13,56 @@
|
||||
#include "include/org_rocksdb_ColumnFamilyHandle.h"
|
||||
#include "rocksjni/portal.h"
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_ColumnFamilyHandle
|
||||
* Method: getName
|
||||
* Signature: (J)[B
|
||||
*/
|
||||
jbyteArray Java_org_rocksdb_ColumnFamilyHandle_getName(
|
||||
JNIEnv* env, jobject jobj, jlong jhandle) {
|
||||
auto* cfh = reinterpret_cast<rocksdb::ColumnFamilyHandle*>(jhandle);
|
||||
std::string cf_name = cfh->GetName();
|
||||
return rocksdb::JniUtil::copyBytes(env, cf_name);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_ColumnFamilyHandle
|
||||
* Method: getID
|
||||
* Signature: (J)I
|
||||
*/
|
||||
jint Java_org_rocksdb_ColumnFamilyHandle_getID(
|
||||
JNIEnv* env, jobject jobj, jlong jhandle) {
|
||||
auto* cfh = reinterpret_cast<rocksdb::ColumnFamilyHandle*>(jhandle);
|
||||
const int32_t id = cfh->GetID();
|
||||
return static_cast<jint>(id);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_ColumnFamilyHandle
|
||||
* Method: getDescriptor
|
||||
* Signature: (J)Lorg/rocksdb/ColumnFamilyDescriptor;
|
||||
*/
|
||||
jobject Java_org_rocksdb_ColumnFamilyHandle_getDescriptor(
|
||||
JNIEnv* env, jobject jobj, jlong jhandle) {
|
||||
auto* cfh = reinterpret_cast<rocksdb::ColumnFamilyHandle*>(jhandle);
|
||||
rocksdb::ColumnFamilyDescriptor desc;
|
||||
rocksdb::Status s = cfh->GetDescriptor(&desc);
|
||||
if (s.ok()) {
|
||||
return rocksdb::ColumnFamilyDescriptorJni::construct(env, &desc);
|
||||
} else {
|
||||
rocksdb::RocksDBExceptionJni::ThrowNew(env, s);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_ColumnFamilyHandle
|
||||
* Method: disposeInternal
|
||||
* Signature: (J)V
|
||||
*/
|
||||
void Java_org_rocksdb_ColumnFamilyHandle_disposeInternal(
|
||||
JNIEnv* env, jobject jobj, jlong handle) {
|
||||
auto* cfh = reinterpret_cast<rocksdb::ColumnFamilyHandle*>(handle);
|
||||
JNIEnv* env, jobject jobj, jlong jhandle) {
|
||||
auto* cfh = reinterpret_cast<rocksdb::ColumnFamilyHandle*>(jhandle);
|
||||
assert(cfh != nullptr);
|
||||
delete cfh;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include "include/org_rocksdb_Comparator.h"
|
||||
#include "include/org_rocksdb_DirectComparator.h"
|
||||
#include "include/org_rocksdb_NativeComparatorWrapper.h"
|
||||
#include "rocksjni/comparatorjnicallback.h"
|
||||
#include "rocksjni/portal.h"
|
||||
|
||||
@@ -49,4 +50,16 @@ jlong Java_org_rocksdb_DirectComparator_createNewDirectComparator0(
|
||||
new rocksdb::DirectComparatorJniCallback(env, jobj, copt);
|
||||
return reinterpret_cast<jlong>(c);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_NativeComparatorWrapper
|
||||
* Method: disposeInternal
|
||||
* Signature: (J)V
|
||||
*/
|
||||
void Java_org_rocksdb_NativeComparatorWrapper_disposeInternal(
|
||||
JNIEnv* env, jobject jobj, jlong jcomparator_handle) {
|
||||
auto* comparator =
|
||||
reinterpret_cast<rocksdb::Comparator*>(jcomparator_handle);
|
||||
delete comparator;
|
||||
}
|
||||
// </editor-fold>
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
#include <jni.h>
|
||||
#include <string>
|
||||
|
||||
#include "rocksdb/comparator.h"
|
||||
#include "rocksdb/slice.h"
|
||||
|
||||
#include "include/org_rocksdb_NativeComparatorWrapperTest_NativeStringComparatorWrapper.h"
|
||||
|
||||
namespace rocksdb {
|
||||
|
||||
class NativeComparatorWrapperTestStringComparator
|
||||
: public Comparator {
|
||||
|
||||
const char* Name() const {
|
||||
return "NativeComparatorWrapperTestStringComparator";
|
||||
}
|
||||
|
||||
int Compare(
|
||||
const Slice& a, const Slice& b) const {
|
||||
return a.ToString().compare(b.ToString());
|
||||
}
|
||||
|
||||
void FindShortestSeparator(
|
||||
std::string* start, const Slice& limit) const {
|
||||
return;
|
||||
}
|
||||
|
||||
void FindShortSuccessor(
|
||||
std::string* key) const {
|
||||
return;
|
||||
}
|
||||
};
|
||||
} // end of rocksdb namespace
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_NativeComparatorWrapperTest_NativeStringComparatorWrapper
|
||||
* Method: newStringComparator
|
||||
* Signature: ()J
|
||||
*/
|
||||
jlong Java_org_rocksdb_NativeComparatorWrapperTest_00024NativeStringComparatorWrapper_newStringComparator(
|
||||
JNIEnv* env , jobject jobj) {
|
||||
auto* comparator =
|
||||
new rocksdb::NativeComparatorWrapperTestStringComparator();
|
||||
return reinterpret_cast<jlong>(comparator);
|
||||
}
|
||||
@@ -0,0 +1,267 @@
|
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
//
|
||||
// This file implements the "bridge" between Java and C++
|
||||
// for rocksdb::TransactionDB.
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include "include/org_rocksdb_OptimisticTransactionDB.h"
|
||||
|
||||
#include "rocksdb/options.h"
|
||||
#include "rocksdb/utilities/optimistic_transaction_db.h"
|
||||
#include "rocksdb/utilities/transaction.h"
|
||||
|
||||
#include "rocksjni/portal.h"
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_OptimisticTransactionDB
|
||||
* Method: open
|
||||
* Signature: (JLjava/lang/String;)J
|
||||
*/
|
||||
jlong Java_org_rocksdb_OptimisticTransactionDB_open__JLjava_lang_String_2(
|
||||
JNIEnv* env, jclass jcls, jlong joptions_handle, jstring jdb_path) {
|
||||
const char* db_path = env->GetStringUTFChars(jdb_path, nullptr);
|
||||
if (db_path == nullptr) {
|
||||
// exception thrown: OutOfMemoryError
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto* options = reinterpret_cast<rocksdb::Options*>(joptions_handle);
|
||||
rocksdb::OptimisticTransactionDB* otdb = nullptr;
|
||||
rocksdb::Status s =
|
||||
rocksdb::OptimisticTransactionDB::Open(*options, db_path, &otdb);
|
||||
env->ReleaseStringUTFChars(jdb_path, db_path);
|
||||
|
||||
if (s.ok()) {
|
||||
return reinterpret_cast<jlong>(otdb);
|
||||
} else {
|
||||
rocksdb::RocksDBExceptionJni::ThrowNew(env, s);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_OptimisticTransactionDB
|
||||
* Method: open
|
||||
* Signature: (JLjava/lang/String;[[B[J)[J
|
||||
*/
|
||||
jlongArray Java_org_rocksdb_OptimisticTransactionDB_open__JLjava_lang_String_2_3_3B_3J(
|
||||
JNIEnv* env, jclass jcls, jlong jdb_options_handle, jstring jdb_path,
|
||||
jobjectArray jcolumn_names, jlongArray jcolumn_options_handles) {
|
||||
const char* db_path = env->GetStringUTFChars(jdb_path, nullptr);
|
||||
if (db_path == nullptr) {
|
||||
// exception thrown: OutOfMemoryError
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<rocksdb::ColumnFamilyDescriptor> column_families;
|
||||
const jsize len_cols = env->GetArrayLength(jcolumn_names);
|
||||
if (len_cols > 0) {
|
||||
if (env->EnsureLocalCapacity(len_cols) != 0) {
|
||||
// out of memory
|
||||
env->ReleaseStringUTFChars(jdb_path, db_path);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
jlong* jco =
|
||||
env->GetLongArrayElements(jcolumn_options_handles, nullptr);
|
||||
if(jco == nullptr) {
|
||||
// exception thrown: OutOfMemoryError
|
||||
env->ReleaseStringUTFChars(jdb_path, db_path);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (int i = 0; i < len_cols; i++) {
|
||||
const jobject jcn = env->GetObjectArrayElement(jcolumn_names, i);
|
||||
if (env->ExceptionCheck()) {
|
||||
// exception thrown: ArrayIndexOutOfBoundsException
|
||||
env->ReleaseLongArrayElements(jcolumn_options_handles, jco, JNI_ABORT);
|
||||
env->ReleaseStringUTFChars(jdb_path, db_path);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const jbyteArray jcn_ba = reinterpret_cast<jbyteArray>(jcn);
|
||||
const jsize jcf_name_len = env->GetArrayLength(jcn_ba);
|
||||
if (env->EnsureLocalCapacity(jcf_name_len) != 0) {
|
||||
// out of memory
|
||||
env->DeleteLocalRef(jcn);
|
||||
env->ReleaseLongArrayElements(jcolumn_options_handles, jco, JNI_ABORT);
|
||||
env->ReleaseStringUTFChars(jdb_path, db_path);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
jbyte* jcf_name = env->GetByteArrayElements(jcn_ba, nullptr);
|
||||
if (jcf_name == nullptr) {
|
||||
// exception thrown: OutOfMemoryError
|
||||
env->DeleteLocalRef(jcn);
|
||||
env->ReleaseLongArrayElements(jcolumn_options_handles, jco, JNI_ABORT);
|
||||
env->ReleaseStringUTFChars(jdb_path, db_path);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const std::string cf_name(reinterpret_cast<char *>(jcf_name), jcf_name_len);
|
||||
const rocksdb::ColumnFamilyOptions* cf_options =
|
||||
reinterpret_cast<rocksdb::ColumnFamilyOptions*>(jco[i]);
|
||||
column_families.push_back(
|
||||
rocksdb::ColumnFamilyDescriptor(cf_name, *cf_options));
|
||||
|
||||
env->ReleaseByteArrayElements(jcn_ba, jcf_name, JNI_ABORT);
|
||||
env->DeleteLocalRef(jcn);
|
||||
}
|
||||
env->ReleaseLongArrayElements(jcolumn_options_handles, jco, JNI_ABORT);
|
||||
}
|
||||
|
||||
auto* db_options = reinterpret_cast<rocksdb::DBOptions*>(jdb_options_handle);
|
||||
std::vector<rocksdb::ColumnFamilyHandle*> handles;
|
||||
rocksdb::OptimisticTransactionDB* otdb = nullptr;
|
||||
const rocksdb::Status s = rocksdb::OptimisticTransactionDB::Open(*db_options,
|
||||
db_path, column_families, &handles, &otdb);
|
||||
|
||||
env->ReleaseStringUTFChars(jdb_path, db_path);
|
||||
|
||||
// check if open operation was successful
|
||||
if (s.ok()) {
|
||||
const jsize resultsLen = 1 + len_cols; // db handle + column family handles
|
||||
std::unique_ptr<jlong[]> results =
|
||||
std::unique_ptr<jlong[]>(new jlong[resultsLen]);
|
||||
results[0] = reinterpret_cast<jlong>(otdb);
|
||||
for (int i = 1; i <= len_cols; i++) {
|
||||
results[i] = reinterpret_cast<jlong>(handles[i - 1]);
|
||||
}
|
||||
|
||||
jlongArray jresults = env->NewLongArray(resultsLen);
|
||||
if (jresults == nullptr) {
|
||||
// exception thrown: OutOfMemoryError
|
||||
return nullptr;
|
||||
}
|
||||
env->SetLongArrayRegion(jresults, 0, resultsLen, results.get());
|
||||
if (env->ExceptionCheck()) {
|
||||
// exception thrown: ArrayIndexOutOfBoundsException
|
||||
return nullptr;
|
||||
}
|
||||
return jresults;
|
||||
}
|
||||
|
||||
rocksdb::RocksDBExceptionJni::ThrowNew(env, s);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_OptimisticTransactionDB
|
||||
* Method: beginTransaction
|
||||
* Signature: (JJ)J
|
||||
*/
|
||||
jlong Java_org_rocksdb_OptimisticTransactionDB_beginTransaction__JJ(
|
||||
JNIEnv* env, jobject jobj, jlong jhandle, jlong jwrite_options_handle) {
|
||||
auto* optimistic_txn_db =
|
||||
reinterpret_cast<rocksdb::OptimisticTransactionDB*>(jhandle);
|
||||
auto* write_options =
|
||||
reinterpret_cast<rocksdb::WriteOptions*>(jwrite_options_handle);
|
||||
rocksdb::Transaction* txn =
|
||||
optimistic_txn_db->BeginTransaction(*write_options);
|
||||
return reinterpret_cast<jlong>(txn);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_OptimisticTransactionDB
|
||||
* Method: beginTransaction
|
||||
* Signature: (JJJ)J
|
||||
*/
|
||||
jlong Java_org_rocksdb_OptimisticTransactionDB_beginTransaction__JJJ(
|
||||
JNIEnv* env, jobject jobj, jlong jhandle, jlong jwrite_options_handle,
|
||||
jlong joptimistic_txn_options_handle) {
|
||||
auto* optimistic_txn_db =
|
||||
reinterpret_cast<rocksdb::OptimisticTransactionDB*>(jhandle);
|
||||
auto* write_options =
|
||||
reinterpret_cast<rocksdb::WriteOptions*>(jwrite_options_handle);
|
||||
auto* optimistic_txn_options =
|
||||
reinterpret_cast<rocksdb::OptimisticTransactionOptions*>(
|
||||
joptimistic_txn_options_handle);
|
||||
rocksdb::Transaction* txn =
|
||||
optimistic_txn_db->BeginTransaction(*write_options,
|
||||
*optimistic_txn_options);
|
||||
return reinterpret_cast<jlong>(txn);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_OptimisticTransactionDB
|
||||
* Method: beginTransaction_withOld
|
||||
* Signature: (JJJ)J
|
||||
*/
|
||||
jlong Java_org_rocksdb_OptimisticTransactionDB_beginTransaction_1withOld__JJJ(
|
||||
JNIEnv* env, jobject jobj, jlong jhandle, jlong jwrite_options_handle,
|
||||
jlong jold_txn_handle) {
|
||||
auto* optimistic_txn_db =
|
||||
reinterpret_cast<rocksdb::OptimisticTransactionDB*>(jhandle);
|
||||
auto* write_options =
|
||||
reinterpret_cast<rocksdb::WriteOptions*>(jwrite_options_handle);
|
||||
auto* old_txn =
|
||||
reinterpret_cast<rocksdb::Transaction*>(
|
||||
jold_txn_handle);
|
||||
rocksdb::OptimisticTransactionOptions optimistic_txn_options;
|
||||
rocksdb::Transaction* txn =
|
||||
optimistic_txn_db->BeginTransaction(*write_options,
|
||||
optimistic_txn_options, old_txn);
|
||||
|
||||
// RocksJava relies on the assumption that
|
||||
// we do not allocate a new Transaction object
|
||||
// when providing an old_optimistic_txn
|
||||
assert(txn == old_txn);
|
||||
|
||||
return reinterpret_cast<jlong>(txn);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_OptimisticTransactionDB
|
||||
* Method: beginTransaction_withOld
|
||||
* Signature: (JJJJ)J
|
||||
*/
|
||||
jlong Java_org_rocksdb_OptimisticTransactionDB_beginTransaction_1withOld__JJJJ(
|
||||
JNIEnv* env, jobject jobj, jlong jhandle, jlong jwrite_options_handle,
|
||||
jlong joptimistic_txn_options_handle, jlong jold_txn_handle) {
|
||||
auto* optimistic_txn_db =
|
||||
reinterpret_cast<rocksdb::OptimisticTransactionDB*>(jhandle);
|
||||
auto* write_options =
|
||||
reinterpret_cast<rocksdb::WriteOptions*>(jwrite_options_handle);
|
||||
auto* optimistic_txn_options =
|
||||
reinterpret_cast<rocksdb::OptimisticTransactionOptions*>(
|
||||
joptimistic_txn_options_handle);
|
||||
auto* old_txn =
|
||||
reinterpret_cast<rocksdb::Transaction*>(
|
||||
jold_txn_handle);
|
||||
rocksdb::Transaction* txn =
|
||||
optimistic_txn_db->BeginTransaction(*write_options,
|
||||
*optimistic_txn_options, old_txn);
|
||||
|
||||
// RocksJava relies on the assumption that
|
||||
// we do not allocate a new Transaction object
|
||||
// when providing an old_optimisic_txn
|
||||
assert(txn == old_txn);
|
||||
|
||||
return reinterpret_cast<jlong>(txn);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_OptimisticTransactionDB
|
||||
* Method: getBaseDB
|
||||
* Signature: (J)J
|
||||
*/
|
||||
jlong Java_org_rocksdb_OptimisticTransactionDB_getBaseDB(
|
||||
JNIEnv* env, jobject jobj, jlong jhandle) {
|
||||
auto* optimistic_txn_db =
|
||||
reinterpret_cast<rocksdb::OptimisticTransactionDB*>(jhandle);
|
||||
return reinterpret_cast<jlong>(optimistic_txn_db->GetBaseDB());
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_OptimisticTransactionDB
|
||||
* Method: disposeInternal
|
||||
* Signature: (J)V
|
||||
*/
|
||||
void Java_org_rocksdb_OptimisticTransactionDB_disposeInternal(JNIEnv* env,
|
||||
jobject jobj, jlong jhandle) {
|
||||
delete reinterpret_cast<rocksdb::OptimisticTransactionDB*>(jhandle);
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
//
|
||||
// This file implements the "bridge" between Java and C++
|
||||
// for rocksdb::OptimisticTransactionOptions.
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include "include/org_rocksdb_OptimisticTransactionOptions.h"
|
||||
|
||||
#include "rocksdb/comparator.h"
|
||||
#include "rocksdb/utilities/optimistic_transaction_db.h"
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_OptimisticTransactionOptions
|
||||
* Method: newOptimisticTransactionOptions
|
||||
* Signature: ()J
|
||||
*/
|
||||
jlong Java_org_rocksdb_OptimisticTransactionOptions_newOptimisticTransactionOptions(
|
||||
JNIEnv* env, jclass jcls) {
|
||||
rocksdb::OptimisticTransactionOptions* opts =
|
||||
new rocksdb::OptimisticTransactionOptions();
|
||||
return reinterpret_cast<jlong>(opts);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_OptimisticTransactionOptions
|
||||
* Method: isSetSnapshot
|
||||
* Signature: (J)Z
|
||||
*/
|
||||
jboolean Java_org_rocksdb_OptimisticTransactionOptions_isSetSnapshot(
|
||||
JNIEnv* env, jobject jobj, jlong jhandle) {
|
||||
auto* opts =
|
||||
reinterpret_cast<rocksdb::OptimisticTransactionOptions*>(jhandle);
|
||||
return opts->set_snapshot;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_OptimisticTransactionOptions
|
||||
* Method: setSetSnapshot
|
||||
* Signature: (JZ)V
|
||||
*/
|
||||
void Java_org_rocksdb_OptimisticTransactionOptions_setSetSnapshot(JNIEnv* env,
|
||||
jobject jobj, jlong jhandle, jboolean jset_snapshot) {
|
||||
auto* opts =
|
||||
reinterpret_cast<rocksdb::OptimisticTransactionOptions*>(jhandle);
|
||||
opts->set_snapshot = jset_snapshot;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_OptimisticTransactionOptions
|
||||
* Method: setComparator
|
||||
* Signature: (JJ)V
|
||||
*/
|
||||
void Java_org_rocksdb_OptimisticTransactionOptions_setComparator(
|
||||
JNIEnv* env, jobject jobj, jlong jhandle, jlong jcomparator_handle) {
|
||||
auto* opts =
|
||||
reinterpret_cast<rocksdb::OptimisticTransactionOptions*>(jhandle);
|
||||
opts->cmp = reinterpret_cast<rocksdb::Comparator*>(jcomparator_handle);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_OptimisticTransactionOptions
|
||||
* Method: disposeInternal
|
||||
* Signature: (J)V
|
||||
*/
|
||||
void Java_org_rocksdb_OptimisticTransactionOptions_disposeInternal(JNIEnv* env,
|
||||
jobject jobj, jlong jhandle) {
|
||||
delete reinterpret_cast<rocksdb::OptimisticTransactionOptions*>(jhandle);
|
||||
}
|
||||
+48
-20
@@ -158,19 +158,33 @@ void Java_org_rocksdb_Options_setComparatorHandle__JI(
|
||||
/*
|
||||
* Class: org_rocksdb_Options
|
||||
* Method: setComparatorHandle
|
||||
* Signature: (JJZ)V
|
||||
* Signature: (JJB)V
|
||||
*/
|
||||
void Java_org_rocksdb_Options_setComparatorHandle__JJZ(
|
||||
void Java_org_rocksdb_Options_setComparatorHandle__JJB(
|
||||
JNIEnv* env, jobject jobj, jlong jopt_handle, jlong jcomparator_handle,
|
||||
jboolean is_direct) {
|
||||
auto* opt = reinterpret_cast<rocksdb::Options*>(jopt_handle);
|
||||
if(is_direct) {
|
||||
opt->comparator =
|
||||
reinterpret_cast<rocksdb::DirectComparatorJniCallback*>(jcomparator_handle);
|
||||
} else {
|
||||
opt->comparator =
|
||||
reinterpret_cast<rocksdb::ComparatorJniCallback*>(jcomparator_handle);
|
||||
jbyte jcomparator_type) {
|
||||
rocksdb::Comparator *comparator = nullptr;
|
||||
switch(jcomparator_type) {
|
||||
// JAVA_COMPARATOR
|
||||
case 0x0:
|
||||
comparator =
|
||||
reinterpret_cast<rocksdb::ComparatorJniCallback*>(jcomparator_handle);
|
||||
break;
|
||||
|
||||
// JAVA_DIRECT_COMPARATOR
|
||||
case 0x1:
|
||||
comparator =
|
||||
reinterpret_cast<rocksdb::DirectComparatorJniCallback*>(jcomparator_handle);
|
||||
break;
|
||||
|
||||
// JAVA_NATIVE_COMPARATOR_WRAPPER
|
||||
case 0x2:
|
||||
comparator =
|
||||
reinterpret_cast<rocksdb::Comparator*>(jcomparator_handle);
|
||||
break;
|
||||
}
|
||||
auto* opt = reinterpret_cast<rocksdb::Options*>(jopt_handle);
|
||||
opt->comparator = comparator;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2984,19 +2998,33 @@ void Java_org_rocksdb_ColumnFamilyOptions_setComparatorHandle__JI(
|
||||
/*
|
||||
* Class: org_rocksdb_ColumnFamilyOptions
|
||||
* Method: setComparatorHandle
|
||||
* Signature: (JJZ)V
|
||||
* Signature: (JJB)V
|
||||
*/
|
||||
void Java_org_rocksdb_ColumnFamilyOptions_setComparatorHandle__JJZ(
|
||||
void Java_org_rocksdb_ColumnFamilyOptions_setComparatorHandle__JJB(
|
||||
JNIEnv* env, jobject jobj, jlong jopt_handle, jlong jcomparator_handle,
|
||||
jboolean is_direct) {
|
||||
auto* opt = reinterpret_cast<rocksdb::ColumnFamilyOptions*>(jopt_handle);
|
||||
if(is_direct) {
|
||||
opt->comparator =
|
||||
reinterpret_cast<rocksdb::DirectComparatorJniCallback*>(jcomparator_handle);
|
||||
} else {
|
||||
opt->comparator =
|
||||
reinterpret_cast<rocksdb::ComparatorJniCallback*>(jcomparator_handle);
|
||||
jbyte jcomparator_type) {
|
||||
rocksdb::Comparator *comparator = nullptr;
|
||||
switch(jcomparator_type) {
|
||||
// JAVA_COMPARATOR
|
||||
case 0x0:
|
||||
comparator =
|
||||
reinterpret_cast<rocksdb::ComparatorJniCallback*>(jcomparator_handle);
|
||||
break;
|
||||
|
||||
// JAVA_DIRECT_COMPARATOR
|
||||
case 0x1:
|
||||
comparator =
|
||||
reinterpret_cast<rocksdb::DirectComparatorJniCallback*>(jcomparator_handle);
|
||||
break;
|
||||
|
||||
// JAVA_NATIVE_COMPARATOR_WRAPPER
|
||||
case 0x2:
|
||||
comparator =
|
||||
reinterpret_cast<rocksdb::Comparator*>(jcomparator_handle);
|
||||
break;
|
||||
}
|
||||
auto* opt = reinterpret_cast<rocksdb::ColumnFamilyOptions*>(jopt_handle);
|
||||
opt->comparator = comparator;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+1376
-62
File diff suppressed because it is too large
Load Diff
@@ -20,24 +20,34 @@
|
||||
/*
|
||||
* Class: org_rocksdb_SstFileWriter
|
||||
* Method: newSstFileWriter
|
||||
* Signature: (JJJZ)J
|
||||
* Signature: (JJJB)J
|
||||
*/
|
||||
jlong Java_org_rocksdb_SstFileWriter_newSstFileWriter__JJJZ(JNIEnv *env,
|
||||
jclass jcls, jlong jenvoptions, jlong joptions, jlong jcomparator,
|
||||
jboolean is_direct) {
|
||||
jlong Java_org_rocksdb_SstFileWriter_newSstFileWriter__JJJB(JNIEnv *env,
|
||||
jclass jcls, jlong jenvoptions, jlong joptions, jlong jcomparator_handle,
|
||||
jbyte jcomparator_type) {
|
||||
rocksdb::Comparator *comparator = nullptr;
|
||||
switch(jcomparator_type) {
|
||||
// JAVA_COMPARATOR
|
||||
case 0x0:
|
||||
comparator =
|
||||
reinterpret_cast<rocksdb::ComparatorJniCallback*>(jcomparator_handle);
|
||||
break;
|
||||
|
||||
// JAVA_DIRECT_COMPARATOR
|
||||
case 0x1:
|
||||
comparator =
|
||||
reinterpret_cast<rocksdb::DirectComparatorJniCallback*>(jcomparator_handle);
|
||||
break;
|
||||
|
||||
// JAVA_NATIVE_COMPARATOR_WRAPPER
|
||||
case 0x2:
|
||||
comparator =
|
||||
reinterpret_cast<rocksdb::Comparator*>(jcomparator_handle);
|
||||
break;
|
||||
}
|
||||
auto *env_options =
|
||||
reinterpret_cast<const rocksdb::EnvOptions *>(jenvoptions);
|
||||
auto *options = reinterpret_cast<const rocksdb::Options *>(joptions);
|
||||
|
||||
rocksdb::Comparator *comparator = nullptr;
|
||||
if(is_direct) {
|
||||
comparator =
|
||||
reinterpret_cast<rocksdb::DirectComparatorJniCallback*>(jcomparator);
|
||||
} else {
|
||||
comparator =
|
||||
reinterpret_cast<rocksdb::ComparatorJniCallback*>(jcomparator);
|
||||
}
|
||||
|
||||
rocksdb::SstFileWriter *sst_file_writer =
|
||||
new rocksdb::SstFileWriter(*env_options, *options, comparator);
|
||||
return reinterpret_cast<jlong>(sst_file_writer);
|
||||
|
||||
+20
-13
@@ -38,13 +38,14 @@ jlong Java_org_rocksdb_PlainTableConfig_newTableFactoryHandle(
|
||||
/*
|
||||
* Class: org_rocksdb_BlockBasedTableConfig
|
||||
* Method: newTableFactoryHandle
|
||||
* Signature: (ZJIJIIZIZZZJIBBI)J
|
||||
* Signature: (ZJIJJIIZIZZZJIBBI)J
|
||||
*/
|
||||
jlong Java_org_rocksdb_BlockBasedTableConfig_newTableFactoryHandle(
|
||||
JNIEnv* env, jobject jobj, jboolean no_block_cache, jlong block_cache_size,
|
||||
jint block_cache_num_shardbits, jlong block_size, jint block_size_deviation,
|
||||
jint block_restart_interval, jboolean whole_key_filtering,
|
||||
jlong jfilterPolicy, jboolean cache_index_and_filter_blocks,
|
||||
JNIEnv *env, jobject jobj, jboolean no_block_cache, jlong block_cache_size,
|
||||
jint block_cache_num_shardbits, jlong jblock_cache, jlong block_size,
|
||||
jint block_size_deviation, jint block_restart_interval,
|
||||
jboolean whole_key_filtering, jlong jfilter_policy,
|
||||
jboolean cache_index_and_filter_blocks,
|
||||
jboolean pin_l0_filter_and_index_blocks_in_cache,
|
||||
jboolean hash_index_allow_collision, jlong block_cache_compressed_size,
|
||||
jint block_cache_compressd_num_shard_bits, jbyte jchecksum_type,
|
||||
@@ -52,22 +53,28 @@ jlong Java_org_rocksdb_BlockBasedTableConfig_newTableFactoryHandle(
|
||||
rocksdb::BlockBasedTableOptions options;
|
||||
options.no_block_cache = no_block_cache;
|
||||
|
||||
if (!no_block_cache && block_cache_size > 0) {
|
||||
if (block_cache_num_shardbits > 0) {
|
||||
options.block_cache =
|
||||
rocksdb::NewLRUCache(block_cache_size, block_cache_num_shardbits);
|
||||
} else {
|
||||
options.block_cache = rocksdb::NewLRUCache(block_cache_size);
|
||||
if (!no_block_cache) {
|
||||
if (jblock_cache > 0) {
|
||||
std::shared_ptr<rocksdb::Cache> *pCache =
|
||||
reinterpret_cast<std::shared_ptr<rocksdb::Cache> *>(jblock_cache);
|
||||
options.block_cache = *pCache;
|
||||
} else if (block_cache_size > 0) {
|
||||
if (block_cache_num_shardbits > 0) {
|
||||
options.block_cache =
|
||||
rocksdb::NewLRUCache(block_cache_size, block_cache_num_shardbits);
|
||||
} else {
|
||||
options.block_cache = rocksdb::NewLRUCache(block_cache_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
options.block_size = block_size;
|
||||
options.block_size_deviation = block_size_deviation;
|
||||
options.block_restart_interval = block_restart_interval;
|
||||
options.whole_key_filtering = whole_key_filtering;
|
||||
if (jfilterPolicy > 0) {
|
||||
if (jfilter_policy > 0) {
|
||||
std::shared_ptr<rocksdb::FilterPolicy> *pFilterPolicy =
|
||||
reinterpret_cast<std::shared_ptr<rocksdb::FilterPolicy> *>(
|
||||
jfilterPolicy);
|
||||
jfilter_policy);
|
||||
options.filter_policy = *pFilterPolicy;
|
||||
}
|
||||
options.cache_index_and_filter_blocks = cache_index_and_filter_blocks;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,431 @@
|
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
//
|
||||
// This file implements the "bridge" between Java and C++
|
||||
// for rocksdb::TransactionDB.
|
||||
|
||||
#include <jni.h>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
|
||||
#include "include/org_rocksdb_TransactionDB.h"
|
||||
|
||||
#include "rocksdb/options.h"
|
||||
#include "rocksdb/utilities/transaction.h"
|
||||
#include "rocksdb/utilities/transaction_db.h"
|
||||
|
||||
#include "rocksjni/portal.h"
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_TransactionDB
|
||||
* Method: open
|
||||
* Signature: (JJLjava/lang/String;)J
|
||||
*/
|
||||
jlong Java_org_rocksdb_TransactionDB_open__JJLjava_lang_String_2(JNIEnv* env,
|
||||
jclass jcls, jlong joptions_handle, jlong jtxn_db_options_handle,
|
||||
jstring jdb_path) {
|
||||
auto* options = reinterpret_cast<rocksdb::Options*>(joptions_handle);
|
||||
auto* txn_db_options =
|
||||
reinterpret_cast<rocksdb::TransactionDBOptions*>(jtxn_db_options_handle);
|
||||
rocksdb::TransactionDB* tdb = nullptr;
|
||||
const char* db_path = env->GetStringUTFChars(jdb_path, nullptr);
|
||||
if (db_path == nullptr) {
|
||||
// exception thrown: OutOfMemoryError
|
||||
return 0;
|
||||
}
|
||||
rocksdb::Status s =
|
||||
rocksdb::TransactionDB::Open(*options, *txn_db_options, db_path, &tdb);
|
||||
env->ReleaseStringUTFChars(jdb_path, db_path);
|
||||
|
||||
if (s.ok()) {
|
||||
return reinterpret_cast<jlong>(tdb);
|
||||
} else {
|
||||
rocksdb::RocksDBExceptionJni::ThrowNew(env, s);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_TransactionDB
|
||||
* Method: open
|
||||
* Signature: (JJLjava/lang/String;[[B[J)[J
|
||||
*/
|
||||
jlongArray Java_org_rocksdb_TransactionDB_open__JJLjava_lang_String_2_3_3B_3J(
|
||||
JNIEnv* env, jclass jcls, jlong jdb_options_handle,
|
||||
jlong jtxn_db_options_handle, jstring jdb_path,
|
||||
jobjectArray jcolumn_names,
|
||||
jlongArray jcolumn_options_handles) {
|
||||
const char* db_path = env->GetStringUTFChars(jdb_path, nullptr);
|
||||
if (db_path == nullptr) {
|
||||
// exception thrown: OutOfMemoryError
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const jsize len_cols = env->GetArrayLength(jcolumn_names);
|
||||
if (env->EnsureLocalCapacity(len_cols) != 0) {
|
||||
// out of memory
|
||||
env->ReleaseStringUTFChars(jdb_path, db_path);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
jlong* jco = env->GetLongArrayElements(jcolumn_options_handles, nullptr);
|
||||
if (jco == nullptr) {
|
||||
// exception thrown: OutOfMemoryError
|
||||
env->ReleaseStringUTFChars(jdb_path, db_path);
|
||||
return nullptr;
|
||||
}
|
||||
std::vector<rocksdb::ColumnFamilyDescriptor> column_families;
|
||||
for (int i = 0; i < len_cols; i++) {
|
||||
const jobject jcn = env->GetObjectArrayElement(jcolumn_names, i);
|
||||
if (env->ExceptionCheck()) {
|
||||
// exception thrown: ArrayIndexOutOfBoundsException
|
||||
env->ReleaseLongArrayElements(jcolumn_options_handles, jco, JNI_ABORT);
|
||||
env->ReleaseStringUTFChars(jdb_path, db_path);
|
||||
return nullptr;
|
||||
}
|
||||
const jbyteArray jcn_ba = reinterpret_cast<jbyteArray>(jcn);
|
||||
jbyte* jcf_name = env->GetByteArrayElements(jcn_ba, nullptr);
|
||||
if (jcf_name == nullptr) {
|
||||
// exception thrown: OutOfMemoryError
|
||||
env->DeleteLocalRef(jcn);
|
||||
env->ReleaseLongArrayElements(jcolumn_options_handles, jco, JNI_ABORT);
|
||||
env->ReleaseStringUTFChars(jdb_path, db_path);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const int jcf_name_len = env->GetArrayLength(jcn_ba);
|
||||
if (env->EnsureLocalCapacity(jcf_name_len) != 0) {
|
||||
// out of memory
|
||||
env->ReleaseByteArrayElements(jcn_ba, jcf_name, JNI_ABORT);
|
||||
env->DeleteLocalRef(jcn);
|
||||
env->ReleaseLongArrayElements(jcolumn_options_handles, jco, JNI_ABORT);
|
||||
env->ReleaseStringUTFChars(jdb_path, db_path);
|
||||
return nullptr;
|
||||
}
|
||||
const std::string cf_name(reinterpret_cast<char *>(jcf_name), jcf_name_len);
|
||||
const rocksdb::ColumnFamilyOptions* cf_options =
|
||||
reinterpret_cast<rocksdb::ColumnFamilyOptions*>(jco[i]);
|
||||
column_families.push_back(
|
||||
rocksdb::ColumnFamilyDescriptor(cf_name, *cf_options));
|
||||
|
||||
env->ReleaseByteArrayElements(jcn_ba, jcf_name, JNI_ABORT);
|
||||
env->DeleteLocalRef(jcn);
|
||||
}
|
||||
env->ReleaseLongArrayElements(jcolumn_options_handles, jco, JNI_ABORT);
|
||||
|
||||
auto* db_options = reinterpret_cast<rocksdb::DBOptions*>(jdb_options_handle);
|
||||
auto* txn_db_options =
|
||||
reinterpret_cast<rocksdb::TransactionDBOptions*>(jtxn_db_options_handle);
|
||||
std::vector<rocksdb::ColumnFamilyHandle*> handles;
|
||||
rocksdb::TransactionDB* tdb = nullptr;
|
||||
const rocksdb::Status s = rocksdb::TransactionDB::Open(*db_options, *txn_db_options,
|
||||
db_path, column_families, &handles, &tdb);
|
||||
|
||||
// check if open operation was successful
|
||||
if (s.ok()) {
|
||||
const jsize resultsLen = 1 + len_cols; // db handle + column family handles
|
||||
std::unique_ptr<jlong[]> results =
|
||||
std::unique_ptr<jlong[]>(new jlong[resultsLen]);
|
||||
results[0] = reinterpret_cast<jlong>(tdb);
|
||||
for (int i = 1; i <= len_cols; i++) {
|
||||
results[i] = reinterpret_cast<jlong>(handles[i - 1]);
|
||||
}
|
||||
|
||||
jlongArray jresults = env->NewLongArray(resultsLen);
|
||||
if (jresults == nullptr) {
|
||||
// exception thrown: OutOfMemoryError
|
||||
return nullptr;
|
||||
}
|
||||
env->SetLongArrayRegion(jresults, 0, resultsLen, results.get());
|
||||
if (env->ExceptionCheck()) {
|
||||
// exception thrown: ArrayIndexOutOfBoundsException
|
||||
env->DeleteLocalRef(jresults);
|
||||
return nullptr;
|
||||
}
|
||||
return jresults;
|
||||
} else {
|
||||
rocksdb::RocksDBExceptionJni::ThrowNew(env, s);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_TransactionDB
|
||||
* Method: beginTransaction
|
||||
* Signature: (JJ)J
|
||||
*/
|
||||
jlong Java_org_rocksdb_TransactionDB_beginTransaction__JJ(JNIEnv* env,
|
||||
jobject jobj, jlong jhandle, jlong jwrite_options_handle) {
|
||||
auto* txn_db = reinterpret_cast<rocksdb::TransactionDB*>(jhandle);
|
||||
auto* write_options =
|
||||
reinterpret_cast<rocksdb::WriteOptions*>(jwrite_options_handle);
|
||||
rocksdb::Transaction* txn = txn_db->BeginTransaction(*write_options);
|
||||
return reinterpret_cast<jlong>(txn);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_TransactionDB
|
||||
* Method: beginTransaction
|
||||
* Signature: (JJJ)J
|
||||
*/
|
||||
jlong Java_org_rocksdb_TransactionDB_beginTransaction__JJJ(JNIEnv* env,
|
||||
jobject jobj, jlong jhandle, jlong jwrite_options_handle,
|
||||
jlong jtxn_options_handle) {
|
||||
auto* txn_db = reinterpret_cast<rocksdb::TransactionDB*>(jhandle);
|
||||
auto* write_options =
|
||||
reinterpret_cast<rocksdb::WriteOptions*>(jwrite_options_handle);
|
||||
auto* txn_options =
|
||||
reinterpret_cast<rocksdb::TransactionOptions*>(jtxn_options_handle);
|
||||
rocksdb::Transaction* txn =
|
||||
txn_db->BeginTransaction(*write_options, *txn_options);
|
||||
return reinterpret_cast<jlong>(txn);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_TransactionDB
|
||||
* Method: beginTransaction_withOld
|
||||
* Signature: (JJJ)J
|
||||
*/
|
||||
jlong Java_org_rocksdb_TransactionDB_beginTransaction_1withOld__JJJ(
|
||||
JNIEnv* env, jobject jobj, jlong jhandle, jlong jwrite_options_handle,
|
||||
jlong jold_txn_handle) {
|
||||
auto* txn_db = reinterpret_cast<rocksdb::TransactionDB*>(jhandle);
|
||||
auto* write_options =
|
||||
reinterpret_cast<rocksdb::WriteOptions*>(jwrite_options_handle);
|
||||
auto* old_txn = reinterpret_cast<rocksdb::Transaction*>(jold_txn_handle);
|
||||
rocksdb::TransactionOptions txn_options;
|
||||
rocksdb::Transaction* txn =
|
||||
txn_db->BeginTransaction(*write_options, txn_options, old_txn);
|
||||
|
||||
// RocksJava relies on the assumption that
|
||||
// we do not allocate a new Transaction object
|
||||
// when providing an old_txn
|
||||
assert(txn == old_txn);
|
||||
|
||||
return reinterpret_cast<jlong>(txn);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_TransactionDB
|
||||
* Method: beginTransaction_withOld
|
||||
* Signature: (JJJJ)J
|
||||
*/
|
||||
jlong Java_org_rocksdb_TransactionDB_beginTransaction_1withOld__JJJJ(
|
||||
JNIEnv* env, jobject jobj, jlong jhandle, jlong jwrite_options_handle,
|
||||
jlong jtxn_options_handle, jlong jold_txn_handle) {
|
||||
auto* txn_db = reinterpret_cast<rocksdb::TransactionDB*>(jhandle);
|
||||
auto* write_options =
|
||||
reinterpret_cast<rocksdb::WriteOptions*>(jwrite_options_handle);
|
||||
auto* txn_options =
|
||||
reinterpret_cast<rocksdb::TransactionOptions*>(jtxn_options_handle);
|
||||
auto* old_txn = reinterpret_cast<rocksdb::Transaction*>(jold_txn_handle);
|
||||
rocksdb::Transaction* txn = txn_db->BeginTransaction(*write_options,
|
||||
*txn_options, old_txn);
|
||||
|
||||
// RocksJava relies on the assumption that
|
||||
// we do not allocate a new Transaction object
|
||||
// when providing an old_txn
|
||||
assert(txn == old_txn);
|
||||
|
||||
return reinterpret_cast<jlong>(txn);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_TransactionDB
|
||||
* Method: getTransactionByName
|
||||
* Signature: (JLjava/lang/String;)J
|
||||
*/
|
||||
jlong Java_org_rocksdb_TransactionDB_getTransactionByName(JNIEnv* env,
|
||||
jobject jobj, jlong jhandle, jstring jname) {
|
||||
auto* txn_db = reinterpret_cast<rocksdb::TransactionDB*>(jhandle);
|
||||
const char* name = env->GetStringUTFChars(jname, nullptr);
|
||||
if (name == nullptr) {
|
||||
// exception thrown: OutOfMemoryError
|
||||
return 0;
|
||||
}
|
||||
rocksdb::Transaction* txn = txn_db->GetTransactionByName(name);
|
||||
env->ReleaseStringUTFChars(jname, name);
|
||||
return reinterpret_cast<jlong>(txn);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_TransactionDB
|
||||
* Method: getAllPreparedTransactions
|
||||
* Signature: (J)[J
|
||||
*/
|
||||
jlongArray Java_org_rocksdb_TransactionDB_getAllPreparedTransactions(
|
||||
JNIEnv* env, jobject jobj, jlong jhandle) {
|
||||
auto* txn_db = reinterpret_cast<rocksdb::TransactionDB*>(jhandle);
|
||||
std::vector<rocksdb::Transaction*> txns;
|
||||
txn_db->GetAllPreparedTransactions(&txns);
|
||||
|
||||
const size_t size = txns.size();
|
||||
assert(size < UINT32_MAX); // does it fit in a jint?
|
||||
|
||||
const jsize len = static_cast<jsize>(size);
|
||||
jlong tmp[len];
|
||||
for (jsize i = 0; i < len; ++i) {
|
||||
tmp[i] = reinterpret_cast<jlong>(txns[i]);
|
||||
}
|
||||
|
||||
jlongArray jtxns = env->NewLongArray(len);
|
||||
if (jtxns == nullptr) {
|
||||
// exception thrown: OutOfMemoryError
|
||||
return nullptr;
|
||||
}
|
||||
env->SetLongArrayRegion(jtxns, 0, len, tmp);
|
||||
if (env->ExceptionCheck()) {
|
||||
// exception thrown: ArrayIndexOutOfBoundsException
|
||||
env->DeleteLocalRef(jtxns);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return jtxns;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_TransactionDB
|
||||
* Method: getLockStatusData
|
||||
* Signature: (J)Ljava/util/Map;
|
||||
*/
|
||||
jobject Java_org_rocksdb_TransactionDB_getLockStatusData(
|
||||
JNIEnv* env, jobject jobj, jlong jhandle) {
|
||||
auto* txn_db = reinterpret_cast<rocksdb::TransactionDB*>(jhandle);
|
||||
const std::unordered_multimap<uint32_t, rocksdb::KeyLockInfo> lock_status_data =
|
||||
txn_db->GetLockStatusData();
|
||||
const jobject jlock_status_data = rocksdb::HashMapJni::construct(env,
|
||||
static_cast<uint32_t>(lock_status_data.size()));
|
||||
if (jlock_status_data == nullptr) {
|
||||
// exception occurred
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const rocksdb::HashMapJni::FnMapKV<const int32_t, const rocksdb::KeyLockInfo> fn_map_kv =
|
||||
[env, txn_db, &lock_status_data](const std::pair<const int32_t, const rocksdb::KeyLockInfo>& pair) {
|
||||
const jobject jlong_column_family_id =
|
||||
rocksdb::LongJni::valueOf(env, pair.first);
|
||||
if (jlong_column_family_id == nullptr) {
|
||||
// an error occurred
|
||||
return std::unique_ptr<std::pair<jobject, jobject>>(nullptr);
|
||||
}
|
||||
const jobject jkey_lock_info =
|
||||
rocksdb::KeyLockInfoJni::construct(env, pair.second);
|
||||
if (jkey_lock_info == nullptr) {
|
||||
// an error occurred
|
||||
return std::unique_ptr<std::pair<jobject, jobject>>(nullptr);
|
||||
}
|
||||
return std::unique_ptr<std::pair<jobject, jobject>>(new std::pair<jobject, jobject>(jlong_column_family_id,
|
||||
jkey_lock_info));
|
||||
};
|
||||
|
||||
if(!rocksdb::HashMapJni::putAll(env, jlock_status_data,
|
||||
lock_status_data.begin(), lock_status_data.end(), fn_map_kv)) {
|
||||
// exception occcurred
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return jlock_status_data;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_TransactionDB
|
||||
* Method: getDeadlockInfoBuffer
|
||||
* Signature: (J)[Lorg/rocksdb/TransactionDB/DeadlockPath;
|
||||
*/
|
||||
jobjectArray Java_org_rocksdb_TransactionDB_getDeadlockInfoBuffer(
|
||||
JNIEnv* env, jobject jobj, jlong jhandle) {
|
||||
auto* txn_db = reinterpret_cast<rocksdb::TransactionDB*>(jhandle);
|
||||
const std::vector<rocksdb::DeadlockPath> deadlock_info_buffer =
|
||||
txn_db->GetDeadlockInfoBuffer();
|
||||
|
||||
const jsize deadlock_info_buffer_len =
|
||||
static_cast<jsize>(deadlock_info_buffer.size());
|
||||
jobjectArray jdeadlock_info_buffer =
|
||||
env->NewObjectArray(deadlock_info_buffer_len,
|
||||
rocksdb::DeadlockPathJni::getJClass(env), nullptr);
|
||||
if (jdeadlock_info_buffer == nullptr) {
|
||||
// exception thrown: OutOfMemoryError
|
||||
return nullptr;
|
||||
}
|
||||
jsize jdeadlock_info_buffer_offset = 0;
|
||||
|
||||
auto buf_end = deadlock_info_buffer.end();
|
||||
for (auto buf_it = deadlock_info_buffer.begin(); buf_it != buf_end; ++buf_it) {
|
||||
const rocksdb::DeadlockPath deadlock_path = *buf_it;
|
||||
const std::vector<rocksdb::DeadlockInfo> deadlock_infos
|
||||
= deadlock_path.path;
|
||||
const jsize deadlock_infos_len =
|
||||
static_cast<jsize>(deadlock_info_buffer.size());
|
||||
jobjectArray jdeadlock_infos = env->NewObjectArray(deadlock_infos_len,
|
||||
rocksdb::DeadlockInfoJni::getJClass(env), nullptr);
|
||||
if (jdeadlock_infos == nullptr) {
|
||||
// exception thrown: OutOfMemoryError
|
||||
env->DeleteLocalRef(jdeadlock_info_buffer);
|
||||
return nullptr;
|
||||
}
|
||||
jsize jdeadlock_infos_offset = 0;
|
||||
|
||||
auto infos_end = deadlock_infos.end();
|
||||
for (auto infos_it = deadlock_infos.begin(); infos_it != infos_end; ++infos_it) {
|
||||
const rocksdb::DeadlockInfo deadlock_info = *infos_it;
|
||||
const jobject jdeadlock_info = rocksdb::TransactionDBJni::newDeadlockInfo(
|
||||
env, jobj, deadlock_info.m_txn_id, deadlock_info.m_cf_id,
|
||||
deadlock_info.m_waiting_key, deadlock_info.m_exclusive);
|
||||
if (jdeadlock_info == nullptr) {
|
||||
// exception occcurred
|
||||
env->DeleteLocalRef(jdeadlock_info_buffer);
|
||||
return nullptr;
|
||||
}
|
||||
env->SetObjectArrayElement(jdeadlock_infos, jdeadlock_infos_offset++, jdeadlock_info);
|
||||
if (env->ExceptionCheck()) {
|
||||
// exception thrown: ArrayIndexOutOfBoundsException or ArrayStoreException
|
||||
env->DeleteLocalRef(jdeadlock_info);
|
||||
env->DeleteLocalRef(jdeadlock_info_buffer);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
const jobject jdeadlock_path =
|
||||
rocksdb::DeadlockPathJni::construct(env, jdeadlock_infos,
|
||||
deadlock_path.limit_exceeded);
|
||||
if(jdeadlock_path == nullptr) {
|
||||
// exception occcurred
|
||||
env->DeleteLocalRef(jdeadlock_info_buffer);
|
||||
return nullptr;
|
||||
}
|
||||
env->SetObjectArrayElement(jdeadlock_info_buffer, jdeadlock_info_buffer_offset++, jdeadlock_path);
|
||||
if (env->ExceptionCheck()) {
|
||||
// exception thrown: ArrayIndexOutOfBoundsException or ArrayStoreException
|
||||
env->DeleteLocalRef(jdeadlock_path);
|
||||
env->DeleteLocalRef(jdeadlock_info_buffer);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return jdeadlock_info_buffer;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_TransactionDB
|
||||
* Method: setDeadlockInfoBufferSize
|
||||
* Signature: (JI)V
|
||||
*/
|
||||
void Java_org_rocksdb_TransactionDB_setDeadlockInfoBufferSize(
|
||||
JNIEnv* env, jobject jobj, jlong jhandle, jint jdeadlock_info_buffer_size) {
|
||||
auto* txn_db = reinterpret_cast<rocksdb::TransactionDB*>(jhandle);
|
||||
txn_db->SetDeadlockInfoBufferSize(jdeadlock_info_buffer_size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_TransactionDB
|
||||
* Method: disposeInternal
|
||||
* Signature: (J)V
|
||||
*/
|
||||
void Java_org_rocksdb_TransactionDB_disposeInternal(JNIEnv* env, jobject jobj,
|
||||
jlong jhandle) {
|
||||
delete reinterpret_cast<rocksdb::TransactionDB*>(jhandle);
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
//
|
||||
// This file implements the "bridge" between Java and C++
|
||||
// for rocksdb::TransactionDBOptions.
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include "include/org_rocksdb_TransactionDBOptions.h"
|
||||
|
||||
#include "rocksdb/utilities/transaction_db.h"
|
||||
|
||||
#include "rocksjni/portal.h"
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_TransactionDBOptions
|
||||
* Method: newTransactionDBOptions
|
||||
* Signature: ()J
|
||||
*/
|
||||
jlong Java_org_rocksdb_TransactionDBOptions_newTransactionDBOptions(
|
||||
JNIEnv* env, jclass jcls) {
|
||||
rocksdb::TransactionDBOptions* opts = new rocksdb::TransactionDBOptions();
|
||||
return reinterpret_cast<jlong>(opts);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_TransactionDBOptions
|
||||
* Method: getMaxNumLocks
|
||||
* Signature: (J)J
|
||||
*/
|
||||
jlong Java_org_rocksdb_TransactionDBOptions_getMaxNumLocks(JNIEnv* env,
|
||||
jobject jobj, jlong jhandle) {
|
||||
auto* opts = reinterpret_cast<rocksdb::TransactionDBOptions*>(jhandle);
|
||||
return opts->max_num_locks;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_TransactionDBOptions
|
||||
* Method: setMaxNumLocks
|
||||
* Signature: (JJ)V
|
||||
*/
|
||||
void Java_org_rocksdb_TransactionDBOptions_setMaxNumLocks(JNIEnv* env,
|
||||
jobject jobj, jlong jhandle, jlong jmax_num_locks) {
|
||||
auto* opts = reinterpret_cast<rocksdb::TransactionDBOptions*>(jhandle);
|
||||
opts->max_num_locks = jmax_num_locks;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_TransactionDBOptions
|
||||
* Method: getNumStripes
|
||||
* Signature: (J)J
|
||||
*/
|
||||
jlong Java_org_rocksdb_TransactionDBOptions_getNumStripes(JNIEnv* env,
|
||||
jobject jobj, jlong jhandle) {
|
||||
auto* opts = reinterpret_cast<rocksdb::TransactionDBOptions*>(jhandle);
|
||||
return opts->num_stripes;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_TransactionDBOptions
|
||||
* Method: setNumStripes
|
||||
* Signature: (JJ)V
|
||||
*/
|
||||
void Java_org_rocksdb_TransactionDBOptions_setNumStripes(JNIEnv* env,
|
||||
jobject jobj, jlong jhandle, jlong jnum_stripes) {
|
||||
auto* opts = reinterpret_cast<rocksdb::TransactionDBOptions*>(jhandle);
|
||||
opts->num_stripes = jnum_stripes;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_TransactionDBOptions
|
||||
* Method: getTransactionLockTimeout
|
||||
* Signature: (J)J
|
||||
*/
|
||||
jlong Java_org_rocksdb_TransactionDBOptions_getTransactionLockTimeout(
|
||||
JNIEnv* env, jobject jobj, jlong jhandle) {
|
||||
auto* opts = reinterpret_cast<rocksdb::TransactionDBOptions*>(jhandle);
|
||||
return opts->transaction_lock_timeout;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_TransactionDBOptions
|
||||
* Method: setTransactionLockTimeout
|
||||
* Signature: (JJ)V
|
||||
*/
|
||||
void Java_org_rocksdb_TransactionDBOptions_setTransactionLockTimeout(
|
||||
JNIEnv* env, jobject jobj, jlong jhandle, jlong jtransaction_lock_timeout) {
|
||||
auto* opts = reinterpret_cast<rocksdb::TransactionDBOptions*>(jhandle);
|
||||
opts->transaction_lock_timeout = jtransaction_lock_timeout;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_TransactionDBOptions
|
||||
* Method: getDefaultLockTimeout
|
||||
* Signature: (J)J
|
||||
*/
|
||||
jlong Java_org_rocksdb_TransactionDBOptions_getDefaultLockTimeout(
|
||||
JNIEnv* env, jobject jobj, jlong jhandle) {
|
||||
auto* opts = reinterpret_cast<rocksdb::TransactionDBOptions*>(jhandle);
|
||||
return opts->default_lock_timeout;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_TransactionDBOptions
|
||||
* Method: setDefaultLockTimeout
|
||||
* Signature: (JJ)V
|
||||
*/
|
||||
void Java_org_rocksdb_TransactionDBOptions_setDefaultLockTimeout(
|
||||
JNIEnv* env, jobject jobj, jlong jhandle, jlong jdefault_lock_timeout) {
|
||||
auto* opts = reinterpret_cast<rocksdb::TransactionDBOptions*>(jhandle);
|
||||
opts->default_lock_timeout = jdefault_lock_timeout;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_TransactionDBOptions
|
||||
* Method: getWritePolicy
|
||||
* Signature: (J)B
|
||||
*/
|
||||
jbyte Java_org_rocksdb_TransactionDBOptions_getWritePolicy(
|
||||
JNIEnv* env, jobject jobj, jlong jhandle) {
|
||||
auto* opts = reinterpret_cast<rocksdb::TransactionDBOptions*>(jhandle);
|
||||
return rocksdb::TxnDBWritePolicyJni::toJavaTxnDBWritePolicy(opts->write_policy);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_TransactionDBOptions
|
||||
* Method: setWritePolicy
|
||||
* Signature: (JB)V
|
||||
*/
|
||||
void Java_org_rocksdb_TransactionDBOptions_setWritePolicy(
|
||||
JNIEnv* env, jobject jobj, jlong jhandle, jbyte jwrite_policy) {
|
||||
auto* opts = reinterpret_cast<rocksdb::TransactionDBOptions*>(jhandle);
|
||||
opts->write_policy =
|
||||
rocksdb::TxnDBWritePolicyJni::toCppTxnDBWritePolicy(jwrite_policy);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_TransactionDBOptions
|
||||
* Method: disposeInternal
|
||||
* Signature: (J)V
|
||||
*/
|
||||
void Java_org_rocksdb_TransactionDBOptions_disposeInternal(JNIEnv* env,
|
||||
jobject jobj, jlong jhandle) {
|
||||
delete reinterpret_cast<rocksdb::TransactionDBOptions*>(jhandle);
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
//
|
||||
// This file implements the "bridge" between Java and C++
|
||||
// for rocksdb::TransactionNotifier.
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include "include/org_rocksdb_AbstractTransactionNotifier.h"
|
||||
#include "rocksjni/transaction_notifier_jnicallback.h"
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_AbstractTransactionNotifier
|
||||
* Method: createNewTransactionNotifier
|
||||
* Signature: ()J
|
||||
*/
|
||||
jlong Java_org_rocksdb_AbstractTransactionNotifier_createNewTransactionNotifier(
|
||||
JNIEnv* env, jobject jobj) {
|
||||
auto* transaction_notifier =
|
||||
new rocksdb::TransactionNotifierJniCallback(env, jobj);
|
||||
auto* sptr_transaction_notifier =
|
||||
new std::shared_ptr<rocksdb::TransactionNotifierJniCallback>(
|
||||
transaction_notifier);
|
||||
return reinterpret_cast<jlong>(sptr_transaction_notifier);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_AbstractTransactionNotifier
|
||||
* Method: disposeInternal
|
||||
* Signature: (J)V
|
||||
*/
|
||||
void Java_org_rocksdb_AbstractTransactionNotifier_disposeInternal(JNIEnv* env,
|
||||
jobject jobj, jlong jhandle) {
|
||||
// TODO(AR) refactor to use JniCallback::JniCallback
|
||||
// when https://github.com/facebook/rocksdb/pull/1241/ is merged
|
||||
std::shared_ptr<rocksdb::TransactionNotifierJniCallback>* handle =
|
||||
reinterpret_cast<std::shared_ptr<
|
||||
rocksdb::TransactionNotifierJniCallback>*>(jhandle);
|
||||
delete handle;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
//
|
||||
// This file implements the callback "bridge" between Java and C++ for
|
||||
// rocksdb::TransactionNotifier.
|
||||
|
||||
#include "rocksjni/transaction_notifier_jnicallback.h"
|
||||
#include "rocksjni/portal.h"
|
||||
|
||||
namespace rocksdb {
|
||||
|
||||
TransactionNotifierJniCallback::TransactionNotifierJniCallback(JNIEnv* env,
|
||||
jobject jtransaction_notifier) : JniCallback(env, jtransaction_notifier) {
|
||||
// we cache the method id for the JNI callback
|
||||
m_jsnapshot_created_methodID =
|
||||
AbstractTransactionNotifierJni::getSnapshotCreatedMethodId(env);
|
||||
}
|
||||
|
||||
void TransactionNotifierJniCallback::SnapshotCreated(
|
||||
const Snapshot* newSnapshot) {
|
||||
jboolean attached_thread = JNI_FALSE;
|
||||
JNIEnv* env = getJniEnv(&attached_thread);
|
||||
assert(env != nullptr);
|
||||
|
||||
env->CallVoidMethod(m_jcallback_obj,
|
||||
m_jsnapshot_created_methodID, reinterpret_cast<jlong>(newSnapshot));
|
||||
|
||||
if(env->ExceptionCheck()) {
|
||||
// exception thrown from CallVoidMethod
|
||||
env->ExceptionDescribe(); // print out exception to stderr
|
||||
releaseJniEnv(attached_thread);
|
||||
return;
|
||||
}
|
||||
|
||||
releaseJniEnv(attached_thread);
|
||||
}
|
||||
} // namespace rocksdb
|
||||
@@ -0,0 +1,42 @@
|
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
//
|
||||
// This file implements the callback "bridge" between Java and C++ for
|
||||
// rocksdb::TransactionNotifier.
|
||||
|
||||
#ifndef JAVA_ROCKSJNI_TRANSACTION_NOTIFIER_JNICALLBACK_H_
|
||||
#define JAVA_ROCKSJNI_TRANSACTION_NOTIFIER_JNICALLBACK_H_
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include "rocksdb/utilities/transaction.h"
|
||||
#include "rocksjni/jnicallback.h"
|
||||
|
||||
namespace rocksdb {
|
||||
|
||||
/**
|
||||
* This class acts as a bridge between C++
|
||||
* and Java. The methods in this class will be
|
||||
* called back from the RocksDB TransactionDB or OptimisticTransactionDB (C++),
|
||||
* we then callback to the appropriate Java method
|
||||
* this enables TransactionNotifier to be implemented in Java.
|
||||
*
|
||||
* Unlike RocksJava's Comparator JNI Callback, we do not attempt
|
||||
* to reduce Java object allocations by caching the Snapshot object
|
||||
* presented to the callback. This could be revisited in future
|
||||
* if performance is lacking.
|
||||
*/
|
||||
class TransactionNotifierJniCallback: public JniCallback,
|
||||
public TransactionNotifier {
|
||||
public:
|
||||
TransactionNotifierJniCallback(JNIEnv* env, jobject jtransaction_notifier);
|
||||
virtual void SnapshotCreated(const Snapshot* newSnapshot);
|
||||
|
||||
private:
|
||||
jmethodID m_jsnapshot_created_methodID;
|
||||
};
|
||||
} // namespace rocksdb
|
||||
|
||||
#endif // JAVA_ROCKSJNI_TRANSACTION_NOTIFIER_JNICALLBACK_H_
|
||||
@@ -0,0 +1,166 @@
|
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
//
|
||||
// This file implements the "bridge" between Java and C++
|
||||
// for rocksdb::TransactionOptions.
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include "include/org_rocksdb_TransactionOptions.h"
|
||||
|
||||
#include "rocksdb/utilities/transaction_db.h"
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_TransactionOptions
|
||||
* Method: newTransactionOptions
|
||||
* Signature: ()J
|
||||
*/
|
||||
jlong Java_org_rocksdb_TransactionOptions_newTransactionOptions(JNIEnv* env,
|
||||
jclass jcls) {
|
||||
auto* opts = new rocksdb::TransactionOptions();
|
||||
return reinterpret_cast<jlong>(opts);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_TransactionOptions
|
||||
* Method: isSetSnapshot
|
||||
* Signature: (J)Z
|
||||
*/
|
||||
jboolean Java_org_rocksdb_TransactionOptions_isSetSnapshot(JNIEnv* env,
|
||||
jobject jobj, jlong jhandle) {
|
||||
auto* opts = reinterpret_cast<rocksdb::TransactionOptions*>(jhandle);
|
||||
return opts->set_snapshot;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_TransactionOptions
|
||||
* Method: setSetSnapshot
|
||||
* Signature: (JZ)V
|
||||
*/
|
||||
void Java_org_rocksdb_TransactionOptions_setSetSnapshot(JNIEnv* env,
|
||||
jobject jobj, jlong jhandle, jboolean jset_snapshot) {
|
||||
auto* opts = reinterpret_cast<rocksdb::TransactionOptions*>(jhandle);
|
||||
opts->set_snapshot = jset_snapshot;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_TransactionOptions
|
||||
* Method: isDeadlockDetect
|
||||
* Signature: (J)Z
|
||||
*/
|
||||
jboolean Java_org_rocksdb_TransactionOptions_isDeadlockDetect(
|
||||
JNIEnv* env, jobject jobj, jlong jhandle) {
|
||||
auto* opts = reinterpret_cast<rocksdb::TransactionOptions*>(jhandle);
|
||||
return opts->deadlock_detect;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_TransactionOptions
|
||||
* Method: setDeadlockDetect
|
||||
* Signature: (JZ)V
|
||||
*/
|
||||
void Java_org_rocksdb_TransactionOptions_setDeadlockDetect(
|
||||
JNIEnv* env, jobject jobj, jlong jhandle, jboolean jdeadlock_detect) {
|
||||
auto* opts = reinterpret_cast<rocksdb::TransactionOptions*>(jhandle);
|
||||
opts->deadlock_detect = jdeadlock_detect;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_TransactionOptions
|
||||
* Method: getLockTimeout
|
||||
* Signature: (J)J
|
||||
*/
|
||||
jlong Java_org_rocksdb_TransactionOptions_getLockTimeout(JNIEnv* env,
|
||||
jobject jobj, jlong jhandle) {
|
||||
auto* opts = reinterpret_cast<rocksdb::TransactionOptions*>(jhandle);
|
||||
return opts->lock_timeout;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_TransactionOptions
|
||||
* Method: setLockTimeout
|
||||
* Signature: (JJ)V
|
||||
*/
|
||||
void Java_org_rocksdb_TransactionOptions_setLockTimeout(JNIEnv* env,
|
||||
jobject jobj, jlong jhandle, jlong jlock_timeout) {
|
||||
auto* opts = reinterpret_cast<rocksdb::TransactionOptions*>(jhandle);
|
||||
opts->lock_timeout = jlock_timeout;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_TransactionOptions
|
||||
* Method: getExpiration
|
||||
* Signature: (J)J
|
||||
*/
|
||||
jlong Java_org_rocksdb_TransactionOptions_getExpiration(JNIEnv* env,
|
||||
jobject jobj, jlong jhandle) {
|
||||
auto* opts = reinterpret_cast<rocksdb::TransactionOptions*>(jhandle);
|
||||
return opts->expiration;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_TransactionOptions
|
||||
* Method: setExpiration
|
||||
* Signature: (JJ)V
|
||||
*/
|
||||
void Java_org_rocksdb_TransactionOptions_setExpiration(JNIEnv* env,
|
||||
jobject jobj, jlong jhandle, jlong jexpiration) {
|
||||
auto* opts = reinterpret_cast<rocksdb::TransactionOptions*>(jhandle);
|
||||
opts->expiration = jexpiration;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_TransactionOptions
|
||||
* Method: getDeadlockDetectDepth
|
||||
* Signature: (J)J
|
||||
*/
|
||||
jlong Java_org_rocksdb_TransactionOptions_getDeadlockDetectDepth(
|
||||
JNIEnv* env, jobject jobj, jlong jhandle) {
|
||||
auto* opts = reinterpret_cast<rocksdb::TransactionOptions*>(jhandle);
|
||||
return opts->deadlock_detect_depth;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_TransactionOptions
|
||||
* Method: setDeadlockDetectDepth
|
||||
* Signature: (JJ)V
|
||||
*/
|
||||
void Java_org_rocksdb_TransactionOptions_setDeadlockDetectDepth(
|
||||
JNIEnv* env, jobject jobj, jlong jhandle, jlong jdeadlock_detect_depth) {
|
||||
auto* opts = reinterpret_cast<rocksdb::TransactionOptions*>(jhandle);
|
||||
opts->deadlock_detect_depth = jdeadlock_detect_depth;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_TransactionOptions
|
||||
* Method: getMaxWriteBatchSize
|
||||
* Signature: (J)J
|
||||
*/
|
||||
jlong Java_org_rocksdb_TransactionOptions_getMaxWriteBatchSize(
|
||||
JNIEnv* env, jobject jobj, jlong jhandle) {
|
||||
auto* opts = reinterpret_cast<rocksdb::TransactionOptions*>(jhandle);
|
||||
return opts->max_write_batch_size;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_TransactionOptions
|
||||
* Method: setMaxWriteBatchSize
|
||||
* Signature: (JJ)V
|
||||
*/
|
||||
void Java_org_rocksdb_TransactionOptions_setMaxWriteBatchSize(
|
||||
JNIEnv* env, jobject jobj, jlong jhandle, jlong jmax_write_batch_size) {
|
||||
auto* opts = reinterpret_cast<rocksdb::TransactionOptions*>(jhandle);
|
||||
opts->max_write_batch_size = jmax_write_batch_size;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_TransactionOptions
|
||||
* Method: disposeInternal
|
||||
* Signature: (J)V
|
||||
*/
|
||||
void Java_org_rocksdb_TransactionOptions_disposeInternal(JNIEnv* env,
|
||||
jobject jobj, jlong jhandle) {
|
||||
delete reinterpret_cast<rocksdb::TransactionOptions*>(jhandle);
|
||||
}
|
||||
+330
-34
@@ -27,12 +27,34 @@
|
||||
* Method: newWriteBatch
|
||||
* Signature: (I)J
|
||||
*/
|
||||
jlong Java_org_rocksdb_WriteBatch_newWriteBatch(
|
||||
jlong Java_org_rocksdb_WriteBatch_newWriteBatch__I(
|
||||
JNIEnv* env, jclass jcls, jint jreserved_bytes) {
|
||||
auto* wb = new rocksdb::WriteBatch(static_cast<size_t>(jreserved_bytes));
|
||||
return reinterpret_cast<jlong>(wb);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_WriteBatch
|
||||
* Method: newWriteBatch
|
||||
* Signature: ([BI)J
|
||||
*/
|
||||
jlong Java_org_rocksdb_WriteBatch_newWriteBatch___3BI(
|
||||
JNIEnv* env, jclass jcls, jbyteArray jserialized,
|
||||
jint jserialized_length) {
|
||||
jboolean has_exception = JNI_FALSE;
|
||||
std::string serialized = rocksdb::JniUtil::byteString<std::string>(env,
|
||||
jserialized, jserialized_length,
|
||||
[](const char* str, const size_t len) { return std::string(str, len); },
|
||||
&has_exception);
|
||||
if(has_exception == JNI_TRUE) {
|
||||
// exception occurred
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto* wb = new rocksdb::WriteBatch(serialized);
|
||||
return reinterpret_cast<jlong>(wb);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_WriteBatch
|
||||
* Method: count0
|
||||
@@ -90,6 +112,37 @@ void Java_org_rocksdb_WriteBatch_rollbackToSavePoint0(
|
||||
rocksdb::RocksDBExceptionJni::ThrowNew(env, s);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_WriteBatch
|
||||
* Method: popSavePoint
|
||||
* Signature: (J)V
|
||||
*/
|
||||
void Java_org_rocksdb_WriteBatch_popSavePoint(
|
||||
JNIEnv* env, jobject jobj, jlong jwb_handle) {
|
||||
auto* wb = reinterpret_cast<rocksdb::WriteBatch*>(jwb_handle);
|
||||
assert(wb != nullptr);
|
||||
|
||||
auto s = wb->PopSavePoint();
|
||||
|
||||
if (s.ok()) {
|
||||
return;
|
||||
}
|
||||
rocksdb::RocksDBExceptionJni::ThrowNew(env, s);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_WriteBatch
|
||||
* Method: setMaxBytes
|
||||
* Signature: (JJ)V
|
||||
*/
|
||||
void Java_org_rocksdb_WriteBatch_setMaxBytes(
|
||||
JNIEnv* env, jobject jobj, jlong jwb_handle, jlong jmax_bytes) {
|
||||
auto* wb = reinterpret_cast<rocksdb::WriteBatch*>(jwb_handle);
|
||||
assert(wb != nullptr);
|
||||
|
||||
wb->SetMaxBytes(static_cast<size_t>(jmax_bytes));
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_WriteBatch
|
||||
* Method: put
|
||||
@@ -102,10 +155,13 @@ void Java_org_rocksdb_WriteBatch_put__J_3BI_3BI(
|
||||
auto* wb = reinterpret_cast<rocksdb::WriteBatch*>(jwb_handle);
|
||||
assert(wb != nullptr);
|
||||
auto put = [&wb] (rocksdb::Slice key, rocksdb::Slice value) {
|
||||
wb->Put(key, value);
|
||||
return wb->Put(key, value);
|
||||
};
|
||||
rocksdb::JniUtil::kv_op(put, env, jobj, jkey, jkey_len, jentry_value,
|
||||
jentry_value_len);
|
||||
std::unique_ptr<rocksdb::Status> status = rocksdb::JniUtil::kv_op(put, env,
|
||||
jobj, jkey, jkey_len, jentry_value, jentry_value_len);
|
||||
if (status != nullptr && !status->ok()) {
|
||||
rocksdb::RocksDBExceptionJni::ThrowNew(env, status);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -122,10 +178,13 @@ void Java_org_rocksdb_WriteBatch_put__J_3BI_3BIJ(
|
||||
auto* cf_handle = reinterpret_cast<rocksdb::ColumnFamilyHandle*>(jcf_handle);
|
||||
assert(cf_handle != nullptr);
|
||||
auto put = [&wb, &cf_handle] (rocksdb::Slice key, rocksdb::Slice value) {
|
||||
wb->Put(cf_handle, key, value);
|
||||
return wb->Put(cf_handle, key, value);
|
||||
};
|
||||
rocksdb::JniUtil::kv_op(put, env, jobj, jkey, jkey_len, jentry_value,
|
||||
jentry_value_len);
|
||||
std::unique_ptr<rocksdb::Status> status = rocksdb::JniUtil::kv_op(put, env,
|
||||
jobj, jkey, jkey_len, jentry_value, jentry_value_len);
|
||||
if (status != nullptr && !status->ok()) {
|
||||
rocksdb::RocksDBExceptionJni::ThrowNew(env, status);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -140,10 +199,13 @@ void Java_org_rocksdb_WriteBatch_merge__J_3BI_3BI(
|
||||
auto* wb = reinterpret_cast<rocksdb::WriteBatch*>(jwb_handle);
|
||||
assert(wb != nullptr);
|
||||
auto merge = [&wb] (rocksdb::Slice key, rocksdb::Slice value) {
|
||||
wb->Merge(key, value);
|
||||
return wb->Merge(key, value);
|
||||
};
|
||||
rocksdb::JniUtil::kv_op(merge, env, jobj, jkey, jkey_len, jentry_value,
|
||||
jentry_value_len);
|
||||
std::unique_ptr<rocksdb::Status> status = rocksdb::JniUtil::kv_op(merge, env,
|
||||
jobj, jkey, jkey_len, jentry_value, jentry_value_len);
|
||||
if (status != nullptr && !status->ok()) {
|
||||
rocksdb::RocksDBExceptionJni::ThrowNew(env, status);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -160,34 +222,41 @@ void Java_org_rocksdb_WriteBatch_merge__J_3BI_3BIJ(
|
||||
auto* cf_handle = reinterpret_cast<rocksdb::ColumnFamilyHandle*>(jcf_handle);
|
||||
assert(cf_handle != nullptr);
|
||||
auto merge = [&wb, &cf_handle] (rocksdb::Slice key, rocksdb::Slice value) {
|
||||
wb->Merge(cf_handle, key, value);
|
||||
return wb->Merge(cf_handle, key, value);
|
||||
};
|
||||
rocksdb::JniUtil::kv_op(merge, env, jobj, jkey, jkey_len, jentry_value,
|
||||
jentry_value_len);
|
||||
std::unique_ptr<rocksdb::Status> status = rocksdb::JniUtil::kv_op(merge, env,
|
||||
jobj, jkey, jkey_len, jentry_value, jentry_value_len);
|
||||
if (status != nullptr && !status->ok()) {
|
||||
rocksdb::RocksDBExceptionJni::ThrowNew(env, status);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_WriteBatch
|
||||
* Method: remove
|
||||
* Method: delete
|
||||
* Signature: (J[BI)V
|
||||
*/
|
||||
void Java_org_rocksdb_WriteBatch_remove__J_3BI(
|
||||
void Java_org_rocksdb_WriteBatch_delete__J_3BI(
|
||||
JNIEnv* env, jobject jobj, jlong jwb_handle,
|
||||
jbyteArray jkey, jint jkey_len) {
|
||||
auto* wb = reinterpret_cast<rocksdb::WriteBatch*>(jwb_handle);
|
||||
assert(wb != nullptr);
|
||||
auto remove = [&wb] (rocksdb::Slice key) {
|
||||
wb->Delete(key);
|
||||
return wb->Delete(key);
|
||||
};
|
||||
rocksdb::JniUtil::k_op(remove, env, jobj, jkey, jkey_len);
|
||||
std::unique_ptr<rocksdb::Status> status = rocksdb::JniUtil::k_op(remove, env,
|
||||
jobj, jkey, jkey_len);
|
||||
if (status != nullptr && !status->ok()) {
|
||||
rocksdb::RocksDBExceptionJni::ThrowNew(env, status);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_WriteBatch
|
||||
* Method: remove
|
||||
* Method: delete
|
||||
* Signature: (J[BIJ)V
|
||||
*/
|
||||
void Java_org_rocksdb_WriteBatch_remove__J_3BIJ(
|
||||
void Java_org_rocksdb_WriteBatch_delete__J_3BIJ(
|
||||
JNIEnv* env, jobject jobj, jlong jwb_handle,
|
||||
jbyteArray jkey, jint jkey_len, jlong jcf_handle) {
|
||||
auto* wb = reinterpret_cast<rocksdb::WriteBatch*>(jwb_handle);
|
||||
@@ -195,9 +264,55 @@ void Java_org_rocksdb_WriteBatch_remove__J_3BIJ(
|
||||
auto* cf_handle = reinterpret_cast<rocksdb::ColumnFamilyHandle*>(jcf_handle);
|
||||
assert(cf_handle != nullptr);
|
||||
auto remove = [&wb, &cf_handle] (rocksdb::Slice key) {
|
||||
wb->Delete(cf_handle, key);
|
||||
return wb->Delete(cf_handle, key);
|
||||
};
|
||||
rocksdb::JniUtil::k_op(remove, env, jobj, jkey, jkey_len);
|
||||
std::unique_ptr<rocksdb::Status> status = rocksdb::JniUtil::k_op(remove, env,
|
||||
jobj, jkey, jkey_len);
|
||||
if (status != nullptr && !status->ok()) {
|
||||
rocksdb::RocksDBExceptionJni::ThrowNew(env, status);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_WriteBatch
|
||||
* Method: singleDelete
|
||||
* Signature: (J[BI)V
|
||||
*/
|
||||
void Java_org_rocksdb_WriteBatch_singleDelete__J_3BI(
|
||||
JNIEnv* env, jobject jobj, jlong jwb_handle, jbyteArray jkey,
|
||||
jint jkey_len) {
|
||||
auto* wb = reinterpret_cast<rocksdb::WriteBatch*>(jwb_handle);
|
||||
assert(wb != nullptr);
|
||||
auto single_delete = [&wb] (rocksdb::Slice key) {
|
||||
return wb->SingleDelete(key);
|
||||
};
|
||||
std::unique_ptr<rocksdb::Status> status = rocksdb::JniUtil::k_op(single_delete,
|
||||
env, jobj, jkey, jkey_len);
|
||||
if (status != nullptr && !status->ok()) {
|
||||
rocksdb::RocksDBExceptionJni::ThrowNew(env, status);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_WriteBatch
|
||||
* Method: singleDelete
|
||||
* Signature: (J[BIJ)V
|
||||
*/
|
||||
void Java_org_rocksdb_WriteBatch_singleDelete__J_3BIJ(
|
||||
JNIEnv* env, jobject jobj, jlong jwb_handle, jbyteArray jkey,
|
||||
jint jkey_len, jlong jcf_handle) {
|
||||
auto* wb = reinterpret_cast<rocksdb::WriteBatch*>(jwb_handle);
|
||||
assert(wb != nullptr);
|
||||
auto* cf_handle = reinterpret_cast<rocksdb::ColumnFamilyHandle*>(jcf_handle);
|
||||
assert(cf_handle != nullptr);
|
||||
auto single_delete = [&wb, &cf_handle] (rocksdb::Slice key) {
|
||||
return wb->SingleDelete(cf_handle, key);
|
||||
};
|
||||
std::unique_ptr<rocksdb::Status> status = rocksdb::JniUtil::k_op(single_delete,
|
||||
env, jobj, jkey, jkey_len);
|
||||
if (status != nullptr && !status->ok()) {
|
||||
rocksdb::RocksDBExceptionJni::ThrowNew(env, status);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -205,19 +320,20 @@ void Java_org_rocksdb_WriteBatch_remove__J_3BIJ(
|
||||
* Method: deleteRange
|
||||
* Signature: (J[BI[BI)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_org_rocksdb_WriteBatch_deleteRange__J_3BI_3BI(
|
||||
JNIEnv*, jobject, jlong, jbyteArray, jint, jbyteArray, jint);
|
||||
|
||||
void Java_org_rocksdb_WriteBatch_deleteRange__J_3BI_3BI(
|
||||
JNIEnv* env, jobject jobj, jlong jwb_handle, jbyteArray jbegin_key,
|
||||
jint jbegin_key_len, jbyteArray jend_key, jint jend_key_len) {
|
||||
auto* wb = reinterpret_cast<rocksdb::WriteBatch*>(jwb_handle);
|
||||
assert(wb != nullptr);
|
||||
auto deleteRange = [&wb](rocksdb::Slice beginKey, rocksdb::Slice endKey) {
|
||||
wb->DeleteRange(beginKey, endKey);
|
||||
return wb->DeleteRange(beginKey, endKey);
|
||||
};
|
||||
rocksdb::JniUtil::kv_op(deleteRange, env, jobj, jbegin_key, jbegin_key_len,
|
||||
jend_key, jend_key_len);
|
||||
std::unique_ptr<rocksdb::Status> status = rocksdb::JniUtil::kv_op(
|
||||
deleteRange, env, jobj, jbegin_key, jbegin_key_len, jend_key,
|
||||
jend_key_len);
|
||||
if (status != nullptr && !status->ok()) {
|
||||
rocksdb::RocksDBExceptionJni::ThrowNew(env, status);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -234,11 +350,15 @@ void Java_org_rocksdb_WriteBatch_deleteRange__J_3BI_3BIJ(
|
||||
auto* cf_handle = reinterpret_cast<rocksdb::ColumnFamilyHandle*>(jcf_handle);
|
||||
assert(cf_handle != nullptr);
|
||||
auto deleteRange = [&wb, &cf_handle](rocksdb::Slice beginKey,
|
||||
rocksdb::Slice endKey) {
|
||||
wb->DeleteRange(cf_handle, beginKey, endKey);
|
||||
rocksdb::Slice endKey) {
|
||||
return wb->DeleteRange(cf_handle, beginKey, endKey);
|
||||
};
|
||||
rocksdb::JniUtil::kv_op(deleteRange, env, jobj, jbegin_key, jbegin_key_len,
|
||||
jend_key, jend_key_len);
|
||||
std::unique_ptr<rocksdb::Status> status = rocksdb::JniUtil::kv_op(
|
||||
deleteRange, env, jobj, jbegin_key, jbegin_key_len, jend_key,
|
||||
jend_key_len);
|
||||
if (status != nullptr && !status->ok()) {
|
||||
rocksdb::RocksDBExceptionJni::ThrowNew(env, status);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -252,9 +372,13 @@ void Java_org_rocksdb_WriteBatch_putLogData(
|
||||
auto* wb = reinterpret_cast<rocksdb::WriteBatch*>(jwb_handle);
|
||||
assert(wb != nullptr);
|
||||
auto putLogData = [&wb] (rocksdb::Slice blob) {
|
||||
wb->PutLogData(blob);
|
||||
return wb->PutLogData(blob);
|
||||
};
|
||||
rocksdb::JniUtil::k_op(putLogData, env, jobj, jblob, jblob_len);
|
||||
std::unique_ptr<rocksdb::Status> status = rocksdb::JniUtil::k_op(putLogData,
|
||||
env, jobj, jblob, jblob_len);
|
||||
if (status != nullptr && !status->ok()) {
|
||||
rocksdb::RocksDBExceptionJni::ThrowNew(env, status);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -263,7 +387,7 @@ void Java_org_rocksdb_WriteBatch_putLogData(
|
||||
* Signature: (JJ)V
|
||||
*/
|
||||
void Java_org_rocksdb_WriteBatch_iterate(
|
||||
JNIEnv* env , jobject jobj, jlong jwb_handle, jlong handlerHandle) {
|
||||
JNIEnv* env, jobject jobj, jlong jwb_handle, jlong handlerHandle) {
|
||||
auto* wb = reinterpret_cast<rocksdb::WriteBatch*>(jwb_handle);
|
||||
assert(wb != nullptr);
|
||||
|
||||
@@ -276,6 +400,178 @@ void Java_org_rocksdb_WriteBatch_iterate(
|
||||
rocksdb::RocksDBExceptionJni::ThrowNew(env, s);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_WriteBatch
|
||||
* Method: data
|
||||
* Signature: (J)[B
|
||||
*/
|
||||
jbyteArray Java_org_rocksdb_WriteBatch_data(
|
||||
JNIEnv* env, jobject jobj, jlong jwb_handle) {
|
||||
auto* wb = reinterpret_cast<rocksdb::WriteBatch*>(jwb_handle);
|
||||
assert(wb != nullptr);
|
||||
|
||||
auto data = wb->Data();
|
||||
return rocksdb::JniUtil::copyBytes(env, data);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_WriteBatch
|
||||
* Method: getDataSize
|
||||
* Signature: (J)J
|
||||
*/
|
||||
jlong Java_org_rocksdb_WriteBatch_getDataSize(
|
||||
JNIEnv* env, jobject jobj, jlong jwb_handle) {
|
||||
auto* wb = reinterpret_cast<rocksdb::WriteBatch*>(jwb_handle);
|
||||
assert(wb != nullptr);
|
||||
|
||||
auto data_size = wb->GetDataSize();
|
||||
return static_cast<jlong>(data_size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_WriteBatch
|
||||
* Method: hasPut
|
||||
* Signature: (J)Z
|
||||
*/
|
||||
jboolean Java_org_rocksdb_WriteBatch_hasPut(
|
||||
JNIEnv* env, jobject jobj, jlong jwb_handle) {
|
||||
auto* wb = reinterpret_cast<rocksdb::WriteBatch*>(jwb_handle);
|
||||
assert(wb != nullptr);
|
||||
|
||||
return wb->HasPut();
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_WriteBatch
|
||||
* Method: hasDelete
|
||||
* Signature: (J)Z
|
||||
*/
|
||||
jboolean Java_org_rocksdb_WriteBatch_hasDelete(
|
||||
JNIEnv* env, jobject jobj, jlong jwb_handle) {
|
||||
auto* wb = reinterpret_cast<rocksdb::WriteBatch*>(jwb_handle);
|
||||
assert(wb != nullptr);
|
||||
|
||||
return wb->HasDelete();
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_WriteBatch
|
||||
* Method: hasSingleDelete
|
||||
* Signature: (J)Z
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL Java_org_rocksdb_WriteBatch_hasSingleDelete(
|
||||
JNIEnv* env , jobject jobj, jlong jwb_handle) {
|
||||
auto* wb = reinterpret_cast<rocksdb::WriteBatch*>(jwb_handle);
|
||||
assert(wb != nullptr);
|
||||
|
||||
return wb->HasSingleDelete();
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_WriteBatch
|
||||
* Method: hasDeleteRange
|
||||
* Signature: (J)Z
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL Java_org_rocksdb_WriteBatch_hasDeleteRange(
|
||||
JNIEnv* env , jobject jobj, jlong jwb_handle) {
|
||||
auto* wb = reinterpret_cast<rocksdb::WriteBatch*>(jwb_handle);
|
||||
assert(wb != nullptr);
|
||||
|
||||
return wb->HasDeleteRange();
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_WriteBatch
|
||||
* Method: hasMerge
|
||||
* Signature: (J)Z
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL Java_org_rocksdb_WriteBatch_hasMerge(
|
||||
JNIEnv* env , jobject jobj, jlong jwb_handle) {
|
||||
auto* wb = reinterpret_cast<rocksdb::WriteBatch*>(jwb_handle);
|
||||
assert(wb != nullptr);
|
||||
|
||||
return wb->HasMerge();
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_WriteBatch
|
||||
* Method: hasBeginPrepare
|
||||
* Signature: (J)Z
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL Java_org_rocksdb_WriteBatch_hasBeginPrepare(
|
||||
JNIEnv* env , jobject jobj, jlong jwb_handle) {
|
||||
auto* wb = reinterpret_cast<rocksdb::WriteBatch*>(jwb_handle);
|
||||
assert(wb != nullptr);
|
||||
|
||||
return wb->HasBeginPrepare();
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_WriteBatch
|
||||
* Method: hasEndPrepare
|
||||
* Signature: (J)Z
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL Java_org_rocksdb_WriteBatch_hasEndPrepare(
|
||||
JNIEnv* env , jobject jobj, jlong jwb_handle) {
|
||||
auto* wb = reinterpret_cast<rocksdb::WriteBatch*>(jwb_handle);
|
||||
assert(wb != nullptr);
|
||||
|
||||
return wb->HasEndPrepare();
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_WriteBatch
|
||||
* Method: hasCommit
|
||||
* Signature: (J)Z
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL Java_org_rocksdb_WriteBatch_hasCommit(
|
||||
JNIEnv* env , jobject jobj, jlong jwb_handle) {
|
||||
auto* wb = reinterpret_cast<rocksdb::WriteBatch*>(jwb_handle);
|
||||
assert(wb != nullptr);
|
||||
|
||||
return wb->HasCommit();
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_WriteBatch
|
||||
* Method: hasRollback
|
||||
* Signature: (J)Z
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL Java_org_rocksdb_WriteBatch_hasRollback(
|
||||
JNIEnv* env , jobject jobj, jlong jwb_handle) {
|
||||
auto* wb = reinterpret_cast<rocksdb::WriteBatch*>(jwb_handle);
|
||||
assert(wb != nullptr);
|
||||
|
||||
return wb->HasRollback();
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_WriteBatch
|
||||
* Method: markWalTerminationPoint
|
||||
* Signature: (J)V
|
||||
*/
|
||||
void Java_org_rocksdb_WriteBatch_markWalTerminationPoint(
|
||||
JNIEnv* env, jobject jobj, jlong jwb_handle) {
|
||||
auto* wb = reinterpret_cast<rocksdb::WriteBatch*>(jwb_handle);
|
||||
assert(wb != nullptr);
|
||||
|
||||
wb->MarkWalTerminationPoint();
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_WriteBatch
|
||||
* Method: getWalTerminationPoint
|
||||
* Signature: (J)Lorg/rocksdb/WriteBatch/SavePoint;
|
||||
*/
|
||||
jobject Java_org_rocksdb_WriteBatch_getWalTerminationPoint(
|
||||
JNIEnv* env, jobject jobj, jlong jwb_handle) {
|
||||
auto* wb = reinterpret_cast<rocksdb::WriteBatch*>(jwb_handle);
|
||||
assert(wb != nullptr);
|
||||
|
||||
auto save_point = wb->GetWalTerminationPoint();
|
||||
return rocksdb::WriteBatchSavePointJni::construct(env, save_point);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_WriteBatch
|
||||
* Method: disposeInternal
|
||||
|
||||
@@ -87,8 +87,32 @@ jbyteArray Java_org_rocksdb_WriteBatchTest_getContents(
|
||||
state.append(")");
|
||||
count++;
|
||||
break;
|
||||
case rocksdb::kTypeSingleDeletion:
|
||||
state.append("SingleDelete(");
|
||||
state.append(ikey.user_key.ToString());
|
||||
state.append(")");
|
||||
count++;
|
||||
break;
|
||||
case rocksdb::kTypeRangeDeletion:
|
||||
state.append("DeleteRange(");
|
||||
state.append(ikey.user_key.ToString());
|
||||
state.append(", ");
|
||||
state.append(iter->value().ToString());
|
||||
state.append(")");
|
||||
count++;
|
||||
break;
|
||||
case rocksdb::kTypeLogData:
|
||||
state.append("LogData(");
|
||||
state.append(ikey.user_key.ToString());
|
||||
state.append(")");
|
||||
count++;
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
state.append("Err:Expected(");
|
||||
state.append(std::to_string(ikey.type));
|
||||
state.append(")");
|
||||
count++;
|
||||
break;
|
||||
}
|
||||
state.append("@");
|
||||
@@ -96,8 +120,12 @@ jbyteArray Java_org_rocksdb_WriteBatchTest_getContents(
|
||||
}
|
||||
if (!s.ok()) {
|
||||
state.append(s.ToString());
|
||||
} else if (count != rocksdb::WriteBatchInternal::Count(b)) {
|
||||
state.append("CountMismatch()");
|
||||
} else if (rocksdb::WriteBatchInternal::Count(b) != count) {
|
||||
state.append("Err:CountMismatch(expected=");
|
||||
state.append(std::to_string(rocksdb::WriteBatchInternal::Count(b)));
|
||||
state.append(", actual=");
|
||||
state.append(std::to_string(count));
|
||||
state.append(")");
|
||||
}
|
||||
delete mem->Unref();
|
||||
|
||||
|
||||
@@ -39,19 +39,31 @@ jlong Java_org_rocksdb_WriteBatchWithIndex_newWriteBatchWithIndex__Z(
|
||||
/*
|
||||
* Class: org_rocksdb_WriteBatchWithIndex
|
||||
* Method: newWriteBatchWithIndex
|
||||
* Signature: (JZIZ)J
|
||||
* Signature: (JBIZ)J
|
||||
*/
|
||||
jlong Java_org_rocksdb_WriteBatchWithIndex_newWriteBatchWithIndex__JZIZ(
|
||||
jlong Java_org_rocksdb_WriteBatchWithIndex_newWriteBatchWithIndex__JBIZ(
|
||||
JNIEnv* env, jclass jcls, jlong jfallback_index_comparator_handle,
|
||||
jboolean is_direct, jint jreserved_bytes, jboolean joverwrite_key) {
|
||||
rocksdb::Comparator *fallback_comparator = nullptr;
|
||||
if(is_direct) {
|
||||
fallback_comparator =
|
||||
reinterpret_cast<rocksdb::DirectComparatorJniCallback*>(jfallback_index_comparator_handle);
|
||||
} else {
|
||||
fallback_comparator =
|
||||
reinterpret_cast<rocksdb::ComparatorJniCallback*>(jfallback_index_comparator_handle);
|
||||
}
|
||||
jbyte jcomparator_type, jint jreserved_bytes, jboolean joverwrite_key) {
|
||||
rocksdb::Comparator *fallback_comparator = nullptr;
|
||||
switch(jcomparator_type) {
|
||||
// JAVA_COMPARATOR
|
||||
case 0x0:
|
||||
fallback_comparator =
|
||||
reinterpret_cast<rocksdb::ComparatorJniCallback*>(jfallback_index_comparator_handle);
|
||||
break;
|
||||
|
||||
// JAVA_DIRECT_COMPARATOR
|
||||
case 0x1:
|
||||
fallback_comparator =
|
||||
reinterpret_cast<rocksdb::DirectComparatorJniCallback*>(jfallback_index_comparator_handle);
|
||||
break;
|
||||
|
||||
// JAVA_NATIVE_COMPARATOR_WRAPPER
|
||||
case 0x2:
|
||||
fallback_comparator =
|
||||
reinterpret_cast<rocksdb::Comparator*>(jfallback_index_comparator_handle);
|
||||
break;
|
||||
}
|
||||
auto* wbwi =
|
||||
new rocksdb::WriteBatchWithIndex(
|
||||
fallback_comparator,
|
||||
@@ -83,10 +95,13 @@ void Java_org_rocksdb_WriteBatchWithIndex_put__J_3BI_3BI(
|
||||
auto* wbwi = reinterpret_cast<rocksdb::WriteBatchWithIndex*>(jwbwi_handle);
|
||||
assert(wbwi != nullptr);
|
||||
auto put = [&wbwi] (rocksdb::Slice key, rocksdb::Slice value) {
|
||||
wbwi->Put(key, value);
|
||||
return wbwi->Put(key, value);
|
||||
};
|
||||
rocksdb::JniUtil::kv_op(put, env, jobj, jkey, jkey_len, jentry_value,
|
||||
jentry_value_len);
|
||||
std::unique_ptr<rocksdb::Status> status = rocksdb::JniUtil::kv_op(put, env,
|
||||
jobj, jkey, jkey_len, jentry_value, jentry_value_len);
|
||||
if (status != nullptr && !status->ok()) {
|
||||
rocksdb::RocksDBExceptionJni::ThrowNew(env, status);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -103,10 +118,13 @@ void Java_org_rocksdb_WriteBatchWithIndex_put__J_3BI_3BIJ(
|
||||
auto* cf_handle = reinterpret_cast<rocksdb::ColumnFamilyHandle*>(jcf_handle);
|
||||
assert(cf_handle != nullptr);
|
||||
auto put = [&wbwi, &cf_handle] (rocksdb::Slice key, rocksdb::Slice value) {
|
||||
wbwi->Put(cf_handle, key, value);
|
||||
return wbwi->Put(cf_handle, key, value);
|
||||
};
|
||||
rocksdb::JniUtil::kv_op(put, env, jobj, jkey, jkey_len, jentry_value,
|
||||
jentry_value_len);
|
||||
std::unique_ptr<rocksdb::Status> status = rocksdb::JniUtil::kv_op(put, env,
|
||||
jobj, jkey, jkey_len, jentry_value, jentry_value_len);
|
||||
if (status != nullptr && !status->ok()) {
|
||||
rocksdb::RocksDBExceptionJni::ThrowNew(env, status);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -120,10 +138,13 @@ void Java_org_rocksdb_WriteBatchWithIndex_merge__J_3BI_3BI(
|
||||
auto* wbwi = reinterpret_cast<rocksdb::WriteBatchWithIndex*>(jwbwi_handle);
|
||||
assert(wbwi != nullptr);
|
||||
auto merge = [&wbwi] (rocksdb::Slice key, rocksdb::Slice value) {
|
||||
wbwi->Merge(key, value);
|
||||
return wbwi->Merge(key, value);
|
||||
};
|
||||
rocksdb::JniUtil::kv_op(merge, env, jobj, jkey, jkey_len, jentry_value,
|
||||
jentry_value_len);
|
||||
std::unique_ptr<rocksdb::Status> status = rocksdb::JniUtil::kv_op(merge, env,
|
||||
jobj, jkey, jkey_len, jentry_value, jentry_value_len);
|
||||
if (status != nullptr && !status->ok()) {
|
||||
rocksdb::RocksDBExceptionJni::ThrowNew(env, status);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -140,34 +161,41 @@ void Java_org_rocksdb_WriteBatchWithIndex_merge__J_3BI_3BIJ(
|
||||
auto* cf_handle = reinterpret_cast<rocksdb::ColumnFamilyHandle*>(jcf_handle);
|
||||
assert(cf_handle != nullptr);
|
||||
auto merge = [&wbwi, &cf_handle] (rocksdb::Slice key, rocksdb::Slice value) {
|
||||
wbwi->Merge(cf_handle, key, value);
|
||||
return wbwi->Merge(cf_handle, key, value);
|
||||
};
|
||||
rocksdb::JniUtil::kv_op(merge, env, jobj, jkey, jkey_len, jentry_value,
|
||||
jentry_value_len);
|
||||
std::unique_ptr<rocksdb::Status> status = rocksdb::JniUtil::kv_op(merge, env,
|
||||
jobj, jkey, jkey_len, jentry_value, jentry_value_len);
|
||||
if (status != nullptr && !status->ok()) {
|
||||
rocksdb::RocksDBExceptionJni::ThrowNew(env, status);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_WriteBatchWithIndex
|
||||
* Method: remove
|
||||
* Method: delete
|
||||
* Signature: (J[BI)V
|
||||
*/
|
||||
void Java_org_rocksdb_WriteBatchWithIndex_remove__J_3BI(
|
||||
void Java_org_rocksdb_WriteBatchWithIndex_delete__J_3BI(
|
||||
JNIEnv* env, jobject jobj, jlong jwbwi_handle, jbyteArray jkey,
|
||||
jint jkey_len) {
|
||||
auto* wbwi = reinterpret_cast<rocksdb::WriteBatchWithIndex*>(jwbwi_handle);
|
||||
assert(wbwi != nullptr);
|
||||
auto remove = [&wbwi] (rocksdb::Slice key) {
|
||||
wbwi->Delete(key);
|
||||
return wbwi->Delete(key);
|
||||
};
|
||||
rocksdb::JniUtil::k_op(remove, env, jobj, jkey, jkey_len);
|
||||
std::unique_ptr<rocksdb::Status> status = rocksdb::JniUtil::k_op(remove, env,
|
||||
jobj, jkey, jkey_len);
|
||||
if (status != nullptr && !status->ok()) {
|
||||
rocksdb::RocksDBExceptionJni::ThrowNew(env, status);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_WriteBatchWithIndex
|
||||
* Method: remove
|
||||
* Method: delete
|
||||
* Signature: (J[BIJ)V
|
||||
*/
|
||||
void Java_org_rocksdb_WriteBatchWithIndex_remove__J_3BIJ(
|
||||
void Java_org_rocksdb_WriteBatchWithIndex_delete__J_3BIJ(
|
||||
JNIEnv* env, jobject jobj, jlong jwbwi_handle, jbyteArray jkey,
|
||||
jint jkey_len, jlong jcf_handle) {
|
||||
auto* wbwi = reinterpret_cast<rocksdb::WriteBatchWithIndex*>(jwbwi_handle);
|
||||
@@ -175,9 +203,55 @@ void Java_org_rocksdb_WriteBatchWithIndex_remove__J_3BIJ(
|
||||
auto* cf_handle = reinterpret_cast<rocksdb::ColumnFamilyHandle*>(jcf_handle);
|
||||
assert(cf_handle != nullptr);
|
||||
auto remove = [&wbwi, &cf_handle] (rocksdb::Slice key) {
|
||||
wbwi->Delete(cf_handle, key);
|
||||
return wbwi->Delete(cf_handle, key);
|
||||
};
|
||||
rocksdb::JniUtil::k_op(remove, env, jobj, jkey, jkey_len);
|
||||
std::unique_ptr<rocksdb::Status> status = rocksdb::JniUtil::k_op(remove, env,
|
||||
jobj, jkey, jkey_len);
|
||||
if (status != nullptr && !status->ok()) {
|
||||
rocksdb::RocksDBExceptionJni::ThrowNew(env, status);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_WriteBatchWithIndex
|
||||
* Method: singleDelete
|
||||
* Signature: (J[BI)V
|
||||
*/
|
||||
void Java_org_rocksdb_WriteBatchWithIndex_singleDelete__J_3BI(
|
||||
JNIEnv* env, jobject jobj, jlong jwbwi_handle, jbyteArray jkey,
|
||||
jint jkey_len) {
|
||||
auto* wbwi = reinterpret_cast<rocksdb::WriteBatchWithIndex*>(jwbwi_handle);
|
||||
assert(wbwi != nullptr);
|
||||
auto single_delete = [&wbwi] (rocksdb::Slice key) {
|
||||
return wbwi->SingleDelete(key);
|
||||
};
|
||||
std::unique_ptr<rocksdb::Status> status = rocksdb::JniUtil::k_op(single_delete,
|
||||
env, jobj, jkey, jkey_len);
|
||||
if (status != nullptr && !status->ok()) {
|
||||
rocksdb::RocksDBExceptionJni::ThrowNew(env, status);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_WriteBatchWithIndex
|
||||
* Method: singleDelete
|
||||
* Signature: (J[BIJ)V
|
||||
*/
|
||||
void Java_org_rocksdb_WriteBatchWithIndex_singleDelete__J_3BIJ(
|
||||
JNIEnv* env, jobject jobj, jlong jwbwi_handle, jbyteArray jkey,
|
||||
jint jkey_len, jlong jcf_handle) {
|
||||
auto* wbwi = reinterpret_cast<rocksdb::WriteBatchWithIndex*>(jwbwi_handle);
|
||||
assert(wbwi != nullptr);
|
||||
auto* cf_handle = reinterpret_cast<rocksdb::ColumnFamilyHandle*>(jcf_handle);
|
||||
assert(cf_handle != nullptr);
|
||||
auto single_delete = [&wbwi, &cf_handle] (rocksdb::Slice key) {
|
||||
return wbwi->SingleDelete(cf_handle, key);
|
||||
};
|
||||
std::unique_ptr<rocksdb::Status> status = rocksdb::JniUtil::k_op(single_delete,
|
||||
env, jobj, jkey, jkey_len);
|
||||
if (status != nullptr && !status->ok()) {
|
||||
rocksdb::RocksDBExceptionJni::ThrowNew(env, status);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -191,10 +265,14 @@ void Java_org_rocksdb_WriteBatchWithIndex_deleteRange__J_3BI_3BI(
|
||||
auto* wbwi = reinterpret_cast<rocksdb::WriteBatchWithIndex*>(jwbwi_handle);
|
||||
assert(wbwi != nullptr);
|
||||
auto deleteRange = [&wbwi](rocksdb::Slice beginKey, rocksdb::Slice endKey) {
|
||||
wbwi->DeleteRange(beginKey, endKey);
|
||||
return wbwi->DeleteRange(beginKey, endKey);
|
||||
};
|
||||
rocksdb::JniUtil::kv_op(deleteRange, env, jobj, jbegin_key, jbegin_key_len,
|
||||
jend_key, jend_key_len);
|
||||
std::unique_ptr<rocksdb::Status> status = rocksdb::JniUtil::kv_op(
|
||||
deleteRange, env, jobj, jbegin_key, jbegin_key_len, jend_key,
|
||||
jend_key_len);
|
||||
if (status != nullptr && !status->ok()) {
|
||||
rocksdb::RocksDBExceptionJni::ThrowNew(env, status);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -211,11 +289,15 @@ void Java_org_rocksdb_WriteBatchWithIndex_deleteRange__J_3BI_3BIJ(
|
||||
auto* cf_handle = reinterpret_cast<rocksdb::ColumnFamilyHandle*>(jcf_handle);
|
||||
assert(cf_handle != nullptr);
|
||||
auto deleteRange = [&wbwi, &cf_handle](rocksdb::Slice beginKey,
|
||||
rocksdb::Slice endKey) {
|
||||
wbwi->DeleteRange(cf_handle, beginKey, endKey);
|
||||
rocksdb::Slice endKey) {
|
||||
return wbwi->DeleteRange(cf_handle, beginKey, endKey);
|
||||
};
|
||||
rocksdb::JniUtil::kv_op(deleteRange, env, jobj, jbegin_key, jbegin_key_len,
|
||||
jend_key, jend_key_len);
|
||||
std::unique_ptr<rocksdb::Status> status = rocksdb::JniUtil::kv_op(
|
||||
deleteRange, env, jobj, jbegin_key, jbegin_key_len, jend_key,
|
||||
jend_key_len);
|
||||
if (status != nullptr && !status->ok()) {
|
||||
rocksdb::RocksDBExceptionJni::ThrowNew(env, status);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -229,9 +311,13 @@ void Java_org_rocksdb_WriteBatchWithIndex_putLogData(
|
||||
auto* wbwi = reinterpret_cast<rocksdb::WriteBatchWithIndex*>(jwbwi_handle);
|
||||
assert(wbwi != nullptr);
|
||||
auto putLogData = [&wbwi] (rocksdb::Slice blob) {
|
||||
wbwi->PutLogData(blob);
|
||||
return wbwi->PutLogData(blob);
|
||||
};
|
||||
rocksdb::JniUtil::k_op(putLogData, env, jobj, jblob, jblob_len);
|
||||
std::unique_ptr<rocksdb::Status> status = rocksdb::JniUtil::k_op(putLogData,
|
||||
env, jobj, jblob, jblob_len);
|
||||
if (status != nullptr && !status->ok()) {
|
||||
rocksdb::RocksDBExceptionJni::ThrowNew(env, status);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -279,6 +365,54 @@ void Java_org_rocksdb_WriteBatchWithIndex_rollbackToSavePoint0(
|
||||
rocksdb::RocksDBExceptionJni::ThrowNew(env, s);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_WriteBatchWithIndex
|
||||
* Method: popSavePoint
|
||||
* Signature: (J)V
|
||||
*/
|
||||
void Java_org_rocksdb_WriteBatchWithIndex_popSavePoint(
|
||||
JNIEnv* env, jobject jobj, jlong jwbwi_handle) {
|
||||
auto* wbwi = reinterpret_cast<rocksdb::WriteBatchWithIndex*>(jwbwi_handle);
|
||||
assert(wbwi != nullptr);
|
||||
|
||||
auto s = wbwi->PopSavePoint();
|
||||
|
||||
if (s.ok()) {
|
||||
return;
|
||||
}
|
||||
|
||||
rocksdb::RocksDBExceptionJni::ThrowNew(env, s);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_WriteBatchWithIndex
|
||||
* Method: setMaxBytes
|
||||
* Signature: (JJ)V
|
||||
*/
|
||||
void Java_org_rocksdb_WriteBatchWithIndex_setMaxBytes(
|
||||
JNIEnv* env, jobject jobj, jlong jwbwi_handle, jlong jmax_bytes) {
|
||||
auto* wbwi = reinterpret_cast<rocksdb::WriteBatchWithIndex*>(jwbwi_handle);
|
||||
assert(wbwi != nullptr);
|
||||
|
||||
wbwi->SetMaxBytes(static_cast<size_t>(jmax_bytes));
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_WriteBatchWithIndex
|
||||
* Method: getWriteBatch
|
||||
* Signature: (J)Lorg/rocksdb/WriteBatch;
|
||||
*/
|
||||
jobject Java_org_rocksdb_WriteBatchWithIndex_getWriteBatch(
|
||||
JNIEnv* env, jobject jobj, jlong jwbwi_handle) {
|
||||
auto* wbwi = reinterpret_cast<rocksdb::WriteBatchWithIndex*>(jwbwi_handle);
|
||||
assert(wbwi != nullptr);
|
||||
|
||||
auto* wb = wbwi->GetWriteBatch();
|
||||
|
||||
// TODO(AR) is the `wb` object owned by us?
|
||||
return rocksdb::WriteBatchJni::construct(env, wb);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_WriteBatchWithIndex
|
||||
* Method: iterator0
|
||||
@@ -551,33 +685,15 @@ jlongArray Java_org_rocksdb_WBWIRocksIterator_entry1(
|
||||
|
||||
jlong results[3];
|
||||
|
||||
//set the type of the write entry
|
||||
switch (we.type) {
|
||||
case rocksdb::kPutRecord:
|
||||
results[0] = 0x1;
|
||||
break;
|
||||
// set the type of the write entry
|
||||
results[0] = rocksdb::WriteTypeJni::toJavaWriteType(we.type);
|
||||
|
||||
case rocksdb::kMergeRecord:
|
||||
results[0] = 0x2;
|
||||
break;
|
||||
|
||||
case rocksdb::kDeleteRecord:
|
||||
results[0] = 0x4;
|
||||
break;
|
||||
|
||||
case rocksdb::kLogDataRecord:
|
||||
results[0] = 0x8;
|
||||
break;
|
||||
|
||||
default:
|
||||
results[0] = 0x0;
|
||||
}
|
||||
|
||||
// key_slice and value_slice will be freed by org.rocksdb.DirectSlice#close
|
||||
// NOTE: key_slice and value_slice will be freed by org.rocksdb.DirectSlice#close
|
||||
|
||||
auto* key_slice = new rocksdb::Slice(we.key.data(), we.key.size());
|
||||
results[1] = reinterpret_cast<jlong>(key_slice);
|
||||
if (we.type == rocksdb::kDeleteRecord
|
||||
|| we.type == rocksdb::kSingleDeleteRecord
|
||||
|| we.type == rocksdb::kLogDataRecord) {
|
||||
// set native handle of value slice to null if no value available
|
||||
results[2] = 0;
|
||||
|
||||
@@ -14,24 +14,62 @@ WriteBatchHandlerJniCallback::WriteBatchHandlerJniCallback(
|
||||
JNIEnv* env, jobject jWriteBatchHandler)
|
||||
: JniCallback(env, jWriteBatchHandler), m_env(env) {
|
||||
|
||||
m_jPutCfMethodId = WriteBatchHandlerJni::getPutCfMethodId(env);
|
||||
if(m_jPutCfMethodId == nullptr) {
|
||||
// exception thrown
|
||||
return;
|
||||
}
|
||||
|
||||
m_jPutMethodId = WriteBatchHandlerJni::getPutMethodId(env);
|
||||
if(m_jPutMethodId == nullptr) {
|
||||
// exception thrown
|
||||
return;
|
||||
}
|
||||
|
||||
m_jMergeCfMethodId = WriteBatchHandlerJni::getMergeCfMethodId(env);
|
||||
if(m_jMergeCfMethodId == nullptr) {
|
||||
// exception thrown
|
||||
return;
|
||||
}
|
||||
|
||||
m_jMergeMethodId = WriteBatchHandlerJni::getMergeMethodId(env);
|
||||
if(m_jMergeMethodId == nullptr) {
|
||||
// exception thrown
|
||||
return;
|
||||
}
|
||||
|
||||
m_jDeleteCfMethodId = WriteBatchHandlerJni::getDeleteCfMethodId(env);
|
||||
if(m_jDeleteCfMethodId == nullptr) {
|
||||
// exception thrown
|
||||
return;
|
||||
}
|
||||
|
||||
m_jDeleteMethodId = WriteBatchHandlerJni::getDeleteMethodId(env);
|
||||
if(m_jDeleteMethodId == nullptr) {
|
||||
// exception thrown
|
||||
return;
|
||||
}
|
||||
|
||||
m_jSingleDeleteCfMethodId =
|
||||
WriteBatchHandlerJni::getSingleDeleteCfMethodId(env);
|
||||
if(m_jSingleDeleteCfMethodId == nullptr) {
|
||||
// exception thrown
|
||||
return;
|
||||
}
|
||||
|
||||
m_jSingleDeleteMethodId = WriteBatchHandlerJni::getSingleDeleteMethodId(env);
|
||||
if(m_jSingleDeleteMethodId == nullptr) {
|
||||
// exception thrown
|
||||
return;
|
||||
}
|
||||
|
||||
m_jDeleteRangeCfMethodId =
|
||||
WriteBatchHandlerJni::getDeleteRangeCfMethodId(env);
|
||||
if (m_jDeleteRangeCfMethodId == nullptr) {
|
||||
// exception thrown
|
||||
return;
|
||||
}
|
||||
|
||||
m_jDeleteRangeMethodId = WriteBatchHandlerJni::getDeleteRangeMethodId(env);
|
||||
if (m_jDeleteRangeMethodId == nullptr) {
|
||||
// exception thrown
|
||||
@@ -44,6 +82,45 @@ WriteBatchHandlerJniCallback::WriteBatchHandlerJniCallback(
|
||||
return;
|
||||
}
|
||||
|
||||
m_jPutBlobIndexCfMethodId =
|
||||
WriteBatchHandlerJni::getPutBlobIndexCfMethodId(env);
|
||||
if(m_jPutBlobIndexCfMethodId == nullptr) {
|
||||
// exception thrown
|
||||
return;
|
||||
}
|
||||
|
||||
m_jMarkBeginPrepareMethodId =
|
||||
WriteBatchHandlerJni::getMarkBeginPrepareMethodId(env);
|
||||
if(m_jMarkBeginPrepareMethodId == nullptr) {
|
||||
// exception thrown
|
||||
return;
|
||||
}
|
||||
|
||||
m_jMarkEndPrepareMethodId =
|
||||
WriteBatchHandlerJni::getMarkEndPrepareMethodId(env);
|
||||
if(m_jMarkEndPrepareMethodId == nullptr) {
|
||||
// exception thrown
|
||||
return;
|
||||
}
|
||||
|
||||
m_jMarkNoopMethodId = WriteBatchHandlerJni::getMarkNoopMethodId(env);
|
||||
if(m_jMarkNoopMethodId == nullptr) {
|
||||
// exception thrown
|
||||
return;
|
||||
}
|
||||
|
||||
m_jMarkRollbackMethodId = WriteBatchHandlerJni::getMarkRollbackMethodId(env);
|
||||
if(m_jMarkRollbackMethodId == nullptr) {
|
||||
// exception thrown
|
||||
return;
|
||||
}
|
||||
|
||||
m_jMarkCommitMethodId = WriteBatchHandlerJni::getMarkCommitMethodId(env);
|
||||
if(m_jMarkCommitMethodId == nullptr) {
|
||||
// exception thrown
|
||||
return;
|
||||
}
|
||||
|
||||
m_jContinueMethodId = WriteBatchHandlerJni::getContinueMethodId(env);
|
||||
if(m_jContinueMethodId == nullptr) {
|
||||
// exception thrown
|
||||
@@ -51,196 +128,272 @@ WriteBatchHandlerJniCallback::WriteBatchHandlerJniCallback(
|
||||
}
|
||||
}
|
||||
|
||||
rocksdb::Status WriteBatchHandlerJniCallback::PutCF(uint32_t column_family_id,
|
||||
const Slice& key, const Slice& value) {
|
||||
auto put = [this, column_family_id] (
|
||||
jbyteArray j_key, jbyteArray j_value) {
|
||||
m_env->CallVoidMethod(
|
||||
m_jcallback_obj,
|
||||
m_jPutCfMethodId,
|
||||
static_cast<jint>(column_family_id),
|
||||
j_key,
|
||||
j_value);
|
||||
};
|
||||
auto status = WriteBatchHandlerJniCallback::kv_op(key, value, put);
|
||||
if(status == nullptr) {
|
||||
return rocksdb::Status::OK(); // TODO(AR) what to do if there is an Exception but we don't know the rocksdb::Status?
|
||||
} else {
|
||||
return rocksdb::Status(*status);
|
||||
}
|
||||
}
|
||||
|
||||
void WriteBatchHandlerJniCallback::Put(const Slice& key, const Slice& value) {
|
||||
const jbyteArray j_key = sliceToJArray(key);
|
||||
if(j_key == nullptr) {
|
||||
// exception thrown
|
||||
if(m_env->ExceptionCheck()) {
|
||||
m_env->ExceptionDescribe();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const jbyteArray j_value = sliceToJArray(value);
|
||||
if(j_value == nullptr) {
|
||||
// exception thrown
|
||||
if(m_env->ExceptionCheck()) {
|
||||
m_env->ExceptionDescribe();
|
||||
}
|
||||
if(j_key != nullptr) {
|
||||
m_env->DeleteLocalRef(j_key);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
m_env->CallVoidMethod(
|
||||
auto put = [this] (
|
||||
jbyteArray j_key, jbyteArray j_value) {
|
||||
m_env->CallVoidMethod(
|
||||
m_jcallback_obj,
|
||||
m_jPutMethodId,
|
||||
j_key,
|
||||
j_value);
|
||||
if(m_env->ExceptionCheck()) {
|
||||
// exception thrown
|
||||
m_env->ExceptionDescribe();
|
||||
if(j_value != nullptr) {
|
||||
m_env->DeleteLocalRef(j_value);
|
||||
}
|
||||
if(j_key != nullptr) {
|
||||
m_env->DeleteLocalRef(j_key);
|
||||
}
|
||||
return;
|
||||
}
|
||||
};
|
||||
WriteBatchHandlerJniCallback::kv_op(key, value, put);
|
||||
}
|
||||
|
||||
if(j_value != nullptr) {
|
||||
m_env->DeleteLocalRef(j_value);
|
||||
}
|
||||
if(j_key != nullptr) {
|
||||
m_env->DeleteLocalRef(j_key);
|
||||
rocksdb::Status WriteBatchHandlerJniCallback::MergeCF(uint32_t column_family_id,
|
||||
const Slice& key, const Slice& value) {
|
||||
auto merge = [this, column_family_id] (
|
||||
jbyteArray j_key, jbyteArray j_value) {
|
||||
m_env->CallVoidMethod(
|
||||
m_jcallback_obj,
|
||||
m_jMergeCfMethodId,
|
||||
static_cast<jint>(column_family_id),
|
||||
j_key,
|
||||
j_value);
|
||||
};
|
||||
auto status = WriteBatchHandlerJniCallback::kv_op(key, value, merge);
|
||||
if(status == nullptr) {
|
||||
return rocksdb::Status::OK(); // TODO(AR) what to do if there is an Exception but we don't know the rocksdb::Status?
|
||||
} else {
|
||||
return rocksdb::Status(*status);
|
||||
}
|
||||
}
|
||||
|
||||
void WriteBatchHandlerJniCallback::Merge(const Slice& key, const Slice& value) {
|
||||
const jbyteArray j_key = sliceToJArray(key);
|
||||
if(j_key == nullptr) {
|
||||
// exception thrown
|
||||
if(m_env->ExceptionCheck()) {
|
||||
m_env->ExceptionDescribe();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const jbyteArray j_value = sliceToJArray(value);
|
||||
if(j_value == nullptr) {
|
||||
// exception thrown
|
||||
if(m_env->ExceptionCheck()) {
|
||||
m_env->ExceptionDescribe();
|
||||
}
|
||||
if(j_key != nullptr) {
|
||||
m_env->DeleteLocalRef(j_key);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
m_env->CallVoidMethod(
|
||||
auto merge = [this] (
|
||||
jbyteArray j_key, jbyteArray j_value) {
|
||||
m_env->CallVoidMethod(
|
||||
m_jcallback_obj,
|
||||
m_jMergeMethodId,
|
||||
j_key,
|
||||
j_value);
|
||||
if(m_env->ExceptionCheck()) {
|
||||
// exception thrown
|
||||
m_env->ExceptionDescribe();
|
||||
if(j_value != nullptr) {
|
||||
m_env->DeleteLocalRef(j_value);
|
||||
}
|
||||
if(j_key != nullptr) {
|
||||
m_env->DeleteLocalRef(j_key);
|
||||
}
|
||||
return;
|
||||
}
|
||||
};
|
||||
WriteBatchHandlerJniCallback::kv_op(key, value, merge);
|
||||
}
|
||||
|
||||
if(j_value != nullptr) {
|
||||
m_env->DeleteLocalRef(j_value);
|
||||
}
|
||||
if(j_key != nullptr) {
|
||||
m_env->DeleteLocalRef(j_key);
|
||||
rocksdb::Status WriteBatchHandlerJniCallback::DeleteCF(uint32_t column_family_id,
|
||||
const Slice& key) {
|
||||
auto remove = [this, column_family_id] (jbyteArray j_key) {
|
||||
m_env->CallVoidMethod(
|
||||
m_jcallback_obj,
|
||||
m_jDeleteCfMethodId,
|
||||
static_cast<jint>(column_family_id),
|
||||
j_key);
|
||||
};
|
||||
auto status = WriteBatchHandlerJniCallback::k_op(key, remove);
|
||||
if(status == nullptr) {
|
||||
return rocksdb::Status::OK(); // TODO(AR) what to do if there is an Exception but we don't know the rocksdb::Status?
|
||||
} else {
|
||||
return rocksdb::Status(*status);
|
||||
}
|
||||
}
|
||||
|
||||
void WriteBatchHandlerJniCallback::Delete(const Slice& key) {
|
||||
const jbyteArray j_key = sliceToJArray(key);
|
||||
if(j_key == nullptr) {
|
||||
// exception thrown
|
||||
if(m_env->ExceptionCheck()) {
|
||||
m_env->ExceptionDescribe();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
m_env->CallVoidMethod(
|
||||
auto remove = [this] (jbyteArray j_key) {
|
||||
m_env->CallVoidMethod(
|
||||
m_jcallback_obj,
|
||||
m_jDeleteMethodId,
|
||||
j_key);
|
||||
if(m_env->ExceptionCheck()) {
|
||||
// exception thrown
|
||||
m_env->ExceptionDescribe();
|
||||
if(j_key != nullptr) {
|
||||
m_env->DeleteLocalRef(j_key);
|
||||
}
|
||||
return;
|
||||
}
|
||||
};
|
||||
WriteBatchHandlerJniCallback::k_op(key, remove);
|
||||
}
|
||||
|
||||
if(j_key != nullptr) {
|
||||
m_env->DeleteLocalRef(j_key);
|
||||
rocksdb::Status WriteBatchHandlerJniCallback::SingleDeleteCF(uint32_t column_family_id,
|
||||
const Slice& key) {
|
||||
auto singleDelete = [this, column_family_id] (jbyteArray j_key) {
|
||||
m_env->CallVoidMethod(
|
||||
m_jcallback_obj,
|
||||
m_jSingleDeleteCfMethodId,
|
||||
static_cast<jint>(column_family_id),
|
||||
j_key);
|
||||
};
|
||||
auto status = WriteBatchHandlerJniCallback::k_op(key, singleDelete);
|
||||
if(status == nullptr) {
|
||||
return rocksdb::Status::OK(); // TODO(AR) what to do if there is an Exception but we don't know the rocksdb::Status?
|
||||
} else {
|
||||
return rocksdb::Status(*status);
|
||||
}
|
||||
}
|
||||
|
||||
void WriteBatchHandlerJniCallback::SingleDelete(const Slice& key) {
|
||||
auto singleDelete = [this] (jbyteArray j_key) {
|
||||
m_env->CallVoidMethod(
|
||||
m_jcallback_obj,
|
||||
m_jSingleDeleteMethodId,
|
||||
j_key);
|
||||
};
|
||||
WriteBatchHandlerJniCallback::k_op(key, singleDelete);
|
||||
}
|
||||
|
||||
rocksdb::Status WriteBatchHandlerJniCallback::DeleteRangeCF(uint32_t column_family_id,
|
||||
const Slice& beginKey, const Slice& endKey) {
|
||||
auto deleteRange = [this, column_family_id] (
|
||||
jbyteArray j_beginKey, jbyteArray j_endKey) {
|
||||
m_env->CallVoidMethod(
|
||||
m_jcallback_obj,
|
||||
m_jDeleteRangeCfMethodId,
|
||||
static_cast<jint>(column_family_id),
|
||||
j_beginKey,
|
||||
j_endKey);
|
||||
};
|
||||
auto status = WriteBatchHandlerJniCallback::kv_op(beginKey, endKey, deleteRange);
|
||||
if(status == nullptr) {
|
||||
return rocksdb::Status::OK(); // TODO(AR) what to do if there is an Exception but we don't know the rocksdb::Status?
|
||||
} else {
|
||||
return rocksdb::Status(*status);
|
||||
}
|
||||
}
|
||||
|
||||
void WriteBatchHandlerJniCallback::DeleteRange(const Slice& beginKey,
|
||||
const Slice& endKey) {
|
||||
const jbyteArray j_beginKey = sliceToJArray(beginKey);
|
||||
if (j_beginKey == nullptr) {
|
||||
// exception thrown
|
||||
if (m_env->ExceptionCheck()) {
|
||||
m_env->ExceptionDescribe();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const jbyteArray j_endKey = sliceToJArray(beginKey);
|
||||
if (j_endKey == nullptr) {
|
||||
// exception thrown
|
||||
if (m_env->ExceptionCheck()) {
|
||||
m_env->ExceptionDescribe();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
m_env->CallVoidMethod(m_jcallback_obj, m_jDeleteRangeMethodId,
|
||||
j_beginKey, j_endKey);
|
||||
if (m_env->ExceptionCheck()) {
|
||||
// exception thrown
|
||||
m_env->ExceptionDescribe();
|
||||
if (j_beginKey != nullptr) {
|
||||
m_env->DeleteLocalRef(j_beginKey);
|
||||
}
|
||||
if (j_endKey != nullptr) {
|
||||
m_env->DeleteLocalRef(j_endKey);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (j_beginKey != nullptr) {
|
||||
m_env->DeleteLocalRef(j_beginKey);
|
||||
}
|
||||
|
||||
if (j_endKey != nullptr) {
|
||||
m_env->DeleteLocalRef(j_endKey);
|
||||
}
|
||||
const Slice& endKey) {
|
||||
auto deleteRange = [this] (
|
||||
jbyteArray j_beginKey, jbyteArray j_endKey) {
|
||||
m_env->CallVoidMethod(
|
||||
m_jcallback_obj,
|
||||
m_jDeleteRangeMethodId,
|
||||
j_beginKey,
|
||||
j_endKey);
|
||||
};
|
||||
WriteBatchHandlerJniCallback::kv_op(beginKey, endKey, deleteRange);
|
||||
}
|
||||
|
||||
void WriteBatchHandlerJniCallback::LogData(const Slice& blob) {
|
||||
const jbyteArray j_blob = sliceToJArray(blob);
|
||||
if(j_blob == nullptr) {
|
||||
// exception thrown
|
||||
if(m_env->ExceptionCheck()) {
|
||||
m_env->ExceptionDescribe();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
m_env->CallVoidMethod(
|
||||
auto logData = [this] (jbyteArray j_blob) {
|
||||
m_env->CallVoidMethod(
|
||||
m_jcallback_obj,
|
||||
m_jLogDataMethodId,
|
||||
j_blob);
|
||||
if(m_env->ExceptionCheck()) {
|
||||
};
|
||||
WriteBatchHandlerJniCallback::k_op(blob, logData);
|
||||
}
|
||||
|
||||
rocksdb::Status WriteBatchHandlerJniCallback::PutBlobIndexCF(uint32_t column_family_id,
|
||||
const Slice& key, const Slice& value) {
|
||||
auto putBlobIndex = [this, column_family_id] (
|
||||
jbyteArray j_key, jbyteArray j_value) {
|
||||
m_env->CallVoidMethod(
|
||||
m_jcallback_obj,
|
||||
m_jPutBlobIndexCfMethodId,
|
||||
static_cast<jint>(column_family_id),
|
||||
j_key,
|
||||
j_value);
|
||||
};
|
||||
auto status = WriteBatchHandlerJniCallback::kv_op(key, value, putBlobIndex);
|
||||
if(status == nullptr) {
|
||||
return rocksdb::Status::OK(); // TODO(AR) what to do if there is an Exception but we don't know the rocksdb::Status?
|
||||
} else {
|
||||
return rocksdb::Status(*status);
|
||||
}
|
||||
}
|
||||
|
||||
rocksdb::Status WriteBatchHandlerJniCallback::MarkBeginPrepare() {
|
||||
m_env->CallVoidMethod(m_jcallback_obj, m_jMarkBeginPrepareMethodId);
|
||||
|
||||
// check for Exception, in-particular RocksDBException
|
||||
if (m_env->ExceptionCheck()) {
|
||||
// exception thrown
|
||||
m_env->ExceptionDescribe();
|
||||
if(j_blob != nullptr) {
|
||||
m_env->DeleteLocalRef(j_blob);
|
||||
jthrowable exception = m_env->ExceptionOccurred();
|
||||
std::unique_ptr<rocksdb::Status> status = rocksdb::RocksDBExceptionJni::toCppStatus(m_env, exception);
|
||||
if (status == nullptr) {
|
||||
// unkown status or exception occurred extracting status
|
||||
m_env->ExceptionDescribe();
|
||||
return rocksdb::Status::OK(); // TODO(AR) probably need a better error code here
|
||||
|
||||
} else {
|
||||
m_env->ExceptionClear(); // clear the exception, as we have extracted the status
|
||||
return rocksdb::Status(*status);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(j_blob != nullptr) {
|
||||
m_env->DeleteLocalRef(j_blob);
|
||||
return rocksdb::Status::OK();
|
||||
}
|
||||
|
||||
rocksdb::Status WriteBatchHandlerJniCallback::MarkEndPrepare(const Slice& xid) {
|
||||
auto markEndPrepare = [this] (
|
||||
jbyteArray j_xid) {
|
||||
m_env->CallVoidMethod(
|
||||
m_jcallback_obj,
|
||||
m_jMarkEndPrepareMethodId,
|
||||
j_xid);
|
||||
};
|
||||
auto status = WriteBatchHandlerJniCallback::k_op(xid, markEndPrepare);
|
||||
if(status == nullptr) {
|
||||
return rocksdb::Status::OK(); // TODO(AR) what to do if there is an Exception but we don't know the rocksdb::Status?
|
||||
} else {
|
||||
return rocksdb::Status(*status);
|
||||
}
|
||||
}
|
||||
|
||||
rocksdb::Status WriteBatchHandlerJniCallback::MarkNoop(bool empty_batch) {
|
||||
m_env->CallVoidMethod(m_jcallback_obj, m_jMarkNoopMethodId, static_cast<jboolean>(empty_batch));
|
||||
|
||||
// check for Exception, in-particular RocksDBException
|
||||
if (m_env->ExceptionCheck()) {
|
||||
// exception thrown
|
||||
jthrowable exception = m_env->ExceptionOccurred();
|
||||
std::unique_ptr<rocksdb::Status> status = rocksdb::RocksDBExceptionJni::toCppStatus(m_env, exception);
|
||||
if (status == nullptr) {
|
||||
// unkown status or exception occurred extracting status
|
||||
m_env->ExceptionDescribe();
|
||||
return rocksdb::Status::OK(); // TODO(AR) probably need a better error code here
|
||||
|
||||
} else {
|
||||
m_env->ExceptionClear(); // clear the exception, as we have extracted the status
|
||||
return rocksdb::Status(*status);
|
||||
}
|
||||
}
|
||||
|
||||
return rocksdb::Status::OK();
|
||||
}
|
||||
|
||||
rocksdb::Status WriteBatchHandlerJniCallback::MarkRollback(const Slice& xid) {
|
||||
auto markRollback = [this] (
|
||||
jbyteArray j_xid) {
|
||||
m_env->CallVoidMethod(
|
||||
m_jcallback_obj,
|
||||
m_jMarkRollbackMethodId,
|
||||
j_xid);
|
||||
};
|
||||
auto status = WriteBatchHandlerJniCallback::k_op(xid, markRollback);
|
||||
if(status == nullptr) {
|
||||
return rocksdb::Status::OK(); // TODO(AR) what to do if there is an Exception but we don't know the rocksdb::Status?
|
||||
} else {
|
||||
return rocksdb::Status(*status);
|
||||
}
|
||||
}
|
||||
|
||||
rocksdb::Status WriteBatchHandlerJniCallback::MarkCommit(const Slice& xid) {
|
||||
auto markCommit = [this] (
|
||||
jbyteArray j_xid) {
|
||||
m_env->CallVoidMethod(
|
||||
m_jcallback_obj,
|
||||
m_jMarkCommitMethodId,
|
||||
j_xid);
|
||||
};
|
||||
auto status = WriteBatchHandlerJniCallback::k_op(xid, markCommit);
|
||||
if(status == nullptr) {
|
||||
return rocksdb::Status::OK(); // TODO(AR) what to do if there is an Exception but we don't know the rocksdb::Status?
|
||||
} else {
|
||||
return rocksdb::Status(*status);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -256,39 +409,101 @@ bool WriteBatchHandlerJniCallback::Continue() {
|
||||
return static_cast<bool>(jContinue == JNI_TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a Java Byte Array from the data in a Slice
|
||||
*
|
||||
* When calling this function
|
||||
* you must remember to call env->DeleteLocalRef
|
||||
* on the result after you have finished with it
|
||||
*
|
||||
* @param s A Slice to convery to a Java byte array
|
||||
*
|
||||
* @return A reference to a Java byte array, or a nullptr if an
|
||||
* exception occurs
|
||||
*/
|
||||
jbyteArray WriteBatchHandlerJniCallback::sliceToJArray(const Slice& s) {
|
||||
|
||||
// TODO(AR) move to JniUtil
|
||||
|
||||
jbyteArray ja = m_env->NewByteArray(static_cast<jsize>(s.size()));
|
||||
if(ja == nullptr) {
|
||||
// exception thrown: OutOfMemoryError
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
m_env->SetByteArrayRegion(
|
||||
ja, 0, static_cast<jsize>(s.size()),
|
||||
const_cast<jbyte*>(reinterpret_cast<const jbyte*>(s.data())));
|
||||
if(m_env->ExceptionCheck()) {
|
||||
if(ja != nullptr) {
|
||||
m_env->DeleteLocalRef(ja);
|
||||
std::unique_ptr<rocksdb::Status> WriteBatchHandlerJniCallback::kv_op(const Slice& key, const Slice& value, std::function<void(jbyteArray, jbyteArray)> kvFn) {
|
||||
const jbyteArray j_key = JniUtil::copyBytes(m_env, key);
|
||||
if (j_key == nullptr) {
|
||||
// exception thrown
|
||||
if (m_env->ExceptionCheck()) {
|
||||
m_env->ExceptionDescribe();
|
||||
}
|
||||
// exception thrown: ArrayIndexOutOfBoundsException
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return ja;
|
||||
const jbyteArray j_value = JniUtil::copyBytes(m_env, value);
|
||||
if (j_value == nullptr) {
|
||||
// exception thrown
|
||||
if (m_env->ExceptionCheck()) {
|
||||
m_env->ExceptionDescribe();
|
||||
}
|
||||
if (j_key != nullptr) {
|
||||
m_env->DeleteLocalRef(j_key);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
kvFn(j_key, j_value);
|
||||
|
||||
// check for Exception, in-particular RocksDBException
|
||||
if (m_env->ExceptionCheck()) {
|
||||
if (j_value != nullptr) {
|
||||
m_env->DeleteLocalRef(j_value);
|
||||
}
|
||||
if (j_key != nullptr) {
|
||||
m_env->DeleteLocalRef(j_key);
|
||||
}
|
||||
|
||||
// exception thrown
|
||||
jthrowable exception = m_env->ExceptionOccurred();
|
||||
std::unique_ptr<rocksdb::Status> status = rocksdb::RocksDBExceptionJni::toCppStatus(m_env, exception);
|
||||
if (status == nullptr) {
|
||||
// unkown status or exception occurred extracting status
|
||||
m_env->ExceptionDescribe();
|
||||
return nullptr;
|
||||
|
||||
} else {
|
||||
m_env->ExceptionClear(); // clear the exception, as we have extracted the status
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
if (j_value != nullptr) {
|
||||
m_env->DeleteLocalRef(j_value);
|
||||
}
|
||||
if (j_key != nullptr) {
|
||||
m_env->DeleteLocalRef(j_key);
|
||||
}
|
||||
|
||||
// all OK
|
||||
return std::unique_ptr<rocksdb::Status>(new rocksdb::Status(rocksdb::Status::OK()));
|
||||
}
|
||||
|
||||
std::unique_ptr<rocksdb::Status> WriteBatchHandlerJniCallback::k_op(const Slice& key, std::function<void(jbyteArray)> kFn) {
|
||||
const jbyteArray j_key = JniUtil::copyBytes(m_env, key);
|
||||
if (j_key == nullptr) {
|
||||
// exception thrown
|
||||
if (m_env->ExceptionCheck()) {
|
||||
m_env->ExceptionDescribe();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
kFn(j_key);
|
||||
|
||||
// check for Exception, in-particular RocksDBException
|
||||
if (m_env->ExceptionCheck()) {
|
||||
if (j_key != nullptr) {
|
||||
m_env->DeleteLocalRef(j_key);
|
||||
}
|
||||
|
||||
// exception thrown
|
||||
jthrowable exception = m_env->ExceptionOccurred();
|
||||
std::unique_ptr<rocksdb::Status> status = rocksdb::RocksDBExceptionJni::toCppStatus(m_env, exception);
|
||||
if (status == nullptr) {
|
||||
// unkown status or exception occurred extracting status
|
||||
m_env->ExceptionDescribe();
|
||||
return nullptr;
|
||||
|
||||
} else {
|
||||
m_env->ExceptionClear(); // clear the exception, as we have extracted the status
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
if (j_key != nullptr) {
|
||||
m_env->DeleteLocalRef(j_key);
|
||||
}
|
||||
|
||||
// all OK
|
||||
return std::unique_ptr<rocksdb::Status>(new rocksdb::Status(rocksdb::Status::OK()));
|
||||
}
|
||||
} // namespace rocksdb
|
||||
|
||||
@@ -9,7 +9,9 @@
|
||||
#ifndef JAVA_ROCKSJNI_WRITEBATCHHANDLERJNICALLBACK_H_
|
||||
#define JAVA_ROCKSJNI_WRITEBATCHHANDLERJNICALLBACK_H_
|
||||
|
||||
#include <functional>
|
||||
#include <jni.h>
|
||||
#include <memory>
|
||||
#include "rocksjni/jnicallback.h"
|
||||
#include "rocksdb/write_batch.h"
|
||||
|
||||
@@ -25,22 +27,57 @@ class WriteBatchHandlerJniCallback : public JniCallback, public WriteBatch::Hand
|
||||
public:
|
||||
WriteBatchHandlerJniCallback(
|
||||
JNIEnv* env, jobject jWriteBackHandler);
|
||||
Status PutCF(uint32_t column_family_id, const Slice& key,
|
||||
const Slice& value);
|
||||
void Put(const Slice& key, const Slice& value);
|
||||
Status MergeCF(uint32_t column_family_id, const Slice& key,
|
||||
const Slice& value);
|
||||
void Merge(const Slice& key, const Slice& value);
|
||||
Status DeleteCF(uint32_t column_family_id, const Slice& key);
|
||||
void Delete(const Slice& key);
|
||||
Status SingleDeleteCF(uint32_t column_family_id, const Slice& key);
|
||||
void SingleDelete(const Slice& key);
|
||||
Status DeleteRangeCF(uint32_t column_family_id, const Slice& beginKey,
|
||||
const Slice& endKey);
|
||||
void DeleteRange(const Slice& beginKey, const Slice& endKey);
|
||||
void LogData(const Slice& blob);
|
||||
Status PutBlobIndexCF(uint32_t column_family_id, const Slice& key,
|
||||
const Slice& value);
|
||||
Status MarkBeginPrepare();
|
||||
Status MarkEndPrepare(const Slice& xid);
|
||||
Status MarkNoop(bool empty_batch);
|
||||
Status MarkRollback(const Slice& xid);
|
||||
Status MarkCommit(const Slice& xid);
|
||||
bool Continue();
|
||||
|
||||
private:
|
||||
JNIEnv* m_env;
|
||||
jbyteArray sliceToJArray(const Slice& s);
|
||||
jmethodID m_jPutCfMethodId;
|
||||
jmethodID m_jPutMethodId;
|
||||
jmethodID m_jMergeCfMethodId;
|
||||
jmethodID m_jMergeMethodId;
|
||||
jmethodID m_jDeleteCfMethodId;
|
||||
jmethodID m_jDeleteMethodId;
|
||||
jmethodID m_jSingleDeleteCfMethodId;
|
||||
jmethodID m_jSingleDeleteMethodId;
|
||||
jmethodID m_jDeleteRangeCfMethodId;
|
||||
jmethodID m_jDeleteRangeMethodId;
|
||||
jmethodID m_jLogDataMethodId;
|
||||
jmethodID m_jPutBlobIndexCfMethodId;
|
||||
jmethodID m_jMarkBeginPrepareMethodId;
|
||||
jmethodID m_jMarkEndPrepareMethodId;
|
||||
jmethodID m_jMarkNoopMethodId;
|
||||
jmethodID m_jMarkRollbackMethodId;
|
||||
jmethodID m_jMarkCommitMethodId;
|
||||
jmethodID m_jContinueMethodId;
|
||||
/**
|
||||
* @return A pointer to a rocksdb::Status or nullptr if an unexpected exception occurred
|
||||
*/
|
||||
std::unique_ptr<rocksdb::Status> kv_op(const Slice& key, const Slice& value, std::function<void(jbyteArray, jbyteArray)> kvFn);
|
||||
/**
|
||||
* @return A pointer to a rocksdb::Status or nullptr if an unexpected exception occurred
|
||||
*/
|
||||
std::unique_ptr<rocksdb::Status> k_op(const Slice& key, std::function<void(jbyteArray)> kFn);
|
||||
};
|
||||
} // namespace rocksdb
|
||||
|
||||
|
||||
@@ -0,0 +1,184 @@
|
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
import org.rocksdb.*;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
/**
|
||||
* Demonstrates using Transactions on an OptimisticTransactionDB with
|
||||
* varying isolation guarantees
|
||||
*/
|
||||
public class OptimisticTransactionSample {
|
||||
private static final String dbPath = "/tmp/rocksdb_optimistic_transaction_example";
|
||||
|
||||
public static final void main(final String args[]) throws RocksDBException {
|
||||
|
||||
try(final Options options = new Options()
|
||||
.setCreateIfMissing(true);
|
||||
final OptimisticTransactionDB txnDb =
|
||||
OptimisticTransactionDB.open(options, dbPath)) {
|
||||
|
||||
try (final WriteOptions writeOptions = new WriteOptions();
|
||||
final ReadOptions readOptions = new ReadOptions()) {
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
//
|
||||
// Simple OptimisticTransaction Example ("Read Committed")
|
||||
//
|
||||
////////////////////////////////////////////////////////
|
||||
readCommitted(txnDb, writeOptions, readOptions);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
//
|
||||
// "Repeatable Read" (Snapshot Isolation) Example
|
||||
// -- Using a single Snapshot
|
||||
//
|
||||
////////////////////////////////////////////////////////
|
||||
repeatableRead(txnDb, writeOptions, readOptions);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
//
|
||||
// "Read Committed" (Monotonic Atomic Views) Example
|
||||
// --Using multiple Snapshots
|
||||
//
|
||||
////////////////////////////////////////////////////////
|
||||
readCommitted_monotonicAtomicViews(txnDb, writeOptions, readOptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Demonstrates "Read Committed" isolation
|
||||
*/
|
||||
private static void readCommitted(final OptimisticTransactionDB txnDb,
|
||||
final WriteOptions writeOptions, final ReadOptions readOptions)
|
||||
throws RocksDBException {
|
||||
final byte key1[] = "abc".getBytes(UTF_8);
|
||||
final byte value1[] = "def".getBytes(UTF_8);
|
||||
|
||||
final byte key2[] = "xyz".getBytes(UTF_8);
|
||||
final byte value2[] = "zzz".getBytes(UTF_8);
|
||||
|
||||
// Start a transaction
|
||||
try(final Transaction txn = txnDb.beginTransaction(writeOptions)) {
|
||||
// Read a key in this transaction
|
||||
byte[] value = txn.get(readOptions, key1);
|
||||
assert(value == null);
|
||||
|
||||
// Write a key in this transaction
|
||||
txn.put(key1, value1);
|
||||
|
||||
// Read a key OUTSIDE this transaction. Does not affect txn.
|
||||
value = txnDb.get(readOptions, key1);
|
||||
assert(value == null);
|
||||
|
||||
// Write a key OUTSIDE of this transaction.
|
||||
// Does not affect txn since this is an unrelated key.
|
||||
// If we wrote key 'abc' here, the transaction would fail to commit.
|
||||
txnDb.put(writeOptions, key2, value2);
|
||||
|
||||
// Commit transaction
|
||||
txn.commit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Demonstrates "Repeatable Read" (Snapshot Isolation) isolation
|
||||
*/
|
||||
private static void repeatableRead(final OptimisticTransactionDB txnDb,
|
||||
final WriteOptions writeOptions, final ReadOptions readOptions)
|
||||
throws RocksDBException {
|
||||
|
||||
final byte key1[] = "ghi".getBytes(UTF_8);
|
||||
final byte value1[] = "jkl".getBytes(UTF_8);
|
||||
|
||||
// Set a snapshot at start of transaction by setting setSnapshot(true)
|
||||
try(final OptimisticTransactionOptions txnOptions =
|
||||
new OptimisticTransactionOptions().setSetSnapshot(true);
|
||||
final Transaction txn =
|
||||
txnDb.beginTransaction(writeOptions, txnOptions)) {
|
||||
|
||||
final Snapshot snapshot = txn.getSnapshot();
|
||||
|
||||
// Write a key OUTSIDE of transaction
|
||||
txnDb.put(writeOptions, key1, value1);
|
||||
|
||||
// Read a key using the snapshot.
|
||||
readOptions.setSnapshot(snapshot);
|
||||
final byte[] value = txn.getForUpdate(readOptions, key1, true);
|
||||
assert(value == value1);
|
||||
|
||||
try {
|
||||
// Attempt to commit transaction
|
||||
txn.commit();
|
||||
throw new IllegalStateException();
|
||||
} catch(final RocksDBException e) {
|
||||
// Transaction could not commit since the write outside of the txn
|
||||
// conflicted with the read!
|
||||
assert(e.getStatus().getCode() == Status.Code.Busy);
|
||||
}
|
||||
|
||||
txn.rollback();
|
||||
} finally {
|
||||
// Clear snapshot from read options since it is no longer valid
|
||||
readOptions.setSnapshot(null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Demonstrates "Read Committed" (Monotonic Atomic Views) isolation
|
||||
*
|
||||
* In this example, we set the snapshot multiple times. This is probably
|
||||
* only necessary if you have very strict isolation requirements to
|
||||
* implement.
|
||||
*/
|
||||
private static void readCommitted_monotonicAtomicViews(
|
||||
final OptimisticTransactionDB txnDb, final WriteOptions writeOptions,
|
||||
final ReadOptions readOptions) throws RocksDBException {
|
||||
|
||||
final byte keyX[] = "x".getBytes(UTF_8);
|
||||
final byte valueX[] = "x".getBytes(UTF_8);
|
||||
|
||||
final byte keyY[] = "y".getBytes(UTF_8);
|
||||
final byte valueY[] = "y".getBytes(UTF_8);
|
||||
|
||||
try (final OptimisticTransactionOptions txnOptions =
|
||||
new OptimisticTransactionOptions().setSetSnapshot(true);
|
||||
final Transaction txn =
|
||||
txnDb.beginTransaction(writeOptions, txnOptions)) {
|
||||
|
||||
// Do some reads and writes to key "x"
|
||||
Snapshot snapshot = txnDb.getSnapshot();
|
||||
readOptions.setSnapshot(snapshot);
|
||||
byte[] value = txn.get(readOptions, keyX);
|
||||
txn.put(valueX, valueX);
|
||||
|
||||
// Do a write outside of the transaction to key "y"
|
||||
txnDb.put(writeOptions, keyY, valueY);
|
||||
|
||||
// Set a new snapshot in the transaction
|
||||
txn.setSnapshot();
|
||||
snapshot = txnDb.getSnapshot();
|
||||
readOptions.setSnapshot(snapshot);
|
||||
|
||||
// Do some reads and writes to key "y"
|
||||
// Since the snapshot was advanced, the write done outside of the
|
||||
// transaction does not conflict.
|
||||
value = txn.getForUpdate(readOptions, keyY, true);
|
||||
txn.put(keyY, valueY);
|
||||
|
||||
// Commit. Since the snapshot was advanced, the write done outside of the
|
||||
// transaction does not prevent this transaction from Committing.
|
||||
txn.commit();
|
||||
|
||||
} finally {
|
||||
// Clear snapshot from read options since it is no longer valid
|
||||
readOptions.setSnapshot(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
import org.rocksdb.*;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
/**
|
||||
* Demonstrates using Transactions on a TransactionDB with
|
||||
* varying isolation guarantees
|
||||
*/
|
||||
public class TransactionSample {
|
||||
private static final String dbPath = "/tmp/rocksdb_transaction_example";
|
||||
|
||||
public static final void main(final String args[]) throws RocksDBException {
|
||||
|
||||
try(final Options options = new Options()
|
||||
.setCreateIfMissing(true);
|
||||
final TransactionDBOptions txnDbOptions = new TransactionDBOptions();
|
||||
final TransactionDB txnDb =
|
||||
TransactionDB.open(options, txnDbOptions, dbPath)) {
|
||||
|
||||
try (final WriteOptions writeOptions = new WriteOptions();
|
||||
final ReadOptions readOptions = new ReadOptions()) {
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
//
|
||||
// Simple Transaction Example ("Read Committed")
|
||||
//
|
||||
////////////////////////////////////////////////////////
|
||||
readCommitted(txnDb, writeOptions, readOptions);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
//
|
||||
// "Repeatable Read" (Snapshot Isolation) Example
|
||||
// -- Using a single Snapshot
|
||||
//
|
||||
////////////////////////////////////////////////////////
|
||||
repeatableRead(txnDb, writeOptions, readOptions);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
//
|
||||
// "Read Committed" (Monotonic Atomic Views) Example
|
||||
// --Using multiple Snapshots
|
||||
//
|
||||
////////////////////////////////////////////////////////
|
||||
readCommitted_monotonicAtomicViews(txnDb, writeOptions, readOptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Demonstrates "Read Committed" isolation
|
||||
*/
|
||||
private static void readCommitted(final TransactionDB txnDb,
|
||||
final WriteOptions writeOptions, final ReadOptions readOptions)
|
||||
throws RocksDBException {
|
||||
final byte key1[] = "abc".getBytes(UTF_8);
|
||||
final byte value1[] = "def".getBytes(UTF_8);
|
||||
|
||||
final byte key2[] = "xyz".getBytes(UTF_8);
|
||||
final byte value2[] = "zzz".getBytes(UTF_8);
|
||||
|
||||
// Start a transaction
|
||||
try(final Transaction txn = txnDb.beginTransaction(writeOptions)) {
|
||||
// Read a key in this transaction
|
||||
byte[] value = txn.get(readOptions, key1);
|
||||
assert(value == null);
|
||||
|
||||
// Write a key in this transaction
|
||||
txn.put(key1, value1);
|
||||
|
||||
// Read a key OUTSIDE this transaction. Does not affect txn.
|
||||
value = txnDb.get(readOptions, key1);
|
||||
assert(value == null);
|
||||
|
||||
// Write a key OUTSIDE of this transaction.
|
||||
// Does not affect txn since this is an unrelated key.
|
||||
// If we wrote key 'abc' here, the transaction would fail to commit.
|
||||
txnDb.put(writeOptions, key2, value2);
|
||||
|
||||
// Commit transaction
|
||||
txn.commit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Demonstrates "Repeatable Read" (Snapshot Isolation) isolation
|
||||
*/
|
||||
private static void repeatableRead(final TransactionDB txnDb,
|
||||
final WriteOptions writeOptions, final ReadOptions readOptions)
|
||||
throws RocksDBException {
|
||||
|
||||
final byte key1[] = "ghi".getBytes(UTF_8);
|
||||
final byte value1[] = "jkl".getBytes(UTF_8);
|
||||
|
||||
// Set a snapshot at start of transaction by setting setSnapshot(true)
|
||||
try(final TransactionOptions txnOptions = new TransactionOptions()
|
||||
.setSetSnapshot(true);
|
||||
final Transaction txn =
|
||||
txnDb.beginTransaction(writeOptions, txnOptions)) {
|
||||
|
||||
final Snapshot snapshot = txn.getSnapshot();
|
||||
|
||||
// Write a key OUTSIDE of transaction
|
||||
txnDb.put(writeOptions, key1, value1);
|
||||
|
||||
// Attempt to read a key using the snapshot. This will fail since
|
||||
// the previous write outside this txn conflicts with this read.
|
||||
readOptions.setSnapshot(snapshot);
|
||||
|
||||
try {
|
||||
final byte[] value = txn.getForUpdate(readOptions, key1, true);
|
||||
throw new IllegalStateException();
|
||||
} catch(final RocksDBException e) {
|
||||
assert(e.getStatus().getCode() == Status.Code.Busy);
|
||||
}
|
||||
|
||||
txn.rollback();
|
||||
} finally {
|
||||
// Clear snapshot from read options since it is no longer valid
|
||||
readOptions.setSnapshot(null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Demonstrates "Read Committed" (Monotonic Atomic Views) isolation
|
||||
*
|
||||
* In this example, we set the snapshot multiple times. This is probably
|
||||
* only necessary if you have very strict isolation requirements to
|
||||
* implement.
|
||||
*/
|
||||
private static void readCommitted_monotonicAtomicViews(
|
||||
final TransactionDB txnDb, final WriteOptions writeOptions,
|
||||
final ReadOptions readOptions) throws RocksDBException {
|
||||
|
||||
final byte keyX[] = "x".getBytes(UTF_8);
|
||||
final byte valueX[] = "x".getBytes(UTF_8);
|
||||
|
||||
final byte keyY[] = "y".getBytes(UTF_8);
|
||||
final byte valueY[] = "y".getBytes(UTF_8);
|
||||
|
||||
try (final TransactionOptions txnOptions = new TransactionOptions()
|
||||
.setSetSnapshot(true);
|
||||
final Transaction txn =
|
||||
txnDb.beginTransaction(writeOptions, txnOptions)) {
|
||||
|
||||
// Do some reads and writes to key "x"
|
||||
Snapshot snapshot = txnDb.getSnapshot();
|
||||
readOptions.setSnapshot(snapshot);
|
||||
byte[] value = txn.get(readOptions, keyX);
|
||||
txn.put(valueX, valueX);
|
||||
|
||||
// Do a write outside of the transaction to key "y"
|
||||
txnDb.put(writeOptions, keyY, valueY);
|
||||
|
||||
// Set a new snapshot in the transaction
|
||||
txn.setSnapshot();
|
||||
txn.setSavePoint();
|
||||
snapshot = txnDb.getSnapshot();
|
||||
readOptions.setSnapshot(snapshot);
|
||||
|
||||
// Do some reads and writes to key "y"
|
||||
// Since the snapshot was advanced, the write done outside of the
|
||||
// transaction does not conflict.
|
||||
value = txn.getForUpdate(readOptions, keyY, true);
|
||||
txn.put(keyY, valueY);
|
||||
|
||||
// Decide we want to revert the last write from this transaction.
|
||||
txn.rollbackToSavePoint();
|
||||
|
||||
// Commit.
|
||||
txn.commit();
|
||||
} finally {
|
||||
// Clear snapshot from read options since it is no longer valid
|
||||
readOptions.setSnapshot(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,10 +17,23 @@ package org.rocksdb;
|
||||
public abstract class AbstractComparator<T extends AbstractSlice<?>>
|
||||
extends RocksCallbackObject {
|
||||
|
||||
protected AbstractComparator() {
|
||||
super();
|
||||
}
|
||||
|
||||
protected AbstractComparator(final ComparatorOptions copt) {
|
||||
super(copt.nativeHandle_);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the type of this comparator.
|
||||
*
|
||||
* Used for determining the correct C++ cast in native code.
|
||||
*
|
||||
* @return The type of the comparator.
|
||||
*/
|
||||
abstract ComparatorType getComparatorType();
|
||||
|
||||
/**
|
||||
* The name of the comparator. Used to check for comparator
|
||||
* mismatches (i.e., a DB created with one comparator is
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
package org.rocksdb;
|
||||
|
||||
/**
|
||||
* Provides notification to the caller of SetSnapshotOnNextOperation when
|
||||
* the actual snapshot gets created
|
||||
*/
|
||||
public abstract class AbstractTransactionNotifier
|
||||
extends RocksCallbackObject {
|
||||
|
||||
protected AbstractTransactionNotifier() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement this method to receive notification when a snapshot is
|
||||
* requested via {@link Transaction#setSnapshotOnNextOperation()}.
|
||||
*
|
||||
* @param newSnapshot the snapshot that has been created.
|
||||
*/
|
||||
public abstract void snapshotCreated(final Snapshot newSnapshot);
|
||||
|
||||
/**
|
||||
* This is intentionally private as it is the callback hook
|
||||
* from JNI
|
||||
*/
|
||||
private void snapshotCreated(final long snapshotHandle) {
|
||||
snapshotCreated(new Snapshot(snapshotHandle));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long initializeNative(final long... nativeParameterHandles) {
|
||||
return createNewTransactionNotifier();
|
||||
}
|
||||
|
||||
private native long createNewTransactionNotifier();
|
||||
|
||||
/**
|
||||
* Deletes underlying C++ TransactionNotifier pointer.
|
||||
*
|
||||
* Note that this function should be called only after all
|
||||
* Transactions referencing the comparator are closed.
|
||||
* Otherwise an undefined behavior will occur.
|
||||
*/
|
||||
@Override
|
||||
protected void disposeInternal() {
|
||||
disposeInternal(nativeHandle_);
|
||||
}
|
||||
protected final native void disposeInternal(final long handle);
|
||||
}
|
||||
@@ -18,52 +18,80 @@ public abstract class AbstractWriteBatch extends RocksObject
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(byte[] key, byte[] value) {
|
||||
public void put(byte[] key, byte[] value) throws RocksDBException {
|
||||
put(nativeHandle_, key, key.length, value, value.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(ColumnFamilyHandle columnFamilyHandle, byte[] key,
|
||||
byte[] value) {
|
||||
byte[] value) throws RocksDBException {
|
||||
put(nativeHandle_, key, key.length, value, value.length,
|
||||
columnFamilyHandle.nativeHandle_);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void merge(byte[] key, byte[] value) {
|
||||
public void merge(byte[] key, byte[] value) throws RocksDBException {
|
||||
merge(nativeHandle_, key, key.length, value, value.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void merge(ColumnFamilyHandle columnFamilyHandle, byte[] key,
|
||||
byte[] value) {
|
||||
byte[] value) throws RocksDBException {
|
||||
merge(nativeHandle_, key, key.length, value, value.length,
|
||||
columnFamilyHandle.nativeHandle_);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(byte[] key) {
|
||||
remove(nativeHandle_, key, key.length);
|
||||
@Deprecated
|
||||
public void remove(byte[] key) throws RocksDBException {
|
||||
delete(nativeHandle_, key, key.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(ColumnFamilyHandle columnFamilyHandle, byte[] key) {
|
||||
remove(nativeHandle_, key, key.length, columnFamilyHandle.nativeHandle_);
|
||||
@Deprecated
|
||||
public void remove(ColumnFamilyHandle columnFamilyHandle, byte[] key)
|
||||
throws RocksDBException {
|
||||
delete(nativeHandle_, key, key.length, columnFamilyHandle.nativeHandle_);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteRange(byte[] beginKey, byte[] endKey) {
|
||||
public void delete(byte[] key) throws RocksDBException {
|
||||
delete(nativeHandle_, key, key.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(ColumnFamilyHandle columnFamilyHandle, byte[] key)
|
||||
throws RocksDBException {
|
||||
delete(nativeHandle_, key, key.length, columnFamilyHandle.nativeHandle_);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void singleDelete(byte[] key) throws RocksDBException {
|
||||
singleDelete(nativeHandle_, key, key.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void singleDelete(ColumnFamilyHandle columnFamilyHandle, byte[] key)
|
||||
throws RocksDBException {
|
||||
singleDelete(nativeHandle_, key, key.length, columnFamilyHandle.nativeHandle_);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteRange(byte[] beginKey, byte[] endKey)
|
||||
throws RocksDBException {
|
||||
deleteRange(nativeHandle_, beginKey, beginKey.length, endKey, endKey.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteRange(ColumnFamilyHandle columnFamilyHandle, byte[] beginKey, byte[] endKey) {
|
||||
public void deleteRange(ColumnFamilyHandle columnFamilyHandle,
|
||||
byte[] beginKey, byte[] endKey) throws RocksDBException {
|
||||
deleteRange(nativeHandle_, beginKey, beginKey.length, endKey, endKey.length,
|
||||
columnFamilyHandle.nativeHandle_);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putLogData(byte[] blob) {
|
||||
public void putLogData(byte[] blob) throws RocksDBException {
|
||||
putLogData(nativeHandle_, blob, blob.length);
|
||||
}
|
||||
|
||||
@@ -82,38 +110,67 @@ public abstract class AbstractWriteBatch extends RocksObject
|
||||
rollbackToSavePoint0(nativeHandle_);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void popSavePoint() throws RocksDBException {
|
||||
popSavePoint(nativeHandle_);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxBytes(final long maxBytes) {
|
||||
setMaxBytes(nativeHandle_, maxBytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WriteBatch getWriteBatch() {
|
||||
return getWriteBatch(nativeHandle_);
|
||||
}
|
||||
|
||||
abstract int count0(final long handle);
|
||||
|
||||
abstract void put(final long handle, final byte[] key, final int keyLen,
|
||||
final byte[] value, final int valueLen);
|
||||
final byte[] value, final int valueLen) throws RocksDBException;
|
||||
|
||||
abstract void put(final long handle, final byte[] key, final int keyLen,
|
||||
final byte[] value, final int valueLen, final long cfHandle);
|
||||
final byte[] value, final int valueLen, final long cfHandle)
|
||||
throws RocksDBException;
|
||||
|
||||
abstract void merge(final long handle, final byte[] key, final int keyLen,
|
||||
final byte[] value, final int valueLen);
|
||||
final byte[] value, final int valueLen) throws RocksDBException;
|
||||
|
||||
abstract void merge(final long handle, final byte[] key, final int keyLen,
|
||||
final byte[] value, final int valueLen, final long cfHandle);
|
||||
final byte[] value, final int valueLen, final long cfHandle)
|
||||
throws RocksDBException;
|
||||
|
||||
abstract void remove(final long handle, final byte[] key,
|
||||
final int keyLen);
|
||||
abstract void delete(final long handle, final byte[] key,
|
||||
final int keyLen) throws RocksDBException;
|
||||
|
||||
abstract void remove(final long handle, final byte[] key,
|
||||
final int keyLen, final long cfHandle);
|
||||
abstract void delete(final long handle, final byte[] key,
|
||||
final int keyLen, final long cfHandle) throws RocksDBException;
|
||||
|
||||
abstract void singleDelete(final long handle, final byte[] key,
|
||||
final int keyLen) throws RocksDBException;
|
||||
|
||||
abstract void singleDelete(final long handle, final byte[] key,
|
||||
final int keyLen, final long cfHandle) throws RocksDBException;
|
||||
|
||||
abstract void deleteRange(final long handle, final byte[] beginKey, final int beginKeyLen,
|
||||
final byte[] endKey, final int endKeyLen);
|
||||
final byte[] endKey, final int endKeyLen) throws RocksDBException;
|
||||
|
||||
abstract void deleteRange(final long handle, final byte[] beginKey, final int beginKeyLen,
|
||||
final byte[] endKey, final int endKeyLen, final long cfHandle);
|
||||
final byte[] endKey, final int endKeyLen, final long cfHandle) throws RocksDBException;
|
||||
|
||||
abstract void putLogData(final long handle, final byte[] blob,
|
||||
final int blobLen);
|
||||
final int blobLen) throws RocksDBException;
|
||||
|
||||
abstract void clear0(final long handle);
|
||||
|
||||
abstract void setSavePoint0(final long handle);
|
||||
|
||||
abstract void rollbackToSavePoint0(final long handle);
|
||||
|
||||
abstract void popSavePoint(final long handle) throws RocksDBException;
|
||||
|
||||
abstract void setMaxBytes(final long handle, long maxBytes);
|
||||
|
||||
abstract WriteBatch getWriteBatch(final long handle);
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ public class BlockBasedTableConfig extends TableFormatConfig {
|
||||
noBlockCache_ = false;
|
||||
blockCacheSize_ = 8 * 1024 * 1024;
|
||||
blockCacheNumShardBits_ = 0;
|
||||
blockCache_ = null;
|
||||
blockSize_ = 4 * 1024;
|
||||
blockSizeDeviation_ = 10;
|
||||
blockRestartInterval_ = 16;
|
||||
@@ -71,6 +72,24 @@ public class BlockBasedTableConfig extends TableFormatConfig {
|
||||
return blockCacheSize_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the specified cache for blocks.
|
||||
* When not null this take precedence even if the user sets a block cache size.
|
||||
*
|
||||
* {@link org.rocksdb.Cache} should not be disposed before options instances
|
||||
* using this cache is disposed.
|
||||
*
|
||||
* {@link org.rocksdb.Cache} instance can be re-used in multiple options
|
||||
* instances.
|
||||
*
|
||||
* @param cache {@link org.rocksdb.Cache} Cache java instance (e.g. LRUCache).
|
||||
* @return the reference to the current config.
|
||||
*/
|
||||
public BlockBasedTableConfig setBlockCache(final Cache cache) {
|
||||
blockCache_ = cache;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Controls the number of shards for the block cache.
|
||||
* This is applied only if cacheSize is set to non-negative.
|
||||
@@ -413,25 +432,25 @@ public class BlockBasedTableConfig extends TableFormatConfig {
|
||||
filterHandle = filter_.nativeHandle_;
|
||||
}
|
||||
|
||||
return newTableFactoryHandle(noBlockCache_, blockCacheSize_,
|
||||
blockCacheNumShardBits_, blockSize_, blockSizeDeviation_,
|
||||
blockRestartInterval_, wholeKeyFiltering_,
|
||||
filterHandle, cacheIndexAndFilterBlocks_,
|
||||
pinL0FilterAndIndexBlocksInCache_,
|
||||
hashIndexAllowCollision_, blockCacheCompressedSize_,
|
||||
blockCacheCompressedNumShardBits_,
|
||||
checksumType_.getValue(), indexType_.getValue(),
|
||||
long blockCacheHandle = 0;
|
||||
if (blockCache_ != null) {
|
||||
blockCacheHandle = blockCache_.nativeHandle_;
|
||||
}
|
||||
|
||||
return newTableFactoryHandle(noBlockCache_, blockCacheSize_, blockCacheNumShardBits_,
|
||||
blockCacheHandle, blockSize_, blockSizeDeviation_, blockRestartInterval_,
|
||||
wholeKeyFiltering_, filterHandle, cacheIndexAndFilterBlocks_,
|
||||
pinL0FilterAndIndexBlocksInCache_, hashIndexAllowCollision_, blockCacheCompressedSize_,
|
||||
blockCacheCompressedNumShardBits_, checksumType_.getValue(), indexType_.getValue(),
|
||||
formatVersion_);
|
||||
}
|
||||
|
||||
private native long newTableFactoryHandle(
|
||||
boolean noBlockCache, long blockCacheSize, int blockCacheNumShardBits,
|
||||
long blockSize, int blockSizeDeviation, int blockRestartInterval,
|
||||
boolean wholeKeyFiltering, long filterPolicyHandle,
|
||||
private native long newTableFactoryHandle(boolean noBlockCache, long blockCacheSize,
|
||||
int blockCacheNumShardBits, long blockCacheHandle, long blockSize, int blockSizeDeviation,
|
||||
int blockRestartInterval, boolean wholeKeyFiltering, long filterPolicyHandle,
|
||||
boolean cacheIndexAndFilterBlocks, boolean pinL0FilterAndIndexBlocksInCache,
|
||||
boolean hashIndexAllowCollision, long blockCacheCompressedSize,
|
||||
int blockCacheCompressedNumShardBits, byte checkSumType,
|
||||
byte indexType, int formatVersion);
|
||||
int blockCacheCompressedNumShardBits, byte checkSumType, byte indexType, int formatVersion);
|
||||
|
||||
private boolean cacheIndexAndFilterBlocks_;
|
||||
private boolean pinL0FilterAndIndexBlocksInCache_;
|
||||
@@ -442,6 +461,7 @@ public class BlockBasedTableConfig extends TableFormatConfig {
|
||||
private long blockSize_;
|
||||
private long blockCacheSize_;
|
||||
private int blockCacheNumShardBits_;
|
||||
private Cache blockCache_;
|
||||
private long blockCacheCompressedSize_;
|
||||
private int blockCacheCompressedNumShardBits_;
|
||||
private int blockSizeDeviation_;
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
|
||||
package org.rocksdb;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* <p>Describes a column family with a
|
||||
* name and respective Options.</p>
|
||||
@@ -32,7 +34,7 @@ public class ColumnFamilyDescriptor {
|
||||
* @since 3.10.0
|
||||
*/
|
||||
public ColumnFamilyDescriptor(final byte[] columnFamilyName,
|
||||
final ColumnFamilyOptions columnFamilyOptions) {
|
||||
final ColumnFamilyOptions columnFamilyOptions) {
|
||||
columnFamilyName_ = columnFamilyName;
|
||||
columnFamilyOptions_ = columnFamilyOptions;
|
||||
}
|
||||
@@ -43,19 +45,65 @@ public class ColumnFamilyDescriptor {
|
||||
* @return column family name.
|
||||
* @since 3.10.0
|
||||
*/
|
||||
public byte[] columnFamilyName() {
|
||||
public byte[] getName() {
|
||||
return columnFamilyName_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve name of column family.
|
||||
*
|
||||
* @return column family name.
|
||||
* @since 3.10.0
|
||||
*
|
||||
* @deprecated Use {@link #getName()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public byte[] columnFamilyName() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve assigned options instance.
|
||||
*
|
||||
* @return Options instance assigned to this instance.
|
||||
*/
|
||||
public ColumnFamilyOptions columnFamilyOptions() {
|
||||
public ColumnFamilyOptions getOptions() {
|
||||
return columnFamilyOptions_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve assigned options instance.
|
||||
*
|
||||
* @return Options instance assigned to this instance.
|
||||
*
|
||||
* @deprecated Use {@link #getOptions()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public ColumnFamilyOptions columnFamilyOptions() {
|
||||
return getOptions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final ColumnFamilyDescriptor that = (ColumnFamilyDescriptor) o;
|
||||
return Arrays.equals(columnFamilyName_, that.columnFamilyName_)
|
||||
&& columnFamilyOptions_.nativeHandle_ == that.columnFamilyOptions_.nativeHandle_;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = (int) (columnFamilyOptions_.nativeHandle_ ^ (columnFamilyOptions_.nativeHandle_ >>> 32));
|
||||
result = 31 * result + Arrays.hashCode(columnFamilyName_);
|
||||
return result;
|
||||
}
|
||||
|
||||
private final byte[] columnFamilyName_;
|
||||
private final ColumnFamilyOptions columnFamilyOptions_;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
|
||||
package org.rocksdb;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* ColumnFamilyHandle class to hold handles to underlying rocksdb
|
||||
* ColumnFamily Pointers.
|
||||
@@ -21,6 +24,63 @@ public class ColumnFamilyHandle extends RocksObject {
|
||||
this.rocksDB_ = rocksDB;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the Column Family.
|
||||
*
|
||||
* @return The name of the Column Family.
|
||||
*/
|
||||
public byte[] getName() {
|
||||
return getName(nativeHandle_);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ID of the Column Family.
|
||||
*
|
||||
* @return the ID of the Column Family.
|
||||
*/
|
||||
public int getID() {
|
||||
return getID(nativeHandle_);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the up-to-date descriptor of the column family
|
||||
* associated with this handle. Since it fills "*desc" with the up-to-date
|
||||
* information, this call might internally lock and release DB mutex to
|
||||
* access the up-to-date CF options. In addition, all the pointer-typed
|
||||
* options cannot be referenced any longer than the original options exist.
|
||||
*
|
||||
* Note that this function is not supported in RocksDBLite.
|
||||
*
|
||||
* @return the up-to-date descriptor.
|
||||
*
|
||||
* @throws RocksDBException if an error occurs whilst retrieving the
|
||||
* descriptor.
|
||||
*/
|
||||
public ColumnFamilyDescriptor getDescriptor() throws RocksDBException {
|
||||
assert(isOwningHandle());
|
||||
return getDescriptor(nativeHandle_);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final ColumnFamilyHandle that = (ColumnFamilyHandle) o;
|
||||
return rocksDB_.nativeHandle_ == that.rocksDB_.nativeHandle_ &&
|
||||
getID() == that.getID() &&
|
||||
Arrays.equals(getName(), that.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(getName(), getID(), rocksDB_.nativeHandle_);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Deletes underlying C++ iterator pointer.</p>
|
||||
*
|
||||
@@ -36,6 +96,9 @@ public class ColumnFamilyHandle extends RocksObject {
|
||||
}
|
||||
}
|
||||
|
||||
private native byte[] getName(final long handle);
|
||||
private native int getID(final long handle);
|
||||
private native ColumnFamilyDescriptor getDescriptor(final long handle) throws RocksDBException;
|
||||
@Override protected final native void disposeInternal(final long handle);
|
||||
|
||||
private final RocksDB rocksDB_;
|
||||
|
||||
@@ -53,6 +53,18 @@ public class ColumnFamilyOptions extends RocksObject
|
||||
this.compressionOptions_ = other.compressionOptions_;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Constructor to be used by
|
||||
* {@link #getColumnFamilyOptionsFromProps(java.util.Properties)},
|
||||
* {@link ColumnFamilyDescriptor#columnFamilyOptions()}
|
||||
* and also called via JNI.</p>
|
||||
*
|
||||
* @param handle native handle to ColumnFamilyOptions instance.
|
||||
*/
|
||||
ColumnFamilyOptions(final long handle) {
|
||||
super(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Method to get a options instance by using pre-configured
|
||||
* property values. If one or many values are undefined in
|
||||
@@ -151,7 +163,7 @@ public class ColumnFamilyOptions extends RocksObject
|
||||
final AbstractComparator<? extends AbstractSlice<?>> comparator) {
|
||||
assert (isOwningHandle());
|
||||
setComparatorHandle(nativeHandle_, comparator.nativeHandle_,
|
||||
comparator instanceof DirectComparator);
|
||||
comparator.getComparatorType().getValue());
|
||||
comparator_ = comparator;
|
||||
return this;
|
||||
}
|
||||
@@ -788,17 +800,6 @@ public class ColumnFamilyOptions extends RocksObject
|
||||
return forceConsistencyChecks(nativeHandle_);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Constructor to be used by
|
||||
* {@link #getColumnFamilyOptionsFromProps(java.util.Properties)}</p>
|
||||
* and also called via JNI.
|
||||
*
|
||||
* @param handle native handle to ColumnFamilyOptions instance.
|
||||
*/
|
||||
public ColumnFamilyOptions(final long handle) {
|
||||
super(handle);
|
||||
}
|
||||
|
||||
private static native long getColumnFamilyOptionsFromProps(
|
||||
String optString);
|
||||
|
||||
@@ -815,7 +816,7 @@ public class ColumnFamilyOptions extends RocksObject
|
||||
long memtableMemoryBudget);
|
||||
private native void setComparatorHandle(long handle, int builtinComparator);
|
||||
private native void setComparatorHandle(long optHandle,
|
||||
long comparatorHandle, boolean isDirect);
|
||||
long comparatorHandle, byte comparatorType);
|
||||
private native void setMergeOperatorName(long handle, String name);
|
||||
private native void setMergeOperator(long handle, long mergeOperatorHandle);
|
||||
private native void setCompactionFilterHandle(long handle,
|
||||
|
||||
@@ -25,5 +25,10 @@ public abstract class Comparator extends AbstractComparator<Slice> {
|
||||
return createNewComparator0(nativeParameterHandles[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
final ComparatorType getComparatorType() {
|
||||
return ComparatorType.JAVA_COMPARATOR;
|
||||
}
|
||||
|
||||
private native long createNewComparator0(final long comparatorOptionsHandle);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
package org.rocksdb;
|
||||
|
||||
enum ComparatorType {
|
||||
JAVA_COMPARATOR((byte)0x0),
|
||||
JAVA_DIRECT_COMPARATOR((byte)0x1),
|
||||
JAVA_NATIVE_COMPARATOR_WRAPPER((byte)0x2);
|
||||
|
||||
private final byte value;
|
||||
|
||||
ComparatorType(final byte value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns the byte value of the enumerations value.</p>
|
||||
*
|
||||
* @return byte representation
|
||||
*/
|
||||
byte getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Get the ComparatorType enumeration value by
|
||||
* passing the byte identifier to this method.</p>
|
||||
*
|
||||
* @param byteIdentifier of ComparatorType.
|
||||
*
|
||||
* @return ComparatorType instance.
|
||||
*
|
||||
* @throws IllegalArgumentException if the comparator type for the byteIdentifier
|
||||
* cannot be found
|
||||
*/
|
||||
static ComparatorType getComparatorType(final byte byteIdentifier) {
|
||||
for (final ComparatorType comparatorType : ComparatorType.values()) {
|
||||
if (comparatorType.getValue() == byteIdentifier) {
|
||||
return comparatorType;
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(
|
||||
"Illegal value provided for ComparatorType.");
|
||||
}
|
||||
}
|
||||
@@ -269,7 +269,10 @@ public interface DBOptionsInterface<T extends DBOptionsInterface> {
|
||||
* Statistics objects should not be shared between DB instances as
|
||||
* it does not use any locks to prevent concurrent updates.</p>
|
||||
*
|
||||
* @param statistics The statistics to set
|
||||
*
|
||||
* @return the instance of the current object.
|
||||
*
|
||||
* @see RocksDB#open(org.rocksdb.Options, String)
|
||||
*/
|
||||
T setStatistics(final Statistics statistics);
|
||||
@@ -277,7 +280,9 @@ public interface DBOptionsInterface<T extends DBOptionsInterface> {
|
||||
/**
|
||||
* <p>Returns statistics object.</p>
|
||||
*
|
||||
* @return the instance of the statistics object or null if there is no statistics object.
|
||||
* @return the instance of the statistics object or null if there is no
|
||||
* statistics object.
|
||||
*
|
||||
* @see #setStatistics(Statistics)
|
||||
*/
|
||||
Statistics statistics();
|
||||
|
||||
@@ -25,6 +25,11 @@ public abstract class DirectComparator extends AbstractComparator<DirectSlice> {
|
||||
return createNewDirectComparator0(nativeParameterHandles[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
final ComparatorType getComparatorType() {
|
||||
return ComparatorType.JAVA_DIRECT_COMPARATOR;
|
||||
}
|
||||
|
||||
private native long createNewDirectComparator0(
|
||||
final long comparatorOptionsHandle);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
package org.rocksdb;
|
||||
|
||||
/**
|
||||
* A simple abstraction to allow a Java class to wrap a custom comparator
|
||||
* implemented in C++.
|
||||
*
|
||||
* The native comparator must directly extend rocksdb::Comparator.
|
||||
*/
|
||||
public abstract class NativeComparatorWrapper
|
||||
extends AbstractComparator<Slice> {
|
||||
|
||||
@Override
|
||||
final ComparatorType getComparatorType() {
|
||||
return ComparatorType.JAVA_NATIVE_COMPARATOR_WRAPPER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String name() {
|
||||
throw new IllegalStateException("This should not be called. " +
|
||||
"Implementation is in Native code");
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int compare(final Slice s1, final Slice s2) {
|
||||
throw new IllegalStateException("This should not be called. " +
|
||||
"Implementation is in Native code");
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String findShortestSeparator(final String start, final Slice limit) {
|
||||
throw new IllegalStateException("This should not be called. " +
|
||||
"Implementation is in Native code");
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String findShortSuccessor(final String key) {
|
||||
throw new IllegalStateException("This should not be called. " +
|
||||
"Implementation is in Native code");
|
||||
}
|
||||
|
||||
/**
|
||||
* We override {@link RocksCallbackObject#disposeInternal()}
|
||||
* as disposing of a native rocksd::Comparator extension requires
|
||||
* a slightly different approach as it is not really a RocksCallbackObject
|
||||
*/
|
||||
@Override
|
||||
protected void disposeInternal() {
|
||||
disposeInternal(nativeHandle_);
|
||||
}
|
||||
|
||||
private native void disposeInternal(final long handle);
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
package org.rocksdb;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Database with Transaction support.
|
||||
*/
|
||||
public class OptimisticTransactionDB extends RocksDB
|
||||
implements TransactionalDB<OptimisticTransactionOptions> {
|
||||
|
||||
/**
|
||||
* Private constructor.
|
||||
*
|
||||
* @param nativeHandle The native handle of the C++ OptimisticTransactionDB
|
||||
* object
|
||||
*/
|
||||
private OptimisticTransactionDB(final long nativeHandle) {
|
||||
super(nativeHandle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Open an OptimisticTransactionDB similar to
|
||||
* {@link RocksDB#open(Options, String)}.
|
||||
*
|
||||
* @param options {@link org.rocksdb.Options} instance.
|
||||
* @param path the path to the rocksdb.
|
||||
*
|
||||
* @return a {@link OptimisticTransactionDB} instance on success, null if the
|
||||
* specified {@link OptimisticTransactionDB} can not be opened.
|
||||
*
|
||||
* @throws RocksDBException if an error occurs whilst opening the database.
|
||||
*/
|
||||
public static OptimisticTransactionDB open(final Options options,
|
||||
final String path) throws RocksDBException {
|
||||
final OptimisticTransactionDB otdb = new OptimisticTransactionDB(open(
|
||||
options.nativeHandle_, path));
|
||||
|
||||
// when non-default Options is used, keeping an Options reference
|
||||
// in RocksDB can prevent Java to GC during the life-time of
|
||||
// the currently-created RocksDB.
|
||||
otdb.storeOptionsInstance(options);
|
||||
|
||||
return otdb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open an OptimisticTransactionDB similar to
|
||||
* {@link RocksDB#open(DBOptions, String, List, List)}.
|
||||
*
|
||||
* @param dbOptions {@link org.rocksdb.DBOptions} instance.
|
||||
* @param path the path to the rocksdb.
|
||||
* @param columnFamilyDescriptors list of column family descriptors
|
||||
* @param columnFamilyHandles will be filled with ColumnFamilyHandle instances
|
||||
*
|
||||
* @return a {@link OptimisticTransactionDB} instance on success, null if the
|
||||
* specified {@link OptimisticTransactionDB} can not be opened.
|
||||
*
|
||||
* @throws RocksDBException if an error occurs whilst opening the database.
|
||||
*/
|
||||
public static OptimisticTransactionDB open(final DBOptions dbOptions,
|
||||
final String path,
|
||||
final List<ColumnFamilyDescriptor> columnFamilyDescriptors,
|
||||
final List<ColumnFamilyHandle> columnFamilyHandles)
|
||||
throws RocksDBException {
|
||||
|
||||
final byte[][] cfNames = new byte[columnFamilyDescriptors.size()][];
|
||||
final long[] cfOptionHandles = new long[columnFamilyDescriptors.size()];
|
||||
for (int i = 0; i < columnFamilyDescriptors.size(); i++) {
|
||||
final ColumnFamilyDescriptor cfDescriptor = columnFamilyDescriptors
|
||||
.get(i);
|
||||
cfNames[i] = cfDescriptor.columnFamilyName();
|
||||
cfOptionHandles[i] = cfDescriptor.columnFamilyOptions().nativeHandle_;
|
||||
}
|
||||
|
||||
final long[] handles = open(dbOptions.nativeHandle_, path, cfNames,
|
||||
cfOptionHandles);
|
||||
final OptimisticTransactionDB otdb =
|
||||
new OptimisticTransactionDB(handles[0]);
|
||||
|
||||
// when non-default Options is used, keeping an Options reference
|
||||
// in RocksDB can prevent Java to GC during the life-time of
|
||||
// the currently-created RocksDB.
|
||||
otdb.storeOptionsInstance(dbOptions);
|
||||
|
||||
for (int i = 1; i < handles.length; i++) {
|
||||
columnFamilyHandles.add(new ColumnFamilyHandle(otdb, handles[i]));
|
||||
}
|
||||
|
||||
return otdb;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Transaction beginTransaction(final WriteOptions writeOptions) {
|
||||
return new Transaction(this, beginTransaction(nativeHandle_,
|
||||
writeOptions.nativeHandle_));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Transaction beginTransaction(final WriteOptions writeOptions,
|
||||
final OptimisticTransactionOptions optimisticTransactionOptions) {
|
||||
return new Transaction(this, beginTransaction(nativeHandle_,
|
||||
writeOptions.nativeHandle_,
|
||||
optimisticTransactionOptions.nativeHandle_));
|
||||
}
|
||||
|
||||
// TODO(AR) consider having beingTransaction(... oldTransaction) set a
|
||||
// reference count inside Transaction, so that we can always call
|
||||
// Transaction#close but the object is only disposed when there are as many
|
||||
// closes as beginTransaction. Makes the try-with-resources paradigm easier for
|
||||
// java developers
|
||||
|
||||
@Override
|
||||
public Transaction beginTransaction(final WriteOptions writeOptions,
|
||||
final Transaction oldTransaction) {
|
||||
final long jtxn_handle = beginTransaction_withOld(nativeHandle_,
|
||||
writeOptions.nativeHandle_, oldTransaction.nativeHandle_);
|
||||
|
||||
// RocksJava relies on the assumption that
|
||||
// we do not allocate a new Transaction object
|
||||
// when providing an old_txn
|
||||
assert(jtxn_handle == oldTransaction.nativeHandle_);
|
||||
|
||||
return oldTransaction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Transaction beginTransaction(final WriteOptions writeOptions,
|
||||
final OptimisticTransactionOptions optimisticTransactionOptions,
|
||||
final Transaction oldTransaction) {
|
||||
final long jtxn_handle = beginTransaction_withOld(nativeHandle_,
|
||||
writeOptions.nativeHandle_, optimisticTransactionOptions.nativeHandle_,
|
||||
oldTransaction.nativeHandle_);
|
||||
|
||||
// RocksJava relies on the assumption that
|
||||
// we do not allocate a new Transaction object
|
||||
// when providing an old_txn
|
||||
assert(jtxn_handle == oldTransaction.nativeHandle_);
|
||||
|
||||
return oldTransaction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the underlying database that was opened.
|
||||
*
|
||||
* @return The underlying database that was opened.
|
||||
*/
|
||||
public RocksDB getBaseDB() {
|
||||
final RocksDB db = new RocksDB(getBaseDB(nativeHandle_));
|
||||
db.disOwnNativeHandle();
|
||||
return db;
|
||||
}
|
||||
|
||||
protected static native long open(final long optionsHandle,
|
||||
final String path) throws RocksDBException;
|
||||
protected static native long[] open(final long handle, final String path,
|
||||
final byte[][] columnFamilyNames, final long[] columnFamilyOptions);
|
||||
private native long beginTransaction(final long handle,
|
||||
final long writeOptionsHandle);
|
||||
private native long beginTransaction(final long handle,
|
||||
final long writeOptionsHandle,
|
||||
final long optimisticTransactionOptionsHandle);
|
||||
private native long beginTransaction_withOld(final long handle,
|
||||
final long writeOptionsHandle, final long oldTransactionHandle);
|
||||
private native long beginTransaction_withOld(final long handle,
|
||||
final long writeOptionsHandle,
|
||||
final long optimisticTransactionOptionsHandle,
|
||||
final long oldTransactionHandle);
|
||||
private native long getBaseDB(final long handle);
|
||||
@Override protected final native void disposeInternal(final long handle);
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
package org.rocksdb;
|
||||
|
||||
public class OptimisticTransactionOptions extends RocksObject
|
||||
implements TransactionalOptions {
|
||||
|
||||
public OptimisticTransactionOptions() {
|
||||
super(newOptimisticTransactionOptions());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSetSnapshot() {
|
||||
assert(isOwningHandle());
|
||||
return isSetSnapshot(nativeHandle_);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OptimisticTransactionOptions setSetSnapshot(
|
||||
final boolean setSnapshot) {
|
||||
assert(isOwningHandle());
|
||||
setSetSnapshot(nativeHandle_, setSnapshot);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should be set if the DB has a non-default comparator.
|
||||
* See comment in
|
||||
* {@link WriteBatchWithIndex#WriteBatchWithIndex(AbstractComparator, int, boolean)}
|
||||
* constructor.
|
||||
*
|
||||
* @param comparator The comparator to use for the transaction.
|
||||
*
|
||||
* @return this OptimisticTransactionOptions instance
|
||||
*/
|
||||
public OptimisticTransactionOptions setComparator(
|
||||
final AbstractComparator<? extends AbstractSlice<?>> comparator) {
|
||||
assert(isOwningHandle());
|
||||
setComparator(nativeHandle_, comparator.nativeHandle_);
|
||||
return this;
|
||||
}
|
||||
|
||||
private native static long newOptimisticTransactionOptions();
|
||||
private native boolean isSetSnapshot(final long handle);
|
||||
private native void setSetSnapshot(final long handle,
|
||||
final boolean setSnapshot);
|
||||
private native void setComparator(final long handle,
|
||||
final long comparatorHandle);
|
||||
@Override protected final native void disposeInternal(final long handle);
|
||||
}
|
||||
@@ -191,7 +191,7 @@ public class Options extends RocksObject
|
||||
final AbstractComparator<? extends AbstractSlice<?>> comparator) {
|
||||
assert(isOwningHandle());
|
||||
setComparatorHandle(nativeHandle_, comparator.nativeHandle_,
|
||||
comparator instanceof DirectComparator);
|
||||
comparator.getComparatorType().getValue());
|
||||
comparator_ = comparator;
|
||||
return this;
|
||||
}
|
||||
@@ -1756,7 +1756,7 @@ public class Options extends RocksObject
|
||||
long memtableMemoryBudget);
|
||||
private native void setComparatorHandle(long handle, int builtinComparator);
|
||||
private native void setComparatorHandle(long optHandle,
|
||||
long comparatorHandle, boolean isDirect);
|
||||
long comparatorHandle, byte comparatorType);
|
||||
private native void setMergeOperatorName(
|
||||
long handle, String name);
|
||||
private native void setMergeOperator(
|
||||
|
||||
@@ -435,7 +435,7 @@ public class RocksDB extends RocksObject {
|
||||
path));
|
||||
}
|
||||
|
||||
private void storeOptionsInstance(DBOptionsInterface options) {
|
||||
protected void storeOptionsInstance(DBOptionsInterface options) {
|
||||
options_ = options;
|
||||
}
|
||||
|
||||
@@ -1683,7 +1683,7 @@ public class RocksDB extends RocksObject {
|
||||
* @return The handle of the default column family
|
||||
*/
|
||||
public ColumnFamilyHandle getDefaultColumnFamily() {
|
||||
ColumnFamilyHandle cfHandle = new ColumnFamilyHandle(this,
|
||||
final ColumnFamilyHandle cfHandle = new ColumnFamilyHandle(this,
|
||||
getDefaultColumnFamily(nativeHandle_));
|
||||
cfHandle.disOwnNativeHandle();
|
||||
return cfHandle;
|
||||
@@ -2359,8 +2359,9 @@ public class RocksDB extends RocksObject {
|
||||
final long[] columnFamilyHandles, final long readOptHandle)
|
||||
throws RocksDBException;
|
||||
protected native long getSnapshot(long nativeHandle);
|
||||
protected native void releaseSnapshot(long nativeHandle, long snapshotHandle);
|
||||
@Override protected final native void disposeInternal(final long handle);
|
||||
protected native void releaseSnapshot(
|
||||
long nativeHandle, long snapshotHandle);
|
||||
@Override protected native void disposeInternal(final long handle);
|
||||
private native long getDefaultColumnFamily(long handle);
|
||||
private native long createColumnFamily(final long handle,
|
||||
final byte[] columnFamilyName, final long columnFamilyOptions)
|
||||
|
||||
@@ -11,6 +11,10 @@ package org.rocksdb;
|
||||
public class Snapshot extends RocksObject {
|
||||
Snapshot(final long nativeHandle) {
|
||||
super(nativeHandle);
|
||||
|
||||
// The pointer to the snapshot is always released
|
||||
// by the database instance.
|
||||
disOwnNativeHandle();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -20,17 +24,17 @@ public class Snapshot extends RocksObject {
|
||||
* this snapshot.
|
||||
*/
|
||||
public long getSequenceNumber() {
|
||||
assert(isOwningHandle());
|
||||
return getSequenceNumber(nativeHandle_);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dont release C++ Snapshot pointer. The pointer
|
||||
* to the snapshot is released by the database
|
||||
* instance.
|
||||
*/
|
||||
@Override
|
||||
protected final void disposeInternal(final long handle) {
|
||||
/**
|
||||
* Nothing to release, we never own the pointer for a
|
||||
* Snapshot. The pointer
|
||||
* to the snapshot is released by the database
|
||||
* instance.
|
||||
*/
|
||||
}
|
||||
|
||||
private native long getSequenceNumber(long handle);
|
||||
|
||||
@@ -31,7 +31,7 @@ public class SstFileWriter extends RocksObject {
|
||||
final AbstractComparator<? extends AbstractSlice<?>> comparator) {
|
||||
super(newSstFileWriter(
|
||||
envOptions.nativeHandle_, options.nativeHandle_, comparator.nativeHandle_,
|
||||
comparator instanceof DirectComparator));
|
||||
comparator.getComparatorType().getValue()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -225,7 +225,7 @@ public void put(final byte[] key, final byte[] value)
|
||||
|
||||
private native static long newSstFileWriter(
|
||||
final long envOptionsHandle, final long optionsHandle,
|
||||
final long userComparatorHandle, final boolean isDirect);
|
||||
final long userComparatorHandle, final byte comparatorType);
|
||||
|
||||
private native static long newSstFileWriter(final long envOptionsHandle,
|
||||
final long optionsHandle);
|
||||
|
||||
@@ -117,6 +117,8 @@ public class Statistics extends RocksObject {
|
||||
|
||||
/**
|
||||
* Resets all ticker and histogram stats.
|
||||
*
|
||||
* @throws RocksDBException if an error occurs when resetting the statistics.
|
||||
*/
|
||||
public void reset() throws RocksDBException {
|
||||
assert(isOwningHandle());
|
||||
@@ -126,6 +128,7 @@ public class Statistics extends RocksObject {
|
||||
/**
|
||||
* String representation of the statistic object.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
assert(isOwningHandle());
|
||||
return toString(nativeHandle_);
|
||||
|
||||
@@ -87,6 +87,15 @@ public class Status {
|
||||
throw new IllegalArgumentException(
|
||||
"Illegal value provided for Code (" + value + ").");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the byte value of the enumerations value.
|
||||
*
|
||||
* @return byte representation
|
||||
*/
|
||||
public byte getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
// should stay in sync with /include/rocksdb/status.h:SubCode and /java/rocksjni/portal.h:toJavaStatusSubCode
|
||||
@@ -116,5 +125,14 @@ public class Status {
|
||||
throw new IllegalArgumentException(
|
||||
"Illegal value provided for SubCode (" + value + ").");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the byte value of the enumerations value.
|
||||
*
|
||||
* @return byte representation
|
||||
*/
|
||||
public byte getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,354 @@
|
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
package org.rocksdb;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Database with Transaction support
|
||||
*/
|
||||
public class TransactionDB extends RocksDB
|
||||
implements TransactionalDB<TransactionOptions> {
|
||||
|
||||
private TransactionDBOptions transactionDbOptions_;
|
||||
|
||||
/**
|
||||
* Private constructor.
|
||||
*
|
||||
* @param nativeHandle The native handle of the C++ TransactionDB object
|
||||
*/
|
||||
private TransactionDB(final long nativeHandle) {
|
||||
super(nativeHandle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a TransactionDB, similar to {@link RocksDB#open(Options, String)}.
|
||||
*
|
||||
* @param options {@link org.rocksdb.Options} instance.
|
||||
* @param transactionDbOptions {@link org.rocksdb.TransactionDBOptions}
|
||||
* instance.
|
||||
* @param path the path to the rocksdb.
|
||||
*
|
||||
* @return a {@link TransactionDB} instance on success, null if the specified
|
||||
* {@link TransactionDB} can not be opened.
|
||||
*
|
||||
* @throws RocksDBException if an error occurs whilst opening the database.
|
||||
*/
|
||||
public static TransactionDB open(final Options options,
|
||||
final TransactionDBOptions transactionDbOptions, final String path)
|
||||
throws RocksDBException {
|
||||
final TransactionDB tdb = new TransactionDB(open(options.nativeHandle_,
|
||||
transactionDbOptions.nativeHandle_, path));
|
||||
|
||||
// when non-default Options is used, keeping an Options reference
|
||||
// in RocksDB can prevent Java to GC during the life-time of
|
||||
// the currently-created RocksDB.
|
||||
tdb.storeOptionsInstance(options);
|
||||
tdb.storeTransactionDbOptions(transactionDbOptions);
|
||||
|
||||
return tdb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a TransactionDB, similar to
|
||||
* {@link RocksDB#open(DBOptions, String, List, List)}.
|
||||
*
|
||||
* @param dbOptions {@link org.rocksdb.DBOptions} instance.
|
||||
* @param transactionDbOptions {@link org.rocksdb.TransactionDBOptions}
|
||||
* instance.
|
||||
* @param path the path to the rocksdb.
|
||||
* @param columnFamilyDescriptors list of column family descriptors
|
||||
* @param columnFamilyHandles will be filled with ColumnFamilyHandle instances
|
||||
*
|
||||
* @return a {@link TransactionDB} instance on success, null if the specified
|
||||
* {@link TransactionDB} can not be opened.
|
||||
*
|
||||
* @throws RocksDBException if an error occurs whilst opening the database.
|
||||
*/
|
||||
public static TransactionDB open(final DBOptions dbOptions,
|
||||
final TransactionDBOptions transactionDbOptions,
|
||||
final String path,
|
||||
final List<ColumnFamilyDescriptor> columnFamilyDescriptors,
|
||||
final List<ColumnFamilyHandle> columnFamilyHandles)
|
||||
throws RocksDBException {
|
||||
|
||||
final byte[][] cfNames = new byte[columnFamilyDescriptors.size()][];
|
||||
final long[] cfOptionHandles = new long[columnFamilyDescriptors.size()];
|
||||
for (int i = 0; i < columnFamilyDescriptors.size(); i++) {
|
||||
final ColumnFamilyDescriptor cfDescriptor = columnFamilyDescriptors
|
||||
.get(i);
|
||||
cfNames[i] = cfDescriptor.columnFamilyName();
|
||||
cfOptionHandles[i] = cfDescriptor.columnFamilyOptions().nativeHandle_;
|
||||
}
|
||||
|
||||
final long[] handles = open(dbOptions.nativeHandle_,
|
||||
transactionDbOptions.nativeHandle_, path, cfNames, cfOptionHandles);
|
||||
final TransactionDB tdb = new TransactionDB(handles[0]);
|
||||
|
||||
// when non-default Options is used, keeping an Options reference
|
||||
// in RocksDB can prevent Java to GC during the life-time of
|
||||
// the currently-created RocksDB.
|
||||
tdb.storeOptionsInstance(dbOptions);
|
||||
tdb.storeTransactionDbOptions(transactionDbOptions);
|
||||
|
||||
for (int i = 1; i < handles.length; i++) {
|
||||
columnFamilyHandles.add(new ColumnFamilyHandle(tdb, handles[i]));
|
||||
}
|
||||
|
||||
return tdb;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Transaction beginTransaction(final WriteOptions writeOptions) {
|
||||
return new Transaction(this, beginTransaction(nativeHandle_,
|
||||
writeOptions.nativeHandle_));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Transaction beginTransaction(final WriteOptions writeOptions,
|
||||
final TransactionOptions transactionOptions) {
|
||||
return new Transaction(this, beginTransaction(nativeHandle_,
|
||||
writeOptions.nativeHandle_, transactionOptions.nativeHandle_));
|
||||
}
|
||||
|
||||
// TODO(AR) consider having beingTransaction(... oldTransaction) set a
|
||||
// reference count inside Transaction, so that we can always call
|
||||
// Transaction#close but the object is only disposed when there are as many
|
||||
// closes as beginTransaction. Makes the try-with-resources paradigm easier for
|
||||
// java developers
|
||||
|
||||
@Override
|
||||
public Transaction beginTransaction(final WriteOptions writeOptions,
|
||||
final Transaction oldTransaction) {
|
||||
final long jtxnHandle = beginTransaction_withOld(nativeHandle_,
|
||||
writeOptions.nativeHandle_, oldTransaction.nativeHandle_);
|
||||
|
||||
// RocksJava relies on the assumption that
|
||||
// we do not allocate a new Transaction object
|
||||
// when providing an old_txn
|
||||
assert(jtxnHandle == oldTransaction.nativeHandle_);
|
||||
|
||||
return oldTransaction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Transaction beginTransaction(final WriteOptions writeOptions,
|
||||
final TransactionOptions transactionOptions,
|
||||
final Transaction oldTransaction) {
|
||||
final long jtxn_handle = beginTransaction_withOld(nativeHandle_,
|
||||
writeOptions.nativeHandle_, transactionOptions.nativeHandle_,
|
||||
oldTransaction.nativeHandle_);
|
||||
|
||||
// RocksJava relies on the assumption that
|
||||
// we do not allocate a new Transaction object
|
||||
// when providing an old_txn
|
||||
assert(jtxn_handle == oldTransaction.nativeHandle_);
|
||||
|
||||
return oldTransaction;
|
||||
}
|
||||
|
||||
public Transaction getTransactionByName(final String transactionName) {
|
||||
final long jtxnHandle = getTransactionByName(nativeHandle_, transactionName);
|
||||
if(jtxnHandle == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Transaction txn = new Transaction(this, jtxnHandle);
|
||||
|
||||
// this instance doesn't own the underlying C++ object
|
||||
txn.disOwnNativeHandle();
|
||||
|
||||
return txn;
|
||||
}
|
||||
|
||||
public List<Transaction> getAllPreparedTransactions() {
|
||||
final long[] jtxnHandles = getAllPreparedTransactions(nativeHandle_);
|
||||
|
||||
final List<Transaction> txns = new ArrayList<>();
|
||||
for(final long jtxnHandle : jtxnHandles) {
|
||||
final Transaction txn = new Transaction(this, jtxnHandle);
|
||||
|
||||
// this instance doesn't own the underlying C++ object
|
||||
txn.disOwnNativeHandle();
|
||||
|
||||
txns.add(txn);
|
||||
}
|
||||
return txns;
|
||||
}
|
||||
|
||||
public static class KeyLockInfo {
|
||||
private final String key;
|
||||
private final long[] transactionIDs;
|
||||
private final boolean exclusive;
|
||||
|
||||
public KeyLockInfo(final String key, final long transactionIDs[],
|
||||
final boolean exclusive) {
|
||||
this.key = key;
|
||||
this.transactionIDs = transactionIDs;
|
||||
this.exclusive = exclusive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the key.
|
||||
*
|
||||
* @return the key
|
||||
*/
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Transaction IDs.
|
||||
*
|
||||
* @return the Transaction IDs.
|
||||
*/
|
||||
public long[] getTransactionIDs() {
|
||||
return transactionIDs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Lock status.
|
||||
*
|
||||
* @return true if the lock is exclusive, false if the lock is shared.
|
||||
*/
|
||||
public boolean isExclusive() {
|
||||
return exclusive;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns map of all locks held.
|
||||
*
|
||||
* @return a map of all the locks held.
|
||||
*/
|
||||
public Map<Long, KeyLockInfo> getLockStatusData() {
|
||||
return getLockStatusData(nativeHandle_);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from C++ native method {@link #getDeadlockInfoBuffer(long)}
|
||||
* to construct a DeadlockInfo object.
|
||||
*
|
||||
* @param transactionID The transaction id
|
||||
* @param columnFamilyId The id of the {@link ColumnFamilyHandle}
|
||||
* @param waitingKey the key that we are waiting on
|
||||
* @param exclusive true if the lock is exclusive, false if the lock is shared
|
||||
*
|
||||
* @return The waiting transactions
|
||||
*/
|
||||
private DeadlockInfo newDeadlockInfo(
|
||||
final long transactionID, final long columnFamilyId,
|
||||
final String waitingKey, final boolean exclusive) {
|
||||
return new DeadlockInfo(transactionID, columnFamilyId,
|
||||
waitingKey, exclusive);
|
||||
}
|
||||
|
||||
public static class DeadlockInfo {
|
||||
private final long transactionID;
|
||||
private final long columnFamilyId;
|
||||
private final String waitingKey;
|
||||
private final boolean exclusive;
|
||||
|
||||
private DeadlockInfo(final long transactionID, final long columnFamilyId,
|
||||
final String waitingKey, final boolean exclusive) {
|
||||
this.transactionID = transactionID;
|
||||
this.columnFamilyId = columnFamilyId;
|
||||
this.waitingKey = waitingKey;
|
||||
this.exclusive = exclusive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Transaction ID.
|
||||
*
|
||||
* @return the transaction ID
|
||||
*/
|
||||
public long getTransactionID() {
|
||||
return transactionID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Column Family ID.
|
||||
*
|
||||
* @return The column family ID
|
||||
*/
|
||||
public long getColumnFamilyId() {
|
||||
return columnFamilyId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the key that we are waiting on.
|
||||
*
|
||||
* @return the key that we are waiting on
|
||||
*/
|
||||
public String getWaitingKey() {
|
||||
return waitingKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Lock status.
|
||||
*
|
||||
* @return true if the lock is exclusive, false if the lock is shared.
|
||||
*/
|
||||
public boolean isExclusive() {
|
||||
return exclusive;
|
||||
}
|
||||
}
|
||||
|
||||
public static class DeadlockPath {
|
||||
final DeadlockInfo[] path;
|
||||
final boolean limitExceeded;
|
||||
|
||||
public DeadlockPath(final DeadlockInfo[] path, final boolean limitExceeded) {
|
||||
this.path = path;
|
||||
this.limitExceeded = limitExceeded;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return path.length == 0 && !limitExceeded;
|
||||
}
|
||||
}
|
||||
|
||||
public DeadlockPath[] getDeadlockInfoBuffer() {
|
||||
return getDeadlockInfoBuffer(nativeHandle_);
|
||||
}
|
||||
|
||||
public void setDeadlockInfoBufferSize(final int targetSize) {
|
||||
setDeadlockInfoBufferSize(nativeHandle_, targetSize);
|
||||
}
|
||||
|
||||
private void storeTransactionDbOptions(
|
||||
final TransactionDBOptions transactionDbOptions) {
|
||||
this.transactionDbOptions_ = transactionDbOptions;
|
||||
}
|
||||
|
||||
private static native long open(final long optionsHandle,
|
||||
final long transactionDbOptionsHandle, final String path)
|
||||
throws RocksDBException;
|
||||
private static native long[] open(final long dbOptionsHandle,
|
||||
final long transactionDbOptionsHandle, final String path,
|
||||
final byte[][] columnFamilyNames, final long[] columnFamilyOptions);
|
||||
private native long beginTransaction(final long handle,
|
||||
final long writeOptionsHandle);
|
||||
private native long beginTransaction(final long handle,
|
||||
final long writeOptionsHandle, final long transactionOptionsHandle);
|
||||
private native long beginTransaction_withOld(final long handle,
|
||||
final long writeOptionsHandle, final long oldTransactionHandle);
|
||||
private native long beginTransaction_withOld(final long handle,
|
||||
final long writeOptionsHandle, final long transactionOptionsHandle,
|
||||
final long oldTransactionHandle);
|
||||
private native long getTransactionByName(final long handle,
|
||||
final String name);
|
||||
private native long[] getAllPreparedTransactions(final long handle);
|
||||
private native Map<Long, KeyLockInfo> getLockStatusData(
|
||||
final long handle);
|
||||
private native DeadlockPath[] getDeadlockInfoBuffer(final long handle);
|
||||
private native void setDeadlockInfoBufferSize(final long handle,
|
||||
final int targetSize);
|
||||
@Override protected final native void disposeInternal(final long handle);
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
package org.rocksdb;
|
||||
|
||||
public class TransactionDBOptions extends RocksObject {
|
||||
|
||||
public TransactionDBOptions() {
|
||||
super(newTransactionDBOptions());
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the maximum number of keys that can be locked at the same time
|
||||
* per column family.
|
||||
*
|
||||
* If the number of locked keys is greater than {@link #getMaxNumLocks()},
|
||||
* transaction writes (or GetForUpdate) will return an error.
|
||||
*
|
||||
* @return The maximum number of keys that can be locked
|
||||
*/
|
||||
public long getMaxNumLocks() {
|
||||
assert(isOwningHandle());
|
||||
return getMaxNumLocks(nativeHandle_);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the maximum number of keys that can be locked at the same time
|
||||
* per column family.
|
||||
*
|
||||
* If the number of locked keys is greater than {@link #getMaxNumLocks()},
|
||||
* transaction writes (or GetForUpdate) will return an error.
|
||||
*
|
||||
* @param maxNumLocks The maximum number of keys that can be locked;
|
||||
* If this value is not positive, no limit will be enforced.
|
||||
*
|
||||
* @return this TransactionDBOptions instance
|
||||
*/
|
||||
public TransactionDBOptions setMaxNumLocks(final long maxNumLocks) {
|
||||
assert(isOwningHandle());
|
||||
setMaxNumLocks(nativeHandle_, maxNumLocks);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of sub-tables per lock table (per column family)
|
||||
*
|
||||
* @return The number of sub-tables
|
||||
*/
|
||||
public long getNumStripes() {
|
||||
assert(isOwningHandle());
|
||||
return getNumStripes(nativeHandle_);
|
||||
}
|
||||
|
||||
/**
|
||||
* Increasing this value will increase the concurrency by dividing the lock
|
||||
* table (per column family) into more sub-tables, each with their own
|
||||
* separate mutex.
|
||||
*
|
||||
* Default: 16
|
||||
*
|
||||
* @param numStripes The number of sub-tables
|
||||
*
|
||||
* @return this TransactionDBOptions instance
|
||||
*/
|
||||
public TransactionDBOptions setNumStripes(final long numStripes) {
|
||||
assert(isOwningHandle());
|
||||
setNumStripes(nativeHandle_, numStripes);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The default wait timeout in milliseconds when
|
||||
* a transaction attempts to lock a key if not specified by
|
||||
* {@link TransactionOptions#setLockTimeout(long)}
|
||||
*
|
||||
* If 0, no waiting is done if a lock cannot instantly be acquired.
|
||||
* If negative, there is no timeout.
|
||||
*
|
||||
* @return the default wait timeout in milliseconds
|
||||
*/
|
||||
public long getTransactionLockTimeout() {
|
||||
assert(isOwningHandle());
|
||||
return getTransactionLockTimeout(nativeHandle_);
|
||||
}
|
||||
|
||||
/**
|
||||
* If positive, specifies the default wait timeout in milliseconds when
|
||||
* a transaction attempts to lock a key if not specified by
|
||||
* {@link TransactionOptions#setLockTimeout(long)}
|
||||
*
|
||||
* If 0, no waiting is done if a lock cannot instantly be acquired.
|
||||
* If negative, there is no timeout. Not using a timeout is not recommended
|
||||
* as it can lead to deadlocks. Currently, there is no deadlock-detection to
|
||||
* recover from a deadlock.
|
||||
*
|
||||
* Default: 1000
|
||||
*
|
||||
* @param transactionLockTimeout the default wait timeout in milliseconds
|
||||
*
|
||||
* @return this TransactionDBOptions instance
|
||||
*/
|
||||
public TransactionDBOptions setTransactionLockTimeout(
|
||||
final long transactionLockTimeout) {
|
||||
assert(isOwningHandle());
|
||||
setTransactionLockTimeout(nativeHandle_, transactionLockTimeout);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The wait timeout in milliseconds when writing a key
|
||||
* OUTSIDE of a transaction (ie by calling {@link RocksDB#put},
|
||||
* {@link RocksDB#merge}, {@link RocksDB#remove} or {@link RocksDB#write}
|
||||
* directly).
|
||||
*
|
||||
* If 0, no waiting is done if a lock cannot instantly be acquired.
|
||||
* If negative, there is no timeout and will block indefinitely when acquiring
|
||||
* a lock.
|
||||
*
|
||||
* @return the timeout in milliseconds when writing a key OUTSIDE of a
|
||||
* transaction
|
||||
*/
|
||||
public long getDefaultLockTimeout() {
|
||||
assert(isOwningHandle());
|
||||
return getDefaultLockTimeout(nativeHandle_);
|
||||
}
|
||||
|
||||
/**
|
||||
* If positive, specifies the wait timeout in milliseconds when writing a key
|
||||
* OUTSIDE of a transaction (ie by calling {@link RocksDB#put},
|
||||
* {@link RocksDB#merge}, {@link RocksDB#remove} or {@link RocksDB#write}
|
||||
* directly).
|
||||
*
|
||||
* If 0, no waiting is done if a lock cannot instantly be acquired.
|
||||
* If negative, there is no timeout and will block indefinitely when acquiring
|
||||
* a lock.
|
||||
*
|
||||
* Not using a timeout can lead to deadlocks. Currently, there
|
||||
* is no deadlock-detection to recover from a deadlock. While DB writes
|
||||
* cannot deadlock with other DB writes, they can deadlock with a transaction.
|
||||
* A negative timeout should only be used if all transactions have a small
|
||||
* expiration set.
|
||||
*
|
||||
* Default: 1000
|
||||
*
|
||||
* @param defaultLockTimeout the timeout in milliseconds when writing a key
|
||||
* OUTSIDE of a transaction
|
||||
* @return this TransactionDBOptions instance
|
||||
*/
|
||||
public TransactionDBOptions setDefaultLockTimeout(
|
||||
final long defaultLockTimeout) {
|
||||
assert(isOwningHandle());
|
||||
setDefaultLockTimeout(nativeHandle_, defaultLockTimeout);
|
||||
return this;
|
||||
}
|
||||
|
||||
// /**
|
||||
// * If set, the {@link TransactionDB} will use this implementation of a mutex
|
||||
// * and condition variable for all transaction locking instead of the default
|
||||
// * mutex/condvar implementation.
|
||||
// *
|
||||
// * @param transactionDbMutexFactory the mutex factory for the transactions
|
||||
// *
|
||||
// * @return this TransactionDBOptions instance
|
||||
// */
|
||||
// public TransactionDBOptions setCustomMutexFactory(
|
||||
// final TransactionDBMutexFactory transactionDbMutexFactory) {
|
||||
//
|
||||
// }
|
||||
|
||||
/**
|
||||
* The policy for when to write the data into the DB. The default policy is to
|
||||
* write only the committed data {@link TxnDBWritePolicy#WRITE_COMMITTED}.
|
||||
* The data could be written before the commit phase. The DB then needs to
|
||||
* provide the mechanisms to tell apart committed from uncommitted data.
|
||||
*
|
||||
* @return The write policy.
|
||||
*/
|
||||
public TxnDBWritePolicy getWritePolicy() {
|
||||
assert(isOwningHandle());
|
||||
return TxnDBWritePolicy.getTxnDBWritePolicy(getWritePolicy(nativeHandle_));
|
||||
}
|
||||
|
||||
/**
|
||||
* The policy for when to write the data into the DB. The default policy is to
|
||||
* write only the committed data {@link TxnDBWritePolicy#WRITE_COMMITTED}.
|
||||
* The data could be written before the commit phase. The DB then needs to
|
||||
* provide the mechanisms to tell apart committed from uncommitted data.
|
||||
*
|
||||
* @param writePolicy The write policy.
|
||||
*
|
||||
* @return this TransactionDBOptions instance
|
||||
*/
|
||||
public TransactionDBOptions setWritePolicy(
|
||||
final TxnDBWritePolicy writePolicy) {
|
||||
assert(isOwningHandle());
|
||||
setWritePolicy(nativeHandle_, writePolicy.getValue());
|
||||
return this;
|
||||
}
|
||||
|
||||
private native static long newTransactionDBOptions();
|
||||
private native long getMaxNumLocks(final long handle);
|
||||
private native void setMaxNumLocks(final long handle,
|
||||
final long maxNumLocks);
|
||||
private native long getNumStripes(final long handle);
|
||||
private native void setNumStripes(final long handle, final long numStripes);
|
||||
private native long getTransactionLockTimeout(final long handle);
|
||||
private native void setTransactionLockTimeout(final long handle,
|
||||
final long transactionLockTimeout);
|
||||
private native long getDefaultLockTimeout(final long handle);
|
||||
private native void setDefaultLockTimeout(final long handle,
|
||||
final long transactionLockTimeout);
|
||||
private native byte getWritePolicy(final long handle);
|
||||
private native void setWritePolicy(final long handle, final byte writePolicy);
|
||||
@Override protected final native void disposeInternal(final long handle);
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
package org.rocksdb;
|
||||
|
||||
public class TransactionOptions extends RocksObject
|
||||
implements TransactionalOptions {
|
||||
|
||||
public TransactionOptions() {
|
||||
super(newTransactionOptions());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSetSnapshot() {
|
||||
assert(isOwningHandle());
|
||||
return isSetSnapshot(nativeHandle_);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransactionOptions setSetSnapshot(final boolean setSnapshot) {
|
||||
assert(isOwningHandle());
|
||||
setSetSnapshot(nativeHandle_, setSnapshot);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* True means that before acquiring locks, this transaction will
|
||||
* check if doing so will cause a deadlock. If so, it will return with
|
||||
* {@link Status.Code#Busy}. The user should retry their transaction.
|
||||
*
|
||||
* @return true if a deadlock is detected.
|
||||
*/
|
||||
public boolean isDeadlockDetect() {
|
||||
assert(isOwningHandle());
|
||||
return isDeadlockDetect(nativeHandle_);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setting to true means that before acquiring locks, this transaction will
|
||||
* check if doing so will cause a deadlock. If so, it will return with
|
||||
* {@link Status.Code#Busy}. The user should retry their transaction.
|
||||
*
|
||||
* @param deadlockDetect true if we should detect deadlocks.
|
||||
*
|
||||
* @return this TransactionOptions instance
|
||||
*/
|
||||
public TransactionOptions setDeadlockDetect(final boolean deadlockDetect) {
|
||||
assert(isOwningHandle());
|
||||
setDeadlockDetect(nativeHandle_, deadlockDetect);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The wait timeout in milliseconds when a transaction attempts to lock a key.
|
||||
*
|
||||
* If 0, no waiting is done if a lock cannot instantly be acquired.
|
||||
* If negative, {@link TransactionDBOptions#getTransactionLockTimeout(long)}
|
||||
* will be used
|
||||
*
|
||||
* @return the lock tiemout in milliseconds
|
||||
*/
|
||||
public long getLockTimeout() {
|
||||
assert(isOwningHandle());
|
||||
return getLockTimeout(nativeHandle_);
|
||||
}
|
||||
|
||||
/**
|
||||
* If positive, specifies the wait timeout in milliseconds when
|
||||
* a transaction attempts to lock a key.
|
||||
*
|
||||
* If 0, no waiting is done if a lock cannot instantly be acquired.
|
||||
* If negative, {@link TransactionDBOptions#getTransactionLockTimeout(long)}
|
||||
* will be used
|
||||
*
|
||||
* Default: -1
|
||||
*
|
||||
* @param lockTimeout the lock tiemout in milliseconds
|
||||
*
|
||||
* @return this TransactionOptions instance
|
||||
*/
|
||||
public TransactionOptions setLockTimeout(final long lockTimeout) {
|
||||
assert(isOwningHandle());
|
||||
setLockTimeout(nativeHandle_, lockTimeout);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expiration duration in milliseconds.
|
||||
*
|
||||
* If non-negative, transactions that last longer than this many milliseconds
|
||||
* will fail to commit. If not set, a forgotten transaction that is never
|
||||
* committed, rolled back, or deleted will never relinquish any locks it
|
||||
* holds. This could prevent keys from being written by other writers.
|
||||
*
|
||||
* @return expiration the expiration duration in milliseconds
|
||||
*/
|
||||
public long getExpiration() {
|
||||
assert(isOwningHandle());
|
||||
return getExpiration(nativeHandle_);
|
||||
}
|
||||
|
||||
/**
|
||||
* Expiration duration in milliseconds.
|
||||
*
|
||||
* If non-negative, transactions that last longer than this many milliseconds
|
||||
* will fail to commit. If not set, a forgotten transaction that is never
|
||||
* committed, rolled back, or deleted will never relinquish any locks it
|
||||
* holds. This could prevent keys from being written by other writers.
|
||||
*
|
||||
* Default: -1
|
||||
*
|
||||
* @param expiration the expiration duration in milliseconds
|
||||
*
|
||||
* @return this TransactionOptions instance
|
||||
*/
|
||||
public TransactionOptions setExpiration(final long expiration) {
|
||||
assert(isOwningHandle());
|
||||
setExpiration(nativeHandle_, expiration);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of traversals to make during deadlock detection.
|
||||
*
|
||||
* @return the number of traversals to make during
|
||||
* deadlock detection
|
||||
*/
|
||||
public long getDeadlockDetectDepth() {
|
||||
return getDeadlockDetectDepth(nativeHandle_);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the number of traversals to make during deadlock detection.
|
||||
*
|
||||
* Default: 50
|
||||
*
|
||||
* @param deadlockDetectDepth the the number of traversals to make during
|
||||
* deadlock detection
|
||||
*
|
||||
* @return this TransactionOptions instance
|
||||
*/
|
||||
public TransactionOptions setDeadlockDetectDepth(
|
||||
final long deadlockDetectDepth) {
|
||||
setDeadlockDetectDepth(nativeHandle_, deadlockDetectDepth);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the maximum number of bytes that may be used for the write batch.
|
||||
*
|
||||
* @return the maximum number of bytes, 0 means no limit.
|
||||
*/
|
||||
public long getMaxWriteBatchSize() {
|
||||
return getMaxWriteBatchSize(nativeHandle_);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum number of bytes that may be used for the write batch.
|
||||
*
|
||||
* @param maxWriteBatchSize the maximum number of bytes, 0 means no limit.
|
||||
*
|
||||
* @return this TransactionOptions instance
|
||||
*/
|
||||
public TransactionOptions setMaxWriteBatchSize(final long maxWriteBatchSize) {
|
||||
setMaxWriteBatchSize(nativeHandle_, maxWriteBatchSize);
|
||||
return this;
|
||||
}
|
||||
|
||||
private native static long newTransactionOptions();
|
||||
private native boolean isSetSnapshot(final long handle);
|
||||
private native void setSetSnapshot(final long handle,
|
||||
final boolean setSnapshot);
|
||||
private native boolean isDeadlockDetect(final long handle);
|
||||
private native void setDeadlockDetect(final long handle,
|
||||
final boolean deadlockDetect);
|
||||
private native long getLockTimeout(final long handle);
|
||||
private native void setLockTimeout(final long handle, final long lockTimeout);
|
||||
private native long getExpiration(final long handle);
|
||||
private native void setExpiration(final long handle, final long expiration);
|
||||
private native long getDeadlockDetectDepth(final long handle);
|
||||
private native void setDeadlockDetectDepth(final long handle,
|
||||
final long deadlockDetectDepth);
|
||||
private native long getMaxWriteBatchSize(final long handle);
|
||||
private native void setMaxWriteBatchSize(final long handle,
|
||||
final long maxWriteBatchSize);
|
||||
@Override protected final native void disposeInternal(final long handle);
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
package org.rocksdb;
|
||||
|
||||
|
||||
interface TransactionalDB<T extends TransactionalOptions>
|
||||
extends AutoCloseable {
|
||||
|
||||
/**
|
||||
* Starts a new Transaction.
|
||||
*
|
||||
* Caller is responsible for calling {@link #close()} on the returned
|
||||
* transaction when it is no longer needed.
|
||||
*
|
||||
* @param writeOptions Any write options for the transaction
|
||||
* @return a new transaction
|
||||
*/
|
||||
Transaction beginTransaction(final WriteOptions writeOptions);
|
||||
|
||||
/**
|
||||
* Starts a new Transaction.
|
||||
*
|
||||
* Caller is responsible for calling {@link #close()} on the returned
|
||||
* transaction when it is no longer needed.
|
||||
*
|
||||
* @param writeOptions Any write options for the transaction
|
||||
* @param transactionOptions Any options for the transaction
|
||||
* @return a new transaction
|
||||
*/
|
||||
Transaction beginTransaction(final WriteOptions writeOptions,
|
||||
final T transactionOptions);
|
||||
|
||||
/**
|
||||
* Starts a new Transaction.
|
||||
*
|
||||
* Caller is responsible for calling {@link #close()} on the returned
|
||||
* transaction when it is no longer needed.
|
||||
*
|
||||
* @param writeOptions Any write options for the transaction
|
||||
* @param oldTransaction this Transaction will be reused instead of allocating
|
||||
* a new one. This is an optimization to avoid extra allocations
|
||||
* when repeatedly creating transactions.
|
||||
* @return The oldTransaction which has been reinitialized as a new
|
||||
* transaction
|
||||
*/
|
||||
Transaction beginTransaction(final WriteOptions writeOptions,
|
||||
final Transaction oldTransaction);
|
||||
|
||||
/**
|
||||
* Starts a new Transaction.
|
||||
*
|
||||
* Caller is responsible for calling {@link #close()} on the returned
|
||||
* transaction when it is no longer needed.
|
||||
*
|
||||
* @param writeOptions Any write options for the transaction
|
||||
* @param transactionOptions Any options for the transaction
|
||||
* @param oldTransaction this Transaction will be reused instead of allocating
|
||||
* a new one. This is an optimization to avoid extra allocations
|
||||
* when repeatedly creating transactions.
|
||||
* @return The oldTransaction which has been reinitialized as a new
|
||||
* transaction
|
||||
*/
|
||||
Transaction beginTransaction(final WriteOptions writeOptions,
|
||||
final T transactionOptions, final Transaction oldTransaction);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
package org.rocksdb;
|
||||
|
||||
|
||||
interface TransactionalOptions extends AutoCloseable {
|
||||
|
||||
/**
|
||||
* True indicates snapshots will be set, just like if
|
||||
* {@link Transaction#setSnapshot()} had been called
|
||||
*
|
||||
* @return whether a snapshot will be set
|
||||
*/
|
||||
boolean isSetSnapshot();
|
||||
|
||||
/**
|
||||
* Setting the setSnapshot to true is the same as calling
|
||||
* {@link Transaction#setSnapshot()}.
|
||||
*
|
||||
* Default: false
|
||||
*
|
||||
* @param <T> The type of transactional options.
|
||||
* @param setSnapshot Whether to set a snapshot
|
||||
*
|
||||
* @return this TransactionalOptions instance
|
||||
*/
|
||||
<T extends TransactionalOptions> T setSetSnapshot(final boolean setSnapshot);
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
package org.rocksdb;
|
||||
|
||||
/**
|
||||
* The transaction db write policy.
|
||||
*/
|
||||
public enum TxnDBWritePolicy {
|
||||
/**
|
||||
* Write only the committed data.
|
||||
*/
|
||||
WRITE_COMMITTED((byte)0x00),
|
||||
|
||||
/**
|
||||
* Write data after the prepare phase of 2pc.
|
||||
*/
|
||||
WRITE_PREPARED((byte)0x1),
|
||||
|
||||
/**
|
||||
* Write data before the prepare phase of 2pc.
|
||||
*/
|
||||
WRITE_UNPREPARED((byte)0x2);
|
||||
|
||||
private byte value;
|
||||
|
||||
TxnDBWritePolicy(final byte value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns the byte value of the enumerations value.</p>
|
||||
*
|
||||
* @return byte representation
|
||||
*/
|
||||
public byte getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Get the TxnDBWritePolicy enumeration value by
|
||||
* passing the byte identifier to this method.</p>
|
||||
*
|
||||
* @param byteIdentifier of TxnDBWritePolicy.
|
||||
*
|
||||
* @return TxnDBWritePolicy instance.
|
||||
*
|
||||
* @throws IllegalArgumentException If TxnDBWritePolicy cannot be found for
|
||||
* the provided byteIdentifier
|
||||
*/
|
||||
public static TxnDBWritePolicy getTxnDBWritePolicy(final byte byteIdentifier) {
|
||||
for (final TxnDBWritePolicy txnDBWritePolicy : TxnDBWritePolicy.values()) {
|
||||
if (txnDBWritePolicy.getValue() == byteIdentifier) {
|
||||
return txnDBWritePolicy;
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(
|
||||
"Illegal value provided for TxnDBWritePolicy.");
|
||||
}
|
||||
}
|
||||
@@ -65,7 +65,7 @@ public enum WALRecoveryMode {
|
||||
*
|
||||
* @param byteIdentifier of WALRecoveryMode.
|
||||
*
|
||||
* @return CompressionType instance.
|
||||
* @return WALRecoveryMode instance.
|
||||
*
|
||||
* @throws IllegalArgumentException If WALRecoveryMode cannot be found for the
|
||||
* provided byteIdentifier
|
||||
|
||||
@@ -55,10 +55,13 @@ public class WBWIRocksIterator
|
||||
* that created the record in the Write Batch
|
||||
*/
|
||||
public enum WriteType {
|
||||
PUT((byte)0x1),
|
||||
MERGE((byte)0x2),
|
||||
DELETE((byte)0x4),
|
||||
LOG((byte)0x8);
|
||||
PUT((byte)0x0),
|
||||
MERGE((byte)0x1),
|
||||
DELETE((byte)0x2),
|
||||
SINGLE_DELETE((byte)0x3),
|
||||
DELETE_RANGE((byte)0x4),
|
||||
LOG((byte)0x5),
|
||||
XID((byte)0x6);
|
||||
|
||||
final byte id;
|
||||
WriteType(final byte id) {
|
||||
|
||||
@@ -39,6 +39,14 @@ public class WriteBatch extends AbstractWriteBatch {
|
||||
super(newWriteBatch(reserved_bytes));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a WriteBatch instance from a serialized representation
|
||||
* as returned by {@link #data()}.
|
||||
*/
|
||||
public WriteBatch(final byte[] serialized) {
|
||||
super(newWriteBatch(serialized, serialized.length));
|
||||
}
|
||||
|
||||
/**
|
||||
* Support for iterating over the contents of a batch.
|
||||
*
|
||||
@@ -51,6 +59,134 @@ public class WriteBatch extends AbstractWriteBatch {
|
||||
iterate(nativeHandle_, handler.nativeHandle_);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the serialized version of this batch.
|
||||
*
|
||||
* @return the serialized representation of this write batch.
|
||||
*/
|
||||
public byte[] data() {
|
||||
return data(nativeHandle_);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve data size of the batch.
|
||||
*
|
||||
* @return the serialized data size of the batch.
|
||||
*/
|
||||
public long getDataSize() {
|
||||
return getDataSize(nativeHandle_);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if PutCF will be called during Iterate.
|
||||
*
|
||||
* Return true if PutCF will be called during Iterate.
|
||||
*/
|
||||
public boolean hasPut() {
|
||||
return hasPut(nativeHandle_);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if DeleteCF will be called during Iterate.
|
||||
*
|
||||
* Return true if DeleteCF will be called during Iterate.
|
||||
*/
|
||||
public boolean hasDelete() {
|
||||
return hasDelete(nativeHandle_);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if SingleDeleteCF will be called during Iterate.
|
||||
*
|
||||
* Return true if SingleDeleteCF will be called during Iterate.
|
||||
*/
|
||||
public boolean hasSingleDelete() {
|
||||
return hasSingleDelete(nativeHandle_);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if DeleteRangeCF will be called during Iterate.
|
||||
*
|
||||
* Return true if DeleteRangeCF will be called during Iterate.
|
||||
*/
|
||||
public boolean hasDeleteRange() {
|
||||
return hasDeleteRange(nativeHandle_);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if MergeCF will be called during Iterate.
|
||||
*
|
||||
* Return true if MergeCF will be called during Iterate.
|
||||
*/
|
||||
public boolean hasMerge() {
|
||||
return hasMerge(nativeHandle_);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if MarkBeginPrepare will be called during Iterate.
|
||||
*
|
||||
* Return true if MarkBeginPrepare will be called during Iterate.
|
||||
*/
|
||||
public boolean hasBeginPrepare() {
|
||||
return hasBeginPrepare(nativeHandle_);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if MarkEndPrepare will be called during Iterate.
|
||||
*
|
||||
* Return true if MarkEndPrepare will be called during Iterate.
|
||||
*/
|
||||
public boolean hasEndPrepare() {
|
||||
return hasEndPrepare(nativeHandle_);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if MarkCommit will be called during Iterate.
|
||||
*
|
||||
* Return true if MarkCommit will be called during Iterate.
|
||||
*/
|
||||
public boolean hasCommit() {
|
||||
return hasCommit(nativeHandle_);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if MarkRollback will be called during Iterate.
|
||||
*
|
||||
* Return true if MarkRollback will be called during Iterate.
|
||||
*/
|
||||
public boolean hasRollback() {
|
||||
return hasRollback(nativeHandle_);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WriteBatch getWriteBatch() {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks this point in the WriteBatch as the last record to
|
||||
* be inserted into the WAL, provided the WAL is enabled.
|
||||
*/
|
||||
public void markWalTerminationPoint() {
|
||||
markWalTerminationPoint(nativeHandle_);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the WAL termination point.
|
||||
*
|
||||
* See {@link #markWalTerminationPoint()}
|
||||
*
|
||||
* @return the WAL termination point
|
||||
*/
|
||||
public SavePoint getWalTerminationPoint() {
|
||||
return getWalTerminationPoint(nativeHandle_);
|
||||
}
|
||||
|
||||
@Override
|
||||
WriteBatch getWriteBatch(final long handle) {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Private WriteBatch constructor which is used to construct
|
||||
* WriteBatch instances from C++ side. As the reference to this
|
||||
@@ -87,10 +223,14 @@ public class WriteBatch extends AbstractWriteBatch {
|
||||
@Override final native void merge(final long handle, final byte[] key,
|
||||
final int keyLen, final byte[] value, final int valueLen,
|
||||
final long cfHandle);
|
||||
@Override final native void remove(final long handle, final byte[] key,
|
||||
final int keyLen);
|
||||
@Override final native void remove(final long handle, final byte[] key,
|
||||
final int keyLen, final long cfHandle);
|
||||
@Override final native void delete(final long handle, final byte[] key,
|
||||
final int keyLen) throws RocksDBException;
|
||||
@Override final native void delete(final long handle, final byte[] key,
|
||||
final int keyLen, final long cfHandle) throws RocksDBException;
|
||||
@Override final native void singleDelete(final long handle, final byte[] key,
|
||||
final int keyLen) throws RocksDBException;
|
||||
@Override final native void singleDelete(final long handle, final byte[] key,
|
||||
final int keyLen, final long cfHandle) throws RocksDBException;
|
||||
@Override
|
||||
final native void deleteRange(final long handle, final byte[] beginKey, final int beginKeyLen,
|
||||
final byte[] endKey, final int endKeyLen);
|
||||
@@ -98,15 +238,32 @@ public class WriteBatch extends AbstractWriteBatch {
|
||||
final native void deleteRange(final long handle, final byte[] beginKey, final int beginKeyLen,
|
||||
final byte[] endKey, final int endKeyLen, final long cfHandle);
|
||||
@Override final native void putLogData(final long handle,
|
||||
final byte[] blob, final int blobLen);
|
||||
final byte[] blob, final int blobLen) throws RocksDBException;
|
||||
@Override final native void clear0(final long handle);
|
||||
@Override final native void setSavePoint0(final long handle);
|
||||
@Override final native void rollbackToSavePoint0(final long handle);
|
||||
@Override final native void popSavePoint(final long handle) throws RocksDBException;
|
||||
@Override final native void setMaxBytes(final long nativeHandle,
|
||||
final long maxBytes);
|
||||
|
||||
private native static long newWriteBatch(final int reserved_bytes);
|
||||
private native static long newWriteBatch(final byte[] serialized,
|
||||
final int serializedLength);
|
||||
private native void iterate(final long handle, final long handlerHandle)
|
||||
throws RocksDBException;
|
||||
|
||||
private native byte[] data(final long nativeHandle);
|
||||
private native long getDataSize(final long nativeHandle);
|
||||
private native boolean hasPut(final long nativeHandle);
|
||||
private native boolean hasDelete(final long nativeHandle);
|
||||
private native boolean hasSingleDelete(final long nativeHandle);
|
||||
private native boolean hasDeleteRange(final long nativeHandle);
|
||||
private native boolean hasMerge(final long nativeHandle);
|
||||
private native boolean hasBeginPrepare(final long nativeHandle);
|
||||
private native boolean hasEndPrepare(final long nativeHandle);
|
||||
private native boolean hasCommit(final long nativeHandle);
|
||||
private native boolean hasRollback(final long nativeHandle);
|
||||
private native void markWalTerminationPoint(final long nativeHandle);
|
||||
private native SavePoint getWalTerminationPoint(final long nativeHandle);
|
||||
|
||||
/**
|
||||
* Handler callback for iterating over the contents of a batch.
|
||||
@@ -122,15 +279,38 @@ public class WriteBatch extends AbstractWriteBatch {
|
||||
return createNewHandler0();
|
||||
}
|
||||
|
||||
public abstract void put(byte[] key, byte[] value);
|
||||
public abstract void merge(byte[] key, byte[] value);
|
||||
public abstract void delete(byte[] key);
|
||||
public abstract void deleteRange(byte[] beginKey, byte[] endKey);
|
||||
public abstract void logData(byte[] blob);
|
||||
public abstract void put(final int columnFamilyId, final byte[] key,
|
||||
final byte[] value) throws RocksDBException;
|
||||
public abstract void put(final byte[] key, final byte[] value);
|
||||
public abstract void merge(final int columnFamilyId, final byte[] key,
|
||||
final byte[] value) throws RocksDBException;
|
||||
public abstract void merge(final byte[] key, final byte[] value);
|
||||
public abstract void delete(final int columnFamilyId, final byte[] key)
|
||||
throws RocksDBException;
|
||||
public abstract void delete(final byte[] key);
|
||||
public abstract void singleDelete(final int columnFamilyId,
|
||||
final byte[] key) throws RocksDBException;
|
||||
public abstract void singleDelete(final byte[] key);
|
||||
public abstract void deleteRange(final int columnFamilyId,
|
||||
final byte[] beginKey, final byte[] endKey) throws RocksDBException;
|
||||
public abstract void deleteRange(final byte[] beginKey,
|
||||
final byte[] endKey);
|
||||
public abstract void logData(final byte[] blob);
|
||||
public abstract void putBlobIndex(final int columnFamilyId,
|
||||
final byte[] key, final byte[] value) throws RocksDBException;
|
||||
public abstract void markBeginPrepare() throws RocksDBException;
|
||||
public abstract void markEndPrepare(final byte[] xid)
|
||||
throws RocksDBException;
|
||||
public abstract void markNoop(final boolean emptyBatch)
|
||||
throws RocksDBException;
|
||||
public abstract void markRollback(final byte[] xid)
|
||||
throws RocksDBException;
|
||||
public abstract void markCommit(final byte[] xid)
|
||||
throws RocksDBException;
|
||||
|
||||
/**
|
||||
* shouldContinue is called by the underlying iterator
|
||||
* WriteBatch::Iterate. If it returns false,
|
||||
* {@link WriteBatch#iterate(Handler)}. If it returns false,
|
||||
* iteration is halted. Otherwise, it continues
|
||||
* iterating. The default implementation always
|
||||
* returns true.
|
||||
@@ -144,4 +324,57 @@ public class WriteBatch extends AbstractWriteBatch {
|
||||
|
||||
private native long createNewHandler0();
|
||||
}
|
||||
|
||||
/**
|
||||
* A structure for describing the save point in the Write Batch.
|
||||
*/
|
||||
public static class SavePoint {
|
||||
private long size;
|
||||
private long count;
|
||||
private long contentFlags;
|
||||
|
||||
public SavePoint(final long size, final long count,
|
||||
final long contentFlags) {
|
||||
this.size = size;
|
||||
this.count = count;
|
||||
this.contentFlags = contentFlags;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
this.size = 0;
|
||||
this.count = 0;
|
||||
this.contentFlags = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the size of the serialized representation.
|
||||
*
|
||||
* @return the size of the serialized representation.
|
||||
*/
|
||||
public long getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of elements.
|
||||
*
|
||||
* @return the number of elements.
|
||||
*/
|
||||
public long getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the content flags.
|
||||
*
|
||||
* @return the content flags.
|
||||
*/
|
||||
public long getContentFlags() {
|
||||
return contentFlags;
|
||||
}
|
||||
|
||||
public boolean isCleared() {
|
||||
return (size | count | contentFlags) == 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ public interface WriteBatchInterface {
|
||||
* @param key the specified key to be inserted.
|
||||
* @param value the value associated with the specified key.
|
||||
*/
|
||||
void put(byte[] key, byte[] value);
|
||||
void put(byte[] key, byte[] value) throws RocksDBException;
|
||||
|
||||
/**
|
||||
* <p>Store the mapping "key->value" within given column
|
||||
@@ -36,7 +36,7 @@ public interface WriteBatchInterface {
|
||||
* @param value the value associated with the specified key.
|
||||
*/
|
||||
void put(ColumnFamilyHandle columnFamilyHandle,
|
||||
byte[] key, byte[] value);
|
||||
byte[] key, byte[] value) throws RocksDBException;
|
||||
|
||||
/**
|
||||
* <p>Merge "value" with the existing value of "key" in the database.
|
||||
@@ -46,7 +46,7 @@ public interface WriteBatchInterface {
|
||||
* @param value the value to be merged with the current value for
|
||||
* the specified key.
|
||||
*/
|
||||
void merge(byte[] key, byte[] value);
|
||||
void merge(byte[] key, byte[] value) throws RocksDBException;
|
||||
|
||||
/**
|
||||
* <p>Merge "value" with the existing value of "key" in given column family.
|
||||
@@ -58,14 +58,36 @@ public interface WriteBatchInterface {
|
||||
* the specified key.
|
||||
*/
|
||||
void merge(ColumnFamilyHandle columnFamilyHandle,
|
||||
byte[] key, byte[] value);
|
||||
byte[] key, byte[] value) throws RocksDBException;
|
||||
|
||||
/**
|
||||
* <p>If the database contains a mapping for "key", erase it. Else do nothing.</p>
|
||||
*
|
||||
* @param key Key to delete within database
|
||||
*
|
||||
* @deprecated Use {@link #delete(byte[])}
|
||||
*/
|
||||
@Deprecated
|
||||
void remove(byte[] key) throws RocksDBException;
|
||||
|
||||
/**
|
||||
* <p>If column family contains a mapping for "key", erase it. Else do nothing.</p>
|
||||
*
|
||||
* @param columnFamilyHandle {@link ColumnFamilyHandle} instance
|
||||
* @param key Key to delete within database
|
||||
*
|
||||
* @deprecated Use {@link #delete(ColumnFamilyHandle, byte[])}
|
||||
*/
|
||||
@Deprecated
|
||||
void remove(ColumnFamilyHandle columnFamilyHandle, byte[] key)
|
||||
throws RocksDBException;
|
||||
|
||||
/**
|
||||
* <p>If the database contains a mapping for "key", erase it. Else do nothing.</p>
|
||||
*
|
||||
* @param key Key to delete within database
|
||||
*/
|
||||
void remove(byte[] key);
|
||||
void delete(byte[] key) throws RocksDBException;
|
||||
|
||||
/**
|
||||
* <p>If column family contains a mapping for "key", erase it. Else do nothing.</p>
|
||||
@@ -73,7 +95,58 @@ public interface WriteBatchInterface {
|
||||
* @param columnFamilyHandle {@link ColumnFamilyHandle} instance
|
||||
* @param key Key to delete within database
|
||||
*/
|
||||
void remove(ColumnFamilyHandle columnFamilyHandle, byte[] key);
|
||||
void delete(ColumnFamilyHandle columnFamilyHandle, byte[] key)
|
||||
throws RocksDBException;
|
||||
|
||||
/**
|
||||
* Remove the database entry for {@code key}. Requires that the key exists
|
||||
* and was not overwritten. It is not an error if the key did not exist
|
||||
* in the database.
|
||||
*
|
||||
* If a key is overwritten (by calling {@link #put(byte[], byte[])} multiple
|
||||
* times), then the result of calling SingleDelete() on this key is undefined.
|
||||
* SingleDelete() only behaves correctly if there has been only one Put()
|
||||
* for this key since the previous call to SingleDelete() for this key.
|
||||
*
|
||||
* This feature is currently an experimental performance optimization
|
||||
* for a very specific workload. It is up to the caller to ensure that
|
||||
* SingleDelete is only used for a key that is not deleted using Delete() or
|
||||
* written using Merge(). Mixing SingleDelete operations with Deletes and
|
||||
* Merges can result in undefined behavior.
|
||||
*
|
||||
* @param key Key to delete within database
|
||||
*
|
||||
* @throws RocksDBException thrown if error happens in underlying
|
||||
* native library.
|
||||
*/
|
||||
@Experimental("Performance optimization for a very specific workload")
|
||||
void singleDelete(final byte[] key) throws RocksDBException;
|
||||
|
||||
/**
|
||||
* Remove the database entry for {@code key}. Requires that the key exists
|
||||
* and was not overwritten. It is not an error if the key did not exist
|
||||
* in the database.
|
||||
*
|
||||
* If a key is overwritten (by calling {@link #put(byte[], byte[])} multiple
|
||||
* times), then the result of calling SingleDelete() on this key is undefined.
|
||||
* SingleDelete() only behaves correctly if there has been only one Put()
|
||||
* for this key since the previous call to SingleDelete() for this key.
|
||||
*
|
||||
* This feature is currently an experimental performance optimization
|
||||
* for a very specific workload. It is up to the caller to ensure that
|
||||
* SingleDelete is only used for a key that is not deleted using Delete() or
|
||||
* written using Merge(). Mixing SingleDelete operations with Deletes and
|
||||
* Merges can result in undefined behavior.
|
||||
*
|
||||
* @param columnFamilyHandle The column family to delete the key from
|
||||
* @param key Key to delete within database
|
||||
*
|
||||
* @throws RocksDBException thrown if error happens in underlying
|
||||
* native library.
|
||||
*/
|
||||
@Experimental("Performance optimization for a very specific workload")
|
||||
void singleDelete(final ColumnFamilyHandle columnFamilyHandle,
|
||||
final byte[] key) throws RocksDBException;
|
||||
|
||||
/**
|
||||
* Removes the database entries in the range ["beginKey", "endKey"), i.e.,
|
||||
@@ -89,7 +162,7 @@ public interface WriteBatchInterface {
|
||||
* @param endKey
|
||||
* Last key to delete within database (excluded)
|
||||
*/
|
||||
void deleteRange(byte[] beginKey, byte[] endKey);
|
||||
void deleteRange(byte[] beginKey, byte[] endKey) throws RocksDBException;
|
||||
|
||||
/**
|
||||
* Removes the database entries in the range ["beginKey", "endKey"), i.e.,
|
||||
@@ -106,7 +179,8 @@ public interface WriteBatchInterface {
|
||||
* @param endKey
|
||||
* Last key to delete within database (excluded)
|
||||
*/
|
||||
void deleteRange(ColumnFamilyHandle columnFamilyHandle, byte[] beginKey, byte[] endKey);
|
||||
void deleteRange(ColumnFamilyHandle columnFamilyHandle, byte[] beginKey,
|
||||
byte[] endKey) throws RocksDBException;
|
||||
|
||||
/**
|
||||
* Append a blob of arbitrary size to the records in this batch. The blob will
|
||||
@@ -122,7 +196,7 @@ public interface WriteBatchInterface {
|
||||
*
|
||||
* @param blob binary object to be inserted
|
||||
*/
|
||||
void putLogData(byte[] blob);
|
||||
void putLogData(byte[] blob) throws RocksDBException;
|
||||
|
||||
/**
|
||||
* Clear all updates buffered in this batch
|
||||
@@ -143,4 +217,30 @@ public interface WriteBatchInterface {
|
||||
* @throws RocksDBException if there is no previous call to SetSavePoint()
|
||||
*/
|
||||
void rollbackToSavePoint() throws RocksDBException;
|
||||
|
||||
/**
|
||||
* Pop the most recent save point.
|
||||
*
|
||||
* That is to say that it removes the last save point,
|
||||
* which was set by {@link #setSavePoint()}.
|
||||
*
|
||||
* @throws RocksDBException If there is no previous call to
|
||||
* {@link #setSavePoint()}, an exception with
|
||||
* {@link Status.Code#NotFound} will be thrown.
|
||||
*/
|
||||
void popSavePoint() throws RocksDBException;
|
||||
|
||||
/**
|
||||
* Set the maximum size of the write batch.
|
||||
*
|
||||
* @param maxBytes the maximum size in bytes.
|
||||
*/
|
||||
void setMaxBytes(long maxBytes);
|
||||
|
||||
/**
|
||||
* Get the underlying Write Batch.
|
||||
*
|
||||
* @return the underlying WriteBatch.
|
||||
*/
|
||||
WriteBatch getWriteBatch();
|
||||
}
|
||||
|
||||
@@ -61,7 +61,20 @@ public class WriteBatchWithIndex extends AbstractWriteBatch {
|
||||
fallbackIndexComparator, final int reservedBytes,
|
||||
final boolean overwriteKey) {
|
||||
super(newWriteBatchWithIndex(fallbackIndexComparator.nativeHandle_,
|
||||
fallbackIndexComparator instanceof DirectComparator, reservedBytes, overwriteKey));
|
||||
fallbackIndexComparator.getComparatorType().getValue(), reservedBytes,
|
||||
overwriteKey));
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Private WriteBatchWithIndex constructor which is used to construct
|
||||
* WriteBatchWithIndex instances from C++ side. As the reference to this
|
||||
* object is also managed from C++ side the handle will be disowned.</p>
|
||||
*
|
||||
* @param nativeHandle address of native instance.
|
||||
*/
|
||||
WriteBatchWithIndex(final long nativeHandle) {
|
||||
super(nativeHandle);
|
||||
disOwnNativeHandle();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -244,10 +257,14 @@ public class WriteBatchWithIndex extends AbstractWriteBatch {
|
||||
@Override final native void merge(final long handle, final byte[] key,
|
||||
final int keyLen, final byte[] value, final int valueLen,
|
||||
final long cfHandle);
|
||||
@Override final native void remove(final long handle, final byte[] key,
|
||||
final int keyLen);
|
||||
@Override final native void remove(final long handle, final byte[] key,
|
||||
final int keyLen, final long cfHandle);
|
||||
@Override final native void delete(final long handle, final byte[] key,
|
||||
final int keyLen) throws RocksDBException;
|
||||
@Override final native void delete(final long handle, final byte[] key,
|
||||
final int keyLen, final long cfHandle) throws RocksDBException;
|
||||
@Override final native void singleDelete(final long handle, final byte[] key,
|
||||
final int keyLen) throws RocksDBException;
|
||||
@Override final native void singleDelete(final long handle, final byte[] key,
|
||||
final int keyLen, final long cfHandle) throws RocksDBException;
|
||||
@Override
|
||||
final native void deleteRange(final long handle, final byte[] beginKey, final int beginKeyLen,
|
||||
final byte[] endKey, final int endKeyLen);
|
||||
@@ -255,15 +272,20 @@ public class WriteBatchWithIndex extends AbstractWriteBatch {
|
||||
final native void deleteRange(final long handle, final byte[] beginKey, final int beginKeyLen,
|
||||
final byte[] endKey, final int endKeyLen, final long cfHandle);
|
||||
@Override final native void putLogData(final long handle, final byte[] blob,
|
||||
final int blobLen);
|
||||
final int blobLen) throws RocksDBException;
|
||||
@Override final native void clear0(final long handle);
|
||||
@Override final native void setSavePoint0(final long handle);
|
||||
@Override final native void rollbackToSavePoint0(final long handle);
|
||||
@Override final native void popSavePoint(final long handle) throws RocksDBException;
|
||||
@Override final native void setMaxBytes(final long nativeHandle,
|
||||
final long maxBytes);
|
||||
@Override final native WriteBatch getWriteBatch(final long handle);
|
||||
|
||||
private native static long newWriteBatchWithIndex();
|
||||
private native static long newWriteBatchWithIndex(final boolean overwriteKey);
|
||||
private native static long newWriteBatchWithIndex(
|
||||
final long fallbackIndexComparatorHandle, final boolean isDirect, final int reservedBytes,
|
||||
final long fallbackIndexComparatorHandle,
|
||||
final byte comparatorType, final int reservedBytes,
|
||||
final boolean overwriteKey);
|
||||
private native long iterator0(final long handle);
|
||||
private native long iterator1(final long handle, final long cfHandle);
|
||||
|
||||
@@ -20,6 +20,12 @@ public class WriteOptions extends RocksObject {
|
||||
|
||||
}
|
||||
|
||||
// TODO(AR) consider ownership
|
||||
WriteOptions(final long nativeHandle) {
|
||||
super(nativeHandle);
|
||||
disOwnNativeHandle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor for WriteOptions.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,903 @@
|
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
package org.rocksdb;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
|
||||
/**
|
||||
* Base class of {@link TransactionTest} and {@link OptimisticTransactionTest}
|
||||
*/
|
||||
public abstract class AbstractTransactionTest {
|
||||
|
||||
protected final static byte[] TXN_TEST_COLUMN_FAMILY = "txn_test_cf"
|
||||
.getBytes();
|
||||
|
||||
protected static final Random rand = PlatformRandomHelper.
|
||||
getPlatformSpecificRandomFactory();
|
||||
|
||||
@Rule
|
||||
public TemporaryFolder dbFolder = new TemporaryFolder();
|
||||
|
||||
public abstract DBContainer startDb()
|
||||
throws RocksDBException;
|
||||
|
||||
@Test
|
||||
public void setSnapshot() throws RocksDBException {
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
txn.setSnapshot();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setSnapshotOnNextOperation() throws RocksDBException {
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
txn.setSnapshotOnNextOperation();
|
||||
txn.put("key1".getBytes(), "value1".getBytes());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setSnapshotOnNextOperation_transactionNotifier() throws RocksDBException {
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
|
||||
try(final TestTransactionNotifier notifier = new TestTransactionNotifier()) {
|
||||
txn.setSnapshotOnNextOperation(notifier);
|
||||
txn.put("key1".getBytes(), "value1".getBytes());
|
||||
|
||||
txn.setSnapshotOnNextOperation(notifier);
|
||||
txn.put("key2".getBytes(), "value2".getBytes());
|
||||
|
||||
assertThat(notifier.getCreatedSnapshots().size()).isEqualTo(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSnapshot() throws RocksDBException {
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
txn.setSnapshot();
|
||||
final Snapshot snapshot = txn.getSnapshot();
|
||||
assertThat(snapshot.isOwningHandle()).isFalse();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSnapshot_null() throws RocksDBException {
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
final Snapshot snapshot = txn.getSnapshot();
|
||||
assertThat(snapshot).isNull();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void clearSnapshot() throws RocksDBException {
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
txn.setSnapshot();
|
||||
txn.clearSnapshot();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void clearSnapshot_none() throws RocksDBException {
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
txn.clearSnapshot();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void commit() throws RocksDBException {
|
||||
final byte k1[] = "rollback-key1".getBytes(UTF_8);
|
||||
final byte v1[] = "rollback-value1".getBytes(UTF_8);
|
||||
try(final DBContainer dbContainer = startDb()) {
|
||||
try(final Transaction txn = dbContainer.beginTransaction()) {
|
||||
txn.put(k1, v1);
|
||||
txn.commit();
|
||||
}
|
||||
|
||||
try(final ReadOptions readOptions = new ReadOptions();
|
||||
final Transaction txn2 = dbContainer.beginTransaction()) {
|
||||
assertThat(txn2.get(readOptions, k1)).isEqualTo(v1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rollback() throws RocksDBException {
|
||||
final byte k1[] = "rollback-key1".getBytes(UTF_8);
|
||||
final byte v1[] = "rollback-value1".getBytes(UTF_8);
|
||||
try(final DBContainer dbContainer = startDb()) {
|
||||
try(final Transaction txn = dbContainer.beginTransaction()) {
|
||||
txn.put(k1, v1);
|
||||
txn.rollback();
|
||||
}
|
||||
|
||||
try(final ReadOptions readOptions = new ReadOptions();
|
||||
final Transaction txn2 = dbContainer.beginTransaction()) {
|
||||
assertThat(txn2.get(readOptions, k1)).isNull();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void savePoint() throws RocksDBException {
|
||||
final byte k1[] = "savePoint-key1".getBytes(UTF_8);
|
||||
final byte v1[] = "savePoint-value1".getBytes(UTF_8);
|
||||
final byte k2[] = "savePoint-key2".getBytes(UTF_8);
|
||||
final byte v2[] = "savePoint-value2".getBytes(UTF_8);
|
||||
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final ReadOptions readOptions = new ReadOptions()) {
|
||||
|
||||
|
||||
try(final Transaction txn = dbContainer.beginTransaction()) {
|
||||
txn.put(k1, v1);
|
||||
|
||||
assertThat(txn.get(readOptions, k1)).isEqualTo(v1);
|
||||
|
||||
txn.setSavePoint();
|
||||
|
||||
txn.put(k2, v2);
|
||||
|
||||
assertThat(txn.get(readOptions, k1)).isEqualTo(v1);
|
||||
assertThat(txn.get(readOptions, k2)).isEqualTo(v2);
|
||||
|
||||
txn.rollbackToSavePoint();
|
||||
|
||||
assertThat(txn.get(readOptions, k1)).isEqualTo(v1);
|
||||
assertThat(txn.get(readOptions, k2)).isNull();
|
||||
|
||||
txn.commit();
|
||||
}
|
||||
|
||||
try(final Transaction txn2 = dbContainer.beginTransaction()) {
|
||||
assertThat(txn2.get(readOptions, k1)).isEqualTo(v1);
|
||||
assertThat(txn2.get(readOptions, k2)).isNull();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getPut_cf() throws RocksDBException {
|
||||
final byte k1[] = "key1".getBytes(UTF_8);
|
||||
final byte v1[] = "value1".getBytes(UTF_8);
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final ReadOptions readOptions = new ReadOptions();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
final ColumnFamilyHandle testCf = dbContainer.getTestColumnFamily();
|
||||
assertThat(txn.get(testCf, readOptions, k1)).isNull();
|
||||
txn.put(testCf, k1, v1);
|
||||
assertThat(txn.get(testCf, readOptions, k1)).isEqualTo(v1);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getPut() throws RocksDBException {
|
||||
final byte k1[] = "key1".getBytes(UTF_8);
|
||||
final byte v1[] = "value1".getBytes(UTF_8);
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final ReadOptions readOptions = new ReadOptions();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
assertThat(txn.get(readOptions, k1)).isNull();
|
||||
txn.put(k1, v1);
|
||||
assertThat(txn.get(readOptions, k1)).isEqualTo(v1);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multiGetPut_cf() throws RocksDBException {
|
||||
final byte keys[][] = new byte[][] {
|
||||
"key1".getBytes(UTF_8),
|
||||
"key2".getBytes(UTF_8)};
|
||||
final byte values[][] = new byte[][] {
|
||||
"value1".getBytes(UTF_8),
|
||||
"value2".getBytes(UTF_8)};
|
||||
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final ReadOptions readOptions = new ReadOptions();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
final ColumnFamilyHandle testCf = dbContainer.getTestColumnFamily();
|
||||
final List<ColumnFamilyHandle> cfList = Arrays.asList(testCf, testCf);
|
||||
|
||||
assertThat(txn.multiGet(readOptions, cfList, keys)).isEqualTo(new byte[][] { null, null });
|
||||
|
||||
txn.put(testCf, keys[0], values[0]);
|
||||
txn.put(testCf, keys[1], values[1]);
|
||||
assertThat(txn.multiGet(readOptions, cfList, keys)).isEqualTo(values);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multiGetPut() throws RocksDBException {
|
||||
final byte keys[][] = new byte[][] {
|
||||
"key1".getBytes(UTF_8),
|
||||
"key2".getBytes(UTF_8)};
|
||||
final byte values[][] = new byte[][] {
|
||||
"value1".getBytes(UTF_8),
|
||||
"value2".getBytes(UTF_8)};
|
||||
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final ReadOptions readOptions = new ReadOptions();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
|
||||
assertThat(txn.multiGet(readOptions, keys)).isEqualTo(new byte[][] { null, null });
|
||||
|
||||
txn.put(keys[0], values[0]);
|
||||
txn.put(keys[1], values[1]);
|
||||
assertThat(txn.multiGet(readOptions, keys)).isEqualTo(values);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getForUpdate_cf() throws RocksDBException {
|
||||
final byte k1[] = "key1".getBytes(UTF_8);
|
||||
final byte v1[] = "value1".getBytes(UTF_8);
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final ReadOptions readOptions = new ReadOptions();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
final ColumnFamilyHandle testCf = dbContainer.getTestColumnFamily();
|
||||
assertThat(txn.getForUpdate(readOptions, testCf, k1, true)).isNull();
|
||||
txn.put(testCf, k1, v1);
|
||||
assertThat(txn.getForUpdate(readOptions, testCf, k1, true)).isEqualTo(v1);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getForUpdate() throws RocksDBException {
|
||||
final byte k1[] = "key1".getBytes(UTF_8);
|
||||
final byte v1[] = "value1".getBytes(UTF_8);
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final ReadOptions readOptions = new ReadOptions();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
assertThat(txn.getForUpdate(readOptions, k1, true)).isNull();
|
||||
txn.put(k1, v1);
|
||||
assertThat(txn.getForUpdate(readOptions, k1, true)).isEqualTo(v1);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multiGetForUpdate_cf() throws RocksDBException {
|
||||
final byte keys[][] = new byte[][] {
|
||||
"key1".getBytes(UTF_8),
|
||||
"key2".getBytes(UTF_8)};
|
||||
final byte values[][] = new byte[][] {
|
||||
"value1".getBytes(UTF_8),
|
||||
"value2".getBytes(UTF_8)};
|
||||
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final ReadOptions readOptions = new ReadOptions();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
final ColumnFamilyHandle testCf = dbContainer.getTestColumnFamily();
|
||||
final List<ColumnFamilyHandle> cfList = Arrays.asList(testCf, testCf);
|
||||
|
||||
assertThat(txn.multiGetForUpdate(readOptions, cfList, keys))
|
||||
.isEqualTo(new byte[][] { null, null });
|
||||
|
||||
txn.put(testCf, keys[0], values[0]);
|
||||
txn.put(testCf, keys[1], values[1]);
|
||||
assertThat(txn.multiGetForUpdate(readOptions, cfList, keys))
|
||||
.isEqualTo(values);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multiGetForUpdate() throws RocksDBException {
|
||||
final byte keys[][] = new byte[][]{
|
||||
"key1".getBytes(UTF_8),
|
||||
"key2".getBytes(UTF_8)};
|
||||
final byte values[][] = new byte[][]{
|
||||
"value1".getBytes(UTF_8),
|
||||
"value2".getBytes(UTF_8)};
|
||||
|
||||
try (final DBContainer dbContainer = startDb();
|
||||
final ReadOptions readOptions = new ReadOptions();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
assertThat(txn.multiGetForUpdate(readOptions, keys)).isEqualTo(new byte[][]{null, null});
|
||||
|
||||
txn.put(keys[0], values[0]);
|
||||
txn.put(keys[1], values[1]);
|
||||
assertThat(txn.multiGetForUpdate(readOptions, keys)).isEqualTo(values);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getIterator() throws RocksDBException {
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final ReadOptions readOptions = new ReadOptions();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
|
||||
final byte[] k1 = "key1".getBytes(UTF_8);
|
||||
final byte[] v1 = "value1".getBytes(UTF_8);
|
||||
|
||||
txn.put(k1, v1);
|
||||
|
||||
try(final RocksIterator iterator = txn.getIterator(readOptions)) {
|
||||
iterator.seek(k1);
|
||||
assertThat(iterator.isValid()).isTrue();
|
||||
assertThat(iterator.key()).isEqualTo(k1);
|
||||
assertThat(iterator.value()).isEqualTo(v1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getIterator_cf() throws RocksDBException {
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final ReadOptions readOptions = new ReadOptions();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
final ColumnFamilyHandle testCf = dbContainer.getTestColumnFamily();
|
||||
|
||||
final byte[] k1 = "key1".getBytes(UTF_8);
|
||||
final byte[] v1 = "value1".getBytes(UTF_8);
|
||||
|
||||
txn.put(testCf, k1, v1);
|
||||
|
||||
try(final RocksIterator iterator = txn.getIterator(readOptions, testCf)) {
|
||||
iterator.seek(k1);
|
||||
assertThat(iterator.isValid()).isTrue();
|
||||
assertThat(iterator.key()).isEqualTo(k1);
|
||||
assertThat(iterator.value()).isEqualTo(v1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void merge_cf() throws RocksDBException {
|
||||
final byte[] k1 = "key1".getBytes(UTF_8);
|
||||
final byte[] v1 = "value1".getBytes(UTF_8);
|
||||
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
final ColumnFamilyHandle testCf = dbContainer.getTestColumnFamily();
|
||||
txn.merge(testCf, k1, v1);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void merge() throws RocksDBException {
|
||||
final byte[] k1 = "key1".getBytes(UTF_8);
|
||||
final byte[] v1 = "value1".getBytes(UTF_8);
|
||||
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
txn.merge(k1, v1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void delete_cf() throws RocksDBException {
|
||||
final byte[] k1 = "key1".getBytes(UTF_8);
|
||||
final byte[] v1 = "value1".getBytes(UTF_8);
|
||||
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final ReadOptions readOptions = new ReadOptions();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
final ColumnFamilyHandle testCf = dbContainer.getTestColumnFamily();
|
||||
txn.put(testCf, k1, v1);
|
||||
assertThat(txn.get(testCf, readOptions, k1)).isEqualTo(v1);
|
||||
|
||||
txn.delete(testCf, k1);
|
||||
assertThat(txn.get(testCf, readOptions, k1)).isNull();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void delete() throws RocksDBException {
|
||||
final byte[] k1 = "key1".getBytes(UTF_8);
|
||||
final byte[] v1 = "value1".getBytes(UTF_8);
|
||||
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final ReadOptions readOptions = new ReadOptions();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
txn.put(k1, v1);
|
||||
assertThat(txn.get(readOptions, k1)).isEqualTo(v1);
|
||||
|
||||
txn.delete(k1);
|
||||
assertThat(txn.get(readOptions, k1)).isNull();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void delete_parts_cf() throws RocksDBException {
|
||||
final byte keyParts[][] = new byte[][] {
|
||||
"ke".getBytes(UTF_8),
|
||||
"y1".getBytes(UTF_8)};
|
||||
final byte valueParts[][] = new byte[][] {
|
||||
"val".getBytes(UTF_8),
|
||||
"ue1".getBytes(UTF_8)};
|
||||
final byte[] key = concat(keyParts);
|
||||
final byte[] value = concat(valueParts);
|
||||
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final ReadOptions readOptions = new ReadOptions();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
final ColumnFamilyHandle testCf = dbContainer.getTestColumnFamily();
|
||||
txn.put(testCf, keyParts, valueParts);
|
||||
assertThat(txn.get(testCf, readOptions, key)).isEqualTo(value);
|
||||
|
||||
txn.delete(testCf, keyParts);
|
||||
|
||||
assertThat(txn.get(testCf, readOptions, key))
|
||||
.isNull();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void delete_parts() throws RocksDBException {
|
||||
final byte keyParts[][] = new byte[][] {
|
||||
"ke".getBytes(UTF_8),
|
||||
"y1".getBytes(UTF_8)};
|
||||
final byte valueParts[][] = new byte[][] {
|
||||
"val".getBytes(UTF_8),
|
||||
"ue1".getBytes(UTF_8)};
|
||||
final byte[] key = concat(keyParts);
|
||||
final byte[] value = concat(valueParts);
|
||||
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final ReadOptions readOptions = new ReadOptions();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
|
||||
txn.put(keyParts, valueParts);
|
||||
|
||||
assertThat(txn.get(readOptions, key)).isEqualTo(value);
|
||||
|
||||
txn.delete(keyParts);
|
||||
|
||||
assertThat(txn.get(readOptions, key)).isNull();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getPutUntracked_cf() throws RocksDBException {
|
||||
final byte k1[] = "key1".getBytes(UTF_8);
|
||||
final byte v1[] = "value1".getBytes(UTF_8);
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final ReadOptions readOptions = new ReadOptions();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
final ColumnFamilyHandle testCf = dbContainer.getTestColumnFamily();
|
||||
assertThat(txn.get(testCf, readOptions, k1)).isNull();
|
||||
txn.putUntracked(testCf, k1, v1);
|
||||
assertThat(txn.get(testCf, readOptions, k1)).isEqualTo(v1);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getPutUntracked() throws RocksDBException {
|
||||
final byte k1[] = "key1".getBytes(UTF_8);
|
||||
final byte v1[] = "value1".getBytes(UTF_8);
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final ReadOptions readOptions = new ReadOptions();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
assertThat(txn.get(readOptions, k1)).isNull();
|
||||
txn.putUntracked(k1, v1);
|
||||
assertThat(txn.get(readOptions, k1)).isEqualTo(v1);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multiGetPutUntracked_cf() throws RocksDBException {
|
||||
final byte keys[][] = new byte[][] {
|
||||
"key1".getBytes(UTF_8),
|
||||
"key2".getBytes(UTF_8)};
|
||||
final byte values[][] = new byte[][] {
|
||||
"value1".getBytes(UTF_8),
|
||||
"value2".getBytes(UTF_8)};
|
||||
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final ReadOptions readOptions = new ReadOptions();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
final ColumnFamilyHandle testCf = dbContainer.getTestColumnFamily();
|
||||
|
||||
final List<ColumnFamilyHandle> cfList = Arrays.asList(testCf, testCf);
|
||||
|
||||
assertThat(txn.multiGet(readOptions, cfList, keys)).isEqualTo(new byte[][] { null, null });
|
||||
txn.putUntracked(testCf, keys[0], values[0]);
|
||||
txn.putUntracked(testCf, keys[1], values[1]);
|
||||
assertThat(txn.multiGet(readOptions, cfList, keys)).isEqualTo(values);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multiGetPutUntracked() throws RocksDBException {
|
||||
final byte keys[][] = new byte[][] {
|
||||
"key1".getBytes(UTF_8),
|
||||
"key2".getBytes(UTF_8)};
|
||||
final byte values[][] = new byte[][] {
|
||||
"value1".getBytes(UTF_8),
|
||||
"value2".getBytes(UTF_8)};
|
||||
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final ReadOptions readOptions = new ReadOptions();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
|
||||
assertThat(txn.multiGet(readOptions, keys)).isEqualTo(new byte[][] { null, null });
|
||||
txn.putUntracked(keys[0], values[0]);
|
||||
txn.putUntracked(keys[1], values[1]);
|
||||
assertThat(txn.multiGet(readOptions, keys)).isEqualTo(values);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mergeUntracked_cf() throws RocksDBException {
|
||||
final byte[] k1 = "key1".getBytes(UTF_8);
|
||||
final byte[] v1 = "value1".getBytes(UTF_8);
|
||||
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
final ColumnFamilyHandle testCf = dbContainer.getTestColumnFamily();
|
||||
txn.mergeUntracked(testCf, k1, v1);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mergeUntracked() throws RocksDBException {
|
||||
final byte[] k1 = "key1".getBytes(UTF_8);
|
||||
final byte[] v1 = "value1".getBytes(UTF_8);
|
||||
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
txn.mergeUntracked(k1, v1);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteUntracked_cf() throws RocksDBException {
|
||||
final byte[] k1 = "key1".getBytes(UTF_8);
|
||||
final byte[] v1 = "value1".getBytes(UTF_8);
|
||||
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final ReadOptions readOptions = new ReadOptions();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
final ColumnFamilyHandle testCf = dbContainer.getTestColumnFamily();
|
||||
txn.put(testCf, k1, v1);
|
||||
assertThat(txn.get(testCf, readOptions, k1)).isEqualTo(v1);
|
||||
|
||||
txn.deleteUntracked(testCf, k1);
|
||||
assertThat(txn.get(testCf, readOptions, k1)).isNull();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteUntracked() throws RocksDBException {
|
||||
final byte[] k1 = "key1".getBytes(UTF_8);
|
||||
final byte[] v1 = "value1".getBytes(UTF_8);
|
||||
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final ReadOptions readOptions = new ReadOptions();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
txn.put(k1, v1);
|
||||
assertThat(txn.get(readOptions, k1)).isEqualTo(v1);
|
||||
|
||||
txn.deleteUntracked(k1);
|
||||
assertThat(txn.get(readOptions, k1)).isNull();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteUntracked_parts_cf() throws RocksDBException {
|
||||
final byte keyParts[][] = new byte[][] {
|
||||
"ke".getBytes(UTF_8),
|
||||
"y1".getBytes(UTF_8)};
|
||||
final byte valueParts[][] = new byte[][] {
|
||||
"val".getBytes(UTF_8),
|
||||
"ue1".getBytes(UTF_8)};
|
||||
final byte[] key = concat(keyParts);
|
||||
final byte[] value = concat(valueParts);
|
||||
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final ReadOptions readOptions = new ReadOptions();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
final ColumnFamilyHandle testCf = dbContainer.getTestColumnFamily();
|
||||
txn.put(testCf, keyParts, valueParts);
|
||||
assertThat(txn.get(testCf, readOptions, key)).isEqualTo(value);
|
||||
|
||||
txn.deleteUntracked(testCf, keyParts);
|
||||
assertThat(txn.get(testCf, readOptions, key)).isNull();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteUntracked_parts() throws RocksDBException {
|
||||
final byte keyParts[][] = new byte[][] {
|
||||
"ke".getBytes(UTF_8),
|
||||
"y1".getBytes(UTF_8)};
|
||||
final byte valueParts[][] = new byte[][] {
|
||||
"val".getBytes(UTF_8),
|
||||
"ue1".getBytes(UTF_8)};
|
||||
final byte[] key = concat(keyParts);
|
||||
final byte[] value = concat(valueParts);
|
||||
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final ReadOptions readOptions = new ReadOptions();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
txn.put(keyParts, valueParts);
|
||||
assertThat(txn.get(readOptions, key)).isEqualTo(value);
|
||||
|
||||
txn.deleteUntracked(keyParts);
|
||||
assertThat(txn.get(readOptions, key)).isNull();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void putLogData() throws RocksDBException {
|
||||
final byte[] blob = "blobby".getBytes(UTF_8);
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
txn.putLogData(blob);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void enabledDisableIndexing() throws RocksDBException {
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
txn.disableIndexing();
|
||||
txn.enableIndexing();
|
||||
txn.disableIndexing();
|
||||
txn.enableIndexing();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void numKeys() throws RocksDBException {
|
||||
final byte k1[] = "key1".getBytes(UTF_8);
|
||||
final byte v1[] = "value1".getBytes(UTF_8);
|
||||
final byte k2[] = "key2".getBytes(UTF_8);
|
||||
final byte v2[] = "value2".getBytes(UTF_8);
|
||||
final byte k3[] = "key3".getBytes(UTF_8);
|
||||
final byte v3[] = "value3".getBytes(UTF_8);
|
||||
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
final ColumnFamilyHandle testCf = dbContainer.getTestColumnFamily();
|
||||
txn.put(k1, v1);
|
||||
txn.put(testCf, k2, v2);
|
||||
txn.merge(k3, v3);
|
||||
txn.delete(testCf, k2);
|
||||
|
||||
assertThat(txn.getNumKeys()).isEqualTo(3);
|
||||
assertThat(txn.getNumPuts()).isEqualTo(2);
|
||||
assertThat(txn.getNumMerges()).isEqualTo(1);
|
||||
assertThat(txn.getNumDeletes()).isEqualTo(1);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void elapsedTime() throws RocksDBException, InterruptedException {
|
||||
final long preStartTxnTime = System.currentTimeMillis();
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
Thread.sleep(1);
|
||||
|
||||
final long txnElapsedTime = txn.getElapsedTime();
|
||||
assertThat(txnElapsedTime).isLessThan(System.currentTimeMillis()
|
||||
- preStartTxnTime);
|
||||
assertThat(txnElapsedTime).isGreaterThan(0);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getWriteBatch() throws RocksDBException {
|
||||
final byte k1[] = "key1".getBytes(UTF_8);
|
||||
final byte v1[] = "value1".getBytes(UTF_8);
|
||||
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
|
||||
txn.put(k1, v1);
|
||||
|
||||
final WriteBatchWithIndex writeBatch = txn.getWriteBatch();
|
||||
assertThat(writeBatch).isNotNull();
|
||||
assertThat(writeBatch.isOwningHandle()).isFalse();
|
||||
assertThat(writeBatch.count()).isEqualTo(1);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setLockTimeout() throws RocksDBException {
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
txn.setLockTimeout(1000);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void writeOptions() throws RocksDBException {
|
||||
final byte k1[] = "key1".getBytes(UTF_8);
|
||||
final byte v1[] = "value1".getBytes(UTF_8);
|
||||
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final WriteOptions writeOptions = new WriteOptions()
|
||||
.setDisableWAL(true)
|
||||
.setSync(true);
|
||||
final Transaction txn = dbContainer.beginTransaction(writeOptions)) {
|
||||
|
||||
txn.put(k1, v1);
|
||||
|
||||
WriteOptions txnWriteOptions = txn.getWriteOptions();
|
||||
assertThat(txnWriteOptions).isNotNull();
|
||||
assertThat(txnWriteOptions.isOwningHandle()).isFalse();
|
||||
assertThat(txnWriteOptions).isNotSameAs(writeOptions);
|
||||
assertThat(txnWriteOptions.disableWAL()).isTrue();
|
||||
assertThat(txnWriteOptions.sync()).isTrue();
|
||||
|
||||
txn.setWriteOptions(txnWriteOptions.setSync(false));
|
||||
txnWriteOptions = txn.getWriteOptions();
|
||||
assertThat(txnWriteOptions).isNotNull();
|
||||
assertThat(txnWriteOptions.isOwningHandle()).isFalse();
|
||||
assertThat(txnWriteOptions).isNotSameAs(writeOptions);
|
||||
assertThat(txnWriteOptions.disableWAL()).isTrue();
|
||||
assertThat(txnWriteOptions.sync()).isFalse();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void undoGetForUpdate_cf() throws RocksDBException {
|
||||
final byte k1[] = "key1".getBytes(UTF_8);
|
||||
final byte v1[] = "value1".getBytes(UTF_8);
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final ReadOptions readOptions = new ReadOptions();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
final ColumnFamilyHandle testCf = dbContainer.getTestColumnFamily();
|
||||
assertThat(txn.getForUpdate(readOptions, testCf, k1, true)).isNull();
|
||||
txn.put(testCf, k1, v1);
|
||||
assertThat(txn.getForUpdate(readOptions, testCf, k1, true)).isEqualTo(v1);
|
||||
txn.undoGetForUpdate(testCf, k1);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void undoGetForUpdate() throws RocksDBException {
|
||||
final byte k1[] = "key1".getBytes(UTF_8);
|
||||
final byte v1[] = "value1".getBytes(UTF_8);
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final ReadOptions readOptions = new ReadOptions();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
assertThat(txn.getForUpdate(readOptions, k1, true)).isNull();
|
||||
txn.put(k1, v1);
|
||||
assertThat(txn.getForUpdate(readOptions, k1, true)).isEqualTo(v1);
|
||||
txn.undoGetForUpdate(k1);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rebuildFromWriteBatch() throws RocksDBException {
|
||||
final byte k1[] = "key1".getBytes(UTF_8);
|
||||
final byte v1[] = "value1".getBytes(UTF_8);
|
||||
final byte k2[] = "key2".getBytes(UTF_8);
|
||||
final byte v2[] = "value2".getBytes(UTF_8);
|
||||
final byte k3[] = "key3".getBytes(UTF_8);
|
||||
final byte v3[] = "value3".getBytes(UTF_8);
|
||||
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final ReadOptions readOptions = new ReadOptions();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
|
||||
txn.put(k1, v1);
|
||||
|
||||
assertThat(txn.get(readOptions, k1)).isEqualTo(v1);
|
||||
assertThat(txn.getNumKeys()).isEqualTo(1);
|
||||
|
||||
try(final WriteBatch writeBatch = new WriteBatch()) {
|
||||
writeBatch.put(k2, v2);
|
||||
writeBatch.put(k3, v3);
|
||||
txn.rebuildFromWriteBatch(writeBatch);
|
||||
|
||||
assertThat(txn.get(readOptions, k1)).isEqualTo(v1);
|
||||
assertThat(txn.get(readOptions, k2)).isEqualTo(v2);
|
||||
assertThat(txn.get(readOptions, k3)).isEqualTo(v3);
|
||||
assertThat(txn.getNumKeys()).isEqualTo(3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCommitTimeWriteBatch() throws RocksDBException {
|
||||
final byte k1[] = "key1".getBytes(UTF_8);
|
||||
final byte v1[] = "value1".getBytes(UTF_8);
|
||||
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
|
||||
txn.put(k1, v1);
|
||||
final WriteBatch writeBatch = txn.getCommitTimeWriteBatch();
|
||||
|
||||
assertThat(writeBatch).isNotNull();
|
||||
assertThat(writeBatch.isOwningHandle()).isFalse();
|
||||
assertThat(writeBatch.count()).isEqualTo(0);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void logNumber() throws RocksDBException {
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
assertThat(txn.getLogNumber()).isEqualTo(0);
|
||||
final long logNumber = rand.nextLong();
|
||||
txn.setLogNumber(logNumber);
|
||||
assertThat(txn.getLogNumber()).isEqualTo(logNumber);
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] concat(final byte[][] bufs) {
|
||||
int resultLength = 0;
|
||||
for(final byte[] buf : bufs) {
|
||||
resultLength += buf.length;
|
||||
}
|
||||
|
||||
final byte[] result = new byte[resultLength];
|
||||
int resultOffset = 0;
|
||||
for(final byte[] buf : bufs) {
|
||||
final int srcLength = buf.length;
|
||||
System.arraycopy(buf, 0, result, resultOffset, srcLength);
|
||||
resultOffset += srcLength;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static class TestTransactionNotifier
|
||||
extends AbstractTransactionNotifier {
|
||||
private final List<Snapshot> createdSnapshots = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void snapshotCreated(final Snapshot newSnapshot) {
|
||||
createdSnapshots.add(newSnapshot);
|
||||
}
|
||||
|
||||
public List<Snapshot> getCreatedSnapshots() {
|
||||
return createdSnapshots;
|
||||
}
|
||||
}
|
||||
|
||||
protected static abstract class DBContainer
|
||||
implements AutoCloseable {
|
||||
protected final WriteOptions writeOptions;
|
||||
protected final List<ColumnFamilyHandle> columnFamilyHandles;
|
||||
protected final ColumnFamilyOptions columnFamilyOptions;
|
||||
protected final DBOptions options;
|
||||
|
||||
public DBContainer(final WriteOptions writeOptions,
|
||||
final List<ColumnFamilyHandle> columnFamilyHandles,
|
||||
final ColumnFamilyOptions columnFamilyOptions,
|
||||
final DBOptions options) {
|
||||
this.writeOptions = writeOptions;
|
||||
this.columnFamilyHandles = columnFamilyHandles;
|
||||
this.columnFamilyOptions = columnFamilyOptions;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
public abstract Transaction beginTransaction();
|
||||
|
||||
public abstract Transaction beginTransaction(
|
||||
final WriteOptions writeOptions);
|
||||
|
||||
public ColumnFamilyHandle getTestColumnFamily() {
|
||||
return columnFamilyHandles.get(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract void close();
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,11 @@
|
||||
package org.rocksdb;
|
||||
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -16,6 +20,8 @@ public class BlockBasedTableConfigTest {
|
||||
public static final RocksMemoryResource rocksMemoryResource =
|
||||
new RocksMemoryResource();
|
||||
|
||||
@Rule public TemporaryFolder dbFolder = new TemporaryFolder();
|
||||
|
||||
@Test
|
||||
public void noBlockCache() {
|
||||
BlockBasedTableConfig blockBasedTableConfig = new BlockBasedTableConfig();
|
||||
@@ -31,6 +37,31 @@ public class BlockBasedTableConfigTest {
|
||||
isEqualTo(8 * 1024);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sharedBlockCache() throws RocksDBException {
|
||||
try (final Cache cache = new LRUCache(8 * 1024 * 1024);
|
||||
final Statistics statistics = new Statistics()) {
|
||||
for (int shard = 0; shard < 8; shard++) {
|
||||
try (final Options options =
|
||||
new Options()
|
||||
.setCreateIfMissing(true)
|
||||
.setStatistics(statistics)
|
||||
.setTableFormatConfig(new BlockBasedTableConfig().setBlockCache(cache));
|
||||
final RocksDB db =
|
||||
RocksDB.open(options, dbFolder.getRoot().getAbsolutePath() + "/" + shard)) {
|
||||
final byte[] key = "some-key".getBytes(StandardCharsets.UTF_8);
|
||||
final byte[] value = "some-value".getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
db.put(key, value);
|
||||
db.flush(new FlushOptions());
|
||||
db.get(key);
|
||||
|
||||
assertThat(statistics.getTickerCount(TickerType.BLOCK_CACHE_ADD)).isEqualTo(shard + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void blockSizeDeviation() {
|
||||
BlockBasedTableConfig blockBasedTableConfig = new BlockBasedTableConfig();
|
||||
@@ -148,6 +179,14 @@ public class BlockBasedTableConfigTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void blockBasedTableWithBlockCache() {
|
||||
try (final Options options = new Options().setTableFormatConfig(
|
||||
new BlockBasedTableConfig().setBlockCache(new LRUCache(17 * 1024 * 1024)))) {
|
||||
assertThat(options.tableFactoryName()).isEqualTo("BlockBasedTable");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void blockBasedTableFormatVersion() {
|
||||
BlockBasedTableConfig config = new BlockBasedTableConfig();
|
||||
|
||||
@@ -12,6 +12,7 @@ import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class ColumnFamilyTest {
|
||||
@@ -23,6 +24,31 @@ public class ColumnFamilyTest {
|
||||
@Rule
|
||||
public TemporaryFolder dbFolder = new TemporaryFolder();
|
||||
|
||||
@Test
|
||||
public void columnFamilyDescriptorName() throws RocksDBException {
|
||||
final byte[] cfName = "some_name".getBytes(UTF_8);
|
||||
|
||||
try(final ColumnFamilyOptions cfOptions = new ColumnFamilyOptions()) {
|
||||
final ColumnFamilyDescriptor cfDescriptor =
|
||||
new ColumnFamilyDescriptor(cfName, cfOptions);
|
||||
assertThat(cfDescriptor.getName()).isEqualTo(cfName);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void columnFamilyDescriptorOptions() throws RocksDBException {
|
||||
final byte[] cfName = "some_name".getBytes(UTF_8);
|
||||
|
||||
try(final ColumnFamilyOptions cfOptions = new ColumnFamilyOptions()
|
||||
.setCompressionType(CompressionType.BZLIB2_COMPRESSION)) {
|
||||
final ColumnFamilyDescriptor cfDescriptor =
|
||||
new ColumnFamilyDescriptor(cfName, cfOptions);
|
||||
|
||||
assertThat(cfDescriptor.getOptions().compressionType())
|
||||
.isEqualTo(CompressionType.BZLIB2_COMPRESSION);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void listColumnFamilies() throws RocksDBException {
|
||||
try (final Options options = new Options().setCreateIfMissing(true);
|
||||
@@ -47,6 +73,9 @@ public class ColumnFamilyTest {
|
||||
try {
|
||||
assertThat(cfh).isNotNull();
|
||||
|
||||
assertThat(cfh.getName()).isEqualTo("default".getBytes(UTF_8));
|
||||
assertThat(cfh.getID()).isEqualTo(0);
|
||||
|
||||
final byte[] key = "key".getBytes();
|
||||
final byte[] value = "value".getBytes();
|
||||
|
||||
@@ -64,15 +93,25 @@ public class ColumnFamilyTest {
|
||||
|
||||
@Test
|
||||
public void createColumnFamily() throws RocksDBException {
|
||||
final byte[] cfName = "new_cf".getBytes(UTF_8);
|
||||
final ColumnFamilyDescriptor cfDescriptor = new ColumnFamilyDescriptor(cfName,
|
||||
new ColumnFamilyOptions());
|
||||
|
||||
try (final Options options = new Options().setCreateIfMissing(true);
|
||||
final RocksDB db = RocksDB.open(options,
|
||||
dbFolder.getRoot().getAbsolutePath())) {
|
||||
final ColumnFamilyHandle columnFamilyHandle = db.createColumnFamily(
|
||||
new ColumnFamilyDescriptor("new_cf".getBytes(),
|
||||
new ColumnFamilyOptions()));
|
||||
dbFolder.getRoot().getAbsolutePath())) {
|
||||
|
||||
final ColumnFamilyHandle columnFamilyHandle = db.createColumnFamily(cfDescriptor);
|
||||
|
||||
try {
|
||||
assertThat(columnFamilyHandle.getName()).isEqualTo(cfName);
|
||||
assertThat(columnFamilyHandle.getID()).isEqualTo(1);
|
||||
|
||||
final ColumnFamilyDescriptor latestDescriptor = columnFamilyHandle.getDescriptor();
|
||||
assertThat(latestDescriptor.getName()).isEqualTo(cfName);
|
||||
|
||||
final List<byte[]> columnFamilyNames = RocksDB.listColumnFamilies(
|
||||
options, dbFolder.getRoot().getAbsolutePath());
|
||||
options, dbFolder.getRoot().getAbsolutePath());
|
||||
assertThat(columnFamilyNames).isNotNull();
|
||||
assertThat(columnFamilyNames.size()).isGreaterThan(0);
|
||||
assertThat(columnFamilyNames.size()).isEqualTo(2);
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
package org.rocksdb;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Comparator;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class NativeComparatorWrapperTest {
|
||||
|
||||
@Rule
|
||||
public TemporaryFolder dbFolder = new TemporaryFolder();
|
||||
|
||||
private static final Random random = new Random();
|
||||
|
||||
@Test
|
||||
public void rountrip() throws RocksDBException {
|
||||
final String dbPath = dbFolder.getRoot().getAbsolutePath();
|
||||
final int ITERATIONS = 1_000;
|
||||
|
||||
final String[] storedKeys = new String[ITERATIONS];
|
||||
try (final NativeStringComparatorWrapper comparator = new NativeStringComparatorWrapper();
|
||||
final Options opt = new Options()
|
||||
.setCreateIfMissing(true)
|
||||
.setComparator(comparator)) {
|
||||
|
||||
// store random integer keys
|
||||
try (final RocksDB db = RocksDB.open(opt, dbPath)) {
|
||||
for (int i = 0; i < ITERATIONS; i++) {
|
||||
final String strKey = randomString();
|
||||
final byte key[] = strKey.getBytes();
|
||||
// does key already exist (avoid duplicates)
|
||||
if (i > 0 && db.get(key) != null) {
|
||||
i--; // generate a different key
|
||||
} else {
|
||||
db.put(key, "value".getBytes());
|
||||
storedKeys[i] = strKey;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sort the stored keys into ascending alpha-numeric order
|
||||
Arrays.sort(storedKeys, new Comparator<String>() {
|
||||
@Override
|
||||
public int compare(final String o1, final String o2) {
|
||||
return o1.compareTo(o2);
|
||||
}
|
||||
});
|
||||
|
||||
// re-open db and read from start to end
|
||||
// string keys should be in ascending
|
||||
// order
|
||||
try (final RocksDB db = RocksDB.open(opt, dbPath);
|
||||
final RocksIterator it = db.newIterator()) {
|
||||
int count = 0;
|
||||
for (it.seekToFirst(); it.isValid(); it.next()) {
|
||||
final String strKey = new String(it.key());
|
||||
assertEquals(storedKeys[count++], strKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String randomString() {
|
||||
final char[] chars = new char[12];
|
||||
for(int i = 0; i < 12; i++) {
|
||||
final int letterCode = random.nextInt(24);
|
||||
final char letter = (char) (((int) 'a') + letterCode);
|
||||
chars[i] = letter;
|
||||
}
|
||||
return String.copyValueOf(chars);
|
||||
}
|
||||
|
||||
public static class NativeStringComparatorWrapper
|
||||
extends NativeComparatorWrapper {
|
||||
|
||||
@Override
|
||||
protected long initializeNative(final long... nativeParameterHandles) {
|
||||
return newStringComparator();
|
||||
}
|
||||
|
||||
private native long newStringComparator();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
package org.rocksdb;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class OptimisticTransactionDBTest {
|
||||
|
||||
@Rule
|
||||
public TemporaryFolder dbFolder = new TemporaryFolder();
|
||||
|
||||
@Test
|
||||
public void open() throws RocksDBException {
|
||||
try (final Options options = new Options().setCreateIfMissing(true);
|
||||
final OptimisticTransactionDB otdb = OptimisticTransactionDB.open(options,
|
||||
dbFolder.getRoot().getAbsolutePath())) {
|
||||
assertThat(otdb).isNotNull();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void open_columnFamilies() throws RocksDBException {
|
||||
try(final DBOptions dbOptions = new DBOptions().setCreateIfMissing(true)
|
||||
.setCreateMissingColumnFamilies(true);
|
||||
final ColumnFamilyOptions myCfOpts = new ColumnFamilyOptions()) {
|
||||
|
||||
final List<ColumnFamilyDescriptor> columnFamilyDescriptors =
|
||||
Arrays.asList(
|
||||
new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY),
|
||||
new ColumnFamilyDescriptor("myCf".getBytes(), myCfOpts));
|
||||
|
||||
final List<ColumnFamilyHandle> columnFamilyHandles = new ArrayList<>();
|
||||
|
||||
try (final OptimisticTransactionDB otdb = OptimisticTransactionDB.open(dbOptions,
|
||||
dbFolder.getRoot().getAbsolutePath(),
|
||||
columnFamilyDescriptors, columnFamilyHandles)) {
|
||||
try {
|
||||
assertThat(otdb).isNotNull();
|
||||
} finally {
|
||||
for (final ColumnFamilyHandle handle : columnFamilyHandles) {
|
||||
handle.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beginTransaction() throws RocksDBException {
|
||||
try (final Options options = new Options().setCreateIfMissing(true);
|
||||
final OptimisticTransactionDB otdb = OptimisticTransactionDB.open(
|
||||
options, dbFolder.getRoot().getAbsolutePath());
|
||||
final WriteOptions writeOptions = new WriteOptions()) {
|
||||
|
||||
try(final Transaction txn = otdb.beginTransaction(writeOptions)) {
|
||||
assertThat(txn).isNotNull();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beginTransaction_transactionOptions() throws RocksDBException {
|
||||
try (final Options options = new Options().setCreateIfMissing(true);
|
||||
final OptimisticTransactionDB otdb = OptimisticTransactionDB.open(
|
||||
options, dbFolder.getRoot().getAbsolutePath());
|
||||
final WriteOptions writeOptions = new WriteOptions();
|
||||
final OptimisticTransactionOptions optimisticTxnOptions =
|
||||
new OptimisticTransactionOptions()) {
|
||||
|
||||
try(final Transaction txn = otdb.beginTransaction(writeOptions,
|
||||
optimisticTxnOptions)) {
|
||||
assertThat(txn).isNotNull();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beginTransaction_withOld() throws RocksDBException {
|
||||
try (final Options options = new Options().setCreateIfMissing(true);
|
||||
final OptimisticTransactionDB otdb = OptimisticTransactionDB.open(
|
||||
options, dbFolder.getRoot().getAbsolutePath());
|
||||
final WriteOptions writeOptions = new WriteOptions()) {
|
||||
|
||||
try(final Transaction txn = otdb.beginTransaction(writeOptions)) {
|
||||
final Transaction txnReused = otdb.beginTransaction(writeOptions, txn);
|
||||
assertThat(txnReused).isSameAs(txn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beginTransaction_withOld_transactionOptions()
|
||||
throws RocksDBException {
|
||||
try (final Options options = new Options().setCreateIfMissing(true);
|
||||
final OptimisticTransactionDB otdb = OptimisticTransactionDB.open(
|
||||
options, dbFolder.getRoot().getAbsolutePath());
|
||||
final WriteOptions writeOptions = new WriteOptions();
|
||||
final OptimisticTransactionOptions optimisticTxnOptions =
|
||||
new OptimisticTransactionOptions()) {
|
||||
|
||||
try(final Transaction txn = otdb.beginTransaction(writeOptions)) {
|
||||
final Transaction txnReused = otdb.beginTransaction(writeOptions,
|
||||
optimisticTxnOptions, txn);
|
||||
assertThat(txnReused).isSameAs(txn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void baseDB() throws RocksDBException {
|
||||
try (final Options options = new Options().setCreateIfMissing(true);
|
||||
final OptimisticTransactionDB otdb = OptimisticTransactionDB.open(options,
|
||||
dbFolder.getRoot().getAbsolutePath())) {
|
||||
assertThat(otdb).isNotNull();
|
||||
final RocksDB db = otdb.getBaseDB();
|
||||
assertThat(db).isNotNull();
|
||||
assertThat(db.isOwningHandle()).isFalse();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
package org.rocksdb;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.rocksdb.util.DirectBytewiseComparator;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class OptimisticTransactionOptionsTest {
|
||||
|
||||
private static final Random rand = PlatformRandomHelper.
|
||||
getPlatformSpecificRandomFactory();
|
||||
|
||||
@Test
|
||||
public void setSnapshot() {
|
||||
try (final OptimisticTransactionOptions opt = new OptimisticTransactionOptions()) {
|
||||
final boolean boolValue = rand.nextBoolean();
|
||||
opt.setSetSnapshot(boolValue);
|
||||
assertThat(opt.isSetSnapshot()).isEqualTo(boolValue);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void comparator() {
|
||||
try (final OptimisticTransactionOptions opt = new OptimisticTransactionOptions();
|
||||
final ComparatorOptions copt = new ComparatorOptions();
|
||||
final DirectComparator comparator = new DirectBytewiseComparator(copt)) {
|
||||
opt.setComparator(comparator);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,350 @@
|
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
package org.rocksdb;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
|
||||
public class OptimisticTransactionTest extends AbstractTransactionTest {
|
||||
|
||||
@Test
|
||||
public void getForUpdate_cf_conflict() throws RocksDBException {
|
||||
final byte k1[] = "key1".getBytes(UTF_8);
|
||||
final byte v1[] = "value1".getBytes(UTF_8);
|
||||
final byte v12[] = "value12".getBytes(UTF_8);
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final ReadOptions readOptions = new ReadOptions()) {
|
||||
final ColumnFamilyHandle testCf = dbContainer.getTestColumnFamily();
|
||||
|
||||
try(final Transaction txn = dbContainer.beginTransaction()) {
|
||||
txn.put(testCf, k1, v1);
|
||||
assertThat(txn.get(testCf, readOptions, k1)).isEqualTo(v1);
|
||||
txn.commit();
|
||||
}
|
||||
|
||||
try(final Transaction txn2 = dbContainer.beginTransaction()) {
|
||||
try(final Transaction txn3 = dbContainer.beginTransaction()) {
|
||||
assertThat(txn3.getForUpdate(readOptions, testCf, k1, true)).isEqualTo(v1);
|
||||
|
||||
// NOTE: txn2 updates k1, during txn3
|
||||
txn2.put(testCf, k1, v12);
|
||||
assertThat(txn2.get(testCf, readOptions, k1)).isEqualTo(v12);
|
||||
txn2.commit();
|
||||
|
||||
try {
|
||||
txn3.commit(); // should cause an exception!
|
||||
} catch(final RocksDBException e) {
|
||||
assertThat(e.getStatus().getCode()).isSameAs(Status.Code.Busy);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fail("Expected an exception for put after getForUpdate from conflicting" +
|
||||
"transactions");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getForUpdate_conflict() throws RocksDBException {
|
||||
final byte k1[] = "key1".getBytes(UTF_8);
|
||||
final byte v1[] = "value1".getBytes(UTF_8);
|
||||
final byte v12[] = "value12".getBytes(UTF_8);
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final ReadOptions readOptions = new ReadOptions()) {
|
||||
|
||||
try(final Transaction txn = dbContainer.beginTransaction()) {
|
||||
txn.put(k1, v1);
|
||||
assertThat(txn.get(readOptions, k1)).isEqualTo(v1);
|
||||
txn.commit();
|
||||
}
|
||||
|
||||
try(final Transaction txn2 = dbContainer.beginTransaction()) {
|
||||
try(final Transaction txn3 = dbContainer.beginTransaction()) {
|
||||
assertThat(txn3.getForUpdate(readOptions, k1, true)).isEqualTo(v1);
|
||||
|
||||
// NOTE: txn2 updates k1, during txn3
|
||||
txn2.put(k1, v12);
|
||||
assertThat(txn2.get(readOptions, k1)).isEqualTo(v12);
|
||||
txn2.commit();
|
||||
|
||||
try {
|
||||
txn3.commit(); // should cause an exception!
|
||||
} catch(final RocksDBException e) {
|
||||
assertThat(e.getStatus().getCode()).isSameAs(Status.Code.Busy);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fail("Expected an exception for put after getForUpdate from conflicting" +
|
||||
"transactions");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multiGetForUpdate_cf_conflict() throws RocksDBException {
|
||||
final byte keys[][] = new byte[][] {
|
||||
"key1".getBytes(UTF_8),
|
||||
"key2".getBytes(UTF_8)};
|
||||
final byte values[][] = new byte[][] {
|
||||
"value1".getBytes(UTF_8),
|
||||
"value2".getBytes(UTF_8)};
|
||||
final byte[] otherValue = "otherValue".getBytes(UTF_8);
|
||||
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final ReadOptions readOptions = new ReadOptions()) {
|
||||
final ColumnFamilyHandle testCf = dbContainer.getTestColumnFamily();
|
||||
final List<ColumnFamilyHandle> cfList = Arrays.asList(testCf, testCf);
|
||||
|
||||
try(final Transaction txn = dbContainer.beginTransaction()) {
|
||||
txn.put(testCf, keys[0], values[0]);
|
||||
txn.put(testCf, keys[1], values[1]);
|
||||
assertThat(txn.multiGet(readOptions, cfList, keys)).isEqualTo(values);
|
||||
txn.commit();
|
||||
}
|
||||
|
||||
try(final Transaction txn2 = dbContainer.beginTransaction()) {
|
||||
try(final Transaction txn3 = dbContainer.beginTransaction()) {
|
||||
assertThat(txn3.multiGetForUpdate(readOptions, cfList, keys))
|
||||
.isEqualTo(values);
|
||||
|
||||
// NOTE: txn2 updates k1, during txn3
|
||||
txn2.put(testCf, keys[0], otherValue);
|
||||
assertThat(txn2.get(testCf, readOptions, keys[0]))
|
||||
.isEqualTo(otherValue);
|
||||
txn2.commit();
|
||||
|
||||
try {
|
||||
txn3.commit(); // should cause an exception!
|
||||
} catch(final RocksDBException e) {
|
||||
assertThat(e.getStatus().getCode()).isSameAs(Status.Code.Busy);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fail("Expected an exception for put after getForUpdate from conflicting" +
|
||||
"transactions");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multiGetForUpdate_conflict() throws RocksDBException {
|
||||
final byte keys[][] = new byte[][] {
|
||||
"key1".getBytes(UTF_8),
|
||||
"key2".getBytes(UTF_8)};
|
||||
final byte values[][] = new byte[][] {
|
||||
"value1".getBytes(UTF_8),
|
||||
"value2".getBytes(UTF_8)};
|
||||
final byte[] otherValue = "otherValue".getBytes(UTF_8);
|
||||
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final ReadOptions readOptions = new ReadOptions()) {
|
||||
try(final Transaction txn = dbContainer.beginTransaction()) {
|
||||
txn.put(keys[0], values[0]);
|
||||
txn.put(keys[1], values[1]);
|
||||
assertThat(txn.multiGet(readOptions, keys)).isEqualTo(values);
|
||||
txn.commit();
|
||||
}
|
||||
|
||||
try(final Transaction txn2 = dbContainer.beginTransaction()) {
|
||||
try(final Transaction txn3 = dbContainer.beginTransaction()) {
|
||||
assertThat(txn3.multiGetForUpdate(readOptions, keys))
|
||||
.isEqualTo(values);
|
||||
|
||||
// NOTE: txn2 updates k1, during txn3
|
||||
txn2.put(keys[0], otherValue);
|
||||
assertThat(txn2.get(readOptions, keys[0]))
|
||||
.isEqualTo(otherValue);
|
||||
txn2.commit();
|
||||
|
||||
try {
|
||||
txn3.commit(); // should cause an exception!
|
||||
} catch(final RocksDBException e) {
|
||||
assertThat(e.getStatus().getCode()).isSameAs(Status.Code.Busy);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fail("Expected an exception for put after getForUpdate from conflicting" +
|
||||
"transactions");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void undoGetForUpdate_cf_conflict() throws RocksDBException {
|
||||
final byte k1[] = "key1".getBytes(UTF_8);
|
||||
final byte v1[] = "value1".getBytes(UTF_8);
|
||||
final byte v12[] = "value12".getBytes(UTF_8);
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final ReadOptions readOptions = new ReadOptions()) {
|
||||
final ColumnFamilyHandle testCf = dbContainer.getTestColumnFamily();
|
||||
|
||||
try(final Transaction txn = dbContainer.beginTransaction()) {
|
||||
txn.put(testCf, k1, v1);
|
||||
assertThat(txn.get(testCf, readOptions, k1)).isEqualTo(v1);
|
||||
txn.commit();
|
||||
}
|
||||
|
||||
try(final Transaction txn2 = dbContainer.beginTransaction()) {
|
||||
try(final Transaction txn3 = dbContainer.beginTransaction()) {
|
||||
assertThat(txn3.getForUpdate(readOptions, testCf, k1, true)).isEqualTo(v1);
|
||||
|
||||
// undo the getForUpdate
|
||||
txn3.undoGetForUpdate(testCf, k1);
|
||||
|
||||
// NOTE: txn2 updates k1, during txn3
|
||||
txn2.put(testCf, k1, v12);
|
||||
assertThat(txn2.get(testCf, readOptions, k1)).isEqualTo(v12);
|
||||
txn2.commit();
|
||||
|
||||
// should not cause an exception
|
||||
// because we undid the getForUpdate above!
|
||||
txn3.commit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void undoGetForUpdate_conflict() throws RocksDBException {
|
||||
final byte k1[] = "key1".getBytes(UTF_8);
|
||||
final byte v1[] = "value1".getBytes(UTF_8);
|
||||
final byte v12[] = "value12".getBytes(UTF_8);
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final ReadOptions readOptions = new ReadOptions()) {
|
||||
|
||||
try(final Transaction txn = dbContainer.beginTransaction()) {
|
||||
txn.put(k1, v1);
|
||||
assertThat(txn.get(readOptions, k1)).isEqualTo(v1);
|
||||
txn.commit();
|
||||
}
|
||||
|
||||
try(final Transaction txn2 = dbContainer.beginTransaction()) {
|
||||
try(final Transaction txn3 = dbContainer.beginTransaction()) {
|
||||
assertThat(txn3.getForUpdate(readOptions, k1, true)).isEqualTo(v1);
|
||||
|
||||
// undo the getForUpdate
|
||||
txn3.undoGetForUpdate(k1);
|
||||
|
||||
// NOTE: txn2 updates k1, during txn3
|
||||
txn2.put(k1, v12);
|
||||
assertThat(txn2.get(readOptions, k1)).isEqualTo(v12);
|
||||
txn2.commit();
|
||||
|
||||
// should not cause an exception
|
||||
// because we undid the getForUpdate above!
|
||||
txn3.commit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void name() throws RocksDBException {
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
assertThat(txn.getName()).isEmpty();
|
||||
final String name = "my-transaction-" + rand.nextLong();
|
||||
|
||||
try {
|
||||
txn.setName(name);
|
||||
} catch(final RocksDBException e) {
|
||||
assertThat(e.getStatus().getCode() == Status.Code.InvalidArgument);
|
||||
return;
|
||||
}
|
||||
|
||||
fail("Optimistic transactions cannot be named.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public OptimisticTransactionDBContainer startDb()
|
||||
throws RocksDBException {
|
||||
final DBOptions options = new DBOptions()
|
||||
.setCreateIfMissing(true)
|
||||
.setCreateMissingColumnFamilies(true);
|
||||
|
||||
final ColumnFamilyOptions columnFamilyOptions = new ColumnFamilyOptions();
|
||||
final List<ColumnFamilyDescriptor> columnFamilyDescriptors =
|
||||
Arrays.asList(
|
||||
new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY),
|
||||
new ColumnFamilyDescriptor(TXN_TEST_COLUMN_FAMILY,
|
||||
columnFamilyOptions));
|
||||
final List<ColumnFamilyHandle> columnFamilyHandles = new ArrayList<>();
|
||||
|
||||
final OptimisticTransactionDB optimisticTxnDb;
|
||||
try {
|
||||
optimisticTxnDb = OptimisticTransactionDB.open(
|
||||
options, dbFolder.getRoot().getAbsolutePath(),
|
||||
columnFamilyDescriptors, columnFamilyHandles);
|
||||
} catch(final RocksDBException e) {
|
||||
columnFamilyOptions.close();
|
||||
options.close();
|
||||
throw e;
|
||||
}
|
||||
|
||||
final WriteOptions writeOptions = new WriteOptions();
|
||||
final OptimisticTransactionOptions optimisticTxnOptions =
|
||||
new OptimisticTransactionOptions();
|
||||
|
||||
return new OptimisticTransactionDBContainer(optimisticTxnOptions,
|
||||
writeOptions, columnFamilyHandles, optimisticTxnDb, columnFamilyOptions,
|
||||
options);
|
||||
}
|
||||
|
||||
private static class OptimisticTransactionDBContainer
|
||||
extends DBContainer {
|
||||
|
||||
private final OptimisticTransactionOptions optimisticTxnOptions;
|
||||
private final OptimisticTransactionDB optimisticTxnDb;
|
||||
|
||||
public OptimisticTransactionDBContainer(
|
||||
final OptimisticTransactionOptions optimisticTxnOptions,
|
||||
final WriteOptions writeOptions,
|
||||
final List<ColumnFamilyHandle> columnFamilyHandles,
|
||||
final OptimisticTransactionDB optimisticTxnDb,
|
||||
final ColumnFamilyOptions columnFamilyOptions,
|
||||
final DBOptions options) {
|
||||
super(writeOptions, columnFamilyHandles, columnFamilyOptions,
|
||||
options);
|
||||
this.optimisticTxnOptions = optimisticTxnOptions;
|
||||
this.optimisticTxnDb = optimisticTxnDb;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Transaction beginTransaction() {
|
||||
return optimisticTxnDb.beginTransaction(writeOptions,
|
||||
optimisticTxnOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Transaction beginTransaction(final WriteOptions writeOptions) {
|
||||
return optimisticTxnDb.beginTransaction(writeOptions,
|
||||
optimisticTxnOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
optimisticTxnOptions.close();
|
||||
writeOptions.close();
|
||||
for(final ColumnFamilyHandle columnFamilyHandle : columnFamilyHandles) {
|
||||
columnFamilyHandle.close();
|
||||
}
|
||||
optimisticTxnDb.close();
|
||||
options.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
package org.rocksdb;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class TransactionDBOptionsTest {
|
||||
|
||||
private static final Random rand = PlatformRandomHelper.
|
||||
getPlatformSpecificRandomFactory();
|
||||
|
||||
@Test
|
||||
public void maxNumLocks() {
|
||||
try (final TransactionDBOptions opt = new TransactionDBOptions()) {
|
||||
final long longValue = rand.nextLong();
|
||||
opt.setMaxNumLocks(longValue);
|
||||
assertThat(opt.getMaxNumLocks()).isEqualTo(longValue);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void maxNumStripes() {
|
||||
try (final TransactionDBOptions opt = new TransactionDBOptions()) {
|
||||
final long longValue = rand.nextLong();
|
||||
opt.setNumStripes(longValue);
|
||||
assertThat(opt.getNumStripes()).isEqualTo(longValue);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void transactionLockTimeout() {
|
||||
try (final TransactionDBOptions opt = new TransactionDBOptions()) {
|
||||
final long longValue = rand.nextLong();
|
||||
opt.setTransactionLockTimeout(longValue);
|
||||
assertThat(opt.getTransactionLockTimeout()).isEqualTo(longValue);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultLockTimeout() {
|
||||
try (final TransactionDBOptions opt = new TransactionDBOptions()) {
|
||||
final long longValue = rand.nextLong();
|
||||
opt.setDefaultLockTimeout(longValue);
|
||||
assertThat(opt.getDefaultLockTimeout()).isEqualTo(longValue);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void writePolicy() {
|
||||
try (final TransactionDBOptions opt = new TransactionDBOptions()) {
|
||||
final TxnDBWritePolicy writePolicy = TxnDBWritePolicy.WRITE_UNPREPARED; // non-default
|
||||
opt.setWritePolicy(writePolicy);
|
||||
assertThat(opt.getWritePolicy()).isEqualTo(writePolicy);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
package org.rocksdb;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
public class TransactionDBTest {
|
||||
|
||||
@Rule
|
||||
public TemporaryFolder dbFolder = new TemporaryFolder();
|
||||
|
||||
@Test
|
||||
public void open() throws RocksDBException {
|
||||
try (final Options options = new Options().setCreateIfMissing(true);
|
||||
final TransactionDBOptions txnDbOptions = new TransactionDBOptions();
|
||||
final TransactionDB tdb = TransactionDB.open(options, txnDbOptions,
|
||||
dbFolder.getRoot().getAbsolutePath())) {
|
||||
assertThat(tdb).isNotNull();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void open_columnFamilies() throws RocksDBException {
|
||||
try(final DBOptions dbOptions = new DBOptions().setCreateIfMissing(true)
|
||||
.setCreateMissingColumnFamilies(true);
|
||||
final ColumnFamilyOptions myCfOpts = new ColumnFamilyOptions()) {
|
||||
|
||||
final List<ColumnFamilyDescriptor> columnFamilyDescriptors =
|
||||
Arrays.asList(
|
||||
new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY),
|
||||
new ColumnFamilyDescriptor("myCf".getBytes(), myCfOpts));
|
||||
|
||||
final List<ColumnFamilyHandle> columnFamilyHandles = new ArrayList<>();
|
||||
|
||||
try (final TransactionDBOptions txnDbOptions = new TransactionDBOptions();
|
||||
final TransactionDB tdb = TransactionDB.open(dbOptions, txnDbOptions,
|
||||
dbFolder.getRoot().getAbsolutePath(),
|
||||
columnFamilyDescriptors, columnFamilyHandles)) {
|
||||
try {
|
||||
assertThat(tdb).isNotNull();
|
||||
} finally {
|
||||
for (final ColumnFamilyHandle handle : columnFamilyHandles) {
|
||||
handle.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beginTransaction() throws RocksDBException {
|
||||
try (final Options options = new Options().setCreateIfMissing(true);
|
||||
final TransactionDBOptions txnDbOptions = new TransactionDBOptions();
|
||||
final TransactionDB tdb = TransactionDB.open(options, txnDbOptions,
|
||||
dbFolder.getRoot().getAbsolutePath());
|
||||
final WriteOptions writeOptions = new WriteOptions()) {
|
||||
|
||||
try(final Transaction txn = tdb.beginTransaction(writeOptions)) {
|
||||
assertThat(txn).isNotNull();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beginTransaction_transactionOptions() throws RocksDBException {
|
||||
try (final Options options = new Options().setCreateIfMissing(true);
|
||||
final TransactionDBOptions txnDbOptions = new TransactionDBOptions();
|
||||
final TransactionDB tdb = TransactionDB.open(options, txnDbOptions,
|
||||
dbFolder.getRoot().getAbsolutePath());
|
||||
final WriteOptions writeOptions = new WriteOptions();
|
||||
final TransactionOptions txnOptions = new TransactionOptions()) {
|
||||
|
||||
try(final Transaction txn = tdb.beginTransaction(writeOptions,
|
||||
txnOptions)) {
|
||||
assertThat(txn).isNotNull();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beginTransaction_withOld() throws RocksDBException {
|
||||
try (final Options options = new Options().setCreateIfMissing(true);
|
||||
final TransactionDBOptions txnDbOptions = new TransactionDBOptions();
|
||||
final TransactionDB tdb = TransactionDB.open(options, txnDbOptions,
|
||||
dbFolder.getRoot().getAbsolutePath());
|
||||
final WriteOptions writeOptions = new WriteOptions()) {
|
||||
|
||||
try(final Transaction txn = tdb.beginTransaction(writeOptions)) {
|
||||
final Transaction txnReused = tdb.beginTransaction(writeOptions, txn);
|
||||
assertThat(txnReused).isSameAs(txn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beginTransaction_withOld_transactionOptions()
|
||||
throws RocksDBException {
|
||||
try (final Options options = new Options().setCreateIfMissing(true);
|
||||
final TransactionDBOptions txnDbOptions = new TransactionDBOptions();
|
||||
final TransactionDB tdb = TransactionDB.open(options, txnDbOptions,
|
||||
dbFolder.getRoot().getAbsolutePath());
|
||||
final WriteOptions writeOptions = new WriteOptions();
|
||||
final TransactionOptions txnOptions = new TransactionOptions()) {
|
||||
|
||||
try(final Transaction txn = tdb.beginTransaction(writeOptions)) {
|
||||
final Transaction txnReused = tdb.beginTransaction(writeOptions,
|
||||
txnOptions, txn);
|
||||
assertThat(txnReused).isSameAs(txn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void lockStatusData() throws RocksDBException {
|
||||
try (final Options options = new Options().setCreateIfMissing(true);
|
||||
final TransactionDBOptions txnDbOptions = new TransactionDBOptions();
|
||||
final TransactionDB tdb = TransactionDB.open(options, txnDbOptions,
|
||||
dbFolder.getRoot().getAbsolutePath());
|
||||
final WriteOptions writeOptions = new WriteOptions();
|
||||
final ReadOptions readOptions = new ReadOptions()) {
|
||||
|
||||
try (final Transaction txn = tdb.beginTransaction(writeOptions)) {
|
||||
|
||||
final byte key[] = "key".getBytes(UTF_8);
|
||||
final byte value[] = "value".getBytes(UTF_8);
|
||||
|
||||
txn.put(key, value);
|
||||
assertThat(txn.getForUpdate(readOptions, key, true)).isEqualTo(value);
|
||||
|
||||
final Map<Long, TransactionDB.KeyLockInfo> lockStatus =
|
||||
tdb.getLockStatusData();
|
||||
|
||||
assertThat(lockStatus.size()).isEqualTo(1);
|
||||
final Set<Map.Entry<Long, TransactionDB.KeyLockInfo>> entrySet = lockStatus.entrySet();
|
||||
final Map.Entry<Long, TransactionDB.KeyLockInfo> entry = entrySet.iterator().next();
|
||||
final long columnFamilyId = entry.getKey();
|
||||
assertThat(columnFamilyId).isEqualTo(0);
|
||||
final TransactionDB.KeyLockInfo keyLockInfo = entry.getValue();
|
||||
assertThat(keyLockInfo.getKey()).isEqualTo(new String(key, UTF_8));
|
||||
assertThat(keyLockInfo.getTransactionIDs().length).isEqualTo(1);
|
||||
assertThat(keyLockInfo.getTransactionIDs()[0]).isEqualTo(txn.getId());
|
||||
assertThat(keyLockInfo.isExclusive()).isTrue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deadlockInfoBuffer() throws RocksDBException {
|
||||
try (final Options options = new Options().setCreateIfMissing(true);
|
||||
final TransactionDBOptions txnDbOptions = new TransactionDBOptions();
|
||||
final TransactionDB tdb = TransactionDB.open(options, txnDbOptions,
|
||||
dbFolder.getRoot().getAbsolutePath())) {
|
||||
|
||||
// TODO(AR) can we cause a deadlock so that we can test the output here?
|
||||
assertThat(tdb.getDeadlockInfoBuffer()).isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setDeadlockInfoBufferSize() throws RocksDBException {
|
||||
try (final Options options = new Options().setCreateIfMissing(true);
|
||||
final TransactionDBOptions txnDbOptions = new TransactionDBOptions();
|
||||
final TransactionDB tdb = TransactionDB.open(options, txnDbOptions,
|
||||
dbFolder.getRoot().getAbsolutePath())) {
|
||||
tdb.setDeadlockInfoBufferSize(123);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
package org.rocksdb;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class TransactionOptionsTest {
|
||||
|
||||
private static final Random rand = PlatformRandomHelper.
|
||||
getPlatformSpecificRandomFactory();
|
||||
|
||||
@Test
|
||||
public void snapshot() {
|
||||
try (final TransactionOptions opt = new TransactionOptions()) {
|
||||
final boolean boolValue = rand.nextBoolean();
|
||||
opt.setSetSnapshot(boolValue);
|
||||
assertThat(opt.isSetSnapshot()).isEqualTo(boolValue);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deadlockDetect() {
|
||||
try (final TransactionOptions opt = new TransactionOptions()) {
|
||||
final boolean boolValue = rand.nextBoolean();
|
||||
opt.setDeadlockDetect(boolValue);
|
||||
assertThat(opt.isDeadlockDetect()).isEqualTo(boolValue);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void lockTimeout() {
|
||||
try (final TransactionOptions opt = new TransactionOptions()) {
|
||||
final long longValue = rand.nextLong();
|
||||
opt.setLockTimeout(longValue);
|
||||
assertThat(opt.getLockTimeout()).isEqualTo(longValue);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void expiration() {
|
||||
try (final TransactionOptions opt = new TransactionOptions()) {
|
||||
final long longValue = rand.nextLong();
|
||||
opt.setExpiration(longValue);
|
||||
assertThat(opt.getExpiration()).isEqualTo(longValue);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deadlockDetectDepth() {
|
||||
try (final TransactionOptions opt = new TransactionOptions()) {
|
||||
final long longValue = rand.nextLong();
|
||||
opt.setDeadlockDetectDepth(longValue);
|
||||
assertThat(opt.getDeadlockDetectDepth()).isEqualTo(longValue);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void maxWriteBatchSize() {
|
||||
try (final TransactionOptions opt = new TransactionOptions()) {
|
||||
final long longValue = rand.nextLong();
|
||||
opt.setMaxWriteBatchSize(longValue);
|
||||
assertThat(opt.getMaxWriteBatchSize()).isEqualTo(longValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,308 @@
|
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
package org.rocksdb;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
|
||||
public class TransactionTest extends AbstractTransactionTest {
|
||||
|
||||
@Test
|
||||
public void getForUpdate_cf_conflict() throws RocksDBException {
|
||||
final byte k1[] = "key1".getBytes(UTF_8);
|
||||
final byte v1[] = "value1".getBytes(UTF_8);
|
||||
final byte v12[] = "value12".getBytes(UTF_8);
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final ReadOptions readOptions = new ReadOptions()) {
|
||||
final ColumnFamilyHandle testCf = dbContainer.getTestColumnFamily();
|
||||
|
||||
try(final Transaction txn = dbContainer.beginTransaction()) {
|
||||
txn.put(testCf, k1, v1);
|
||||
assertThat(txn.getForUpdate(readOptions, testCf, k1, true)).isEqualTo(v1);
|
||||
txn.commit();
|
||||
}
|
||||
|
||||
try(final Transaction txn2 = dbContainer.beginTransaction()) {
|
||||
try(final Transaction txn3 = dbContainer.beginTransaction()) {
|
||||
assertThat(txn3.getForUpdate(readOptions, testCf, k1, true)).isEqualTo(v1);
|
||||
|
||||
// NOTE: txn2 updates k1, during txn3
|
||||
try {
|
||||
txn2.put(testCf, k1, v12); // should cause an exception!
|
||||
} catch(final RocksDBException e) {
|
||||
assertThat(e.getStatus().getCode()).isSameAs(Status.Code.TimedOut);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fail("Expected an exception for put after getForUpdate from conflicting" +
|
||||
"transactions");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getForUpdate_conflict() throws RocksDBException {
|
||||
final byte k1[] = "key1".getBytes(UTF_8);
|
||||
final byte v1[] = "value1".getBytes(UTF_8);
|
||||
final byte v12[] = "value12".getBytes(UTF_8);
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final ReadOptions readOptions = new ReadOptions()) {
|
||||
|
||||
try(final Transaction txn = dbContainer.beginTransaction()) {
|
||||
txn.put(k1, v1);
|
||||
assertThat(txn.getForUpdate(readOptions, k1, true)).isEqualTo(v1);
|
||||
txn.commit();
|
||||
}
|
||||
|
||||
try(final Transaction txn2 = dbContainer.beginTransaction()) {
|
||||
try(final Transaction txn3 = dbContainer.beginTransaction()) {
|
||||
assertThat(txn3.getForUpdate(readOptions, k1, true)).isEqualTo(v1);
|
||||
|
||||
// NOTE: txn2 updates k1, during txn3
|
||||
try {
|
||||
txn2.put(k1, v12); // should cause an exception!
|
||||
} catch(final RocksDBException e) {
|
||||
assertThat(e.getStatus().getCode()).isSameAs(Status.Code.TimedOut);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fail("Expected an exception for put after getForUpdate from conflicting" +
|
||||
"transactions");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multiGetForUpdate_cf_conflict() throws RocksDBException {
|
||||
final byte keys[][] = new byte[][] {
|
||||
"key1".getBytes(UTF_8),
|
||||
"key2".getBytes(UTF_8)};
|
||||
final byte values[][] = new byte[][] {
|
||||
"value1".getBytes(UTF_8),
|
||||
"value2".getBytes(UTF_8)};
|
||||
final byte[] otherValue = "otherValue".getBytes(UTF_8);
|
||||
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final ReadOptions readOptions = new ReadOptions()) {
|
||||
final ColumnFamilyHandle testCf = dbContainer.getTestColumnFamily();
|
||||
final List<ColumnFamilyHandle> cfList = Arrays.asList(testCf, testCf);
|
||||
|
||||
try(final Transaction txn = dbContainer.beginTransaction()) {
|
||||
txn.put(testCf, keys[0], values[0]);
|
||||
txn.put(testCf, keys[1], values[1]);
|
||||
assertThat(txn.multiGet(readOptions, cfList, keys)).isEqualTo(values);
|
||||
txn.commit();
|
||||
}
|
||||
|
||||
try(final Transaction txn2 = dbContainer.beginTransaction()) {
|
||||
try(final Transaction txn3 = dbContainer.beginTransaction()) {
|
||||
assertThat(txn3.multiGetForUpdate(readOptions, cfList, keys))
|
||||
.isEqualTo(values);
|
||||
|
||||
// NOTE: txn2 updates k1, during txn3
|
||||
try {
|
||||
txn2.put(testCf, keys[0], otherValue); // should cause an exception!
|
||||
} catch(final RocksDBException e) {
|
||||
assertThat(e.getStatus().getCode()).isSameAs(Status.Code.TimedOut);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fail("Expected an exception for put after getForUpdate from conflicting" +
|
||||
"transactions");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multiGetForUpdate_conflict() throws RocksDBException {
|
||||
final byte keys[][] = new byte[][] {
|
||||
"key1".getBytes(UTF_8),
|
||||
"key2".getBytes(UTF_8)};
|
||||
final byte values[][] = new byte[][] {
|
||||
"value1".getBytes(UTF_8),
|
||||
"value2".getBytes(UTF_8)};
|
||||
final byte[] otherValue = "otherValue".getBytes(UTF_8);
|
||||
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final ReadOptions readOptions = new ReadOptions()) {
|
||||
try(final Transaction txn = dbContainer.beginTransaction()) {
|
||||
txn.put(keys[0], values[0]);
|
||||
txn.put(keys[1], values[1]);
|
||||
assertThat(txn.multiGet(readOptions, keys)).isEqualTo(values);
|
||||
txn.commit();
|
||||
}
|
||||
|
||||
try(final Transaction txn2 = dbContainer.beginTransaction()) {
|
||||
try(final Transaction txn3 = dbContainer.beginTransaction()) {
|
||||
assertThat(txn3.multiGetForUpdate(readOptions, keys))
|
||||
.isEqualTo(values);
|
||||
|
||||
// NOTE: txn2 updates k1, during txn3
|
||||
try {
|
||||
txn2.put(keys[0], otherValue); // should cause an exception!
|
||||
} catch(final RocksDBException e) {
|
||||
assertThat(e.getStatus().getCode()).isSameAs(Status.Code.TimedOut);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fail("Expected an exception for put after getForUpdate from conflicting" +
|
||||
"transactions");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void name() throws RocksDBException {
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
assertThat(txn.getName()).isEmpty();
|
||||
final String name = "my-transaction-" + rand.nextLong();
|
||||
txn.setName(name);
|
||||
assertThat(txn.getName()).isEqualTo(name);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ID() throws RocksDBException {
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
assertThat(txn.getID()).isGreaterThan(0);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deadlockDetect() throws RocksDBException {
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
assertThat(txn.isDeadlockDetect()).isFalse();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void waitingTxns() throws RocksDBException {
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
assertThat(txn.getWaitingTxns().getTransactionIds().length).isEqualTo(0);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void state() throws RocksDBException {
|
||||
try(final DBContainer dbContainer = startDb()) {
|
||||
|
||||
try(final Transaction txn = dbContainer.beginTransaction()) {
|
||||
assertThat(txn.getState())
|
||||
.isSameAs(Transaction.TransactionState.STARTED);
|
||||
txn.commit();
|
||||
assertThat(txn.getState())
|
||||
.isSameAs(Transaction.TransactionState.COMMITED);
|
||||
}
|
||||
|
||||
try(final Transaction txn = dbContainer.beginTransaction()) {
|
||||
assertThat(txn.getState())
|
||||
.isSameAs(Transaction.TransactionState.STARTED);
|
||||
txn.rollback();
|
||||
assertThat(txn.getState())
|
||||
.isSameAs(Transaction.TransactionState.STARTED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void Id() throws RocksDBException {
|
||||
try(final DBContainer dbContainer = startDb();
|
||||
final Transaction txn = dbContainer.beginTransaction()) {
|
||||
assertThat(txn.getId()).isNotNull();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransactionDBContainer startDb() throws RocksDBException {
|
||||
final DBOptions options = new DBOptions()
|
||||
.setCreateIfMissing(true)
|
||||
.setCreateMissingColumnFamilies(true);
|
||||
final TransactionDBOptions txnDbOptions = new TransactionDBOptions();
|
||||
final ColumnFamilyOptions columnFamilyOptions = new ColumnFamilyOptions();
|
||||
final List<ColumnFamilyDescriptor> columnFamilyDescriptors =
|
||||
Arrays.asList(
|
||||
new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY),
|
||||
new ColumnFamilyDescriptor(TXN_TEST_COLUMN_FAMILY,
|
||||
columnFamilyOptions));
|
||||
final List<ColumnFamilyHandle> columnFamilyHandles = new ArrayList<>();
|
||||
|
||||
final TransactionDB txnDb;
|
||||
try {
|
||||
txnDb = TransactionDB.open(options, txnDbOptions,
|
||||
dbFolder.getRoot().getAbsolutePath(), columnFamilyDescriptors,
|
||||
columnFamilyHandles);
|
||||
} catch(final RocksDBException e) {
|
||||
columnFamilyOptions.close();
|
||||
txnDbOptions.close();
|
||||
options.close();
|
||||
throw e;
|
||||
}
|
||||
|
||||
final WriteOptions writeOptions = new WriteOptions();
|
||||
final TransactionOptions txnOptions = new TransactionOptions();
|
||||
|
||||
return new TransactionDBContainer(txnOptions, writeOptions,
|
||||
columnFamilyHandles, txnDb, txnDbOptions, columnFamilyOptions, options);
|
||||
}
|
||||
|
||||
private static class TransactionDBContainer
|
||||
extends DBContainer {
|
||||
private final TransactionOptions txnOptions;
|
||||
private final TransactionDB txnDb;
|
||||
private final TransactionDBOptions txnDbOptions;
|
||||
|
||||
public TransactionDBContainer(
|
||||
final TransactionOptions txnOptions, final WriteOptions writeOptions,
|
||||
final List<ColumnFamilyHandle> columnFamilyHandles,
|
||||
final TransactionDB txnDb, final TransactionDBOptions txnDbOptions,
|
||||
final ColumnFamilyOptions columnFamilyOptions,
|
||||
final DBOptions options) {
|
||||
super(writeOptions, columnFamilyHandles, columnFamilyOptions,
|
||||
options);
|
||||
this.txnOptions = txnOptions;
|
||||
this.txnDb = txnDb;
|
||||
this.txnDbOptions = txnDbOptions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Transaction beginTransaction() {
|
||||
return txnDb.beginTransaction(writeOptions, txnOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Transaction beginTransaction(final WriteOptions writeOptions) {
|
||||
return txnDb.beginTransaction(writeOptions, txnOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
txnOptions.close();
|
||||
writeOptions.close();
|
||||
for(final ColumnFamilyHandle columnFamilyHandle : columnFamilyHandles) {
|
||||
columnFamilyHandle.close();
|
||||
}
|
||||
txnDb.close();
|
||||
txnDbOptions.close();
|
||||
options.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,15 +5,16 @@
|
||||
|
||||
package org.rocksdb;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import org.rocksdb.util.CapturingWriteBatchHandler;
|
||||
import org.rocksdb.util.CapturingWriteBatchHandler.Event;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.rocksdb.util.CapturingWriteBatchHandler.Action.*;
|
||||
|
||||
|
||||
public class WriteBatchHandlerTest {
|
||||
@@ -22,45 +23,37 @@ public class WriteBatchHandlerTest {
|
||||
new RocksMemoryResource();
|
||||
|
||||
@Test
|
||||
public void writeBatchHandler() throws IOException, RocksDBException {
|
||||
public void writeBatchHandler() throws RocksDBException {
|
||||
// setup test data
|
||||
final List<Tuple<Action, Tuple<byte[], byte[]>>> testEvents = Arrays.asList(
|
||||
new Tuple<>(Action.DELETE,
|
||||
new Tuple<byte[], byte[]>("k0".getBytes(), null)),
|
||||
new Tuple<>(Action.PUT,
|
||||
new Tuple<>("k1".getBytes(), "v1".getBytes())),
|
||||
new Tuple<>(Action.PUT,
|
||||
new Tuple<>("k2".getBytes(), "v2".getBytes())),
|
||||
new Tuple<>(Action.PUT,
|
||||
new Tuple<>("k3".getBytes(), "v3".getBytes())),
|
||||
new Tuple<>(Action.LOG,
|
||||
new Tuple<byte[], byte[]>(null, "log1".getBytes())),
|
||||
new Tuple<>(Action.MERGE,
|
||||
new Tuple<>("k2".getBytes(), "v22".getBytes())),
|
||||
new Tuple<>(Action.DELETE,
|
||||
new Tuple<byte[], byte[]>("k3".getBytes(), null))
|
||||
final List<Event> testEvents = Arrays.asList(
|
||||
new Event(DELETE, "k0".getBytes(), null),
|
||||
new Event(PUT, "k1".getBytes(), "v1".getBytes()),
|
||||
new Event(PUT, "k2".getBytes(), "v2".getBytes()),
|
||||
new Event(PUT, "k3".getBytes(), "v3".getBytes()),
|
||||
new Event(LOG, null, "log1".getBytes()),
|
||||
new Event(MERGE, "k2".getBytes(), "v22".getBytes()),
|
||||
new Event(DELETE, "k3".getBytes(), null)
|
||||
);
|
||||
|
||||
// load test data to the write batch
|
||||
try (final WriteBatch batch = new WriteBatch()) {
|
||||
for (final Tuple<Action, Tuple<byte[], byte[]>> testEvent : testEvents) {
|
||||
final Tuple<byte[], byte[]> data = testEvent.value;
|
||||
switch (testEvent.key) {
|
||||
for (final Event testEvent : testEvents) {
|
||||
switch (testEvent.action) {
|
||||
|
||||
case PUT:
|
||||
batch.put(data.key, data.value);
|
||||
batch.put(testEvent.key, testEvent.value);
|
||||
break;
|
||||
|
||||
case MERGE:
|
||||
batch.merge(data.key, data.value);
|
||||
batch.merge(testEvent.key, testEvent.value);
|
||||
break;
|
||||
|
||||
case DELETE:
|
||||
batch.remove(data.key);
|
||||
batch.remove(testEvent.key);
|
||||
break;
|
||||
|
||||
case LOG:
|
||||
batch.putLogData(data.value);
|
||||
batch.putLogData(testEvent.value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -72,98 +65,12 @@ public class WriteBatchHandlerTest {
|
||||
batch.iterate(handler);
|
||||
|
||||
// compare the results to the test data
|
||||
final List<Tuple<Action, Tuple<byte[], byte[]>>> actualEvents =
|
||||
final List<Event> actualEvents =
|
||||
handler.getEvents();
|
||||
assertThat(testEvents.size()).isSameAs(actualEvents.size());
|
||||
|
||||
for (int i = 0; i < testEvents.size(); i++) {
|
||||
assertThat(equals(testEvents.get(i), actualEvents.get(i))).isTrue();
|
||||
}
|
||||
assertThat(testEvents).isEqualTo(actualEvents);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean equals(
|
||||
final Tuple<Action, Tuple<byte[], byte[]>> expected,
|
||||
final Tuple<Action, Tuple<byte[], byte[]>> actual) {
|
||||
if (!expected.key.equals(actual.key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final Tuple<byte[], byte[]> expectedData = expected.value;
|
||||
final Tuple<byte[], byte[]> actualData = actual.value;
|
||||
|
||||
return equals(expectedData.key, actualData.key)
|
||||
&& equals(expectedData.value, actualData.value);
|
||||
}
|
||||
|
||||
private static boolean equals(byte[] expected, byte[] actual) {
|
||||
if (expected != null) {
|
||||
return Arrays.equals(expected, actual);
|
||||
} else {
|
||||
return actual == null;
|
||||
}
|
||||
}
|
||||
|
||||
private static class Tuple<K, V> {
|
||||
public final K key;
|
||||
public final V value;
|
||||
|
||||
public Tuple(final K key, final V value) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumeration of Write Batch
|
||||
* event actions
|
||||
*/
|
||||
private enum Action { PUT, MERGE, DELETE, DELETE_RANGE, LOG }
|
||||
|
||||
/**
|
||||
* A simple WriteBatch Handler which adds a record
|
||||
* of each event that it receives to a list
|
||||
*/
|
||||
private static class CapturingWriteBatchHandler extends WriteBatch.Handler {
|
||||
|
||||
private final List<Tuple<Action, Tuple<byte[], byte[]>>> events
|
||||
= new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Returns a copy of the current events list
|
||||
*
|
||||
* @return a list of the events which have happened upto now
|
||||
*/
|
||||
public List<Tuple<Action, Tuple<byte[], byte[]>>> getEvents() {
|
||||
return new ArrayList<>(events);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(final byte[] key, final byte[] value) {
|
||||
events.add(new Tuple<>(Action.PUT, new Tuple<>(key, value)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void merge(final byte[] key, final byte[] value) {
|
||||
events.add(new Tuple<>(Action.MERGE, new Tuple<>(key, value)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(final byte[] key) {
|
||||
events.add(new Tuple<>(Action.DELETE,
|
||||
new Tuple<byte[], byte[]>(key, null)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteRange(final byte[] beginKey, final byte[] endKey) {
|
||||
events.add(new Tuple<>(Action.DELETE_RANGE, new Tuple<byte[], byte[]>(beginKey, endKey)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logData(final byte[] blob) {
|
||||
events.add(new Tuple<>(Action.LOG,
|
||||
new Tuple<byte[], byte[]>(null, blob)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,20 +12,17 @@ import org.junit.ClassRule;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Arrays;
|
||||
import org.rocksdb.util.CapturingWriteBatchHandler;
|
||||
import org.rocksdb.util.CapturingWriteBatchHandler.Event;
|
||||
import org.rocksdb.util.WriteBatchGetter;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.rocksdb.util.CapturingWriteBatchHandler.Action.*;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
/**
|
||||
* This class mimics the db/write_batch_test.cc
|
||||
* in the c++ rocksdb library.
|
||||
* <p/>
|
||||
* Not ported yet:
|
||||
* <p/>
|
||||
* Continue();
|
||||
* PutGatherSlices();
|
||||
*/
|
||||
public class WriteBatchTest {
|
||||
@ClassRule
|
||||
@@ -44,27 +41,45 @@ public class WriteBatchTest {
|
||||
|
||||
@Test
|
||||
public void multipleBatchOperations()
|
||||
throws UnsupportedEncodingException {
|
||||
try (WriteBatch batch = new WriteBatch()) {
|
||||
batch.put("foo".getBytes("US-ASCII"), "bar".getBytes("US-ASCII"));
|
||||
batch.remove("box".getBytes("US-ASCII"));
|
||||
batch.put("baz".getBytes("US-ASCII"), "boo".getBytes("US-ASCII"));
|
||||
throws RocksDBException {
|
||||
|
||||
WriteBatchTestInternalHelper.setSequence(batch, 100);
|
||||
assertThat(WriteBatchTestInternalHelper.sequence(batch)).
|
||||
isNotNull().
|
||||
isEqualTo(100);
|
||||
assertThat(batch.count()).isEqualTo(3);
|
||||
assertThat(new String(getContents(batch), "US-ASCII")).
|
||||
isEqualTo("Put(baz, boo)@102" +
|
||||
"Delete(box)@101" +
|
||||
"Put(foo, bar)@100");
|
||||
final byte[] foo = "foo".getBytes(UTF_8);
|
||||
final byte[] bar = "bar".getBytes(UTF_8);
|
||||
final byte[] box = "box".getBytes(UTF_8);
|
||||
final byte[] baz = "baz".getBytes(UTF_8);
|
||||
final byte[] boo = "boo".getBytes(UTF_8);
|
||||
final byte[] hoo = "hoo".getBytes(UTF_8);
|
||||
final byte[] hello = "hello".getBytes(UTF_8);
|
||||
|
||||
try (final WriteBatch batch = new WriteBatch()) {
|
||||
batch.put(foo, bar);
|
||||
batch.delete(box);
|
||||
batch.put(baz, boo);
|
||||
batch.merge(baz, hoo);
|
||||
batch.singleDelete(foo);
|
||||
batch.deleteRange(baz, foo);
|
||||
batch.putLogData(hello);
|
||||
|
||||
try(final CapturingWriteBatchHandler handler =
|
||||
new CapturingWriteBatchHandler()) {
|
||||
batch.iterate(handler);
|
||||
|
||||
assertThat(handler.getEvents().size()).isEqualTo(7);
|
||||
|
||||
assertThat(handler.getEvents().get(0)).isEqualTo(new Event(PUT, foo, bar));
|
||||
assertThat(handler.getEvents().get(1)).isEqualTo(new Event(DELETE, box, null));
|
||||
assertThat(handler.getEvents().get(2)).isEqualTo(new Event(PUT, baz, boo));
|
||||
assertThat(handler.getEvents().get(3)).isEqualTo(new Event(MERGE, baz, hoo));
|
||||
assertThat(handler.getEvents().get(4)).isEqualTo(new Event(SINGLE_DELETE, foo, null));
|
||||
assertThat(handler.getEvents().get(5)).isEqualTo(new Event(DELETE_RANGE, baz, foo));
|
||||
assertThat(handler.getEvents().get(6)).isEqualTo(new Event(LOG, null, hello));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAppendOperation()
|
||||
throws UnsupportedEncodingException {
|
||||
throws RocksDBException {
|
||||
try (final WriteBatch b1 = new WriteBatch();
|
||||
final WriteBatch b2 = new WriteBatch()) {
|
||||
WriteBatchTestInternalHelper.setSequence(b1, 200);
|
||||
@@ -72,67 +87,66 @@ public class WriteBatchTest {
|
||||
WriteBatchTestInternalHelper.append(b1, b2);
|
||||
assertThat(getContents(b1).length).isEqualTo(0);
|
||||
assertThat(b1.count()).isEqualTo(0);
|
||||
b2.put("a".getBytes("US-ASCII"), "va".getBytes("US-ASCII"));
|
||||
b2.put("a".getBytes(UTF_8), "va".getBytes(UTF_8));
|
||||
WriteBatchTestInternalHelper.append(b1, b2);
|
||||
assertThat("Put(a, va)@200".equals(new String(getContents(b1),
|
||||
"US-ASCII")));
|
||||
UTF_8)));
|
||||
assertThat(b1.count()).isEqualTo(1);
|
||||
b2.clear();
|
||||
b2.put("b".getBytes("US-ASCII"), "vb".getBytes("US-ASCII"));
|
||||
b2.put("b".getBytes(UTF_8), "vb".getBytes(UTF_8));
|
||||
WriteBatchTestInternalHelper.append(b1, b2);
|
||||
assertThat(("Put(a, va)@200" +
|
||||
"Put(b, vb)@201")
|
||||
.equals(new String(getContents(b1), "US-ASCII")));
|
||||
.equals(new String(getContents(b1), UTF_8)));
|
||||
assertThat(b1.count()).isEqualTo(2);
|
||||
b2.remove("foo".getBytes("US-ASCII"));
|
||||
b2.delete("foo".getBytes(UTF_8));
|
||||
WriteBatchTestInternalHelper.append(b1, b2);
|
||||
assertThat(("Put(a, va)@200" +
|
||||
"Put(b, vb)@202" +
|
||||
"Put(b, vb)@201" +
|
||||
"Delete(foo)@203")
|
||||
.equals(new String(getContents(b1), "US-ASCII")));
|
||||
.equals(new String(getContents(b1), UTF_8)));
|
||||
assertThat(b1.count()).isEqualTo(4);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void blobOperation()
|
||||
throws UnsupportedEncodingException {
|
||||
throws RocksDBException {
|
||||
try (final WriteBatch batch = new WriteBatch()) {
|
||||
batch.put("k1".getBytes("US-ASCII"), "v1".getBytes("US-ASCII"));
|
||||
batch.put("k2".getBytes("US-ASCII"), "v2".getBytes("US-ASCII"));
|
||||
batch.put("k3".getBytes("US-ASCII"), "v3".getBytes("US-ASCII"));
|
||||
batch.putLogData("blob1".getBytes("US-ASCII"));
|
||||
batch.remove("k2".getBytes("US-ASCII"));
|
||||
batch.putLogData("blob2".getBytes("US-ASCII"));
|
||||
batch.merge("foo".getBytes("US-ASCII"), "bar".getBytes("US-ASCII"));
|
||||
batch.put("k1".getBytes(UTF_8), "v1".getBytes(UTF_8));
|
||||
batch.put("k2".getBytes(UTF_8), "v2".getBytes(UTF_8));
|
||||
batch.put("k3".getBytes(UTF_8), "v3".getBytes(UTF_8));
|
||||
batch.putLogData("blob1".getBytes(UTF_8));
|
||||
batch.delete("k2".getBytes(UTF_8));
|
||||
batch.putLogData("blob2".getBytes(UTF_8));
|
||||
batch.merge("foo".getBytes(UTF_8), "bar".getBytes(UTF_8));
|
||||
assertThat(batch.count()).isEqualTo(5);
|
||||
assertThat(("Merge(foo, bar)@4" +
|
||||
"Put(k1, v1)@0" +
|
||||
"Delete(k2)@3" +
|
||||
"Put(k2, v2)@1" +
|
||||
"Put(k3, v3)@2")
|
||||
.equals(new String(getContents(batch), "US-ASCII")));
|
||||
.equals(new String(getContents(batch), UTF_8)));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void savePoints()
|
||||
throws UnsupportedEncodingException, RocksDBException {
|
||||
throws RocksDBException {
|
||||
try (final WriteBatch batch = new WriteBatch()) {
|
||||
batch.put("k1".getBytes("US-ASCII"), "v1".getBytes("US-ASCII"));
|
||||
batch.put("k2".getBytes("US-ASCII"), "v2".getBytes("US-ASCII"));
|
||||
batch.put("k3".getBytes("US-ASCII"), "v3".getBytes("US-ASCII"));
|
||||
batch.put("k1".getBytes(UTF_8), "v1".getBytes(UTF_8));
|
||||
batch.put("k2".getBytes(UTF_8), "v2".getBytes(UTF_8));
|
||||
batch.put("k3".getBytes(UTF_8), "v3".getBytes(UTF_8));
|
||||
|
||||
assertThat(getFromWriteBatch(batch, "k1")).isEqualTo("v1");
|
||||
assertThat(getFromWriteBatch(batch, "k2")).isEqualTo("v2");
|
||||
assertThat(getFromWriteBatch(batch, "k3")).isEqualTo("v3");
|
||||
|
||||
|
||||
batch.setSavePoint();
|
||||
|
||||
batch.remove("k2".getBytes("US-ASCII"));
|
||||
batch.put("k3".getBytes("US-ASCII"), "v3-2".getBytes("US-ASCII"));
|
||||
batch.delete("k2".getBytes(UTF_8));
|
||||
batch.put("k3".getBytes(UTF_8), "v3-2".getBytes(UTF_8));
|
||||
|
||||
assertThat(getFromWriteBatch(batch, "k2")).isNull();
|
||||
assertThat(getFromWriteBatch(batch, "k3")).isEqualTo("v3-2");
|
||||
@@ -140,8 +154,8 @@ public class WriteBatchTest {
|
||||
|
||||
batch.setSavePoint();
|
||||
|
||||
batch.put("k3".getBytes("US-ASCII"), "v3-3".getBytes("US-ASCII"));
|
||||
batch.put("k4".getBytes("US-ASCII"), "v4".getBytes("US-ASCII"));
|
||||
batch.put("k3".getBytes(UTF_8), "v3-3".getBytes(UTF_8));
|
||||
batch.put("k4".getBytes(UTF_8), "v4".getBytes(UTF_8));
|
||||
|
||||
assertThat(getFromWriteBatch(batch, "k3")).isEqualTo("v3-3");
|
||||
assertThat(getFromWriteBatch(batch, "k4")).isEqualTo("v4");
|
||||
@@ -187,6 +201,30 @@ public class WriteBatchTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void restorePoints() throws RocksDBException {
|
||||
try (final WriteBatch batch = new WriteBatch()) {
|
||||
|
||||
batch.put("k1".getBytes(), "v1".getBytes());
|
||||
batch.put("k2".getBytes(), "v2".getBytes());
|
||||
|
||||
batch.setSavePoint();
|
||||
|
||||
batch.put("k1".getBytes(), "123456789".getBytes());
|
||||
batch.delete("k2".getBytes());
|
||||
|
||||
batch.rollbackToSavePoint();
|
||||
|
||||
try(final CapturingWriteBatchHandler handler = new CapturingWriteBatchHandler()) {
|
||||
batch.iterate(handler);
|
||||
|
||||
assertThat(handler.getEvents().size()).isEqualTo(2);
|
||||
assertThat(handler.getEvents().get(0)).isEqualTo(new Event(PUT, "k1".getBytes(), "v1".getBytes()));
|
||||
assertThat(handler.getEvents().get(1)).isEqualTo(new Event(PUT, "k2".getBytes(), "v2".getBytes()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = RocksDBException.class)
|
||||
public void restorePoints_withoutSavePoints() throws RocksDBException {
|
||||
try (final WriteBatch batch = new WriteBatch()) {
|
||||
@@ -206,67 +244,222 @@ public class WriteBatchTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void popSavePoint() throws RocksDBException {
|
||||
try (final WriteBatch batch = new WriteBatch()) {
|
||||
|
||||
batch.put("k1".getBytes(), "v1".getBytes());
|
||||
batch.put("k2".getBytes(), "v2".getBytes());
|
||||
|
||||
batch.setSavePoint();
|
||||
|
||||
batch.put("k1".getBytes(), "123456789".getBytes());
|
||||
batch.delete("k2".getBytes());
|
||||
|
||||
batch.setSavePoint();
|
||||
|
||||
batch.popSavePoint();
|
||||
|
||||
batch.rollbackToSavePoint();
|
||||
|
||||
try(final CapturingWriteBatchHandler handler = new CapturingWriteBatchHandler()) {
|
||||
batch.iterate(handler);
|
||||
|
||||
assertThat(handler.getEvents().size()).isEqualTo(2);
|
||||
assertThat(handler.getEvents().get(0)).isEqualTo(new Event(PUT, "k1".getBytes(), "v1".getBytes()));
|
||||
assertThat(handler.getEvents().get(1)).isEqualTo(new Event(PUT, "k2".getBytes(), "v2".getBytes()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = RocksDBException.class)
|
||||
public void popSavePoint_withoutSavePoints() throws RocksDBException {
|
||||
try (final WriteBatch batch = new WriteBatch()) {
|
||||
batch.popSavePoint();
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = RocksDBException.class)
|
||||
public void popSavePoint_withoutSavePoints_nested() throws RocksDBException {
|
||||
try (final WriteBatch batch = new WriteBatch()) {
|
||||
|
||||
batch.setSavePoint();
|
||||
batch.popSavePoint();
|
||||
|
||||
// without previous corresponding setSavePoint
|
||||
batch.popSavePoint();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void maxBytes() throws RocksDBException {
|
||||
try (final WriteBatch batch = new WriteBatch()) {
|
||||
batch.setMaxBytes(19);
|
||||
|
||||
batch.put("k1".getBytes(), "v1".getBytes());
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = RocksDBException.class)
|
||||
public void maxBytes_over() throws RocksDBException {
|
||||
try (final WriteBatch batch = new WriteBatch()) {
|
||||
batch.setMaxBytes(1);
|
||||
|
||||
batch.put("k1".getBytes(), "v1".getBytes());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void data() throws RocksDBException {
|
||||
try (final WriteBatch batch1 = new WriteBatch()) {
|
||||
batch1.delete("k0".getBytes());
|
||||
batch1.put("k1".getBytes(), "v1".getBytes());
|
||||
batch1.put("k2".getBytes(), "v2".getBytes());
|
||||
batch1.put("k3".getBytes(), "v3".getBytes());
|
||||
batch1.putLogData("log1".getBytes());
|
||||
batch1.merge("k2".getBytes(), "v22".getBytes());
|
||||
batch1.delete("k3".getBytes());
|
||||
|
||||
final byte[] serialized = batch1.data();
|
||||
|
||||
try(final WriteBatch batch2 = new WriteBatch(serialized)) {
|
||||
assertThat(batch2.count()).isEqualTo(batch1.count());
|
||||
|
||||
try(final CapturingWriteBatchHandler handler1 = new CapturingWriteBatchHandler()) {
|
||||
batch1.iterate(handler1);
|
||||
|
||||
try (final CapturingWriteBatchHandler handler2 = new CapturingWriteBatchHandler()) {
|
||||
batch2.iterate(handler2);
|
||||
|
||||
assertThat(handler1.getEvents().equals(handler2.getEvents())).isTrue();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dataSize() throws RocksDBException {
|
||||
try (final WriteBatch batch = new WriteBatch()) {
|
||||
batch.put("k1".getBytes(), "v1".getBytes());
|
||||
|
||||
assertThat(batch.getDataSize()).isEqualTo(19);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hasPut() throws RocksDBException {
|
||||
try (final WriteBatch batch = new WriteBatch()) {
|
||||
assertThat(batch.hasPut()).isFalse();
|
||||
|
||||
batch.put("k1".getBytes(), "v1".getBytes());
|
||||
|
||||
assertThat(batch.hasPut()).isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hasDelete() throws RocksDBException {
|
||||
try (final WriteBatch batch = new WriteBatch()) {
|
||||
assertThat(batch.hasDelete()).isFalse();
|
||||
|
||||
batch.delete("k1".getBytes());
|
||||
|
||||
assertThat(batch.hasDelete()).isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hasSingleDelete() throws RocksDBException {
|
||||
try (final WriteBatch batch = new WriteBatch()) {
|
||||
assertThat(batch.hasSingleDelete()).isFalse();
|
||||
|
||||
batch.singleDelete("k1".getBytes());
|
||||
|
||||
assertThat(batch.hasSingleDelete()).isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hasDeleteRange() throws RocksDBException {
|
||||
try (final WriteBatch batch = new WriteBatch()) {
|
||||
assertThat(batch.hasDeleteRange()).isFalse();
|
||||
|
||||
batch.deleteRange("k1".getBytes(), "k2".getBytes());
|
||||
|
||||
assertThat(batch.hasDeleteRange()).isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hasBeginPrepareRange() throws RocksDBException {
|
||||
try (final WriteBatch batch = new WriteBatch()) {
|
||||
assertThat(batch.hasBeginPrepare()).isFalse();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hasEndrepareRange() throws RocksDBException {
|
||||
try (final WriteBatch batch = new WriteBatch()) {
|
||||
assertThat(batch.hasEndPrepare()).isFalse();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hasCommit() throws RocksDBException {
|
||||
try (final WriteBatch batch = new WriteBatch()) {
|
||||
assertThat(batch.hasCommit()).isFalse();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hasRollback() throws RocksDBException {
|
||||
try (final WriteBatch batch = new WriteBatch()) {
|
||||
assertThat(batch.hasRollback()).isFalse();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void walTerminationPoint() throws RocksDBException {
|
||||
try (final WriteBatch batch = new WriteBatch()) {
|
||||
WriteBatch.SavePoint walTerminationPoint = batch.getWalTerminationPoint();
|
||||
assertThat(walTerminationPoint.isCleared()).isTrue();
|
||||
|
||||
batch.put("k1".getBytes(UTF_8), "v1".getBytes(UTF_8));
|
||||
|
||||
batch.markWalTerminationPoint();
|
||||
|
||||
walTerminationPoint = batch.getWalTerminationPoint();
|
||||
assertThat(walTerminationPoint.getSize()).isEqualTo(19);
|
||||
assertThat(walTerminationPoint.getCount()).isEqualTo(1);
|
||||
assertThat(walTerminationPoint.getContentFlags()).isEqualTo(2);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getWriteBatch() {
|
||||
try (final WriteBatch batch = new WriteBatch()) {
|
||||
assertThat(batch.getWriteBatch()).isEqualTo(batch);
|
||||
}
|
||||
}
|
||||
|
||||
static byte[] getContents(final WriteBatch wb) {
|
||||
return getContents(wb.nativeHandle_);
|
||||
}
|
||||
|
||||
static String getFromWriteBatch(final WriteBatch wb, final String key)
|
||||
throws RocksDBException, UnsupportedEncodingException {
|
||||
throws RocksDBException {
|
||||
final WriteBatchGetter getter =
|
||||
new WriteBatchGetter(key.getBytes("US-ASCII"));
|
||||
new WriteBatchGetter(key.getBytes(UTF_8));
|
||||
wb.iterate(getter);
|
||||
if(getter.getValue() != null) {
|
||||
return new String(getter.getValue(), "US-ASCII");
|
||||
return new String(getter.getValue(), UTF_8);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static native byte[] getContents(final long writeBatchHandle);
|
||||
|
||||
private static class WriteBatchGetter extends WriteBatch.Handler {
|
||||
|
||||
private final byte[] key;
|
||||
private byte[] value;
|
||||
|
||||
public WriteBatchGetter(final byte[] key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public byte[] getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(final byte[] key, final byte[] value) {
|
||||
if(Arrays.equals(this.key, key)) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void merge(final byte[] key, final byte[] value) {
|
||||
if(Arrays.equals(this.key, key)) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(final byte[] key) {
|
||||
if(Arrays.equals(this.key, key)) {
|
||||
this.value = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteRange(final byte[] beginKey, final byte[] endKey) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logData(final byte[] blob) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,11 +14,11 @@ import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
|
||||
public class WriteBatchWithIndexTest {
|
||||
@@ -75,8 +75,8 @@ public class WriteBatchWithIndexTest {
|
||||
assertThat(it.key()).isEqualTo(k2);
|
||||
assertThat(it.value()).isEqualTo(v2Other);
|
||||
|
||||
//remove k1 and make sure we can read back the write
|
||||
wbwi.remove(k1);
|
||||
//delete k1 and make sure we can read back the write
|
||||
wbwi.delete(k1);
|
||||
it.seek(k1);
|
||||
assertThat(it.key()).isNotEqualTo(k1);
|
||||
|
||||
@@ -87,6 +87,19 @@ public class WriteBatchWithIndexTest {
|
||||
assertThat(it.isValid()).isTrue();
|
||||
assertThat(it.key()).isEqualTo(k1);
|
||||
assertThat(it.value()).isEqualTo(v1Other);
|
||||
|
||||
//single remove k3 and make sure we can read back the write
|
||||
wbwi.singleDelete(k3);
|
||||
it.seek(k3);
|
||||
assertThat(it.isValid()).isEqualTo(false);
|
||||
|
||||
//reinsert k3 and make sure we see the new value
|
||||
final byte[] v3Other = "otherValue3".getBytes();
|
||||
wbwi.put(k3, v3Other);
|
||||
it.seek(k3);
|
||||
assertThat(it.isValid()).isTrue();
|
||||
assertThat(it.key()).isEqualTo(k3);
|
||||
assertThat(it.value()).isEqualTo(v3Other);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -124,22 +137,39 @@ public class WriteBatchWithIndexTest {
|
||||
final String v2 = "value2";
|
||||
final String k3 = "key3";
|
||||
final String v3 = "value3";
|
||||
final byte[] k1b = k1.getBytes();
|
||||
final byte[] v1b = v1.getBytes();
|
||||
final byte[] k2b = k2.getBytes();
|
||||
final byte[] v2b = v2.getBytes();
|
||||
final byte[] k3b = k3.getBytes();
|
||||
final byte[] v3b = v3.getBytes();
|
||||
final String k4 = "key4";
|
||||
final String k5 = "key5";
|
||||
final String k6 = "key6";
|
||||
final String k7 = "key7";
|
||||
final String v8 = "value8";
|
||||
final byte[] k1b = k1.getBytes(UTF_8);
|
||||
final byte[] v1b = v1.getBytes(UTF_8);
|
||||
final byte[] k2b = k2.getBytes(UTF_8);
|
||||
final byte[] v2b = v2.getBytes(UTF_8);
|
||||
final byte[] k3b = k3.getBytes(UTF_8);
|
||||
final byte[] v3b = v3.getBytes(UTF_8);
|
||||
final byte[] k4b = k4.getBytes(UTF_8);
|
||||
final byte[] k5b = k5.getBytes(UTF_8);
|
||||
final byte[] k6b = k6.getBytes(UTF_8);
|
||||
final byte[] k7b = k7.getBytes(UTF_8);
|
||||
final byte[] v8b = v8.getBytes(UTF_8);
|
||||
|
||||
//add put records
|
||||
// add put records
|
||||
wbwi.put(k1b, v1b);
|
||||
wbwi.put(k2b, v2b);
|
||||
wbwi.put(k3b, v3b);
|
||||
|
||||
//add a deletion record
|
||||
final String k4 = "key4";
|
||||
final byte[] k4b = k4.getBytes();
|
||||
wbwi.remove(k4b);
|
||||
// add a deletion record
|
||||
wbwi.delete(k4b);
|
||||
|
||||
// add a single deletion record
|
||||
wbwi.singleDelete(k5b);
|
||||
|
||||
// add a delete range record
|
||||
wbwi.deleteRange(k6b, k7b);
|
||||
|
||||
// add a log record
|
||||
wbwi.putLogData(v8b);
|
||||
|
||||
final WBWIRocksIterator.WriteEntry[] expected = {
|
||||
new WBWIRocksIterator.WriteEntry(WBWIRocksIterator.WriteType.PUT,
|
||||
@@ -149,12 +179,16 @@ public class WriteBatchWithIndexTest {
|
||||
new WBWIRocksIterator.WriteEntry(WBWIRocksIterator.WriteType.PUT,
|
||||
new DirectSlice(k3), new DirectSlice(v3)),
|
||||
new WBWIRocksIterator.WriteEntry(WBWIRocksIterator.WriteType.DELETE,
|
||||
new DirectSlice(k4), DirectSlice.NONE)
|
||||
new DirectSlice(k4), DirectSlice.NONE),
|
||||
new WBWIRocksIterator.WriteEntry(WBWIRocksIterator.WriteType.SINGLE_DELETE,
|
||||
new DirectSlice(k5), DirectSlice.NONE),
|
||||
new WBWIRocksIterator.WriteEntry(WBWIRocksIterator.WriteType.DELETE_RANGE,
|
||||
new DirectSlice(k6), new DirectSlice(k7)),
|
||||
};
|
||||
|
||||
try (final WBWIRocksIterator it = wbwi.newIterator()) {
|
||||
//direct access - seek to key offsets
|
||||
final int[] testOffsets = {2, 0, 1, 3};
|
||||
final int[] testOffsets = {2, 0, 3, 4, 1, 5};
|
||||
|
||||
for (int i = 0; i < testOffsets.length; i++) {
|
||||
final int testOffset = testOffsets[i];
|
||||
@@ -164,26 +198,26 @@ public class WriteBatchWithIndexTest {
|
||||
assertThat(it.isValid()).isTrue();
|
||||
|
||||
final WBWIRocksIterator.WriteEntry entry = it.entry();
|
||||
assertThat(entry.equals(expected[testOffset])).isTrue();
|
||||
assertThat(entry).isEqualTo(expected[testOffset]);
|
||||
}
|
||||
|
||||
//forward iterative access
|
||||
int i = 0;
|
||||
for (it.seekToFirst(); it.isValid(); it.next()) {
|
||||
assertThat(it.entry().equals(expected[i++])).isTrue();
|
||||
assertThat(it.entry()).isEqualTo(expected[i++]);
|
||||
}
|
||||
|
||||
//reverse iterative access
|
||||
i = expected.length - 1;
|
||||
for (it.seekToLast(); it.isValid(); it.prev()) {
|
||||
assertThat(it.entry().equals(expected[i--])).isTrue();
|
||||
assertThat(it.entry()).isEqualTo(expected[i--]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void zeroByteTests() {
|
||||
public void zeroByteTests() throws RocksDBException {
|
||||
try (final WriteBatchWithIndex wbwi = new WriteBatchWithIndex(true)) {
|
||||
final byte[] zeroByteValue = new byte[]{0, 0};
|
||||
//add zero byte value
|
||||
@@ -207,8 +241,7 @@ public class WriteBatchWithIndexTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void savePoints()
|
||||
throws UnsupportedEncodingException, RocksDBException {
|
||||
public void savePoints() throws RocksDBException {
|
||||
try (final Options options = new Options().setCreateIfMissing(true);
|
||||
final RocksDB db = RocksDB.open(options,
|
||||
dbFolder.getRoot().getAbsolutePath())) {
|
||||
@@ -228,7 +261,7 @@ public class WriteBatchWithIndexTest {
|
||||
|
||||
wbwi.setSavePoint();
|
||||
|
||||
wbwi.remove("k2".getBytes());
|
||||
wbwi.delete("k2".getBytes());
|
||||
wbwi.put("k3".getBytes(), "v3-2".getBytes());
|
||||
|
||||
assertThat(getFromWriteBatchWithIndex(db, readOptions, wbwi, "k2"))
|
||||
@@ -272,6 +305,27 @@ public class WriteBatchWithIndexTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void restorePoints() throws RocksDBException {
|
||||
try (final WriteBatchWithIndex wbwi = new WriteBatchWithIndex()) {
|
||||
|
||||
wbwi.put("k1".getBytes(UTF_8), "v1".getBytes(UTF_8));
|
||||
wbwi.put("k2".getBytes(UTF_8), "v2".getBytes(UTF_8));
|
||||
|
||||
wbwi.setSavePoint();
|
||||
|
||||
wbwi.put("k1".getBytes(UTF_8), "123456789".getBytes(UTF_8));
|
||||
wbwi.delete("k2".getBytes(UTF_8));
|
||||
|
||||
wbwi.rollbackToSavePoint();
|
||||
|
||||
try(final DBOptions options = new DBOptions()) {
|
||||
assertThat(wbwi.getFromBatch(options,"k1".getBytes(UTF_8))).isEqualTo("v1".getBytes());
|
||||
assertThat(wbwi.getFromBatch(options,"k2".getBytes(UTF_8))).isEqualTo("v2".getBytes());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = RocksDBException.class)
|
||||
public void restorePoints_withoutSavePoints() throws RocksDBException {
|
||||
try (final WriteBatchWithIndex wbwi = new WriteBatchWithIndex()) {
|
||||
@@ -291,6 +345,78 @@ public class WriteBatchWithIndexTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void popSavePoint() throws RocksDBException {
|
||||
try (final WriteBatchWithIndex wbwi = new WriteBatchWithIndex()) {
|
||||
|
||||
wbwi.put("k1".getBytes(), "v1".getBytes());
|
||||
wbwi.put("k2".getBytes(), "v2".getBytes());
|
||||
|
||||
wbwi.setSavePoint();
|
||||
|
||||
wbwi.put("k1".getBytes(), "123456789".getBytes());
|
||||
wbwi.delete("k2".getBytes());
|
||||
|
||||
wbwi.setSavePoint();
|
||||
|
||||
wbwi.popSavePoint();
|
||||
|
||||
wbwi.rollbackToSavePoint();
|
||||
|
||||
try(final DBOptions options = new DBOptions()) {
|
||||
assertThat(wbwi.getFromBatch(options,"k1".getBytes(UTF_8))).isEqualTo("v1".getBytes());
|
||||
assertThat(wbwi.getFromBatch(options,"k2".getBytes(UTF_8))).isEqualTo("v2".getBytes());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = RocksDBException.class)
|
||||
public void popSavePoint_withoutSavePoints() throws RocksDBException {
|
||||
try (final WriteBatchWithIndex wbwi = new WriteBatchWithIndex()) {
|
||||
wbwi.popSavePoint();
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = RocksDBException.class)
|
||||
public void popSavePoint_withoutSavePoints_nested() throws RocksDBException {
|
||||
try (final WriteBatchWithIndex wbwi = new WriteBatchWithIndex()) {
|
||||
|
||||
wbwi.setSavePoint();
|
||||
wbwi.popSavePoint();
|
||||
|
||||
// without previous corresponding setSavePoint
|
||||
wbwi.popSavePoint();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void maxBytes() throws RocksDBException {
|
||||
try (final WriteBatchWithIndex wbwi = new WriteBatchWithIndex()) {
|
||||
wbwi.setMaxBytes(19);
|
||||
|
||||
wbwi.put("k1".getBytes(), "v1".getBytes());
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = RocksDBException.class)
|
||||
public void maxBytes_over() throws RocksDBException {
|
||||
try (final WriteBatchWithIndex wbwi = new WriteBatchWithIndex()) {
|
||||
wbwi.setMaxBytes(1);
|
||||
|
||||
wbwi.put("k1".getBytes(), "v1".getBytes());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getWriteBatch() {
|
||||
try (final WriteBatchWithIndex wbwi = new WriteBatchWithIndex()) {
|
||||
|
||||
final WriteBatch wb = wbwi.getWriteBatch();
|
||||
assertThat(wb).isNotNull();
|
||||
assertThat(wb.isOwningHandle()).isFalse();
|
||||
}
|
||||
}
|
||||
|
||||
private static String getFromWriteBatchWithIndex(final RocksDB db,
|
||||
final ReadOptions readOptions, final WriteBatchWithIndex wbwi,
|
||||
final String skey) {
|
||||
@@ -329,7 +455,7 @@ public class WriteBatchWithIndexTest {
|
||||
assertThat(wbwi.getFromBatch(dbOptions, k3)).isEqualTo(v3);
|
||||
assertThat(wbwi.getFromBatch(dbOptions, k4)).isNull();
|
||||
|
||||
wbwi.remove(k2);
|
||||
wbwi.delete(k2);
|
||||
|
||||
assertThat(wbwi.getFromBatch(dbOptions, k2)).isNull();
|
||||
}
|
||||
@@ -372,7 +498,7 @@ public class WriteBatchWithIndexTest {
|
||||
assertThat(wbwi.getFromBatchAndDB(db, readOptions, k3)).isEqualTo(v3);
|
||||
assertThat(wbwi.getFromBatchAndDB(db, readOptions, k4)).isEqualTo(v4);
|
||||
|
||||
wbwi.remove(k4);
|
||||
wbwi.delete(k4);
|
||||
|
||||
assertThat(wbwi.getFromBatchAndDB(db, readOptions, k4)).isNull();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
package org.rocksdb.util;
|
||||
|
||||
import org.rocksdb.RocksDBException;
|
||||
import org.rocksdb.WriteBatch;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A simple WriteBatch Handler which adds a record
|
||||
* of each event that it receives to a list
|
||||
*/
|
||||
public class CapturingWriteBatchHandler extends WriteBatch.Handler {
|
||||
|
||||
private final List<Event> events = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Returns a copy of the current events list
|
||||
*
|
||||
* @return a list of the events which have happened upto now
|
||||
*/
|
||||
public List<Event> getEvents() {
|
||||
return new ArrayList<>(events);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(final int columnFamilyId, final byte[] key,
|
||||
final byte[] value) {
|
||||
events.add(new Event(Action.PUT, columnFamilyId, key, value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(final byte[] key, final byte[] value) {
|
||||
events.add(new Event(Action.PUT, key, value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void merge(final int columnFamilyId, final byte[] key,
|
||||
final byte[] value) {
|
||||
events.add(new Event(Action.MERGE, columnFamilyId, key, value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void merge(final byte[] key, final byte[] value) {
|
||||
events.add(new Event(Action.MERGE, key, value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(final int columnFamilyId, final byte[] key) {
|
||||
events.add(new Event(Action.DELETE, columnFamilyId, key, (byte[])null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(final byte[] key) {
|
||||
events.add(new Event(Action.DELETE, key, (byte[])null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void singleDelete(final int columnFamilyId, final byte[] key) {
|
||||
events.add(new Event(Action.SINGLE_DELETE,
|
||||
columnFamilyId, key, (byte[])null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void singleDelete(final byte[] key) {
|
||||
events.add(new Event(Action.SINGLE_DELETE, key, (byte[])null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteRange(final int columnFamilyId, final byte[] beginKey,
|
||||
final byte[] endKey) {
|
||||
events.add(new Event(Action.DELETE_RANGE, columnFamilyId, beginKey,
|
||||
endKey));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteRange(final byte[] beginKey, final byte[] endKey) {
|
||||
events.add(new Event(Action.DELETE_RANGE, beginKey, endKey));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logData(final byte[] blob) {
|
||||
events.add(new Event(Action.LOG, (byte[])null, blob));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putBlobIndex(final int columnFamilyId, final byte[] key,
|
||||
final byte[] value) {
|
||||
events.add(new Event(Action.PUT_BLOB_INDEX, key, value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markBeginPrepare() throws RocksDBException {
|
||||
events.add(new Event(Action.MARK_BEGIN_PREPARE, (byte[])null,
|
||||
(byte[])null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markEndPrepare(final byte[] xid) throws RocksDBException {
|
||||
events.add(new Event(Action.MARK_END_PREPARE, (byte[])null,
|
||||
(byte[])null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markNoop(final boolean emptyBatch) throws RocksDBException {
|
||||
events.add(new Event(Action.MARK_NOOP, (byte[])null, (byte[])null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markRollback(final byte[] xid) throws RocksDBException {
|
||||
events.add(new Event(Action.MARK_ROLLBACK, (byte[])null, (byte[])null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markCommit(final byte[] xid) throws RocksDBException {
|
||||
events.add(new Event(Action.MARK_COMMIT, (byte[])null, (byte[])null));
|
||||
}
|
||||
|
||||
public static class Event {
|
||||
public final Action action;
|
||||
public final int columnFamilyId;
|
||||
public final byte[] key;
|
||||
public final byte[] value;
|
||||
|
||||
public Event(final Action action, final byte[] key, final byte[] value) {
|
||||
this(action, 0, key, value);
|
||||
}
|
||||
|
||||
public Event(final Action action, final int columnFamilyId, final byte[] key,
|
||||
final byte[] value) {
|
||||
this.action = action;
|
||||
this.columnFamilyId = columnFamilyId;
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final Event event = (Event) o;
|
||||
return columnFamilyId == event.columnFamilyId &&
|
||||
action == event.action &&
|
||||
((key == null && event.key == null)
|
||||
|| Arrays.equals(key, event.key)) &&
|
||||
((value == null && event.value == null)
|
||||
|| Arrays.equals(value, event.value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
||||
return Objects.hash(action, columnFamilyId, key, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumeration of Write Batch
|
||||
* event actions
|
||||
*/
|
||||
public enum Action {
|
||||
PUT, MERGE, DELETE, SINGLE_DELETE, DELETE_RANGE, LOG, PUT_BLOB_INDEX,
|
||||
MARK_BEGIN_PREPARE, MARK_END_PREPARE, MARK_NOOP, MARK_COMMIT,
|
||||
MARK_ROLLBACK }
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
package org.rocksdb.util;
|
||||
|
||||
import org.rocksdb.RocksDBException;
|
||||
import org.rocksdb.WriteBatch;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class WriteBatchGetter extends WriteBatch.Handler {
|
||||
|
||||
private int columnFamilyId = -1;
|
||||
private final byte[] key;
|
||||
private byte[] value;
|
||||
|
||||
public WriteBatchGetter(final byte[] key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public byte[] getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(final int columnFamilyId, final byte[] key,
|
||||
final byte[] value) {
|
||||
if(Arrays.equals(this.key, key)) {
|
||||
this.columnFamilyId = columnFamilyId;
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(final byte[] key, final byte[] value) {
|
||||
if(Arrays.equals(this.key, key)) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void merge(final int columnFamilyId, final byte[] key,
|
||||
final byte[] value) {
|
||||
if(Arrays.equals(this.key, key)) {
|
||||
this.columnFamilyId = columnFamilyId;
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void merge(final byte[] key, final byte[] value) {
|
||||
if(Arrays.equals(this.key, key)) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(final int columnFamilyId, final byte[] key) {
|
||||
if(Arrays.equals(this.key, key)) {
|
||||
this.columnFamilyId = columnFamilyId;
|
||||
this.value = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(final byte[] key) {
|
||||
if(Arrays.equals(this.key, key)) {
|
||||
this.value = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void singleDelete(final int columnFamilyId, final byte[] key) {
|
||||
if(Arrays.equals(this.key, key)) {
|
||||
this.columnFamilyId = columnFamilyId;
|
||||
this.value = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void singleDelete(final byte[] key) {
|
||||
if(Arrays.equals(this.key, key)) {
|
||||
this.value = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteRange(final int columnFamilyId, final byte[] beginKey,
|
||||
final byte[] endKey) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteRange(final byte[] beginKey, final byte[] endKey) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logData(final byte[] blob) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putBlobIndex(final int columnFamilyId, final byte[] key,
|
||||
final byte[] value) {
|
||||
if(Arrays.equals(this.key, key)) {
|
||||
this.columnFamilyId = columnFamilyId;
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markBeginPrepare() throws RocksDBException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markEndPrepare(final byte[] xid) throws RocksDBException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markNoop(final boolean emptyBatch) throws RocksDBException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markRollback(final byte[] xid) throws RocksDBException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markCommit(final byte[] xid) throws RocksDBException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
@@ -182,6 +182,7 @@ LIB_SOURCES = \
|
||||
utilities/merge_operators/string_append/stringappend.cc \
|
||||
utilities/merge_operators/string_append/stringappend2.cc \
|
||||
utilities/merge_operators/uint64add.cc \
|
||||
utilities/merge_operators/bytesxor.cc \
|
||||
utilities/option_change_migration/option_change_migration.cc \
|
||||
utilities/options/options_util.cc \
|
||||
utilities/persistent_cache/block_cache_tier.cc \
|
||||
@@ -396,6 +397,9 @@ JNI_NATIVE_SOURCES = \
|
||||
java/rocksjni/lru_cache.cc \
|
||||
java/rocksjni/memtablejni.cc \
|
||||
java/rocksjni/merge_operator.cc \
|
||||
java/rocksjni/native_comparator_wrapper_test.cc \
|
||||
java/rocksjni/optimistic_transaction_db.cc \
|
||||
java/rocksjni/optimistic_transaction_options.cc \
|
||||
java/rocksjni/options.cc \
|
||||
java/rocksjni/options_util.cc \
|
||||
java/rocksjni/ratelimiterjni.cc \
|
||||
@@ -412,7 +416,13 @@ JNI_NATIVE_SOURCES = \
|
||||
java/rocksjni/statistics.cc \
|
||||
java/rocksjni/statisticsjni.cc \
|
||||
java/rocksjni/table.cc \
|
||||
java/rocksjni/transaction.cc \
|
||||
java/rocksjni/transaction_db.cc \
|
||||
java/rocksjni/transaction_options.cc \
|
||||
java/rocksjni/transaction_db_options.cc \
|
||||
java/rocksjni/transaction_log.cc \
|
||||
java/rocksjni/transaction_notifier.cc \
|
||||
java/rocksjni/transaction_notifier_jnicallback.cc \
|
||||
java/rocksjni/ttl.cc \
|
||||
java/rocksjni/write_batch.cc \
|
||||
java/rocksjni/writebatchhandlerjnicallback.cc \
|
||||
|
||||
@@ -545,9 +545,10 @@ class BlockBasedTableIterator : public InternalIterator {
|
||||
}
|
||||
bool IsKeyPinned() const override {
|
||||
return pinned_iters_mgr_ && pinned_iters_mgr_->PinningEnabled() &&
|
||||
block_iter_points_to_real_block_;
|
||||
block_iter_points_to_real_block_ && data_block_iter_.IsKeyPinned();
|
||||
}
|
||||
bool IsValuePinned() const override {
|
||||
// BlockIter::IsValuePinned() is always true. No need to check
|
||||
return pinned_iters_mgr_ && pinned_iters_mgr_->PinningEnabled() &&
|
||||
block_iter_points_to_real_block_;
|
||||
}
|
||||
@@ -566,7 +567,7 @@ class BlockBasedTableIterator : public InternalIterator {
|
||||
|
||||
void ResetDataIter() {
|
||||
if (block_iter_points_to_real_block_) {
|
||||
if (pinned_iters_mgr_ != nullptr) {
|
||||
if (pinned_iters_mgr_ != nullptr && pinned_iters_mgr_->PinningEnabled()) {
|
||||
data_block_iter_.DelegateCleanupsTo(pinned_iters_mgr_);
|
||||
}
|
||||
data_block_iter_.~BlockIter();
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
#include "util/xxhash.h"
|
||||
#include "utilities/blob_db/blob_db.h"
|
||||
#include "utilities/merge_operators.h"
|
||||
#include "utilities/merge_operators/bytesxor.h"
|
||||
#include "utilities/persistent_cache/block_cache_tier.h"
|
||||
|
||||
#ifdef OS_WIN
|
||||
@@ -107,6 +108,7 @@ DEFINE_string(
|
||||
"readwhilemerging,"
|
||||
"readrandomwriterandom,"
|
||||
"updaterandom,"
|
||||
"xorupdaterandom,"
|
||||
"randomwithverify,"
|
||||
"fill100K,"
|
||||
"crc32c,"
|
||||
@@ -151,6 +153,8 @@ DEFINE_string(
|
||||
"\tprefixscanrandom -- prefix scan N times in random order\n"
|
||||
"\tupdaterandom -- N threads doing read-modify-write for random "
|
||||
"keys\n"
|
||||
"\txorupdaterandom -- N threads doing read-XOR-write for "
|
||||
"random keys\n"
|
||||
"\tappendrandom -- N threads doing read-modify-write with "
|
||||
"growing values\n"
|
||||
"\tmergerandom -- same as updaterandom/appendrandom using merge"
|
||||
@@ -2525,6 +2529,8 @@ void VerifyDBFromDB(std::string& truth_db_name) {
|
||||
method = &Benchmark::ReadRandomMergeRandom;
|
||||
} else if (name == "updaterandom") {
|
||||
method = &Benchmark::UpdateRandom;
|
||||
} else if (name == "xorupdaterandom") {
|
||||
method = &Benchmark::XORUpdateRandom;
|
||||
} else if (name == "appendrandom") {
|
||||
method = &Benchmark::AppendRandom;
|
||||
} else if (name == "mergerandom") {
|
||||
@@ -4745,6 +4751,58 @@ void VerifyDBFromDB(std::string& truth_db_name) {
|
||||
thread->stats.AddMessage(msg);
|
||||
}
|
||||
|
||||
// Read-XOR-write for random keys. Xors the existing value with a randomly
|
||||
// generated value, and stores the result. Assuming A in the array of bytes
|
||||
// representing the existing value, we generate an array B of the same size,
|
||||
// then compute C = A^B as C[i]=A[i]^B[i], and store C
|
||||
void XORUpdateRandom(ThreadState* thread) {
|
||||
ReadOptions options(FLAGS_verify_checksum, true);
|
||||
RandomGenerator gen;
|
||||
std::string existing_value;
|
||||
int64_t found = 0;
|
||||
Duration duration(FLAGS_duration, readwrites_);
|
||||
|
||||
BytesXOROperator xor_operator;
|
||||
|
||||
std::unique_ptr<const char[]> key_guard;
|
||||
Slice key = AllocateKey(&key_guard);
|
||||
// the number of iterations is the larger of read_ or write_
|
||||
while (!duration.Done(1)) {
|
||||
DB* db = SelectDB(thread);
|
||||
GenerateKeyFromInt(thread->rand.Next() % FLAGS_num, FLAGS_num, &key);
|
||||
|
||||
auto status = db->Get(options, key, &existing_value);
|
||||
if (status.ok()) {
|
||||
++found;
|
||||
} else if (!status.IsNotFound()) {
|
||||
fprintf(stderr, "Get returned an error: %s\n",
|
||||
status.ToString().c_str());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
Slice value = gen.Generate(value_size_);
|
||||
std::string new_value;
|
||||
|
||||
if (status.ok()) {
|
||||
Slice existing_value_slice = Slice(existing_value);
|
||||
xor_operator.XOR(&existing_value_slice, value, &new_value);
|
||||
} else {
|
||||
xor_operator.XOR(nullptr, value, &new_value);
|
||||
}
|
||||
|
||||
Status s = db->Put(write_options_, key, Slice(new_value));
|
||||
if (!s.ok()) {
|
||||
fprintf(stderr, "put error: %s\n", s.ToString().c_str());
|
||||
exit(1);
|
||||
}
|
||||
thread->stats.FinishedOps(nullptr, db, 1);
|
||||
}
|
||||
char msg[100];
|
||||
snprintf(msg, sizeof(msg),
|
||||
"( updates:%" PRIu64 " found:%" PRIu64 ")", readwrites_, found);
|
||||
thread->stats.AddMessage(msg);
|
||||
}
|
||||
|
||||
// Read-modify-write for random keys.
|
||||
// Each operation causes the key grow by value_size (simulating an append).
|
||||
// Generally used for benchmarking against merges of similar type
|
||||
|
||||
@@ -222,7 +222,9 @@ Status CheckpointImpl::CreateCustomCheckpoint(
|
||||
|
||||
TEST_SYNC_POINT("CheckpointImpl::CreateCheckpoint:SavedLiveFiles1");
|
||||
TEST_SYNC_POINT("CheckpointImpl::CreateCheckpoint:SavedLiveFiles2");
|
||||
db_->FlushWAL(false /* sync */);
|
||||
if (db_options.manual_wal_flush) {
|
||||
db_->FlushWAL(false /* sync */);
|
||||
}
|
||||
}
|
||||
// if we have more than one column family, we need to also get WAL files
|
||||
if (s.ok()) {
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
//
|
||||
#ifndef MERGE_OPERATORS_H
|
||||
#define MERGE_OPERATORS_H
|
||||
#pragma once
|
||||
#include "rocksdb/merge_operator.h"
|
||||
|
||||
#include <memory>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "rocksdb/merge_operator.h"
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace rocksdb {
|
||||
|
||||
@@ -21,6 +21,7 @@ class MergeOperators {
|
||||
static std::shared_ptr<MergeOperator> CreateStringAppendOperator();
|
||||
static std::shared_ptr<MergeOperator> CreateStringAppendTESTOperator();
|
||||
static std::shared_ptr<MergeOperator> CreateMaxOperator();
|
||||
static std::shared_ptr<MergeOperator> CreateBytesXOROperator();
|
||||
|
||||
// Will return a different merge operator depending on the string.
|
||||
// TODO: Hook the "name" up to the actual Name() of the MergeOperators?
|
||||
@@ -38,14 +39,13 @@ class MergeOperators {
|
||||
return CreateStringAppendTESTOperator();
|
||||
} else if (name == "max") {
|
||||
return CreateMaxOperator();
|
||||
} else if (name == "bytesxor") {
|
||||
return CreateBytesXOROperator();
|
||||
} else {
|
||||
// Empty or unknown, just return nullptr
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace rocksdb
|
||||
|
||||
#endif
|
||||
} // namespace rocksdb
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
#include "utilities/merge_operators/bytesxor.h"
|
||||
|
||||
namespace rocksdb {
|
||||
|
||||
std::shared_ptr<MergeOperator> MergeOperators::CreateBytesXOROperator() {
|
||||
return std::make_shared<BytesXOROperator>();
|
||||
}
|
||||
|
||||
bool BytesXOROperator::Merge(const Slice& key,
|
||||
const Slice* existing_value,
|
||||
const Slice& value,
|
||||
std::string* new_value,
|
||||
Logger* logger) const {
|
||||
XOR(existing_value, value, new_value);
|
||||
return true;
|
||||
}
|
||||
|
||||
void BytesXOROperator::XOR(const Slice* existing_value,
|
||||
const Slice& value, std::string* new_value) const {
|
||||
if (!existing_value) {
|
||||
new_value->clear();
|
||||
new_value->assign(value.data(), value.size());
|
||||
return;
|
||||
}
|
||||
|
||||
size_t min_size = std::min(existing_value->size(), value.size());
|
||||
size_t max_size = std::max(existing_value->size(), value.size());
|
||||
|
||||
new_value->clear();
|
||||
new_value->reserve(max_size);
|
||||
|
||||
const char* existing_value_data = existing_value->data();
|
||||
const char* value_data = value.data();
|
||||
|
||||
for (size_t i = 0; i < min_size; i++) {
|
||||
new_value->push_back(existing_value_data[i] ^ value_data[i]);
|
||||
}
|
||||
|
||||
if (existing_value->size() == max_size) {
|
||||
for (size_t i = min_size; i < max_size; i++) {
|
||||
new_value->push_back(existing_value_data[i]);
|
||||
}
|
||||
} else {
|
||||
assert(value.size() == max_size);
|
||||
for (size_t i = min_size; i < max_size; i++) {
|
||||
new_value->push_back(value_data[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
@@ -0,0 +1,42 @@
|
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
#ifndef UTILITIES_MERGE_OPERATORS_BYTESXOR_H_
|
||||
#define UTILITIES_MERGE_OPERATORS_BYTESXOR_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include "rocksdb/env.h"
|
||||
#include "rocksdb/merge_operator.h"
|
||||
#include "rocksdb/slice.h"
|
||||
#include "util/coding.h"
|
||||
#include "utilities/merge_operators.h"
|
||||
|
||||
namespace rocksdb {
|
||||
|
||||
// A 'model' merge operator that XORs two (same sized) array of bytes.
|
||||
// Implemented as an AssociativeMergeOperator for simplicity and example.
|
||||
class BytesXOROperator : public AssociativeMergeOperator {
|
||||
public:
|
||||
// XORs the two array of bytes one byte at a time and stores the result
|
||||
// in new_value. len is the number of xored bytes, and the length of new_value
|
||||
virtual bool Merge(const Slice& key,
|
||||
const Slice* existing_value,
|
||||
const Slice& value,
|
||||
std::string* new_value,
|
||||
Logger* logger) const override;
|
||||
|
||||
virtual const char* Name() const override {
|
||||
return "BytesXOR";
|
||||
}
|
||||
|
||||
void XOR(const Slice* existing_value, const Slice& value,
|
||||
std::string* new_value) const;
|
||||
};
|
||||
|
||||
} // namespace rocksdb
|
||||
|
||||
#endif // UTILITIES_MERGE_OPERATORS_BYTESXOR_H_
|
||||
Reference in New Issue
Block a user