mirror of
https://github.com/facebook/rocksdb.git
synced 2024-11-25 22:44:05 +00:00
RocksDB#keyMayExist should not assume database values are unicode strings (#6186)
Summary: Closes https://github.com/facebook/rocksdb/issues/6183 Pull Request resolved: https://github.com/facebook/rocksdb/pull/6186 Differential Revision: D19201281 Pulled By: pdillinger fbshipit-source-id: 1c96b4ea09e826f91e44b0009eba3de0991d9053
This commit is contained in:
parent
4d3264e4ab
commit
e697da0b18
|
@ -3,6 +3,7 @@
|
||||||
### Public API Change
|
### Public API Change
|
||||||
* Added a rocksdb::FileSystem class in include/rocksdb/file_system.h to encapsulate file creation/read/write operations, and an option DBOptions::file_system to allow a user to pass in an instance of rocksdb::FileSystem. If its a non-null value, this will take precendence over DBOptions::env for file operations. A new API rocksdb::FileSystem::Default() returns a platform default object. The DBOptions::env option and Env::Default() API will continue to be used for threading and other OS related functions, and where DBOptions::file_system is not specified, for file operations. For storage developers who are accustomed to rocksdb::Env, the interface in rocksdb::FileSystem is new and will probably undergo some changes as more storage systems are ported to it from rocksdb::Env. As of now, no env other than Posix has been ported to the new interface.
|
* Added a rocksdb::FileSystem class in include/rocksdb/file_system.h to encapsulate file creation/read/write operations, and an option DBOptions::file_system to allow a user to pass in an instance of rocksdb::FileSystem. If its a non-null value, this will take precendence over DBOptions::env for file operations. A new API rocksdb::FileSystem::Default() returns a platform default object. The DBOptions::env option and Env::Default() API will continue to be used for threading and other OS related functions, and where DBOptions::file_system is not specified, for file operations. For storage developers who are accustomed to rocksdb::Env, the interface in rocksdb::FileSystem is new and will probably undergo some changes as more storage systems are ported to it from rocksdb::Env. As of now, no env other than Posix has been ported to the new interface.
|
||||||
* A new rocksdb::NewSstFileManager() API that allows the caller to pass in separate Env and FileSystem objects.
|
* A new rocksdb::NewSstFileManager() API that allows the caller to pass in separate Env and FileSystem objects.
|
||||||
|
* Changed Java API for RocksDB.keyMayExist functions to use Holder<byte[]> instead of StringBuilder, so that retrieved values need not decode to Strings.
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
* Fix a bug that can cause unnecessary bg thread to be scheduled(#6104).
|
* Fix a bug that can cause unnecessary bg thread to be scheduled(#6104).
|
||||||
|
|
|
@ -144,6 +144,7 @@ set(JAVA_MAIN_CLASSES
|
||||||
src/main/java/org/rocksdb/HdfsEnv.java
|
src/main/java/org/rocksdb/HdfsEnv.java
|
||||||
src/main/java/org/rocksdb/HistogramData.java
|
src/main/java/org/rocksdb/HistogramData.java
|
||||||
src/main/java/org/rocksdb/HistogramType.java
|
src/main/java/org/rocksdb/HistogramType.java
|
||||||
|
src/main/java/org/rocksdb/Holder.java
|
||||||
src/main/java/org/rocksdb/IndexType.java
|
src/main/java/org/rocksdb/IndexType.java
|
||||||
src/main/java/org/rocksdb/InfoLogLevel.java
|
src/main/java/org/rocksdb/InfoLogLevel.java
|
||||||
src/main/java/org/rocksdb/IngestExternalFileOptions.java
|
src/main/java/org/rocksdb/IngestExternalFileOptions.java
|
||||||
|
|
|
@ -1588,127 +1588,156 @@ jobjectArray Java_org_rocksdb_RocksDB_multiGet__JJ_3_3B_3I_3I_3J(
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
// rocksdb::DB::KeyMayExist
|
// rocksdb::DB::KeyMayExist
|
||||||
jboolean key_may_exist_helper(JNIEnv* env, rocksdb::DB* db,
|
bool key_may_exist_helper(JNIEnv* env, jlong jdb_handle, jlong jcf_handle,
|
||||||
const rocksdb::ReadOptions& read_opt,
|
jlong jread_opts_handle,
|
||||||
rocksdb::ColumnFamilyHandle* cf_handle,
|
jbyteArray jkey, jint jkey_offset, jint jkey_len,
|
||||||
jbyteArray jkey, jint jkey_off, jint jkey_len,
|
bool* has_exception, std::string* value, bool* value_found) {
|
||||||
jobject jstring_builder, bool* has_exception) {
|
auto* db = reinterpret_cast<rocksdb::DB*>(jdb_handle);
|
||||||
|
rocksdb::ColumnFamilyHandle* cf_handle;
|
||||||
|
if (jcf_handle == 0) {
|
||||||
|
cf_handle = db->DefaultColumnFamily();
|
||||||
|
} else {
|
||||||
|
cf_handle = reinterpret_cast<rocksdb::ColumnFamilyHandle*>(jcf_handle);
|
||||||
|
}
|
||||||
|
rocksdb::ReadOptions read_opts =
|
||||||
|
jread_opts_handle == 0 ? rocksdb::ReadOptions()
|
||||||
|
: *(reinterpret_cast<rocksdb::ReadOptions*>(jread_opts_handle));
|
||||||
|
|
||||||
jbyte* key = new jbyte[jkey_len];
|
jbyte* key = new jbyte[jkey_len];
|
||||||
env->GetByteArrayRegion(jkey, jkey_off, jkey_len, key);
|
env->GetByteArrayRegion(jkey, jkey_offset, jkey_len, key);
|
||||||
if (env->ExceptionCheck()) {
|
if (env->ExceptionCheck()) {
|
||||||
// exception thrown: ArrayIndexOutOfBoundsException
|
// exception thrown: ArrayIndexOutOfBoundsException
|
||||||
delete[] key;
|
delete[] key;
|
||||||
*has_exception = true;
|
*has_exception = true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
rocksdb::Slice key_slice(reinterpret_cast<char*>(key), jkey_len);
|
rocksdb::Slice key_slice(reinterpret_cast<char*>(key), jkey_len);
|
||||||
|
|
||||||
std::string value;
|
const bool exists = db->KeyMayExist(
|
||||||
bool value_found = false;
|
read_opts, cf_handle, key_slice, value, value_found);
|
||||||
bool keyMayExist;
|
|
||||||
if (cf_handle != nullptr) {
|
|
||||||
keyMayExist =
|
|
||||||
db->KeyMayExist(read_opt, cf_handle, key_slice, &value, &value_found);
|
|
||||||
} else {
|
|
||||||
keyMayExist = db->KeyMayExist(read_opt, key_slice, &value, &value_found);
|
|
||||||
}
|
|
||||||
|
|
||||||
// cleanup
|
// cleanup
|
||||||
delete[] key;
|
delete[] key;
|
||||||
|
|
||||||
// extract the value
|
return exists;
|
||||||
if (value_found && !value.empty()) {
|
}
|
||||||
jobject jresult_string_builder =
|
|
||||||
rocksdb::StringBuilderJni::append(env, jstring_builder, value.c_str());
|
|
||||||
if (jresult_string_builder == nullptr) {
|
/*
|
||||||
*has_exception = true;
|
* Class: org_rocksdb_RocksDB
|
||||||
return false;
|
* Method: keyMayExist
|
||||||
|
* Signature: (JJJ[BII)Z
|
||||||
|
*/
|
||||||
|
jboolean Java_org_rocksdb_RocksDB_keyMayExist(
|
||||||
|
JNIEnv* env, jobject, jlong jdb_handle, jlong jcf_handle,
|
||||||
|
jlong jread_opts_handle,
|
||||||
|
jbyteArray jkey, jint jkey_offset, jint jkey_len) {
|
||||||
|
|
||||||
|
bool has_exception = false;
|
||||||
|
std::string value;
|
||||||
|
bool value_found = false;
|
||||||
|
|
||||||
|
const bool exists = key_may_exist_helper(
|
||||||
|
env, jdb_handle, jcf_handle, jread_opts_handle,
|
||||||
|
jkey, jkey_offset, jkey_len,
|
||||||
|
&has_exception, &value, &value_found);
|
||||||
|
|
||||||
|
if (has_exception) {
|
||||||
|
// java exception already raised
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return static_cast<jboolean>(exists);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_rocksdb_RocksDB
|
||||||
|
* Method: keyMayExistFoundValue
|
||||||
|
* Signature: (JJJ[BII)[[B
|
||||||
|
*/
|
||||||
|
jobjectArray Java_org_rocksdb_RocksDB_keyMayExistFoundValue(
|
||||||
|
JNIEnv* env, jobject, jlong jdb_handle, jlong jcf_handle,
|
||||||
|
jlong jread_opts_handle,
|
||||||
|
jbyteArray jkey, jint jkey_offset, jint jkey_len) {
|
||||||
|
|
||||||
|
bool has_exception = false;
|
||||||
|
std::string value;
|
||||||
|
bool value_found = false;
|
||||||
|
|
||||||
|
const bool exists = key_may_exist_helper(
|
||||||
|
env, jdb_handle, jcf_handle, jread_opts_handle,
|
||||||
|
jkey, jkey_offset, jkey_len,
|
||||||
|
&has_exception, &value, &value_found);
|
||||||
|
|
||||||
|
if (has_exception) {
|
||||||
|
// java exception already raised
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
jbyte result_flags[1];
|
||||||
|
if (!exists) {
|
||||||
|
result_flags[0] = 0;
|
||||||
|
} else if (!value_found) {
|
||||||
|
result_flags[0] = 1;
|
||||||
|
} else {
|
||||||
|
// found
|
||||||
|
result_flags[0] = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
jobjectArray jresults = rocksdb::ByteJni::new2dByteArray(env, 2);
|
||||||
|
if (jresults == nullptr) {
|
||||||
|
// exception occurred
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// prepare the result flag
|
||||||
|
jbyteArray jresult_flags = env->NewByteArray(1);
|
||||||
|
if (jresult_flags == nullptr) {
|
||||||
|
// exception thrown: OutOfMemoryError
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
env->SetByteArrayRegion(jresult_flags, 0, 1, result_flags);
|
||||||
|
if (env->ExceptionCheck()) {
|
||||||
|
// exception thrown: ArrayIndexOutOfBoundsException
|
||||||
|
env->DeleteLocalRef(jresult_flags);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
env->SetObjectArrayElement(jresults, 0, jresult_flags);
|
||||||
|
if (env->ExceptionCheck()) {
|
||||||
|
// exception thrown: ArrayIndexOutOfBoundsException
|
||||||
|
env->DeleteLocalRef(jresult_flags);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
env->DeleteLocalRef(jresult_flags);
|
||||||
|
|
||||||
|
if (result_flags[0] == 2) {
|
||||||
|
// set the value
|
||||||
|
const jsize jvalue_len = static_cast<jsize>(value.size());
|
||||||
|
jbyteArray jresult_value = env->NewByteArray(jvalue_len);
|
||||||
|
if (jresult_value == nullptr) {
|
||||||
|
// exception thrown: OutOfMemoryError
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
env->SetByteArrayRegion(jresult_value, 0, jvalue_len,
|
||||||
|
const_cast<jbyte*>(reinterpret_cast<const jbyte*>(value.data())));
|
||||||
|
if (env->ExceptionCheck()) {
|
||||||
|
// exception thrown: ArrayIndexOutOfBoundsException
|
||||||
|
env->DeleteLocalRef(jresult_value);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
env->SetObjectArrayElement(jresults, 1, jresult_value);
|
||||||
|
if (env->ExceptionCheck()) {
|
||||||
|
// exception thrown: ArrayIndexOutOfBoundsException
|
||||||
|
env->DeleteLocalRef(jresult_value);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
env->DeleteLocalRef(jresult_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
*has_exception = false;
|
return jresults;
|
||||||
return static_cast<jboolean>(keyMayExist);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Class: org_rocksdb_RocksDB
|
|
||||||
* Method: keyMayExist
|
|
||||||
* Signature: (J[BIILjava/lang/StringBuilder;)Z
|
|
||||||
*/
|
|
||||||
jboolean Java_org_rocksdb_RocksDB_keyMayExist__J_3BIILjava_lang_StringBuilder_2(
|
|
||||||
JNIEnv* env, jobject, jlong jdb_handle,
|
|
||||||
jbyteArray jkey, jint jkey_off, jint jkey_len, jobject jstring_builder) {
|
|
||||||
auto* db = reinterpret_cast<rocksdb::DB*>(jdb_handle);
|
|
||||||
bool has_exception = false;
|
|
||||||
return key_may_exist_helper(env, db, rocksdb::ReadOptions(), nullptr, jkey,
|
|
||||||
jkey_off, jkey_len, jstring_builder, &has_exception);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Class: org_rocksdb_RocksDB
|
|
||||||
* Method: keyMayExist
|
|
||||||
* Signature: (J[BIIJLjava/lang/StringBuilder;)Z
|
|
||||||
*/
|
|
||||||
jboolean
|
|
||||||
Java_org_rocksdb_RocksDB_keyMayExist__J_3BIIJLjava_lang_StringBuilder_2(
|
|
||||||
JNIEnv* env, jobject, jlong jdb_handle,
|
|
||||||
jbyteArray jkey, jint jkey_off, jint jkey_len,
|
|
||||||
jlong jcf_handle, jobject jstring_builder) {
|
|
||||||
auto* db = reinterpret_cast<rocksdb::DB*>(jdb_handle);
|
|
||||||
auto* cf_handle = reinterpret_cast<rocksdb::ColumnFamilyHandle*>(jcf_handle);
|
|
||||||
if (cf_handle != nullptr) {
|
|
||||||
bool has_exception = false;
|
|
||||||
return key_may_exist_helper(env, db, rocksdb::ReadOptions(), cf_handle,
|
|
||||||
jkey, jkey_off, jkey_len, jstring_builder,
|
|
||||||
&has_exception);
|
|
||||||
} else {
|
|
||||||
rocksdb::RocksDBExceptionJni::ThrowNew(
|
|
||||||
env, rocksdb::Status::InvalidArgument("Invalid ColumnFamilyHandle."));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Class: org_rocksdb_RocksDB
|
|
||||||
* Method: keyMayExist
|
|
||||||
* Signature: (JJ[BIILjava/lang/StringBuilder;)Z
|
|
||||||
*/
|
|
||||||
jboolean
|
|
||||||
Java_org_rocksdb_RocksDB_keyMayExist__JJ_3BIILjava_lang_StringBuilder_2(
|
|
||||||
JNIEnv* env, jobject, jlong jdb_handle, jlong jread_options_handle,
|
|
||||||
jbyteArray jkey, jint jkey_off, jint jkey_len, jobject jstring_builder) {
|
|
||||||
auto* db = reinterpret_cast<rocksdb::DB*>(jdb_handle);
|
|
||||||
auto& read_options =
|
|
||||||
*reinterpret_cast<rocksdb::ReadOptions*>(jread_options_handle);
|
|
||||||
bool has_exception = false;
|
|
||||||
return key_may_exist_helper(env, db, read_options, nullptr, jkey, jkey_off,
|
|
||||||
jkey_len, jstring_builder, &has_exception);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Class: org_rocksdb_RocksDB
|
|
||||||
* Method: keyMayExist
|
|
||||||
* Signature: (JJ[BIIJLjava/lang/StringBuilder;)Z
|
|
||||||
*/
|
|
||||||
jboolean
|
|
||||||
Java_org_rocksdb_RocksDB_keyMayExist__JJ_3BIIJLjava_lang_StringBuilder_2(
|
|
||||||
JNIEnv* env, jobject, jlong jdb_handle, jlong jread_options_handle,
|
|
||||||
jbyteArray jkey, jint jkey_off, jint jkey_len, jlong jcf_handle,
|
|
||||||
jobject jstring_builder) {
|
|
||||||
auto* db = reinterpret_cast<rocksdb::DB*>(jdb_handle);
|
|
||||||
auto& read_options =
|
|
||||||
*reinterpret_cast<rocksdb::ReadOptions*>(jread_options_handle);
|
|
||||||
auto* cf_handle = reinterpret_cast<rocksdb::ColumnFamilyHandle*>(jcf_handle);
|
|
||||||
if (cf_handle != nullptr) {
|
|
||||||
bool has_exception = false;
|
|
||||||
return key_may_exist_helper(env, db, read_options, cf_handle, jkey,
|
|
||||||
jkey_off, jkey_len, jstring_builder, &has_exception);
|
|
||||||
} else {
|
|
||||||
rocksdb::RocksDBExceptionJni::ThrowNew(
|
|
||||||
env, rocksdb::Status::InvalidArgument("Invalid ColumnFamilyHandle."));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
46
java/src/main/java/org/rocksdb/Holder.java
Normal file
46
java/src/main/java/org/rocksdb/Holder.java
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
// Copyright (c) 2016, 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple instance reference wrapper.
|
||||||
|
*/
|
||||||
|
public class Holder<T> {
|
||||||
|
private /* @Nullable */ T value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new Holder with null instance.
|
||||||
|
*/
|
||||||
|
public Holder() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new Holder.
|
||||||
|
*
|
||||||
|
* @param value the instance or null
|
||||||
|
*/
|
||||||
|
public Holder(/* @Nullable */ final T value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the instance reference.
|
||||||
|
*
|
||||||
|
* @return value the instance reference or null
|
||||||
|
*/
|
||||||
|
public /* @Nullable */ T getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the instance reference.
|
||||||
|
*
|
||||||
|
* @param value the instance reference or null
|
||||||
|
*/
|
||||||
|
public void setValue(/* @Nullable */ final T value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
|
@ -2189,68 +2189,94 @@ public class RocksDB extends RocksObject {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the key definitely does not exist in the database, then this method
|
* If the key definitely does not exist in the database, then this method
|
||||||
* returns false, else true.
|
* returns null, else it returns an instance of KeyMayExistResult
|
||||||
*
|
*
|
||||||
* This check is potentially lighter-weight than invoking DB::Get(). One way
|
* If the caller wants to obtain value when the key
|
||||||
* to make this lighter weight is to avoid doing any IOs.
|
* is found in memory, then {@code valueHolder} must be set.
|
||||||
|
*
|
||||||
|
* This check is potentially lighter-weight than invoking
|
||||||
|
* {@link #get(byte[])}. One way to make this lighter weight is to avoid
|
||||||
|
* doing any IOs.
|
||||||
*
|
*
|
||||||
* @param key byte array of a key to search for
|
* @param key byte array of a key to search for
|
||||||
* @param value StringBuilder instance which is a out parameter if a value is
|
* @param valueHolder non-null to retrieve the value if it is found, or null
|
||||||
* found in block-cache.
|
* if the value is not needed. If non-null, upon return of the function,
|
||||||
* @return boolean value indicating if key does not exist or might exist.
|
* the {@code value} will be set if it could be retrieved.
|
||||||
|
*
|
||||||
|
* @return false if the key definitely does not exist in the database,
|
||||||
|
* otherwise true.
|
||||||
*/
|
*/
|
||||||
public boolean keyMayExist(final byte[] key, final StringBuilder value) {
|
public boolean keyMayExist(final byte[] key,
|
||||||
return keyMayExist(nativeHandle_, key, 0, key.length, value);
|
/* @Nullable */ final Holder<byte[]> valueHolder) {
|
||||||
|
return keyMayExist(key, 0, key.length, valueHolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the key definitely does not exist in the database, then this method
|
* If the key definitely does not exist in the database, then this method
|
||||||
* returns false, else true.
|
* returns null, else it returns an instance of KeyMayExistResult
|
||||||
*
|
*
|
||||||
* This check is potentially lighter-weight than invoking DB::Get(). One way
|
* If the caller wants to obtain value when the key
|
||||||
* to make this lighter weight is to avoid doing any IOs.
|
* is found in memory, then {@code valueHolder} must be set.
|
||||||
|
*
|
||||||
|
* This check is potentially lighter-weight than invoking
|
||||||
|
* {@link #get(byte[], int, int)}. One way to make this lighter weight is to
|
||||||
|
* avoid doing any IOs.
|
||||||
*
|
*
|
||||||
* @param key byte array of a key to search for
|
* @param key byte array of a key to search for
|
||||||
* @param offset the offset of the "key" array to be used, must be
|
* @param offset the offset of the "key" array to be used, must be
|
||||||
* non-negative and no larger than "key".length
|
* non-negative and no larger than "key".length
|
||||||
* @param len the length of the "key" array to be used, must be non-negative
|
* @param len the length of the "key" array to be used, must be non-negative
|
||||||
* and no larger than "key".length
|
* and no larger than "key".length
|
||||||
* @param value StringBuilder instance which is a out parameter if a value is
|
* @param valueHolder non-null to retrieve the value if it is found, or null
|
||||||
* found in block-cache.
|
* if the value is not needed. If non-null, upon return of the function,
|
||||||
|
* the {@code value} will be set if it could be retrieved.
|
||||||
*
|
*
|
||||||
* @return boolean value indicating if key does not exist or might exist.
|
* @return false if the key definitely does not exist in the database,
|
||||||
|
* otherwise true.
|
||||||
*/
|
*/
|
||||||
public boolean keyMayExist(final byte[] key, final int offset, final int len,
|
public boolean keyMayExist(final byte[] key,
|
||||||
final StringBuilder value) {
|
final int offset, final int len,
|
||||||
checkBounds(offset, len, key.length);
|
/* @Nullable */ final Holder<byte[]> valueHolder) {
|
||||||
return keyMayExist(nativeHandle_, key, offset, len, value);
|
return keyMayExist((ColumnFamilyHandle)null, key, offset, len, valueHolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the key definitely does not exist in the database, then this method
|
* If the key definitely does not exist in the database, then this method
|
||||||
* returns false, else true.
|
* returns null, else it returns an instance of KeyMayExistResult
|
||||||
*
|
*
|
||||||
* This check is potentially lighter-weight than invoking DB::Get(). One way
|
* If the caller wants to obtain value when the key
|
||||||
* to make this lighter weight is to avoid doing any IOs.
|
* is found in memory, then {@code valueHolder} must be set.
|
||||||
|
*
|
||||||
|
* This check is potentially lighter-weight than invoking
|
||||||
|
* {@link #get(ColumnFamilyHandle,byte[])}. One way to make this lighter
|
||||||
|
* weight is to avoid doing any IOs.
|
||||||
*
|
*
|
||||||
* @param columnFamilyHandle {@link ColumnFamilyHandle} instance
|
* @param columnFamilyHandle {@link ColumnFamilyHandle} instance
|
||||||
* @param key byte array of a key to search for
|
* @param key byte array of a key to search for
|
||||||
* @param value StringBuilder instance which is a out parameter if a value is
|
* @param valueHolder non-null to retrieve the value if it is found, or null
|
||||||
* found in block-cache.
|
* if the value is not needed. If non-null, upon return of the function,
|
||||||
* @return boolean value indicating if key does not exist or might exist.
|
* the {@code value} will be set if it could be retrieved.
|
||||||
|
*
|
||||||
|
* @return false if the key definitely does not exist in the database,
|
||||||
|
* otherwise true.
|
||||||
*/
|
*/
|
||||||
public boolean keyMayExist(final ColumnFamilyHandle columnFamilyHandle,
|
public boolean keyMayExist(
|
||||||
final byte[] key, final StringBuilder value) {
|
final ColumnFamilyHandle columnFamilyHandle, final byte[] key,
|
||||||
return keyMayExist(nativeHandle_, key, 0, key.length,
|
/* @Nullable */ final Holder<byte[]> valueHolder) {
|
||||||
columnFamilyHandle.nativeHandle_, value);
|
return keyMayExist(columnFamilyHandle, key, 0, key.length,
|
||||||
|
valueHolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the key definitely does not exist in the database, then this method
|
* If the key definitely does not exist in the database, then this method
|
||||||
* returns false, else true.
|
* returns null, else it returns an instance of KeyMayExistResult
|
||||||
*
|
*
|
||||||
* This check is potentially lighter-weight than invoking DB::Get(). One way
|
* If the caller wants to obtain value when the key
|
||||||
* to make this lighter weight is to avoid doing any IOs.
|
* is found in memory, then {@code valueHolder} must be set.
|
||||||
|
*
|
||||||
|
* This check is potentially lighter-weight than invoking
|
||||||
|
* {@link #get(ColumnFamilyHandle, byte[], int, int)}. One way to make this
|
||||||
|
* lighter weight is to avoid doing any IOs.
|
||||||
*
|
*
|
||||||
* @param columnFamilyHandle {@link ColumnFamilyHandle} instance
|
* @param columnFamilyHandle {@link ColumnFamilyHandle} instance
|
||||||
* @param key byte array of a key to search for
|
* @param key byte array of a key to search for
|
||||||
|
@ -2258,42 +2284,58 @@ public class RocksDB extends RocksObject {
|
||||||
* non-negative and no larger than "key".length
|
* non-negative and no larger than "key".length
|
||||||
* @param len the length of the "key" array to be used, must be non-negative
|
* @param len the length of the "key" array to be used, must be non-negative
|
||||||
* and no larger than "key".length
|
* and no larger than "key".length
|
||||||
* @param value StringBuilder instance which is a out parameter if a value is
|
* @param valueHolder non-null to retrieve the value if it is found, or null
|
||||||
* found in block-cache.
|
* if the value is not needed. If non-null, upon return of the function,
|
||||||
* @return boolean value indicating if key does not exist or might exist.
|
* the {@code value} will be set if it could be retrieved.
|
||||||
|
*
|
||||||
|
* @return false if the key definitely does not exist in the database,
|
||||||
|
* otherwise true.
|
||||||
*/
|
*/
|
||||||
public boolean keyMayExist(final ColumnFamilyHandle columnFamilyHandle,
|
public boolean keyMayExist(
|
||||||
final byte[] key, int offset, int len, final StringBuilder value) {
|
final ColumnFamilyHandle columnFamilyHandle,
|
||||||
checkBounds(offset, len, key.length);
|
final byte[] key, int offset, int len,
|
||||||
return keyMayExist(nativeHandle_, key, offset, len,
|
/* @Nullable */ final Holder<byte[]> valueHolder) {
|
||||||
columnFamilyHandle.nativeHandle_, value);
|
return keyMayExist(columnFamilyHandle, null, key, offset, len,
|
||||||
|
valueHolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the key definitely does not exist in the database, then this method
|
* If the key definitely does not exist in the database, then this method
|
||||||
* returns false, else true.
|
* returns null, else it returns an instance of KeyMayExistResult
|
||||||
*
|
*
|
||||||
* This check is potentially lighter-weight than invoking DB::Get(). One way
|
* If the caller wants to obtain value when the key
|
||||||
* to make this lighter weight is to avoid doing any IOs.
|
* is found in memory, then {@code valueHolder} must be set.
|
||||||
|
*
|
||||||
|
* This check is potentially lighter-weight than invoking
|
||||||
|
* {@link #get(ReadOptions, byte[])}. One way to make this
|
||||||
|
* lighter weight is to avoid doing any IOs.
|
||||||
*
|
*
|
||||||
* @param readOptions {@link ReadOptions} instance
|
* @param readOptions {@link ReadOptions} instance
|
||||||
* @param key byte array of a key to search for
|
* @param key byte array of a key to search for
|
||||||
* @param value StringBuilder instance which is a out parameter if a value is
|
* @param valueHolder non-null to retrieve the value if it is found, or null
|
||||||
* found in block-cache.
|
* if the value is not needed. If non-null, upon return of the function,
|
||||||
* @return boolean value indicating if key does not exist or might exist.
|
* the {@code value} will be set if it could be retrieved.
|
||||||
|
*
|
||||||
|
* @return false if the key definitely does not exist in the database,
|
||||||
|
* otherwise true.
|
||||||
*/
|
*/
|
||||||
public boolean keyMayExist(final ReadOptions readOptions,
|
public boolean keyMayExist(
|
||||||
final byte[] key, final StringBuilder value) {
|
final ReadOptions readOptions, final byte[] key,
|
||||||
return keyMayExist(nativeHandle_, readOptions.nativeHandle_,
|
/* @Nullable */ final Holder<byte[]> valueHolder) {
|
||||||
key, 0, key.length, value);
|
return keyMayExist(readOptions, key, 0, key.length,
|
||||||
|
valueHolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the key definitely does not exist in the database, then this method
|
* If the key definitely does not exist in the database, then this method
|
||||||
* returns false, else true.
|
* returns null, else it returns an instance of KeyMayExistResult
|
||||||
*
|
*
|
||||||
* This check is potentially lighter-weight than invoking DB::Get(). One way
|
* If the caller wants to obtain value when the key
|
||||||
* to make this lighter weight is to avoid doing any IOs.
|
* is found in memory, then {@code valueHolder} must be set.
|
||||||
|
*
|
||||||
|
* This check is potentially lighter-weight than invoking
|
||||||
|
* {@link #get(ReadOptions, byte[], int, int)}. One way to make this
|
||||||
|
* lighter weight is to avoid doing any IOs.
|
||||||
*
|
*
|
||||||
* @param readOptions {@link ReadOptions} instance
|
* @param readOptions {@link ReadOptions} instance
|
||||||
* @param key byte array of a key to search for
|
* @param key byte array of a key to search for
|
||||||
|
@ -2301,65 +2343,103 @@ public class RocksDB extends RocksObject {
|
||||||
* non-negative and no larger than "key".length
|
* non-negative and no larger than "key".length
|
||||||
* @param len the length of the "key" array to be used, must be non-negative
|
* @param len the length of the "key" array to be used, must be non-negative
|
||||||
* and no larger than "key".length
|
* and no larger than "key".length
|
||||||
* @param value StringBuilder instance which is a out parameter if a value is
|
* @param valueHolder non-null to retrieve the value if it is found, or null
|
||||||
* found in block-cache.
|
* if the value is not needed. If non-null, upon return of the function,
|
||||||
* @return boolean value indicating if key does not exist or might exist.
|
* the {@code value} will be set if it could be retrieved.
|
||||||
|
*
|
||||||
|
* @return false if the key definitely does not exist in the database,
|
||||||
|
* otherwise true.
|
||||||
*/
|
*/
|
||||||
public boolean keyMayExist(final ReadOptions readOptions,
|
public boolean keyMayExist(
|
||||||
|
final ReadOptions readOptions,
|
||||||
final byte[] key, final int offset, final int len,
|
final byte[] key, final int offset, final int len,
|
||||||
final StringBuilder value) {
|
/* @Nullable */ final Holder<byte[]> valueHolder) {
|
||||||
checkBounds(offset, len, key.length);
|
return keyMayExist(null, readOptions,
|
||||||
return keyMayExist(nativeHandle_, readOptions.nativeHandle_,
|
key, offset, len, valueHolder);
|
||||||
key, offset, len, value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the key definitely does not exist in the database, then this method
|
* If the key definitely does not exist in the database, then this method
|
||||||
* returns false, else true.
|
* returns null, else it returns an instance of KeyMayExistResult
|
||||||
*
|
*
|
||||||
* This check is potentially lighter-weight than invoking DB::Get(). One way
|
* If the caller wants to obtain value when the key
|
||||||
* to make this lighter weight is to avoid doing any IOs.
|
* is found in memory, then {@code valueHolder} must be set.
|
||||||
|
*
|
||||||
|
* This check is potentially lighter-weight than invoking
|
||||||
|
* {@link #get(ColumnFamilyHandle, ReadOptions, byte[])}. One way to make this
|
||||||
|
* lighter weight is to avoid doing any IOs.
|
||||||
*
|
*
|
||||||
* @param readOptions {@link ReadOptions} instance
|
|
||||||
* @param columnFamilyHandle {@link ColumnFamilyHandle} instance
|
* @param columnFamilyHandle {@link ColumnFamilyHandle} instance
|
||||||
|
* @param readOptions {@link ReadOptions} instance
|
||||||
* @param key byte array of a key to search for
|
* @param key byte array of a key to search for
|
||||||
* @param value StringBuilder instance which is a out parameter if a value is
|
* @param valueHolder non-null to retrieve the value if it is found, or null
|
||||||
* found in block-cache.
|
* if the value is not needed. If non-null, upon return of the function,
|
||||||
* @return boolean value indicating if key does not exist or might exist.
|
* the {@code value} will be set if it could be retrieved.
|
||||||
|
*
|
||||||
|
* @return false if the key definitely does not exist in the database,
|
||||||
|
* otherwise true.
|
||||||
*/
|
*/
|
||||||
public boolean keyMayExist(final ReadOptions readOptions,
|
public boolean keyMayExist(
|
||||||
final ColumnFamilyHandle columnFamilyHandle, final byte[] key,
|
final ColumnFamilyHandle columnFamilyHandle,
|
||||||
final StringBuilder value) {
|
final ReadOptions readOptions, final byte[] key,
|
||||||
return keyMayExist(nativeHandle_, readOptions.nativeHandle_,
|
/* @Nullable */ final Holder<byte[]> valueHolder) {
|
||||||
key, 0, key.length, columnFamilyHandle.nativeHandle_,
|
return keyMayExist(columnFamilyHandle, readOptions,
|
||||||
value);
|
key, 0, key.length, valueHolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the key definitely does not exist in the database, then this method
|
* If the key definitely does not exist in the database, then this method
|
||||||
* returns false, else true.
|
* returns null, else it returns an instance of KeyMayExistResult
|
||||||
*
|
*
|
||||||
* This check is potentially lighter-weight than invoking DB::Get(). One way
|
* If the caller wants to obtain value when the key
|
||||||
* to make this lighter weight is to avoid doing any IOs.
|
* is found in memory, then {@code valueHolder} must be set.
|
||||||
|
*
|
||||||
|
* This check is potentially lighter-weight than invoking
|
||||||
|
* {@link #get(ColumnFamilyHandle, ReadOptions, byte[], int, int)}.
|
||||||
|
* One way to make this lighter weight is to avoid doing any IOs.
|
||||||
*
|
*
|
||||||
* @param readOptions {@link ReadOptions} instance
|
|
||||||
* @param columnFamilyHandle {@link ColumnFamilyHandle} instance
|
* @param columnFamilyHandle {@link ColumnFamilyHandle} instance
|
||||||
|
* @param readOptions {@link ReadOptions} instance
|
||||||
* @param key byte array of a key to search for
|
* @param key byte array of a key to search for
|
||||||
* @param offset the offset of the "key" array to be used, must be
|
* @param offset the offset of the "key" array to be used, must be
|
||||||
* non-negative and no larger than "key".length
|
* non-negative and no larger than "key".length
|
||||||
* @param len the length of the "key" array to be used, must be non-negative
|
* @param len the length of the "key" array to be used, must be non-negative
|
||||||
* and no larger than "key".length
|
* and no larger than "key".length
|
||||||
* @param value StringBuilder instance which is a out parameter if a value is
|
* @param valueHolder non-null to retrieve the value if it is found, or null
|
||||||
* found in block-cache.
|
* if the value is not needed. If non-null, upon return of the function,
|
||||||
* @return boolean value indicating if key does not exist or might exist.
|
* the {@code value} will be set if it could be retrieved.
|
||||||
|
*
|
||||||
|
* @return false if the key definitely does not exist in the database,
|
||||||
|
* otherwise true.
|
||||||
*/
|
*/
|
||||||
public boolean keyMayExist(final ReadOptions readOptions,
|
public boolean keyMayExist(
|
||||||
final ColumnFamilyHandle columnFamilyHandle, final byte[] key,
|
final ColumnFamilyHandle columnFamilyHandle,
|
||||||
final int offset, final int len, final StringBuilder value) {
|
final ReadOptions readOptions,
|
||||||
|
final byte[] key, final int offset, final int len,
|
||||||
|
/* @Nullable */ final Holder<byte[]> valueHolder) {
|
||||||
checkBounds(offset, len, key.length);
|
checkBounds(offset, len, key.length);
|
||||||
return keyMayExist(nativeHandle_, readOptions.nativeHandle_,
|
if (valueHolder == null) {
|
||||||
key, offset, len, columnFamilyHandle.nativeHandle_,
|
return keyMayExist(nativeHandle_,
|
||||||
value);
|
columnFamilyHandle == null ? 0 : columnFamilyHandle.nativeHandle_,
|
||||||
|
readOptions == null ? 0 : readOptions.nativeHandle_,
|
||||||
|
key, offset, len);
|
||||||
|
} else {
|
||||||
|
final byte[][] result = keyMayExistFoundValue(
|
||||||
|
nativeHandle_,
|
||||||
|
columnFamilyHandle == null ? 0 : columnFamilyHandle.nativeHandle_,
|
||||||
|
readOptions == null ? 0 : readOptions.nativeHandle_,
|
||||||
|
key, offset, len);
|
||||||
|
if (result[0][0] == 0x0) {
|
||||||
|
valueHolder.setValue(null);
|
||||||
|
return false;
|
||||||
|
} else if (result[0][0] == 0x1) {
|
||||||
|
valueHolder.setValue(null);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
valueHolder.setValue(result[1]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -4158,19 +4238,12 @@ public class RocksDB extends RocksObject {
|
||||||
private native byte[][] multiGet(final long dbHandle, final long rOptHandle,
|
private native byte[][] multiGet(final long dbHandle, final long rOptHandle,
|
||||||
final byte[][] keys, final int[] keyOffsets, final int[] keyLengths,
|
final byte[][] keys, final int[] keyOffsets, final int[] keyLengths,
|
||||||
final long[] columnFamilyHandles);
|
final long[] columnFamilyHandles);
|
||||||
private native boolean keyMayExist(final long handle, final byte[] key,
|
private native boolean keyMayExist(
|
||||||
final int keyOffset, final int keyLength,
|
final long handle, final long cfHandle, final long readOptHandle,
|
||||||
final StringBuilder stringBuilder);
|
final byte[] key, final int keyOffset, final int keyLength);
|
||||||
private native boolean keyMayExist(final long handle, final byte[] key,
|
private native byte[][] keyMayExistFoundValue(
|
||||||
final int keyOffset, final int keyLength, final long cfHandle,
|
final long handle, final long cfHandle, final long readOptHandle,
|
||||||
final StringBuilder stringBuilder);
|
final byte[] key, final int keyOffset, final int keyLength);
|
||||||
private native boolean keyMayExist(final long handle,
|
|
||||||
final long optionsHandle, final byte[] key, final int keyOffset,
|
|
||||||
final int keyLength, final StringBuilder stringBuilder);
|
|
||||||
private native boolean keyMayExist(final long handle,
|
|
||||||
final long optionsHandle, final byte[] key, final int keyOffset,
|
|
||||||
final int keyLength, final long cfHandle,
|
|
||||||
final StringBuilder stringBuilder);
|
|
||||||
private native long iterator(final long handle);
|
private native long iterator(final long handle);
|
||||||
private native long iterator(final long handle, final long readOptHandle);
|
private native long iterator(final long handle, final long readOptHandle);
|
||||||
private native long iteratorCF(final long handle, final long cfHandle);
|
private native long iteratorCF(final long handle, final long cfHandle);
|
||||||
|
|
|
@ -55,7 +55,8 @@ public class CompactionFilterFactoryTest {
|
||||||
rocksDb.compactRange(cfHandles.get(1));
|
rocksDb.compactRange(cfHandles.get(1));
|
||||||
|
|
||||||
assertThat(rocksDb.get(cfHandles.get(1), key1)).isEqualTo(value1);
|
assertThat(rocksDb.get(cfHandles.get(1), key1)).isEqualTo(value1);
|
||||||
assertThat(rocksDb.keyMayExist(cfHandles.get(1), key2, new StringBuilder())).isFalse();
|
final boolean exists = rocksDb.keyMayExist(cfHandles.get(1), key2, null);
|
||||||
|
assertThat(exists).isFalse();
|
||||||
} finally {
|
} finally {
|
||||||
for (final ColumnFamilyHandle cfHandle : cfHandles) {
|
for (final ColumnFamilyHandle cfHandle : cfHandles) {
|
||||||
cfHandle.close();
|
cfHandle.close();
|
||||||
|
|
|
@ -13,6 +13,7 @@ import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
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.assertThat;
|
||||||
|
|
||||||
public class KeyMayExistTest {
|
public class KeyMayExistTest {
|
||||||
|
@ -41,81 +42,118 @@ public class KeyMayExistTest {
|
||||||
try {
|
try {
|
||||||
assertThat(columnFamilyHandleList.size()).
|
assertThat(columnFamilyHandleList.size()).
|
||||||
isEqualTo(2);
|
isEqualTo(2);
|
||||||
db.put("key".getBytes(), "value".getBytes());
|
db.put("key".getBytes(UTF_8), "value".getBytes(UTF_8));
|
||||||
// Test without column family
|
// Test without column family
|
||||||
StringBuilder retValue = new StringBuilder();
|
final Holder<byte[]> holder = new Holder<>();
|
||||||
boolean exists = db.keyMayExist("key".getBytes(), retValue);
|
boolean exists = db.keyMayExist("key".getBytes(UTF_8), holder);
|
||||||
|
assertThat(exists).isTrue();
|
||||||
|
assertThat(holder.getValue()).isNotNull();
|
||||||
|
assertThat(new String(holder.getValue(), UTF_8)).isEqualTo("value");
|
||||||
|
|
||||||
|
exists = db.keyMayExist("key".getBytes(UTF_8), null);
|
||||||
assertThat(exists).isTrue();
|
assertThat(exists).isTrue();
|
||||||
assertThat(retValue.toString()).isEqualTo("value");
|
|
||||||
|
|
||||||
// Slice key
|
// Slice key
|
||||||
StringBuilder builder = new StringBuilder("prefix");
|
final StringBuilder builder = new StringBuilder("prefix");
|
||||||
int offset = builder.toString().length();
|
final int offset = builder.toString().length();
|
||||||
builder.append("slice key 0");
|
builder.append("slice key 0");
|
||||||
int len = builder.toString().length() - offset;
|
final int len = builder.toString().length() - offset;
|
||||||
builder.append("suffix");
|
builder.append("suffix");
|
||||||
|
|
||||||
byte[] sliceKey = builder.toString().getBytes();
|
final byte[] sliceKey = builder.toString().getBytes(UTF_8);
|
||||||
byte[] sliceValue = "slice value 0".getBytes();
|
final byte[] sliceValue = "slice value 0".getBytes(UTF_8);
|
||||||
db.put(sliceKey, offset, len, sliceValue, 0, sliceValue.length);
|
db.put(sliceKey, offset, len, sliceValue, 0, sliceValue.length);
|
||||||
|
|
||||||
retValue = new StringBuilder();
|
exists = db.keyMayExist(sliceKey, offset, len, holder);
|
||||||
exists = db.keyMayExist(sliceKey, offset, len, retValue);
|
assertThat(exists).isTrue();
|
||||||
|
assertThat(holder.getValue()).isNotNull();
|
||||||
|
assertThat(holder.getValue()).isEqualTo(sliceValue);
|
||||||
|
|
||||||
|
exists = db.keyMayExist(sliceKey, offset, len, null);
|
||||||
assertThat(exists).isTrue();
|
assertThat(exists).isTrue();
|
||||||
assertThat(retValue.toString().getBytes()).isEqualTo(sliceValue);
|
|
||||||
|
|
||||||
// Test without column family but with readOptions
|
// Test without column family but with readOptions
|
||||||
try (final ReadOptions readOptions = new ReadOptions()) {
|
try (final ReadOptions readOptions = new ReadOptions()) {
|
||||||
retValue = new StringBuilder();
|
exists = db.keyMayExist(readOptions, "key".getBytes(UTF_8), holder);
|
||||||
exists = db.keyMayExist(readOptions, "key".getBytes(), retValue);
|
|
||||||
assertThat(exists).isTrue();
|
assertThat(exists).isTrue();
|
||||||
assertThat(retValue.toString()).isEqualTo("value");
|
assertThat(holder.getValue()).isNotNull();
|
||||||
|
assertThat(new String(holder.getValue(), UTF_8)).isEqualTo("value");
|
||||||
|
|
||||||
retValue = new StringBuilder();
|
exists = db.keyMayExist(readOptions, "key".getBytes(UTF_8), null);
|
||||||
exists = db.keyMayExist(readOptions, sliceKey, offset, len, retValue);
|
assertThat(exists).isTrue();
|
||||||
|
|
||||||
|
exists = db.keyMayExist(readOptions, sliceKey, offset, len, holder);
|
||||||
|
assertThat(exists).isTrue();
|
||||||
|
assertThat(holder.getValue()).isNotNull();
|
||||||
|
assertThat(holder.getValue()).isEqualTo(sliceValue);
|
||||||
|
|
||||||
|
exists = db.keyMayExist(readOptions, sliceKey, offset, len, null);
|
||||||
assertThat(exists).isTrue();
|
assertThat(exists).isTrue();
|
||||||
assertThat(retValue.toString().getBytes()).isEqualTo(sliceValue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test with column family
|
// Test with column family
|
||||||
retValue = new StringBuilder();
|
exists = db.keyMayExist(columnFamilyHandleList.get(0), "key".getBytes(UTF_8),
|
||||||
exists = db.keyMayExist(columnFamilyHandleList.get(0), "key".getBytes(),
|
holder);
|
||||||
retValue);
|
assertThat(exists).isTrue();
|
||||||
|
assertThat(holder.getValue()).isNotNull();
|
||||||
|
assertThat(new String(holder.getValue(), UTF_8)).isEqualTo("value");
|
||||||
|
|
||||||
|
exists = db.keyMayExist(columnFamilyHandleList.get(0), "key".getBytes(UTF_8),
|
||||||
|
null);
|
||||||
assertThat(exists).isTrue();
|
assertThat(exists).isTrue();
|
||||||
assertThat(retValue.toString()).isEqualTo("value");
|
|
||||||
|
|
||||||
// Test slice sky with column family
|
// Test slice sky with column family
|
||||||
retValue = new StringBuilder();
|
|
||||||
exists = db.keyMayExist(columnFamilyHandleList.get(0), sliceKey, offset, len,
|
exists = db.keyMayExist(columnFamilyHandleList.get(0), sliceKey, offset, len,
|
||||||
retValue);
|
holder);
|
||||||
|
assertThat(exists).isTrue();
|
||||||
|
assertThat(holder.getValue()).isNotNull();
|
||||||
|
assertThat(holder.getValue()).isEqualTo(sliceValue);
|
||||||
|
|
||||||
|
exists = db.keyMayExist(columnFamilyHandleList.get(0), sliceKey, offset, len,
|
||||||
|
null);
|
||||||
assertThat(exists).isTrue();
|
assertThat(exists).isTrue();
|
||||||
assertThat(retValue.toString().getBytes()).isEqualTo(sliceValue);
|
|
||||||
|
|
||||||
// Test with column family and readOptions
|
// Test with column family and readOptions
|
||||||
try (final ReadOptions readOptions = new ReadOptions()) {
|
try (final ReadOptions readOptions = new ReadOptions()) {
|
||||||
retValue = new StringBuilder();
|
exists = db.keyMayExist(columnFamilyHandleList.get(0), readOptions,
|
||||||
exists = db.keyMayExist(readOptions,
|
"key".getBytes(UTF_8), holder);
|
||||||
columnFamilyHandleList.get(0), "key".getBytes(),
|
assertThat(exists).isTrue();
|
||||||
retValue);
|
assertThat(holder.getValue()).isNotNull();
|
||||||
|
assertThat(new String(holder.getValue(), UTF_8)).isEqualTo("value");
|
||||||
|
|
||||||
|
exists = db.keyMayExist(columnFamilyHandleList.get(0), readOptions,
|
||||||
|
"key".getBytes(UTF_8), null);
|
||||||
assertThat(exists).isTrue();
|
assertThat(exists).isTrue();
|
||||||
assertThat(retValue.toString()).isEqualTo("value");
|
|
||||||
|
|
||||||
// Test slice key with column family and read options
|
// Test slice key with column family and read options
|
||||||
retValue = new StringBuilder();
|
exists = db.keyMayExist(columnFamilyHandleList.get(0), readOptions,
|
||||||
exists = db.keyMayExist(readOptions,
|
sliceKey, offset, len, holder);
|
||||||
columnFamilyHandleList.get(0), sliceKey, offset, len,
|
assertThat(exists).isTrue();
|
||||||
retValue);
|
assertThat(holder.getValue()).isNotNull();
|
||||||
|
assertThat(holder.getValue()).isEqualTo(sliceValue);
|
||||||
|
|
||||||
|
exists = db.keyMayExist(columnFamilyHandleList.get(0), readOptions,
|
||||||
|
sliceKey, offset, len, null);
|
||||||
assertThat(exists).isTrue();
|
assertThat(exists).isTrue();
|
||||||
assertThat(retValue.toString().getBytes()).isEqualTo(sliceValue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// KeyMayExist in CF1 must return false
|
// KeyMayExist in CF1 must return null value
|
||||||
assertThat(db.keyMayExist(columnFamilyHandleList.get(1),
|
exists = db.keyMayExist(columnFamilyHandleList.get(1),
|
||||||
"key".getBytes(), retValue)).isFalse();
|
"key".getBytes(UTF_8), holder);
|
||||||
|
assertThat(exists).isFalse();
|
||||||
|
assertThat(holder.getValue()).isNull();
|
||||||
|
exists = db.keyMayExist(columnFamilyHandleList.get(1),
|
||||||
|
"key".getBytes(UTF_8), null);
|
||||||
|
assertThat(exists).isFalse();
|
||||||
|
|
||||||
// slice key
|
// slice key
|
||||||
assertThat(db.keyMayExist(columnFamilyHandleList.get(1),
|
exists = db.keyMayExist(columnFamilyHandleList.get(1),
|
||||||
sliceKey, 1, 3, retValue)).isFalse();
|
sliceKey, 1, 3, holder);
|
||||||
|
assertThat(exists).isFalse();
|
||||||
|
assertThat(holder.getValue()).isNull();
|
||||||
|
exists = db.keyMayExist(columnFamilyHandleList.get(1),
|
||||||
|
sliceKey, 1, 3, null);
|
||||||
|
assertThat(exists).isFalse();
|
||||||
} finally {
|
} finally {
|
||||||
for (final ColumnFamilyHandle columnFamilyHandle :
|
for (final ColumnFamilyHandle columnFamilyHandle :
|
||||||
columnFamilyHandleList) {
|
columnFamilyHandleList) {
|
||||||
|
@ -124,4 +162,31 @@ public class KeyMayExistTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void keyMayExistNonUnicodeString() throws RocksDBException {
|
||||||
|
try (final Options options = new Options()
|
||||||
|
.setCreateIfMissing(true)
|
||||||
|
.setCreateMissingColumnFamilies(true);
|
||||||
|
final RocksDB db = RocksDB.open(options,
|
||||||
|
dbFolder.getRoot().getAbsolutePath())) {
|
||||||
|
final byte key[] = "key".getBytes(UTF_8);
|
||||||
|
final byte value[] = { (byte)0x80 }; // invalid unicode code-point
|
||||||
|
db.put(key, value);
|
||||||
|
|
||||||
|
final byte buf[] = new byte[10];
|
||||||
|
final int read = db.get(key, buf);
|
||||||
|
assertThat(read).isEqualTo(1);
|
||||||
|
assertThat(buf).startsWith(value);
|
||||||
|
|
||||||
|
final Holder<byte[]> holder = new Holder<>();
|
||||||
|
boolean exists = db.keyMayExist("key".getBytes(UTF_8), holder);
|
||||||
|
assertThat(exists).isTrue();
|
||||||
|
assertThat(holder.getValue()).isNotNull();
|
||||||
|
assertThat(holder.getValue()).isEqualTo(value);
|
||||||
|
|
||||||
|
exists = db.keyMayExist("key".getBytes(UTF_8), null);
|
||||||
|
assertThat(exists).isTrue();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue