Merge pull request #7835 from sfc-gh-dzhou/blobapi
blob: java bindings for various blob management functions
This commit is contained in:
commit
750c5a9ca0
|
@ -239,6 +239,10 @@ fdb_error_t fdb_future_get_version_v619(FDBFuture* f, int64_t* out_version) {
|
||||||
CATCH_AND_RETURN(*out_version = TSAV(Version, f)->get(););
|
CATCH_AND_RETURN(*out_version = TSAV(Version, f)->get(););
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" DLLEXPORT fdb_error_t fdb_future_get_bool(FDBFuture* f, fdb_bool_t* out_value) {
|
||||||
|
CATCH_AND_RETURN(*out_value = TSAV(bool, f)->get(););
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" DLLEXPORT fdb_error_t fdb_future_get_int64(FDBFuture* f, int64_t* out_value) {
|
extern "C" DLLEXPORT fdb_error_t fdb_future_get_int64(FDBFuture* f, int64_t* out_value) {
|
||||||
CATCH_AND_RETURN(*out_value = TSAV(int64_t, f)->get(););
|
CATCH_AND_RETURN(*out_value = TSAV(int64_t, f)->get(););
|
||||||
}
|
}
|
||||||
|
@ -494,6 +498,54 @@ extern "C" DLLEXPORT FDBFuture* fdb_database_wait_purge_granules_complete(FDBDat
|
||||||
FDBFuture*)(DB(db)->waitPurgeGranulesComplete(StringRef(purge_key_name, purge_key_name_length)).extractPtr());
|
FDBFuture*)(DB(db)->waitPurgeGranulesComplete(StringRef(purge_key_name, purge_key_name_length)).extractPtr());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" DLLEXPORT FDBFuture* fdb_database_blobbify_range(FDBDatabase* db,
|
||||||
|
uint8_t const* begin_key_name,
|
||||||
|
int begin_key_name_length,
|
||||||
|
uint8_t const* end_key_name,
|
||||||
|
int end_key_name_length) {
|
||||||
|
return (FDBFuture*)(DB(db)
|
||||||
|
->blobbifyRange(KeyRangeRef(StringRef(begin_key_name, begin_key_name_length),
|
||||||
|
StringRef(end_key_name, end_key_name_length)))
|
||||||
|
.extractPtr());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" DLLEXPORT FDBFuture* fdb_database_unblobbify_range(FDBDatabase* db,
|
||||||
|
uint8_t const* begin_key_name,
|
||||||
|
int begin_key_name_length,
|
||||||
|
uint8_t const* end_key_name,
|
||||||
|
int end_key_name_length) {
|
||||||
|
return (FDBFuture*)(DB(db)
|
||||||
|
->unblobbifyRange(KeyRangeRef(StringRef(begin_key_name, begin_key_name_length),
|
||||||
|
StringRef(end_key_name, end_key_name_length)))
|
||||||
|
.extractPtr());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" DLLEXPORT FDBFuture* fdb_database_list_blobbified_ranges(FDBDatabase* db,
|
||||||
|
uint8_t const* begin_key_name,
|
||||||
|
int begin_key_name_length,
|
||||||
|
uint8_t const* end_key_name,
|
||||||
|
int end_key_name_length,
|
||||||
|
int rangeLimit) {
|
||||||
|
return (FDBFuture*)(DB(db)
|
||||||
|
->listBlobbifiedRanges(KeyRangeRef(StringRef(begin_key_name, begin_key_name_length),
|
||||||
|
StringRef(end_key_name, end_key_name_length)),
|
||||||
|
rangeLimit)
|
||||||
|
.extractPtr());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" DLLEXPORT WARN_UNUSED_RESULT FDBFuture* fdb_database_verify_blob_range(FDBDatabase* db,
|
||||||
|
uint8_t const* begin_key_name,
|
||||||
|
int begin_key_name_length,
|
||||||
|
uint8_t const* end_key_name,
|
||||||
|
int end_key_name_length,
|
||||||
|
int64_t version) {
|
||||||
|
return (FDBFuture*)(DB(db)
|
||||||
|
->verifyBlobRange(KeyRangeRef(StringRef(begin_key_name, begin_key_name_length),
|
||||||
|
StringRef(end_key_name, end_key_name_length)),
|
||||||
|
version)
|
||||||
|
.extractPtr());
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" DLLEXPORT fdb_error_t fdb_tenant_create_transaction(FDBTenant* tenant, FDBTransaction** out_transaction) {
|
extern "C" DLLEXPORT fdb_error_t fdb_tenant_create_transaction(FDBTenant* tenant, FDBTransaction** out_transaction) {
|
||||||
CATCH_AND_RETURN(*out_transaction = (FDBTransaction*)TENANT(tenant)->createTransaction().extractPtr(););
|
CATCH_AND_RETURN(*out_transaction = (FDBTransaction*)TENANT(tenant)->createTransaction().extractPtr(););
|
||||||
}
|
}
|
||||||
|
@ -856,11 +908,12 @@ extern "C" DLLEXPORT FDBFuture* fdb_transaction_get_blob_granule_ranges(FDBTrans
|
||||||
uint8_t const* begin_key_name,
|
uint8_t const* begin_key_name,
|
||||||
int begin_key_name_length,
|
int begin_key_name_length,
|
||||||
uint8_t const* end_key_name,
|
uint8_t const* end_key_name,
|
||||||
int end_key_name_length) {
|
int end_key_name_length,
|
||||||
|
int rangeLimit) {
|
||||||
RETURN_FUTURE_ON_ERROR(
|
RETURN_FUTURE_ON_ERROR(
|
||||||
Standalone<VectorRef<KeyRangeRef>>,
|
Standalone<VectorRef<KeyRangeRef>>,
|
||||||
KeyRangeRef range(KeyRef(begin_key_name, begin_key_name_length), KeyRef(end_key_name, end_key_name_length));
|
KeyRangeRef range(KeyRef(begin_key_name, begin_key_name_length), KeyRef(end_key_name, end_key_name_length));
|
||||||
return (FDBFuture*)(TXN(tr)->getBlobGranuleRanges(range).extractPtr()););
|
return (FDBFuture*)(TXN(tr)->getBlobGranuleRanges(range, rangeLimit).extractPtr()););
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" DLLEXPORT FDBResult* fdb_transaction_read_blob_granules(FDBTransaction* tr,
|
extern "C" DLLEXPORT FDBResult* fdb_transaction_read_blob_granules(FDBTransaction* tr,
|
||||||
|
|
|
@ -227,6 +227,8 @@ DLLEXPORT WARN_UNUSED_RESULT fdb_error_t fdb_future_set_callback(FDBFuture* f,
|
||||||
DLLEXPORT WARN_UNUSED_RESULT fdb_error_t fdb_future_get_error(FDBFuture* f);
|
DLLEXPORT WARN_UNUSED_RESULT fdb_error_t fdb_future_get_error(FDBFuture* f);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
DLLEXPORT WARN_UNUSED_RESULT fdb_error_t fdb_future_get_bool(FDBFuture* f, fdb_bool_t* out);
|
||||||
|
|
||||||
DLLEXPORT WARN_UNUSED_RESULT fdb_error_t fdb_future_get_int64(FDBFuture* f, int64_t* out);
|
DLLEXPORT WARN_UNUSED_RESULT fdb_error_t fdb_future_get_int64(FDBFuture* f, int64_t* out);
|
||||||
|
|
||||||
DLLEXPORT WARN_UNUSED_RESULT fdb_error_t fdb_future_get_uint64(FDBFuture* f, uint64_t* out);
|
DLLEXPORT WARN_UNUSED_RESULT fdb_error_t fdb_future_get_uint64(FDBFuture* f, uint64_t* out);
|
||||||
|
@ -321,6 +323,32 @@ DLLEXPORT WARN_UNUSED_RESULT FDBFuture* fdb_database_wait_purge_granules_complet
|
||||||
uint8_t const* purge_key_name,
|
uint8_t const* purge_key_name,
|
||||||
int purge_key_name_length);
|
int purge_key_name_length);
|
||||||
|
|
||||||
|
DLLEXPORT WARN_UNUSED_RESULT FDBFuture* fdb_database_blobbify_range(FDBDatabase* db,
|
||||||
|
uint8_t const* begin_key_name,
|
||||||
|
int begin_key_name_length,
|
||||||
|
uint8_t const* end_key_name,
|
||||||
|
int end_key_name_length);
|
||||||
|
|
||||||
|
DLLEXPORT WARN_UNUSED_RESULT FDBFuture* fdb_database_unblobbify_range(FDBDatabase* db,
|
||||||
|
uint8_t const* begin_key_name,
|
||||||
|
int begin_key_name_length,
|
||||||
|
uint8_t const* end_key_name,
|
||||||
|
int end_key_name_length);
|
||||||
|
|
||||||
|
DLLEXPORT WARN_UNUSED_RESULT FDBFuture* fdb_database_list_blobbified_ranges(FDBDatabase* db,
|
||||||
|
uint8_t const* begin_key_name,
|
||||||
|
int begin_key_name_length,
|
||||||
|
uint8_t const* end_key_name,
|
||||||
|
int end_key_name_length,
|
||||||
|
int rangeLimit);
|
||||||
|
|
||||||
|
DLLEXPORT WARN_UNUSED_RESULT FDBFuture* fdb_database_verify_blob_range(FDBDatabase* db,
|
||||||
|
uint8_t const* begin_key_name,
|
||||||
|
int begin_key_name_length,
|
||||||
|
uint8_t const* end_key_name,
|
||||||
|
int end_key_name_length,
|
||||||
|
int64_t version);
|
||||||
|
|
||||||
DLLEXPORT WARN_UNUSED_RESULT fdb_error_t fdb_tenant_create_transaction(FDBTenant* tenant,
|
DLLEXPORT WARN_UNUSED_RESULT fdb_error_t fdb_tenant_create_transaction(FDBTenant* tenant,
|
||||||
FDBTransaction** out_transaction);
|
FDBTransaction** out_transaction);
|
||||||
|
|
||||||
|
@ -479,7 +507,8 @@ DLLEXPORT WARN_UNUSED_RESULT FDBFuture* fdb_transaction_get_blob_granule_ranges(
|
||||||
uint8_t const* begin_key_name,
|
uint8_t const* begin_key_name,
|
||||||
int begin_key_name_length,
|
int begin_key_name_length,
|
||||||
uint8_t const* end_key_name,
|
uint8_t const* end_key_name,
|
||||||
int end_key_name_length);
|
int end_key_name_length,
|
||||||
|
int rangeLimit);
|
||||||
|
|
||||||
/* LatestVersion (-2) for readVersion means get read version from transaction
|
/* LatestVersion (-2) for readVersion means get read version from transaction
|
||||||
Separated out as optional because BG reads can support longer-lived reads than normal FDB transactions */
|
Separated out as optional because BG reads can support longer-lived reads than normal FDB transactions */
|
||||||
|
|
|
@ -180,7 +180,7 @@ private:
|
||||||
}
|
}
|
||||||
execTransaction(
|
execTransaction(
|
||||||
[begin, end, results](auto ctx) {
|
[begin, end, results](auto ctx) {
|
||||||
fdb::Future f = ctx->tx().getBlobGranuleRanges(begin, end).eraseType();
|
fdb::Future f = ctx->tx().getBlobGranuleRanges(begin, end, 1000).eraseType();
|
||||||
ctx->continueAfter(
|
ctx->continueAfter(
|
||||||
f,
|
f,
|
||||||
[ctx, f, results]() {
|
[ctx, f, results]() {
|
||||||
|
|
|
@ -559,9 +559,9 @@ public:
|
||||||
reverse);
|
reverse);
|
||||||
}
|
}
|
||||||
|
|
||||||
TypedFuture<future_var::KeyRangeRefArray> getBlobGranuleRanges(KeyRef begin, KeyRef end) {
|
TypedFuture<future_var::KeyRangeRefArray> getBlobGranuleRanges(KeyRef begin, KeyRef end, int rangeLimit) {
|
||||||
return native::fdb_transaction_get_blob_granule_ranges(
|
return native::fdb_transaction_get_blob_granule_ranges(
|
||||||
tr.get(), begin.data(), intSize(begin), end.data(), intSize(end));
|
tr.get(), begin.data(), intSize(begin), end.data(), intSize(end), rangeLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result readBlobGranules(KeyRef begin,
|
Result readBlobGranules(KeyRef begin,
|
||||||
|
|
|
@ -356,9 +356,15 @@ fdb_error_t Transaction::add_conflict_range(std::string_view begin_key,
|
||||||
tr_, (const uint8_t*)begin_key.data(), begin_key.size(), (const uint8_t*)end_key.data(), end_key.size(), type);
|
tr_, (const uint8_t*)begin_key.data(), begin_key.size(), (const uint8_t*)end_key.data(), end_key.size(), type);
|
||||||
}
|
}
|
||||||
|
|
||||||
KeyRangeArrayFuture Transaction::get_blob_granule_ranges(std::string_view begin_key, std::string_view end_key) {
|
KeyRangeArrayFuture Transaction::get_blob_granule_ranges(std::string_view begin_key,
|
||||||
return KeyRangeArrayFuture(fdb_transaction_get_blob_granule_ranges(
|
std::string_view end_key,
|
||||||
tr_, (const uint8_t*)begin_key.data(), begin_key.size(), (const uint8_t*)end_key.data(), end_key.size()));
|
int rangeLimit) {
|
||||||
|
return KeyRangeArrayFuture(fdb_transaction_get_blob_granule_ranges(tr_,
|
||||||
|
(const uint8_t*)begin_key.data(),
|
||||||
|
begin_key.size(),
|
||||||
|
(const uint8_t*)end_key.data(),
|
||||||
|
end_key.size(),
|
||||||
|
rangeLimit));
|
||||||
}
|
}
|
||||||
KeyValueArrayResult Transaction::read_blob_granules(std::string_view begin_key,
|
KeyValueArrayResult Transaction::read_blob_granules(std::string_view begin_key,
|
||||||
std::string_view end_key,
|
std::string_view end_key,
|
||||||
|
|
|
@ -348,7 +348,7 @@ public:
|
||||||
// Wrapper around fdb_transaction_add_conflict_range.
|
// Wrapper around fdb_transaction_add_conflict_range.
|
||||||
fdb_error_t add_conflict_range(std::string_view begin_key, std::string_view end_key, FDBConflictRangeType type);
|
fdb_error_t add_conflict_range(std::string_view begin_key, std::string_view end_key, FDBConflictRangeType type);
|
||||||
|
|
||||||
KeyRangeArrayFuture get_blob_granule_ranges(std::string_view begin_key, std::string_view end_key);
|
KeyRangeArrayFuture get_blob_granule_ranges(std::string_view begin_key, std::string_view end_key, int rangeLimit);
|
||||||
KeyValueArrayResult read_blob_granules(std::string_view begin_key,
|
KeyValueArrayResult read_blob_granules(std::string_view begin_key,
|
||||||
std::string_view end_key,
|
std::string_view end_key,
|
||||||
int64_t beginVersion,
|
int64_t beginVersion,
|
||||||
|
|
|
@ -2853,7 +2853,7 @@ TEST_CASE("Blob Granule Functions") {
|
||||||
// test ranges
|
// test ranges
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
fdb::KeyRangeArrayFuture f = tr.get_blob_granule_ranges(key("bg"), key("bh"));
|
fdb::KeyRangeArrayFuture f = tr.get_blob_granule_ranges(key("bg"), key("bh"), 1000);
|
||||||
fdb_error_t err = wait_future(f);
|
fdb_error_t err = wait_future(f);
|
||||||
if (err) {
|
if (err) {
|
||||||
fdb::EmptyFuture f2 = tr.on_error(err);
|
fdb::EmptyFuture f2 = tr.on_error(err);
|
||||||
|
|
|
@ -34,9 +34,11 @@ set(JAVA_BINDING_SRCS
|
||||||
src/main/com/apple/foundationdb/FDBDatabase.java
|
src/main/com/apple/foundationdb/FDBDatabase.java
|
||||||
src/main/com/apple/foundationdb/FDBTenant.java
|
src/main/com/apple/foundationdb/FDBTenant.java
|
||||||
src/main/com/apple/foundationdb/FDBTransaction.java
|
src/main/com/apple/foundationdb/FDBTransaction.java
|
||||||
|
src/main/com/apple/foundationdb/FutureBool.java
|
||||||
src/main/com/apple/foundationdb/FutureInt64.java
|
src/main/com/apple/foundationdb/FutureInt64.java
|
||||||
src/main/com/apple/foundationdb/FutureKey.java
|
src/main/com/apple/foundationdb/FutureKey.java
|
||||||
src/main/com/apple/foundationdb/FutureKeyArray.java
|
src/main/com/apple/foundationdb/FutureKeyArray.java
|
||||||
|
src/main/com/apple/foundationdb/FutureKeyRangeArray.java
|
||||||
src/main/com/apple/foundationdb/FutureResult.java
|
src/main/com/apple/foundationdb/FutureResult.java
|
||||||
src/main/com/apple/foundationdb/FutureResults.java
|
src/main/com/apple/foundationdb/FutureResults.java
|
||||||
src/main/com/apple/foundationdb/FutureMappedResults.java
|
src/main/com/apple/foundationdb/FutureMappedResults.java
|
||||||
|
@ -56,6 +58,7 @@ set(JAVA_BINDING_SRCS
|
||||||
src/main/com/apple/foundationdb/RangeQuery.java
|
src/main/com/apple/foundationdb/RangeQuery.java
|
||||||
src/main/com/apple/foundationdb/MappedRangeQuery.java
|
src/main/com/apple/foundationdb/MappedRangeQuery.java
|
||||||
src/main/com/apple/foundationdb/KeyArrayResult.java
|
src/main/com/apple/foundationdb/KeyArrayResult.java
|
||||||
|
src/main/com/apple/foundationdb/KeyRangeArrayResult.java
|
||||||
src/main/com/apple/foundationdb/RangeResult.java
|
src/main/com/apple/foundationdb/RangeResult.java
|
||||||
src/main/com/apple/foundationdb/MappedRangeResult.java
|
src/main/com/apple/foundationdb/MappedRangeResult.java
|
||||||
src/main/com/apple/foundationdb/RangeResultInfo.java
|
src/main/com/apple/foundationdb/RangeResultInfo.java
|
||||||
|
|
|
@ -25,9 +25,11 @@
|
||||||
#include "com_apple_foundationdb_FDB.h"
|
#include "com_apple_foundationdb_FDB.h"
|
||||||
#include "com_apple_foundationdb_FDBDatabase.h"
|
#include "com_apple_foundationdb_FDBDatabase.h"
|
||||||
#include "com_apple_foundationdb_FDBTransaction.h"
|
#include "com_apple_foundationdb_FDBTransaction.h"
|
||||||
|
#include "com_apple_foundationdb_FutureBool.h"
|
||||||
#include "com_apple_foundationdb_FutureInt64.h"
|
#include "com_apple_foundationdb_FutureInt64.h"
|
||||||
#include "com_apple_foundationdb_FutureKey.h"
|
#include "com_apple_foundationdb_FutureKey.h"
|
||||||
#include "com_apple_foundationdb_FutureKeyArray.h"
|
#include "com_apple_foundationdb_FutureKeyArray.h"
|
||||||
|
#include "com_apple_foundationdb_FutureKeyRangeArray.h"
|
||||||
#include "com_apple_foundationdb_FutureResult.h"
|
#include "com_apple_foundationdb_FutureResult.h"
|
||||||
#include "com_apple_foundationdb_FutureResults.h"
|
#include "com_apple_foundationdb_FutureResults.h"
|
||||||
#include "com_apple_foundationdb_FutureStrings.h"
|
#include "com_apple_foundationdb_FutureStrings.h"
|
||||||
|
@ -55,7 +57,11 @@ static jclass mapped_range_result_class;
|
||||||
static jclass mapped_key_value_class;
|
static jclass mapped_key_value_class;
|
||||||
static jclass string_class;
|
static jclass string_class;
|
||||||
static jclass key_array_result_class;
|
static jclass key_array_result_class;
|
||||||
|
static jclass keyrange_class;
|
||||||
|
static jclass keyrange_array_result_class;
|
||||||
static jmethodID key_array_result_init;
|
static jmethodID key_array_result_init;
|
||||||
|
static jmethodID keyrange_init;
|
||||||
|
static jmethodID keyrange_array_result_init;
|
||||||
static jmethodID range_result_init;
|
static jmethodID range_result_init;
|
||||||
static jmethodID mapped_range_result_init;
|
static jmethodID mapped_range_result_init;
|
||||||
static jmethodID mapped_key_value_from_bytes;
|
static jmethodID mapped_key_value_from_bytes;
|
||||||
|
@ -278,6 +284,23 @@ JNIEXPORT void JNICALL Java_com_apple_foundationdb_NativeFuture_Future_1releaseM
|
||||||
fdb_future_release_memory(var);
|
fdb_future_release_memory(var);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jboolean JNICALL Java_com_apple_foundationdb_FutureBool_FutureBool_1get(JNIEnv* jenv, jobject, jlong future) {
|
||||||
|
if (!future) {
|
||||||
|
throwParamNotNull(jenv);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
FDBFuture* f = (FDBFuture*)future;
|
||||||
|
|
||||||
|
fdb_bool_t value = false;
|
||||||
|
fdb_error_t err = fdb_future_get_bool(f, &value);
|
||||||
|
if (err) {
|
||||||
|
safeThrow(jenv, getThrowable(jenv, err));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (jboolean)value;
|
||||||
|
}
|
||||||
|
|
||||||
JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FutureInt64_FutureInt64_1get(JNIEnv* jenv, jobject, jlong future) {
|
JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FutureInt64_FutureInt64_1get(JNIEnv* jenv, jobject, jlong future) {
|
||||||
if (!future) {
|
if (!future) {
|
||||||
throwParamNotNull(jenv);
|
throwParamNotNull(jenv);
|
||||||
|
@ -407,6 +430,61 @@ JNIEXPORT jobject JNICALL Java_com_apple_foundationdb_FutureKeyArray_FutureKeyAr
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jobject JNICALL Java_com_apple_foundationdb_FutureKeyRangeArray_FutureKeyRangeArray_1get(JNIEnv* jenv,
|
||||||
|
jobject,
|
||||||
|
jlong future) {
|
||||||
|
if (!future) {
|
||||||
|
throwParamNotNull(jenv);
|
||||||
|
return JNI_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
FDBFuture* f = (FDBFuture*)future;
|
||||||
|
|
||||||
|
const FDBKeyRange* fdbKr;
|
||||||
|
int count;
|
||||||
|
fdb_error_t err = fdb_future_get_keyrange_array(f, &fdbKr, &count);
|
||||||
|
if (err) {
|
||||||
|
safeThrow(jenv, getThrowable(jenv, err));
|
||||||
|
return JNI_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
jobjectArray kr_values = jenv->NewObjectArray(count, keyrange_class, NULL);
|
||||||
|
if (!kr_values) {
|
||||||
|
if (!jenv->ExceptionOccurred())
|
||||||
|
throwOutOfMem(jenv);
|
||||||
|
return JNI_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
jbyteArray beginArr = jenv->NewByteArray(fdbKr[i].begin_key_length);
|
||||||
|
if (!beginArr) {
|
||||||
|
if (!jenv->ExceptionOccurred())
|
||||||
|
throwOutOfMem(jenv);
|
||||||
|
return JNI_NULL;
|
||||||
|
}
|
||||||
|
jbyteArray endArr = jenv->NewByteArray(fdbKr[i].end_key_length);
|
||||||
|
if (!endArr) {
|
||||||
|
if (!jenv->ExceptionOccurred())
|
||||||
|
throwOutOfMem(jenv);
|
||||||
|
return JNI_NULL;
|
||||||
|
}
|
||||||
|
jenv->SetByteArrayRegion(beginArr, 0, fdbKr[i].begin_key_length, (const jbyte*)fdbKr[i].begin_key);
|
||||||
|
jenv->SetByteArrayRegion(endArr, 0, fdbKr[i].end_key_length, (const jbyte*)fdbKr[i].end_key);
|
||||||
|
|
||||||
|
jobject kr = jenv->NewObject(keyrange_class, keyrange_init, beginArr, endArr);
|
||||||
|
if (jenv->ExceptionOccurred())
|
||||||
|
return JNI_NULL;
|
||||||
|
jenv->SetObjectArrayElement(kr_values, i, kr);
|
||||||
|
if (jenv->ExceptionOccurred())
|
||||||
|
return JNI_NULL;
|
||||||
|
}
|
||||||
|
jobject krarr = jenv->NewObject(keyrange_array_result_class, keyrange_array_result_init, kr_values);
|
||||||
|
if (jenv->ExceptionOccurred())
|
||||||
|
return JNI_NULL;
|
||||||
|
|
||||||
|
return krarr;
|
||||||
|
}
|
||||||
|
|
||||||
// SOMEDAY: explore doing this more efficiently with Direct ByteBuffers
|
// SOMEDAY: explore doing this more efficiently with Direct ByteBuffers
|
||||||
JNIEXPORT jobject JNICALL Java_com_apple_foundationdb_FutureResults_FutureResults_1get(JNIEnv* jenv,
|
JNIEXPORT jobject JNICALL Java_com_apple_foundationdb_FutureResults_FutureResults_1get(JNIEnv* jenv,
|
||||||
jobject,
|
jobject,
|
||||||
|
@ -830,6 +908,142 @@ Java_com_apple_foundationdb_FDBDatabase_Database_1waitPurgeGranulesComplete(JNIE
|
||||||
return (jlong)f;
|
return (jlong)f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBDatabase_Database_1blobbifyRange(JNIEnv* jenv,
|
||||||
|
jobject,
|
||||||
|
jlong dbPtr,
|
||||||
|
jbyteArray beginKeyBytes,
|
||||||
|
jbyteArray endKeyBytes) {
|
||||||
|
if (!dbPtr || !beginKeyBytes || !endKeyBytes) {
|
||||||
|
throwParamNotNull(jenv);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
FDBDatabase* database = (FDBDatabase*)dbPtr;
|
||||||
|
|
||||||
|
uint8_t* beginKeyArr = (uint8_t*)jenv->GetByteArrayElements(beginKeyBytes, JNI_NULL);
|
||||||
|
if (!beginKeyArr) {
|
||||||
|
if (!jenv->ExceptionOccurred())
|
||||||
|
throwRuntimeEx(jenv, "Error getting handle to native resources");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* endKeyArr = (uint8_t*)jenv->GetByteArrayElements(endKeyBytes, JNI_NULL);
|
||||||
|
if (!endKeyArr) {
|
||||||
|
jenv->ReleaseByteArrayElements(beginKeyBytes, (jbyte*)beginKeyArr, JNI_ABORT);
|
||||||
|
if (!jenv->ExceptionOccurred())
|
||||||
|
throwRuntimeEx(jenv, "Error getting handle to native resources");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
FDBFuture* f = fdb_database_blobbify_range(
|
||||||
|
database, beginKeyArr, jenv->GetArrayLength(beginKeyBytes), endKeyArr, jenv->GetArrayLength(endKeyBytes));
|
||||||
|
jenv->ReleaseByteArrayElements(beginKeyBytes, (jbyte*)beginKeyArr, JNI_ABORT);
|
||||||
|
jenv->ReleaseByteArrayElements(endKeyBytes, (jbyte*)endKeyArr, JNI_ABORT);
|
||||||
|
return (jlong)f;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBDatabase_Database_1unblobbifyRange(JNIEnv* jenv,
|
||||||
|
jobject,
|
||||||
|
jlong dbPtr,
|
||||||
|
jbyteArray beginKeyBytes,
|
||||||
|
jbyteArray endKeyBytes) {
|
||||||
|
if (!dbPtr || !beginKeyBytes || !endKeyBytes) {
|
||||||
|
throwParamNotNull(jenv);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
FDBDatabase* database = (FDBDatabase*)dbPtr;
|
||||||
|
|
||||||
|
uint8_t* beginKeyArr = (uint8_t*)jenv->GetByteArrayElements(beginKeyBytes, JNI_NULL);
|
||||||
|
if (!beginKeyArr) {
|
||||||
|
if (!jenv->ExceptionOccurred())
|
||||||
|
throwRuntimeEx(jenv, "Error getting handle to native resources");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* endKeyArr = (uint8_t*)jenv->GetByteArrayElements(endKeyBytes, JNI_NULL);
|
||||||
|
if (!endKeyArr) {
|
||||||
|
jenv->ReleaseByteArrayElements(beginKeyBytes, (jbyte*)beginKeyArr, JNI_ABORT);
|
||||||
|
if (!jenv->ExceptionOccurred())
|
||||||
|
throwRuntimeEx(jenv, "Error getting handle to native resources");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
FDBFuture* f = fdb_database_unblobbify_range(
|
||||||
|
database, beginKeyArr, jenv->GetArrayLength(beginKeyBytes), endKeyArr, jenv->GetArrayLength(endKeyBytes));
|
||||||
|
jenv->ReleaseByteArrayElements(beginKeyBytes, (jbyte*)beginKeyArr, JNI_ABORT);
|
||||||
|
jenv->ReleaseByteArrayElements(endKeyBytes, (jbyte*)endKeyArr, JNI_ABORT);
|
||||||
|
return (jlong)f;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBDatabase_Database_1listBlobbifiedRanges(JNIEnv* jenv,
|
||||||
|
jobject,
|
||||||
|
jlong dbPtr,
|
||||||
|
jbyteArray beginKeyBytes,
|
||||||
|
jbyteArray endKeyBytes,
|
||||||
|
jint rangeLimit) {
|
||||||
|
if (!dbPtr || !beginKeyBytes || !endKeyBytes) {
|
||||||
|
throwParamNotNull(jenv);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
FDBDatabase* tr = (FDBDatabase*)dbPtr;
|
||||||
|
|
||||||
|
uint8_t* startKey = (uint8_t*)jenv->GetByteArrayElements(beginKeyBytes, JNI_NULL);
|
||||||
|
if (!startKey) {
|
||||||
|
if (!jenv->ExceptionOccurred())
|
||||||
|
throwRuntimeEx(jenv, "Error getting handle to native resources");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* endKey = (uint8_t*)jenv->GetByteArrayElements(endKeyBytes, JNI_NULL);
|
||||||
|
if (!endKey) {
|
||||||
|
jenv->ReleaseByteArrayElements(beginKeyBytes, (jbyte*)startKey, JNI_ABORT);
|
||||||
|
if (!jenv->ExceptionOccurred())
|
||||||
|
throwRuntimeEx(jenv, "Error getting handle to native resources");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
FDBFuture* f = fdb_database_list_blobbified_ranges(
|
||||||
|
tr, startKey, jenv->GetArrayLength(beginKeyBytes), endKey, jenv->GetArrayLength(endKeyBytes), rangeLimit);
|
||||||
|
jenv->ReleaseByteArrayElements(beginKeyBytes, (jbyte*)startKey, JNI_ABORT);
|
||||||
|
jenv->ReleaseByteArrayElements(endKeyBytes, (jbyte*)endKey, JNI_ABORT);
|
||||||
|
return (jlong)f;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBDatabase_Database_1verifyBlobRange(JNIEnv* jenv,
|
||||||
|
jobject,
|
||||||
|
jlong dbPtr,
|
||||||
|
jbyteArray beginKeyBytes,
|
||||||
|
jbyteArray endKeyBytes,
|
||||||
|
jlong version) {
|
||||||
|
if (!dbPtr || !beginKeyBytes || !endKeyBytes) {
|
||||||
|
throwParamNotNull(jenv);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
FDBDatabase* tr = (FDBDatabase*)dbPtr;
|
||||||
|
|
||||||
|
uint8_t* startKey = (uint8_t*)jenv->GetByteArrayElements(beginKeyBytes, JNI_NULL);
|
||||||
|
if (!startKey) {
|
||||||
|
if (!jenv->ExceptionOccurred())
|
||||||
|
throwRuntimeEx(jenv, "Error getting handle to native resources");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* endKey = (uint8_t*)jenv->GetByteArrayElements(endKeyBytes, JNI_NULL);
|
||||||
|
if (!endKey) {
|
||||||
|
jenv->ReleaseByteArrayElements(beginKeyBytes, (jbyte*)startKey, JNI_ABORT);
|
||||||
|
if (!jenv->ExceptionOccurred())
|
||||||
|
throwRuntimeEx(jenv, "Error getting handle to native resources");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
FDBFuture* f = fdb_database_list_blobbified_ranges(
|
||||||
|
tr, startKey, jenv->GetArrayLength(beginKeyBytes), endKey, jenv->GetArrayLength(endKeyBytes), version);
|
||||||
|
jenv->ReleaseByteArrayElements(beginKeyBytes, (jbyte*)startKey, JNI_ABORT);
|
||||||
|
jenv->ReleaseByteArrayElements(endKeyBytes, (jbyte*)endKey, JNI_ABORT);
|
||||||
|
return (jlong)f;
|
||||||
|
}
|
||||||
|
|
||||||
JNIEXPORT jboolean JNICALL Java_com_apple_foundationdb_FDB_Error_1predicate(JNIEnv* jenv,
|
JNIEXPORT jboolean JNICALL Java_com_apple_foundationdb_FDB_Error_1predicate(JNIEnv* jenv,
|
||||||
jobject,
|
jobject,
|
||||||
jint predicate,
|
jint predicate,
|
||||||
|
@ -1307,6 +1521,41 @@ Java_com_apple_foundationdb_FDBTransaction_Transaction_1getRangeSplitPoints(JNIE
|
||||||
return (jlong)f;
|
return (jlong)f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jlong JNICALL
|
||||||
|
Java_com_apple_foundationdb_FDBTransaction_Transaction_1getBlobGranuleRanges(JNIEnv* jenv,
|
||||||
|
jobject,
|
||||||
|
jlong tPtr,
|
||||||
|
jbyteArray beginKeyBytes,
|
||||||
|
jbyteArray endKeyBytes,
|
||||||
|
jint rowLimit) {
|
||||||
|
if (!tPtr || !beginKeyBytes || !endKeyBytes || !rowLimit) {
|
||||||
|
throwParamNotNull(jenv);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
FDBTransaction* tr = (FDBTransaction*)tPtr;
|
||||||
|
|
||||||
|
uint8_t* startKey = (uint8_t*)jenv->GetByteArrayElements(beginKeyBytes, JNI_NULL);
|
||||||
|
if (!startKey) {
|
||||||
|
if (!jenv->ExceptionOccurred())
|
||||||
|
throwRuntimeEx(jenv, "Error getting handle to native resources");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* endKey = (uint8_t*)jenv->GetByteArrayElements(endKeyBytes, JNI_NULL);
|
||||||
|
if (!endKey) {
|
||||||
|
jenv->ReleaseByteArrayElements(beginKeyBytes, (jbyte*)startKey, JNI_ABORT);
|
||||||
|
if (!jenv->ExceptionOccurred())
|
||||||
|
throwRuntimeEx(jenv, "Error getting handle to native resources");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
FDBFuture* f = fdb_transaction_get_blob_granule_ranges(
|
||||||
|
tr, startKey, jenv->GetArrayLength(beginKeyBytes), endKey, jenv->GetArrayLength(endKeyBytes), rowLimit);
|
||||||
|
jenv->ReleaseByteArrayElements(beginKeyBytes, (jbyte*)startKey, JNI_ABORT);
|
||||||
|
jenv->ReleaseByteArrayElements(endKeyBytes, (jbyte*)endKey, JNI_ABORT);
|
||||||
|
return (jlong)f;
|
||||||
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1set(JNIEnv* jenv,
|
JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1set(JNIEnv* jenv,
|
||||||
jobject,
|
jobject,
|
||||||
jlong tPtr,
|
jlong tPtr,
|
||||||
|
@ -1746,6 +1995,15 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
|
||||||
key_array_result_init = env->GetMethodID(local_key_array_result_class, "<init>", "([B[I)V");
|
key_array_result_init = env->GetMethodID(local_key_array_result_class, "<init>", "([B[I)V");
|
||||||
key_array_result_class = (jclass)(env)->NewGlobalRef(local_key_array_result_class);
|
key_array_result_class = (jclass)(env)->NewGlobalRef(local_key_array_result_class);
|
||||||
|
|
||||||
|
jclass local_keyrange_class = env->FindClass("com/apple/foundationdb/Range");
|
||||||
|
keyrange_init = env->GetMethodID(local_keyrange_class, "<init>", "([B[B)V");
|
||||||
|
keyrange_class = (jclass)(env)->NewGlobalRef(local_keyrange_class);
|
||||||
|
|
||||||
|
jclass local_keyrange_array_result_class = env->FindClass("com/apple/foundationdb/KeyRangeArrayResult");
|
||||||
|
keyrange_array_result_init =
|
||||||
|
env->GetMethodID(local_keyrange_array_result_class, "<init>", "([Lcom/apple/foundationdb/Range;)V");
|
||||||
|
keyrange_array_result_class = (jclass)(env)->NewGlobalRef(local_keyrange_array_result_class);
|
||||||
|
|
||||||
jclass local_range_result_summary_class = env->FindClass("com/apple/foundationdb/RangeResultSummary");
|
jclass local_range_result_summary_class = env->FindClass("com/apple/foundationdb/RangeResultSummary");
|
||||||
range_result_summary_init = env->GetMethodID(local_range_result_summary_class, "<init>", "([BIZ)V");
|
range_result_summary_init = env->GetMethodID(local_range_result_summary_class, "<init>", "([BIZ)V");
|
||||||
range_result_summary_class = (jclass)(env)->NewGlobalRef(local_range_result_summary_class);
|
range_result_summary_class = (jclass)(env)->NewGlobalRef(local_range_result_summary_class);
|
||||||
|
@ -1770,6 +2028,12 @@ void JNI_OnUnload(JavaVM* vm, void* reserved) {
|
||||||
if (range_result_class != JNI_NULL) {
|
if (range_result_class != JNI_NULL) {
|
||||||
env->DeleteGlobalRef(range_result_class);
|
env->DeleteGlobalRef(range_result_class);
|
||||||
}
|
}
|
||||||
|
if (keyrange_array_result_class != JNI_NULL) {
|
||||||
|
env->DeleteGlobalRef(keyrange_array_result_class);
|
||||||
|
}
|
||||||
|
if (keyrange_class != JNI_NULL) {
|
||||||
|
env->DeleteGlobalRef(keyrange_class);
|
||||||
|
}
|
||||||
if (mapped_range_result_class != JNI_NULL) {
|
if (mapped_range_result_class != JNI_NULL) {
|
||||||
env->DeleteGlobalRef(mapped_range_result_class);
|
env->DeleteGlobalRef(mapped_range_result_class);
|
||||||
}
|
}
|
||||||
|
|
|
@ -161,6 +161,20 @@ public interface Database extends AutoCloseable, TransactionContext {
|
||||||
*/
|
*/
|
||||||
double getMainThreadBusyness();
|
double getMainThreadBusyness();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs {@link #purgeBlobGranules(Function)} on the default executor.
|
||||||
|
*
|
||||||
|
* @param beginKey start of the key range
|
||||||
|
* @param endKey end of the key range
|
||||||
|
* @param purgeVersion version to purge at
|
||||||
|
* @param force if true delete all data, if not keep data >= purgeVersion
|
||||||
|
*
|
||||||
|
* @return the key to watch for purge complete
|
||||||
|
*/
|
||||||
|
default CompletableFuture<byte[]> purgeBlobGranules(byte[] beginKey, byte[] endKey, long purgeVersion, boolean force) {
|
||||||
|
return purgeBlobGranules(beginKey, endKey, purgeVersion, force, getExecutor());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Queues a purge of blob granules for the specified key range, at the specified version.
|
* Queues a purge of blob granules for the specified key range, at the specified version.
|
||||||
*
|
*
|
||||||
|
@ -168,17 +182,126 @@ public interface Database extends AutoCloseable, TransactionContext {
|
||||||
* @param endKey end of the key range
|
* @param endKey end of the key range
|
||||||
* @param purgeVersion version to purge at
|
* @param purgeVersion version to purge at
|
||||||
* @param force if true delete all data, if not keep data >= purgeVersion
|
* @param force if true delete all data, if not keep data >= purgeVersion
|
||||||
|
* @param e the {@link Executor} to use for asynchronous callbacks
|
||||||
|
|
||||||
* @return the key to watch for purge complete
|
* @return the key to watch for purge complete
|
||||||
*/
|
*/
|
||||||
CompletableFuture<byte[]> purgeBlobGranules(byte[] beginKey, byte[] endKey, long purgeVersion, boolean force, Executor e);
|
CompletableFuture<byte[]> purgeBlobGranules(byte[] beginKey, byte[] endKey, long purgeVersion, boolean force, Executor e);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wait for a previous call to purgeBlobGranules to complete
|
* Runs {@link #waitPurgeGranulesComplete(Function)} on the default executor.
|
||||||
*
|
*
|
||||||
* @param purgeKey key to watch
|
* @param purgeKey key to watch
|
||||||
*/
|
*/
|
||||||
|
default CompletableFuture<Void> waitPurgeGranulesComplete(byte[] purgeKey) {
|
||||||
|
return waitPurgeGranulesComplete(purgeKey, getExecutor());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait for a previous call to purgeBlobGranules to complete.
|
||||||
|
*
|
||||||
|
* @param purgeKey key to watch
|
||||||
|
* @param e the {@link Executor} to use for asynchronous callbacks
|
||||||
|
*/
|
||||||
CompletableFuture<Void> waitPurgeGranulesComplete(byte[] purgeKey, Executor e);
|
CompletableFuture<Void> waitPurgeGranulesComplete(byte[] purgeKey, Executor e);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs {@link #blobbifyRange(Function)} on the default executor.
|
||||||
|
*
|
||||||
|
* @param beginKey start of the key range
|
||||||
|
* @param endKey end of the key range
|
||||||
|
|
||||||
|
* @return if the recording of the range was successful
|
||||||
|
*/
|
||||||
|
default CompletableFuture<Boolean> blobbifyRange(byte[] beginKey, byte[] endKey) {
|
||||||
|
return blobbifyRange(beginKey, endKey, getExecutor());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a range to be blobbified in the database. Must be a completely unblobbified range.
|
||||||
|
*
|
||||||
|
* @param beginKey start of the key range
|
||||||
|
* @param endKey end of the key range
|
||||||
|
* @param e the {@link Executor} to use for asynchronous callbacks
|
||||||
|
|
||||||
|
* @return if the recording of the range was successful
|
||||||
|
*/
|
||||||
|
CompletableFuture<Boolean> blobbifyRange(byte[] beginKey, byte[] endKey, Executor e);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs {@link #unblobbifyRange(Function)} on the default executor.
|
||||||
|
*
|
||||||
|
* @param beginKey start of the key range
|
||||||
|
* @param endKey end of the key range
|
||||||
|
|
||||||
|
* @return if the recording of the range was successful
|
||||||
|
*/
|
||||||
|
default CompletableFuture<Boolean> unblobbifyRange(byte[] beginKey, byte[] endKey) {
|
||||||
|
return unblobbifyRange(beginKey, endKey, getExecutor());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a range to be unblobbified in the database.
|
||||||
|
*
|
||||||
|
* @param beginKey start of the key range
|
||||||
|
* @param endKey end of the key range
|
||||||
|
* @param e the {@link Executor} to use for asynchronous callbacks
|
||||||
|
|
||||||
|
* @return if the recording of the range was successful
|
||||||
|
*/
|
||||||
|
CompletableFuture<Boolean> unblobbifyRange(byte[] beginKey, byte[] endKey, Executor e);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs {@link #listBlobbifiedRanges(Function)} on the default executor.
|
||||||
|
*
|
||||||
|
* @param beginKey start of the key range
|
||||||
|
* @param endKey end of the key range
|
||||||
|
* @param rangeLimit batch size
|
||||||
|
* @param e the {@link Executor} to use for asynchronous callbacks
|
||||||
|
|
||||||
|
* @return a future with the list of blobbified ranges.
|
||||||
|
*/
|
||||||
|
default CompletableFuture<KeyRangeArrayResult> listBlobbifiedRanges(byte[] beginKey, byte[] endKey, int rangeLimit) {
|
||||||
|
return listBlobbifiedRanges(beginKey, endKey, rangeLimit, getExecutor());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists blobbified ranges in the database. There may be more if result.size() == rangeLimit.
|
||||||
|
*
|
||||||
|
* @param beginKey start of the key range
|
||||||
|
* @param endKey end of the key range
|
||||||
|
* @param rangeLimit batch size
|
||||||
|
* @param e the {@link Executor} to use for asynchronous callbacks
|
||||||
|
|
||||||
|
* @return a future with the list of blobbified ranges.
|
||||||
|
*/
|
||||||
|
CompletableFuture<KeyRangeArrayResult> listBlobbifiedRanges(byte[] beginKey, byte[] endKey, int rangeLimit, Executor e);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs {@link #verifyBlobRange(Function)} on the default executor.
|
||||||
|
*
|
||||||
|
* @param beginKey start of the key range
|
||||||
|
* @param endKey end of the key range
|
||||||
|
* @param version version to read at
|
||||||
|
*
|
||||||
|
* @return a future with the version of the last blob granule.
|
||||||
|
*/
|
||||||
|
default CompletableFuture<Long> verifyBlobRange(byte[] beginKey, byte[] endKey, long version) {
|
||||||
|
return verifyBlobRange(beginKey, endKey, version, getExecutor());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a blob range is blobbified.
|
||||||
|
*
|
||||||
|
* @param beginKey start of the key range
|
||||||
|
* @param endKey end of the key range
|
||||||
|
* @param version version to read at
|
||||||
|
*
|
||||||
|
* @return a future with the version of the last blob granule.
|
||||||
|
*/
|
||||||
|
CompletableFuture<Long> verifyBlobRange(byte[] beginKey, byte[] endKey, long version, Executor e);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs a read-only transactional function against this {@code Database} with retry logic.
|
* Runs a read-only transactional function against this {@code Database} with retry logic.
|
||||||
* {@link Function#apply(Object) apply(ReadTransaction)} will be called on the
|
* {@link Function#apply(Object) apply(ReadTransaction)} will be called on the
|
||||||
|
|
|
@ -201,20 +201,60 @@ class FDBDatabase extends NativeObjectWrapper implements Database, OptionConsume
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<byte[]> purgeBlobGranules(byte[] beginKey, byte[] endKey, long purgeVersion, boolean force, Executor executor) {
|
public CompletableFuture<byte[]> purgeBlobGranules(byte[] beginKey, byte[] endKey, long purgeVersion, boolean force, Executor e) {
|
||||||
pointerReadLock.lock();
|
pointerReadLock.lock();
|
||||||
try {
|
try {
|
||||||
return new FutureKey(Database_purgeBlobGranules(getPtr(), beginKey, endKey, purgeVersion, force), executor, eventKeeper);
|
return new FutureKey(Database_purgeBlobGranules(getPtr(), beginKey, endKey, purgeVersion, force), e, eventKeeper);
|
||||||
} finally {
|
} finally {
|
||||||
pointerReadLock.unlock();
|
pointerReadLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Void> waitPurgeGranulesComplete(byte[] purgeKey, Executor executor) {
|
public CompletableFuture<Void> waitPurgeGranulesComplete(byte[] purgeKey, Executor e) {
|
||||||
pointerReadLock.lock();
|
pointerReadLock.lock();
|
||||||
try {
|
try {
|
||||||
return new FutureVoid(Database_waitPurgeGranulesComplete(getPtr(), purgeKey), executor);
|
return new FutureVoid(Database_waitPurgeGranulesComplete(getPtr(), purgeKey), e);
|
||||||
|
} finally {
|
||||||
|
pointerReadLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletableFuture<Boolean> blobbifyRange(byte[] beginKey, byte[] endKey, Executor e) {
|
||||||
|
pointerReadLock.lock();
|
||||||
|
try {
|
||||||
|
return new FutureBool(Database_blobbifyRange(getPtr(), beginKey, endKey), e);
|
||||||
|
} finally {
|
||||||
|
pointerReadLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletableFuture<Boolean> unblobbifyRange(byte[] beginKey, byte[] endKey, Executor e) {
|
||||||
|
pointerReadLock.lock();
|
||||||
|
try {
|
||||||
|
return new FutureBool(Database_unblobbifyRange(getPtr(), beginKey, endKey), e);
|
||||||
|
} finally {
|
||||||
|
pointerReadLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletableFuture<KeyRangeArrayResult> listBlobbifiedRanges(byte[] beginKey, byte[] endKey, int rangeLimit, Executor e) {
|
||||||
|
pointerReadLock.lock();
|
||||||
|
try {
|
||||||
|
return new FutureKeyRangeArray(Database_listBlobbifiedRanges(getPtr(), beginKey, endKey, rangeLimit), e);
|
||||||
|
} finally {
|
||||||
|
pointerReadLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletableFuture<Long> verifyBlobRange(byte[] beginKey, byte[] endKey, long version, Executor e) {
|
||||||
|
pointerReadLock.lock();
|
||||||
|
try {
|
||||||
|
return new FutureInt64(Database_verifyBlobRange(getPtr(), beginKey, endKey, version), e);
|
||||||
} finally {
|
} finally {
|
||||||
pointerReadLock.unlock();
|
pointerReadLock.unlock();
|
||||||
}
|
}
|
||||||
|
@ -237,4 +277,8 @@ class FDBDatabase extends NativeObjectWrapper implements Database, OptionConsume
|
||||||
private native double Database_getMainThreadBusyness(long cPtr);
|
private native double Database_getMainThreadBusyness(long cPtr);
|
||||||
private native long Database_purgeBlobGranules(long cPtr, byte[] beginKey, byte[] endKey, long purgeVersion, boolean force);
|
private native long Database_purgeBlobGranules(long cPtr, byte[] beginKey, byte[] endKey, long purgeVersion, boolean force);
|
||||||
private native long Database_waitPurgeGranulesComplete(long cPtr, byte[] purgeKey);
|
private native long Database_waitPurgeGranulesComplete(long cPtr, byte[] purgeKey);
|
||||||
|
private native long Database_blobbifyRange(long cPtr, byte[] beginKey, byte[] endKey);
|
||||||
|
private native long Database_unblobbifyRange(long cPtr, byte[] beginKey, byte[] endKey);
|
||||||
|
private native long Database_listBlobbifiedRanges(long cPtr, byte[] beginKey, byte[] endKey, int rangeLimit);
|
||||||
|
private native long Database_verifyBlobRange(long cPtr, byte[] beginKey, byte[] endKey, long version);
|
||||||
}
|
}
|
|
@ -97,6 +97,11 @@ class FDBTransaction extends NativeObjectWrapper implements Transaction, OptionC
|
||||||
return FDBTransaction.this.getRangeSplitPoints(range, chunkSize);
|
return FDBTransaction.this.getRangeSplitPoints(range, chunkSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletableFuture<KeyRangeArrayResult> getBlobGranuleRanges(byte[] begin, byte[] end, int rowLimit) {
|
||||||
|
return FDBTransaction.this.getBlobGranuleRanges(begin, end, rowLimit);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AsyncIterable<MappedKeyValue> getMappedRange(KeySelector begin, KeySelector end, byte[] mapper,
|
public AsyncIterable<MappedKeyValue> getMappedRange(KeySelector begin, KeySelector end, byte[] mapper,
|
||||||
int limit, int matchIndex, boolean reverse,
|
int limit, int matchIndex, boolean reverse,
|
||||||
|
@ -352,6 +357,16 @@ class FDBTransaction extends NativeObjectWrapper implements Transaction, OptionC
|
||||||
return this.getRangeSplitPoints(range.begin, range.end, chunkSize);
|
return this.getRangeSplitPoints(range.begin, range.end, chunkSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletableFuture<KeyRangeArrayResult> getBlobGranuleRanges(byte[] begin, byte[] end, int rowLimit) {
|
||||||
|
pointerReadLock.lock();
|
||||||
|
try {
|
||||||
|
return new FutureKeyRangeArray(Transaction_getBlobGranuleRanges(getPtr(), begin, end, rowLimit), executor);
|
||||||
|
} finally {
|
||||||
|
pointerReadLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AsyncIterable<MappedKeyValue> getMappedRange(KeySelector begin, KeySelector end, byte[] mapper, int limit,
|
public AsyncIterable<MappedKeyValue> getMappedRange(KeySelector begin, KeySelector end, byte[] mapper, int limit,
|
||||||
int matchIndex, boolean reverse, StreamingMode mode) {
|
int matchIndex, boolean reverse, StreamingMode mode) {
|
||||||
|
@ -842,4 +857,5 @@ class FDBTransaction extends NativeObjectWrapper implements Transaction, OptionC
|
||||||
private native long Transaction_getKeyLocations(long cPtr, byte[] key);
|
private native long Transaction_getKeyLocations(long cPtr, byte[] key);
|
||||||
private native long Transaction_getEstimatedRangeSizeBytes(long cPtr, byte[] keyBegin, byte[] keyEnd);
|
private native long Transaction_getEstimatedRangeSizeBytes(long cPtr, byte[] keyBegin, byte[] keyEnd);
|
||||||
private native long Transaction_getRangeSplitPoints(long cPtr, byte[] keyBegin, byte[] keyEnd, long chunkSize);
|
private native long Transaction_getRangeSplitPoints(long cPtr, byte[] keyBegin, byte[] keyEnd, long chunkSize);
|
||||||
|
private native long Transaction_getBlobGranuleRanges(long cPtr, byte[] keyBegin, byte[] keyEnd, int rowLimit);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* FutureBool.java
|
||||||
|
*
|
||||||
|
* This source file is part of the FoundationDB open source project
|
||||||
|
*
|
||||||
|
* Copyright 2013-2019 Apple Inc. and the FoundationDB project authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.apple.foundationdb;
|
||||||
|
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
class FutureBool extends NativeFuture<Boolean> {
|
||||||
|
FutureBool(long cPtr, Executor executor) {
|
||||||
|
super(cPtr);
|
||||||
|
registerMarshalCallback(executor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Boolean getIfDone_internal(long cPtr) throws FDBException {
|
||||||
|
return FutureBool_get(cPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
private native boolean FutureBool_get(long cPtr) throws FDBException;
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* FutureKeyRangeArray.java
|
||||||
|
*
|
||||||
|
* This source file is part of the FoundationDB open source project
|
||||||
|
*
|
||||||
|
* Copyright 2013-2019 Apple Inc. and the FoundationDB project authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.apple.foundationdb;
|
||||||
|
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
class FutureKeyRangeArray extends NativeFuture<KeyRangeArrayResult> {
|
||||||
|
FutureKeyRangeArray(long cPtr, Executor executor) {
|
||||||
|
super(cPtr);
|
||||||
|
registerMarshalCallback(executor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected KeyRangeArrayResult getIfDone_internal(long cPtr) throws FDBException {
|
||||||
|
return FutureKeyRangeArray_get(cPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
private native KeyRangeArrayResult FutureKeyRangeArray_get(long cPtr) throws FDBException;
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* KeyRangeArrayResult.java
|
||||||
|
*
|
||||||
|
* This source file is part of the FoundationDB open source project
|
||||||
|
*
|
||||||
|
* Copyright 2013-2020 Apple Inc. and the FoundationDB project authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.apple.foundationdb;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class KeyRangeArrayResult {
|
||||||
|
final List<Range> keyRanges;
|
||||||
|
|
||||||
|
public KeyRangeArrayResult(Range[] keyRangeArr) {
|
||||||
|
this.keyRanges = Arrays.asList(keyRangeArr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Range> getKeyRanges() {
|
||||||
|
return keyRanges;
|
||||||
|
}
|
||||||
|
}
|
|
@ -513,6 +513,17 @@ public interface ReadTransaction extends ReadTransactionContext {
|
||||||
*/
|
*/
|
||||||
CompletableFuture<KeyArrayResult> getRangeSplitPoints(Range range, long chunkSize);
|
CompletableFuture<KeyArrayResult> getRangeSplitPoints(Range range, long chunkSize);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the blob granule ranges for a given region.
|
||||||
|
* Returned in batches, requires calling again moving the begin key up.
|
||||||
|
*
|
||||||
|
* @param begin beginning of the range (inclusive)
|
||||||
|
* @param end end of the range (exclusive)
|
||||||
|
|
||||||
|
* @return list of blob granules in the given range. May not be all.
|
||||||
|
*/
|
||||||
|
CompletableFuture<KeyRangeArrayResult> getBlobGranuleRanges(byte[] begin, byte[] end, int rowLimit);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a set of options that can be set on a {@code Transaction}
|
* Returns a set of options that can be set on a {@code Transaction}
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include "fdbclient/FDBOptions.g.h"
|
#include "fdbclient/FDBOptions.g.h"
|
||||||
#include "fdbclient/IClientApi.h"
|
#include "fdbclient/IClientApi.h"
|
||||||
#include "fdbclient/ManagementAPI.actor.h"
|
#include "fdbclient/ManagementAPI.actor.h"
|
||||||
|
#include "fdbclient/NativeAPI.actor.h"
|
||||||
|
|
||||||
#include "flow/Arena.h"
|
#include "flow/Arena.h"
|
||||||
#include "flow/FastRef.h"
|
#include "flow/FastRef.h"
|
||||||
|
@ -31,33 +32,6 @@
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// copy to standalones for krm
|
|
||||||
ACTOR Future<Void> setBlobRange(Database db, Key startKey, Key endKey, Value value) {
|
|
||||||
state Reference<ReadYourWritesTransaction> tr = makeReference<ReadYourWritesTransaction>(db);
|
|
||||||
|
|
||||||
loop {
|
|
||||||
try {
|
|
||||||
tr->setOption(FDBTransactionOptions::ACCESS_SYSTEM_KEYS);
|
|
||||||
tr->setOption(FDBTransactionOptions::PRIORITY_SYSTEM_IMMEDIATE);
|
|
||||||
|
|
||||||
// FIXME: check that the set range is currently inactive, and that a revoked range is currently its own
|
|
||||||
// range in the map and fully set.
|
|
||||||
|
|
||||||
tr->set(blobRangeChangeKey, deterministicRandom()->randomUniqueID().toString());
|
|
||||||
// This is not coalescing because we want to keep each range logically separate.
|
|
||||||
wait(krmSetRange(tr, blobRangeKeys.begin, KeyRange(KeyRangeRef(startKey, endKey)), value));
|
|
||||||
wait(tr->commit());
|
|
||||||
printf("Successfully updated blob range [%s - %s) to %s\n",
|
|
||||||
startKey.printable().c_str(),
|
|
||||||
endKey.printable().c_str(),
|
|
||||||
value.printable().c_str());
|
|
||||||
return Void();
|
|
||||||
} catch (Error& e) {
|
|
||||||
wait(tr->onError(e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ACTOR Future<Version> getLatestReadVersion(Database db) {
|
ACTOR Future<Version> getLatestReadVersion(Database db) {
|
||||||
state Transaction tr(db);
|
state Transaction tr(db);
|
||||||
loop {
|
loop {
|
||||||
|
@ -99,65 +73,10 @@ ACTOR Future<Void> doBlobPurge(Database db, Key startKey, Key endKey, Optional<V
|
||||||
return Void();
|
return Void();
|
||||||
}
|
}
|
||||||
|
|
||||||
ACTOR Future<Version> checkBlobSubrange(Database db, KeyRange keyRange, Optional<Version> version) {
|
|
||||||
state Transaction tr(db);
|
|
||||||
state Version readVersionOut = invalidVersion;
|
|
||||||
loop {
|
|
||||||
try {
|
|
||||||
wait(success(tr.readBlobGranules(keyRange, 0, version, &readVersionOut)));
|
|
||||||
return readVersionOut;
|
|
||||||
} catch (Error& e) {
|
|
||||||
wait(tr.onError(e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ACTOR Future<Void> doBlobCheck(Database db, Key startKey, Key endKey, Optional<Version> version) {
|
ACTOR Future<Void> doBlobCheck(Database db, Key startKey, Key endKey, Optional<Version> version) {
|
||||||
state Transaction tr(db);
|
|
||||||
state Version readVersionOut = invalidVersion;
|
|
||||||
state double elapsed = -timer_monotonic();
|
state double elapsed = -timer_monotonic();
|
||||||
state KeyRange range = KeyRange(KeyRangeRef(startKey, endKey));
|
|
||||||
state Standalone<VectorRef<KeyRangeRef>> allRanges;
|
|
||||||
loop {
|
|
||||||
try {
|
|
||||||
wait(store(allRanges, tr.getBlobGranuleRanges(range)));
|
|
||||||
break;
|
|
||||||
} catch (Error& e) {
|
|
||||||
wait(tr.onError(e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (allRanges.empty()) {
|
state Version readVersionOut = wait(db->verifyBlobRange(KeyRangeRef(startKey, endKey), version));
|
||||||
fmt::print("ERROR: No blob ranges for [{0} - {1})\n", startKey.printable(), endKey.printable());
|
|
||||||
return Void();
|
|
||||||
}
|
|
||||||
fmt::print("Loaded {0} blob ranges to check\n", allRanges.size());
|
|
||||||
state std::vector<Future<Version>> checkParts;
|
|
||||||
// Chunk up to smaller ranges than this limit. Must be smaller than BG_TOO_MANY_GRANULES to not hit the limit
|
|
||||||
int maxChunkSize = CLIENT_KNOBS->BG_TOO_MANY_GRANULES / 2;
|
|
||||||
KeyRange currentChunk;
|
|
||||||
int currentChunkSize = 0;
|
|
||||||
for (auto& it : allRanges) {
|
|
||||||
if (currentChunkSize == maxChunkSize) {
|
|
||||||
checkParts.push_back(checkBlobSubrange(db, currentChunk, version));
|
|
||||||
currentChunkSize = 0;
|
|
||||||
}
|
|
||||||
if (currentChunkSize == 0) {
|
|
||||||
currentChunk = it;
|
|
||||||
} else if (it.begin != currentChunk.end) {
|
|
||||||
fmt::print("ERROR: Blobrange check failed, gap in blob ranges from [{0} - {1})\n",
|
|
||||||
currentChunk.end.printable(),
|
|
||||||
it.begin.printable());
|
|
||||||
return Void();
|
|
||||||
} else {
|
|
||||||
currentChunk = KeyRangeRef(currentChunk.begin, it.end);
|
|
||||||
}
|
|
||||||
currentChunkSize++;
|
|
||||||
}
|
|
||||||
checkParts.push_back(checkBlobSubrange(db, currentChunk, version));
|
|
||||||
|
|
||||||
wait(waitForAll(checkParts));
|
|
||||||
readVersionOut = checkParts.back().get();
|
|
||||||
|
|
||||||
elapsed += timer_monotonic();
|
elapsed += timer_monotonic();
|
||||||
|
|
||||||
|
@ -201,7 +120,7 @@ ACTOR Future<bool> blobRangeCommandActor(Database localDb,
|
||||||
fmt::print("Invalid blob range [{0} - {1})\n", tokens[2].printable(), tokens[3].printable());
|
fmt::print("Invalid blob range [{0} - {1})\n", tokens[2].printable(), tokens[3].printable());
|
||||||
} else {
|
} else {
|
||||||
if (tokencmp(tokens[1], "start") || tokencmp(tokens[1], "stop")) {
|
if (tokencmp(tokens[1], "start") || tokencmp(tokens[1], "stop")) {
|
||||||
bool starting = tokencmp(tokens[1], "start");
|
state bool starting = tokencmp(tokens[1], "start");
|
||||||
if (tokens.size() > 4) {
|
if (tokens.size() > 4) {
|
||||||
printUsage(tokens[0]);
|
printUsage(tokens[0]);
|
||||||
return false;
|
return false;
|
||||||
|
@ -210,7 +129,19 @@ ACTOR Future<bool> blobRangeCommandActor(Database localDb,
|
||||||
starting ? "Starting" : "Stopping",
|
starting ? "Starting" : "Stopping",
|
||||||
tokens[2].printable().c_str(),
|
tokens[2].printable().c_str(),
|
||||||
tokens[3].printable().c_str());
|
tokens[3].printable().c_str());
|
||||||
wait(setBlobRange(localDb, begin, end, starting ? LiteralStringRef("1") : StringRef()));
|
state bool success = false;
|
||||||
|
if (starting) {
|
||||||
|
wait(store(success, localDb->blobbifyRange(KeyRangeRef(begin, end))));
|
||||||
|
} else {
|
||||||
|
wait(store(success, localDb->unblobbifyRange(KeyRangeRef(begin, end))));
|
||||||
|
}
|
||||||
|
if (!success) {
|
||||||
|
fmt::print("{0} blobbify range for [{1} - {2}) failed\n",
|
||||||
|
starting ? "Starting" : "Stopping",
|
||||||
|
tokens[2].printable().c_str(),
|
||||||
|
tokens[3].printable().c_str());
|
||||||
|
}
|
||||||
|
return success;
|
||||||
} else if (tokencmp(tokens[1], "purge") || tokencmp(tokens[1], "forcepurge") || tokencmp(tokens[1], "check")) {
|
} else if (tokencmp(tokens[1], "purge") || tokencmp(tokens[1], "forcepurge") || tokencmp(tokens[1], "check")) {
|
||||||
bool purge = tokencmp(tokens[1], "purge") || tokencmp(tokens[1], "forcepurge");
|
bool purge = tokencmp(tokens[1], "purge") || tokencmp(tokens[1], "forcepurge");
|
||||||
bool forcePurge = tokencmp(tokens[1], "forcepurge");
|
bool forcePurge = tokencmp(tokens[1], "forcepurge");
|
||||||
|
|
|
@ -257,13 +257,14 @@ ThreadFuture<Standalone<VectorRef<KeyRef>>> DLTransaction::getRangeSplitPoints(c
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ThreadFuture<Standalone<VectorRef<KeyRangeRef>>> DLTransaction::getBlobGranuleRanges(const KeyRangeRef& keyRange) {
|
ThreadFuture<Standalone<VectorRef<KeyRangeRef>>> DLTransaction::getBlobGranuleRanges(const KeyRangeRef& keyRange,
|
||||||
|
int rangeLimit) {
|
||||||
if (!api->transactionGetBlobGranuleRanges) {
|
if (!api->transactionGetBlobGranuleRanges) {
|
||||||
return unsupported_operation();
|
return unsupported_operation();
|
||||||
}
|
}
|
||||||
|
|
||||||
FdbCApi::FDBFuture* f = api->transactionGetBlobGranuleRanges(
|
FdbCApi::FDBFuture* f = api->transactionGetBlobGranuleRanges(
|
||||||
tr, keyRange.begin.begin(), keyRange.begin.size(), keyRange.end.begin(), keyRange.end.size());
|
tr, keyRange.begin.begin(), keyRange.begin.size(), keyRange.end.begin(), keyRange.end.size(), rangeLimit);
|
||||||
return toThreadFuture<Standalone<VectorRef<KeyRangeRef>>>(api, f, [](FdbCApi::FDBFuture* f, FdbCApi* api) {
|
return toThreadFuture<Standalone<VectorRef<KeyRangeRef>>>(api, f, [](FdbCApi::FDBFuture* f, FdbCApi* api) {
|
||||||
const FdbCApi::FDBKeyRange* keyRanges;
|
const FdbCApi::FDBKeyRange* keyRanges;
|
||||||
int keyRangesLength;
|
int keyRangesLength;
|
||||||
|
@ -583,6 +584,71 @@ ThreadFuture<Void> DLDatabase::waitPurgeGranulesComplete(const KeyRef& purgeKey)
|
||||||
return toThreadFuture<Void>(api, f, [](FdbCApi::FDBFuture* f, FdbCApi* api) { return Void(); });
|
return toThreadFuture<Void>(api, f, [](FdbCApi::FDBFuture* f, FdbCApi* api) { return Void(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ThreadFuture<bool> DLDatabase::blobbifyRange(const KeyRangeRef& keyRange) {
|
||||||
|
if (!api->databaseBlobbifyRange) {
|
||||||
|
return unsupported_operation();
|
||||||
|
}
|
||||||
|
|
||||||
|
FdbCApi::FDBFuture* f = api->databaseBlobbifyRange(
|
||||||
|
db, keyRange.begin.begin(), keyRange.begin.size(), keyRange.end.begin(), keyRange.end.size());
|
||||||
|
|
||||||
|
return toThreadFuture<bool>(api, f, [](FdbCApi::FDBFuture* f, FdbCApi* api) {
|
||||||
|
bool ret = false;
|
||||||
|
ASSERT(!api->futureGetBool(f, &ret));
|
||||||
|
return ret;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ThreadFuture<bool> DLDatabase::unblobbifyRange(const KeyRangeRef& keyRange) {
|
||||||
|
if (!api->databaseUnblobbifyRange) {
|
||||||
|
return unsupported_operation();
|
||||||
|
}
|
||||||
|
|
||||||
|
FdbCApi::FDBFuture* f = api->databaseUnblobbifyRange(
|
||||||
|
db, keyRange.begin.begin(), keyRange.begin.size(), keyRange.end.begin(), keyRange.end.size());
|
||||||
|
|
||||||
|
return toThreadFuture<bool>(api, f, [](FdbCApi::FDBFuture* f, FdbCApi* api) {
|
||||||
|
bool ret = false;
|
||||||
|
ASSERT(!api->futureGetBool(f, &ret));
|
||||||
|
return ret;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ThreadFuture<Standalone<VectorRef<KeyRangeRef>>> DLDatabase::listBlobbifiedRanges(const KeyRangeRef& keyRange,
|
||||||
|
int rangeLimit) {
|
||||||
|
if (!api->databaseListBlobbifiedRanges) {
|
||||||
|
return unsupported_operation();
|
||||||
|
}
|
||||||
|
|
||||||
|
FdbCApi::FDBFuture* f = api->databaseListBlobbifiedRanges(
|
||||||
|
db, keyRange.begin.begin(), keyRange.begin.size(), keyRange.end.begin(), keyRange.end.size(), rangeLimit);
|
||||||
|
|
||||||
|
return toThreadFuture<Standalone<VectorRef<KeyRangeRef>>>(api, f, [](FdbCApi::FDBFuture* f, FdbCApi* api) {
|
||||||
|
const FdbCApi::FDBKeyRange* keyRanges;
|
||||||
|
int keyRangesLength;
|
||||||
|
FdbCApi::fdb_error_t error = api->futureGetKeyRangeArray(f, &keyRanges, &keyRangesLength);
|
||||||
|
ASSERT(!error);
|
||||||
|
// The memory for this is stored in the FDBFuture and is released when the future gets destroyed.
|
||||||
|
return Standalone<VectorRef<KeyRangeRef>>(VectorRef<KeyRangeRef>((KeyRangeRef*)keyRanges, keyRangesLength),
|
||||||
|
Arena());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ThreadFuture<Version> DLDatabase::verifyBlobRange(const KeyRangeRef& keyRange, Optional<Version> version) {
|
||||||
|
if (!api->databaseVerifyBlobRange) {
|
||||||
|
return unsupported_operation();
|
||||||
|
}
|
||||||
|
|
||||||
|
FdbCApi::FDBFuture* f = api->databaseVerifyBlobRange(
|
||||||
|
db, keyRange.begin.begin(), keyRange.begin.size(), keyRange.end.begin(), keyRange.end.size(), version);
|
||||||
|
|
||||||
|
return toThreadFuture<Version>(api, f, [](FdbCApi::FDBFuture* f, FdbCApi* api) {
|
||||||
|
Version version = invalidVersion;
|
||||||
|
ASSERT(!api->futureGetInt64(f, &version));
|
||||||
|
return version;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// DLApi
|
// DLApi
|
||||||
|
|
||||||
// Loads the specified function from a dynamic library
|
// Loads the specified function from a dynamic library
|
||||||
|
@ -670,6 +736,13 @@ void DLApi::init() {
|
||||||
fdbCPath,
|
fdbCPath,
|
||||||
"fdb_database_wait_purge_granules_complete",
|
"fdb_database_wait_purge_granules_complete",
|
||||||
headerVersion >= 710);
|
headerVersion >= 710);
|
||||||
|
loadClientFunction(&api->databaseBlobbifyRange, lib, fdbCPath, "fdb_database_blobbify_range", headerVersion >= 720);
|
||||||
|
loadClientFunction(
|
||||||
|
&api->databaseUnblobbifyRange, lib, fdbCPath, "fdb_database_unblobbify_range", headerVersion >= 720);
|
||||||
|
loadClientFunction(
|
||||||
|
&api->databaseListBlobbifiedRanges, lib, fdbCPath, "fdb_database_list_blobbified_ranges", headerVersion >= 720);
|
||||||
|
loadClientFunction(
|
||||||
|
&api->databaseVerifyBlobRange, lib, fdbCPath, "fdb_database_verify_blob_range", headerVersion >= 720);
|
||||||
|
|
||||||
loadClientFunction(
|
loadClientFunction(
|
||||||
&api->tenantCreateTransaction, lib, fdbCPath, "fdb_tenant_create_transaction", headerVersion >= 710);
|
&api->tenantCreateTransaction, lib, fdbCPath, "fdb_tenant_create_transaction", headerVersion >= 710);
|
||||||
|
@ -744,6 +817,7 @@ void DLApi::init() {
|
||||||
fdbCPath,
|
fdbCPath,
|
||||||
headerVersion >= 620 ? "fdb_future_get_int64" : "fdb_future_get_version",
|
headerVersion >= 620 ? "fdb_future_get_int64" : "fdb_future_get_version",
|
||||||
headerVersion >= 0);
|
headerVersion >= 0);
|
||||||
|
loadClientFunction(&api->futureGetBool, lib, fdbCPath, "fdb_future_get_bool", headerVersion >= 720);
|
||||||
loadClientFunction(&api->futureGetUInt64, lib, fdbCPath, "fdb_future_get_uint64", headerVersion >= 700);
|
loadClientFunction(&api->futureGetUInt64, lib, fdbCPath, "fdb_future_get_uint64", headerVersion >= 700);
|
||||||
loadClientFunction(&api->futureGetError, lib, fdbCPath, "fdb_future_get_error", headerVersion >= 0);
|
loadClientFunction(&api->futureGetError, lib, fdbCPath, "fdb_future_get_error", headerVersion >= 0);
|
||||||
loadClientFunction(&api->futureGetKey, lib, fdbCPath, "fdb_future_get_key", headerVersion >= 0);
|
loadClientFunction(&api->futureGetKey, lib, fdbCPath, "fdb_future_get_key", headerVersion >= 0);
|
||||||
|
@ -1079,9 +1153,10 @@ ThreadFuture<Standalone<VectorRef<KeyRef>>> MultiVersionTransaction::getRangeSpl
|
||||||
}
|
}
|
||||||
|
|
||||||
ThreadFuture<Standalone<VectorRef<KeyRangeRef>>> MultiVersionTransaction::getBlobGranuleRanges(
|
ThreadFuture<Standalone<VectorRef<KeyRangeRef>>> MultiVersionTransaction::getBlobGranuleRanges(
|
||||||
const KeyRangeRef& keyRange) {
|
const KeyRangeRef& keyRange,
|
||||||
|
int rangeLimit) {
|
||||||
auto tr = getTransaction();
|
auto tr = getTransaction();
|
||||||
auto f = tr.transaction ? tr.transaction->getBlobGranuleRanges(keyRange)
|
auto f = tr.transaction ? tr.transaction->getBlobGranuleRanges(keyRange, rangeLimit)
|
||||||
: makeTimeout<Standalone<VectorRef<KeyRangeRef>>>();
|
: makeTimeout<Standalone<VectorRef<KeyRangeRef>>>();
|
||||||
return abortableFuture(f, tr.onChange);
|
return abortableFuture(f, tr.onChange);
|
||||||
}
|
}
|
||||||
|
@ -1589,6 +1664,32 @@ ThreadFuture<Void> MultiVersionDatabase::waitPurgeGranulesComplete(const KeyRef&
|
||||||
return abortableFuture(f, dbState->dbVar->get().onChange);
|
return abortableFuture(f, dbState->dbVar->get().onChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ThreadFuture<bool> MultiVersionDatabase::blobbifyRange(const KeyRangeRef& keyRange) {
|
||||||
|
auto dbVar = dbState->dbVar->get();
|
||||||
|
auto f = dbVar.value ? dbVar.value->blobbifyRange(keyRange) : ThreadFuture<bool>(Never());
|
||||||
|
return abortableFuture(f, dbVar.onChange);
|
||||||
|
}
|
||||||
|
|
||||||
|
ThreadFuture<bool> MultiVersionDatabase::unblobbifyRange(const KeyRangeRef& keyRange) {
|
||||||
|
auto dbVar = dbState->dbVar->get();
|
||||||
|
auto f = dbVar.value ? dbVar.value->unblobbifyRange(keyRange) : ThreadFuture<bool>(Never());
|
||||||
|
return abortableFuture(f, dbVar.onChange);
|
||||||
|
}
|
||||||
|
|
||||||
|
ThreadFuture<Standalone<VectorRef<KeyRangeRef>>> MultiVersionDatabase::listBlobbifiedRanges(const KeyRangeRef& keyRange,
|
||||||
|
int rangeLimit) {
|
||||||
|
auto dbVar = dbState->dbVar->get();
|
||||||
|
auto f = dbVar.value ? dbVar.value->listBlobbifiedRanges(keyRange, rangeLimit)
|
||||||
|
: ThreadFuture<Standalone<VectorRef<KeyRangeRef>>>(Never());
|
||||||
|
return abortableFuture(f, dbVar.onChange);
|
||||||
|
}
|
||||||
|
|
||||||
|
ThreadFuture<Version> MultiVersionDatabase::verifyBlobRange(const KeyRangeRef& keyRange, Optional<Version> version) {
|
||||||
|
auto dbVar = dbState->dbVar->get();
|
||||||
|
auto f = dbVar.value ? dbVar.value->verifyBlobRange(keyRange, version) : ThreadFuture<Version>(Never());
|
||||||
|
return abortableFuture(f, dbVar.onChange);
|
||||||
|
}
|
||||||
|
|
||||||
// Returns the protocol version reported by the coordinator this client is connected to
|
// Returns the protocol version reported by the coordinator this client is connected to
|
||||||
// If an expected version is given, the future won't return until the protocol version is different than expected
|
// If an expected version is given, the future won't return until the protocol version is different than expected
|
||||||
// Note: this will never return if the server is running a protocol from FDB 5.0 or older
|
// Note: this will never return if the server is running a protocol from FDB 5.0 or older
|
||||||
|
|
|
@ -7638,7 +7638,9 @@ Future<Standalone<VectorRef<KeyRef>>> Transaction::getRangeSplitPoints(KeyRange
|
||||||
|
|
||||||
// the blob granule requests are a bit funky because they piggyback off the existing transaction to read from the system
|
// the blob granule requests are a bit funky because they piggyback off the existing transaction to read from the system
|
||||||
// keyspace
|
// keyspace
|
||||||
ACTOR Future<Standalone<VectorRef<KeyRangeRef>>> getBlobGranuleRangesActor(Transaction* self, KeyRange keyRange) {
|
ACTOR Future<Standalone<VectorRef<KeyRangeRef>>> getBlobGranuleRangesActor(Transaction* self,
|
||||||
|
KeyRange keyRange,
|
||||||
|
int rangeLimit) {
|
||||||
// FIXME: use streaming range read
|
// FIXME: use streaming range read
|
||||||
state KeyRange currentRange = keyRange;
|
state KeyRange currentRange = keyRange;
|
||||||
state Standalone<VectorRef<KeyRangeRef>> results;
|
state Standalone<VectorRef<KeyRangeRef>> results;
|
||||||
|
@ -7661,7 +7663,7 @@ ACTOR Future<Standalone<VectorRef<KeyRangeRef>>> getBlobGranuleRangesActor(Trans
|
||||||
|
|
||||||
// basically krmGetRange, but enable it to not use tenant without RAW_ACCESS by doing manual getRange with
|
// basically krmGetRange, but enable it to not use tenant without RAW_ACCESS by doing manual getRange with
|
||||||
// UseTenant::False
|
// UseTenant::False
|
||||||
GetRangeLimits limits(1000);
|
GetRangeLimits limits(2 * rangeLimit + 2);
|
||||||
limits.minRows = 2;
|
limits.minRows = 2;
|
||||||
RangeResult rawMapping = wait(getRange(self->trState,
|
RangeResult rawMapping = wait(getRange(self->trState,
|
||||||
self->getReadVersion(),
|
self->getReadVersion(),
|
||||||
|
@ -7683,6 +7685,9 @@ ACTOR Future<Standalone<VectorRef<KeyRangeRef>>> getBlobGranuleRangesActor(Trans
|
||||||
if (blobGranuleMapping[i].value.size()) {
|
if (blobGranuleMapping[i].value.size()) {
|
||||||
results.push_back(results.arena(),
|
results.push_back(results.arena(),
|
||||||
KeyRangeRef(blobGranuleMapping[i].key, blobGranuleMapping[i + 1].key));
|
KeyRangeRef(blobGranuleMapping[i].key, blobGranuleMapping[i + 1].key));
|
||||||
|
if (results.size() == rangeLimit) {
|
||||||
|
return results;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
results.arena().dependsOn(blobGranuleMapping.arena());
|
results.arena().dependsOn(blobGranuleMapping.arena());
|
||||||
|
@ -7694,8 +7699,8 @@ ACTOR Future<Standalone<VectorRef<KeyRangeRef>>> getBlobGranuleRangesActor(Trans
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Standalone<VectorRef<KeyRangeRef>>> Transaction::getBlobGranuleRanges(const KeyRange& range) {
|
Future<Standalone<VectorRef<KeyRangeRef>>> Transaction::getBlobGranuleRanges(const KeyRange& range, int rangeLimit) {
|
||||||
return ::getBlobGranuleRangesActor(this, range);
|
return ::getBlobGranuleRangesActor(this, range, rangeLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
// hack (for now) to get blob worker interface into load balance
|
// hack (for now) to get blob worker interface into load balance
|
||||||
|
@ -8007,6 +8012,71 @@ ACTOR Future<Version> setPerpetualStorageWiggle(Database cx, bool enable, LockAw
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ACTOR Future<Version> checkBlobSubrange(Database db, KeyRange keyRange, Optional<Version> version) {
|
||||||
|
state Transaction tr(db);
|
||||||
|
state Version readVersionOut = invalidVersion;
|
||||||
|
loop {
|
||||||
|
try {
|
||||||
|
wait(success(tr.readBlobGranules(keyRange, 0, version, &readVersionOut)));
|
||||||
|
return readVersionOut;
|
||||||
|
} catch (Error& e) {
|
||||||
|
wait(tr.onError(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ACTOR Future<Version> verifyBlobRangeActor(Reference<DatabaseContext> cx, KeyRange range, Optional<Version> version) {
|
||||||
|
state Database db(cx);
|
||||||
|
state Transaction tr(db);
|
||||||
|
state Standalone<VectorRef<KeyRangeRef>> allRanges;
|
||||||
|
state KeyRange curRegion = KeyRangeRef(range.begin, range.begin);
|
||||||
|
state Version readVersionOut = invalidVersion;
|
||||||
|
state int batchSize = CLIENT_KNOBS->BG_TOO_MANY_GRANULES / 2;
|
||||||
|
loop {
|
||||||
|
try {
|
||||||
|
wait(store(allRanges, tr.getBlobGranuleRanges(KeyRangeRef(curRegion.begin, range.end), 20 * batchSize)));
|
||||||
|
} catch (Error& e) {
|
||||||
|
wait(tr.onError(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allRanges.empty()) {
|
||||||
|
if (curRegion.begin < range.end) {
|
||||||
|
return invalidVersion;
|
||||||
|
}
|
||||||
|
return readVersionOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
state std::vector<Future<Version>> checkParts;
|
||||||
|
// Chunk up to smaller ranges than this limit. Must be smaller than BG_TOO_MANY_GRANULES to not hit the limit
|
||||||
|
int batchCount = 0;
|
||||||
|
for (auto& it : allRanges) {
|
||||||
|
if (it.begin != curRegion.end) {
|
||||||
|
return invalidVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
curRegion = KeyRangeRef(curRegion.begin, it.end);
|
||||||
|
batchCount++;
|
||||||
|
|
||||||
|
if (batchCount == batchSize) {
|
||||||
|
checkParts.push_back(checkBlobSubrange(db, curRegion, version));
|
||||||
|
batchCount = 0;
|
||||||
|
curRegion = KeyRangeRef(curRegion.end, curRegion.end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!curRegion.empty()) {
|
||||||
|
checkParts.push_back(checkBlobSubrange(db, curRegion, version));
|
||||||
|
}
|
||||||
|
|
||||||
|
wait(waitForAll(checkParts));
|
||||||
|
readVersionOut = checkParts.back().get();
|
||||||
|
curRegion = KeyRangeRef(curRegion.end, curRegion.end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Version> DatabaseContext::verifyBlobRange(const KeyRange& range, Optional<Version> version) {
|
||||||
|
return verifyBlobRangeActor(Reference<DatabaseContext>::addRef(this), range, version);
|
||||||
|
}
|
||||||
|
|
||||||
ACTOR Future<std::vector<std::pair<UID, StorageWiggleValue>>> readStorageWiggleValues(Database cx,
|
ACTOR Future<std::vector<std::pair<UID, StorageWiggleValue>>> readStorageWiggleValues(Database cx,
|
||||||
bool primary,
|
bool primary,
|
||||||
bool use_system_priority) {
|
bool use_system_priority) {
|
||||||
|
@ -9716,6 +9786,7 @@ Reference<DatabaseContext::TransactionT> DatabaseContext::createTransaction() {
|
||||||
return makeReference<ReadYourWritesTransaction>(Database(Reference<DatabaseContext>::addRef(this)));
|
return makeReference<ReadYourWritesTransaction>(Database(Reference<DatabaseContext>::addRef(this)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BlobGranule API.
|
||||||
ACTOR Future<Key> purgeBlobGranulesActor(Reference<DatabaseContext> db,
|
ACTOR Future<Key> purgeBlobGranulesActor(Reference<DatabaseContext> db,
|
||||||
KeyRange range,
|
KeyRange range,
|
||||||
Version purgeVersion,
|
Version purgeVersion,
|
||||||
|
@ -9807,6 +9878,89 @@ Future<Void> DatabaseContext::waitPurgeGranulesComplete(Key purgeKey) {
|
||||||
return waitPurgeGranulesCompleteActor(Reference<DatabaseContext>::addRef(this), purgeKey);
|
return waitPurgeGranulesCompleteActor(Reference<DatabaseContext>::addRef(this), purgeKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ACTOR Future<bool> setBlobRangeActor(Reference<DatabaseContext> cx, KeyRange range, bool active) {
|
||||||
|
state Database db(cx);
|
||||||
|
state Reference<ReadYourWritesTransaction> tr = makeReference<ReadYourWritesTransaction>(db);
|
||||||
|
|
||||||
|
state Value value = active ? blobRangeActive : blobRangeInactive;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
try {
|
||||||
|
tr->setOption(FDBTransactionOptions::ACCESS_SYSTEM_KEYS);
|
||||||
|
tr->setOption(FDBTransactionOptions::PRIORITY_SYSTEM_IMMEDIATE);
|
||||||
|
|
||||||
|
if (active) {
|
||||||
|
state RangeResult results = wait(krmGetRanges(tr, blobRangeKeys.begin, range));
|
||||||
|
ASSERT(results.size() >= 2);
|
||||||
|
if (results[0].key == range.begin && results[1].key == range.end &&
|
||||||
|
results[0].value == blobRangeActive) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < results.size(); i++) {
|
||||||
|
if (results[i].value == blobRangeActive) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tr->set(blobRangeChangeKey, deterministicRandom()->randomUniqueID().toString());
|
||||||
|
// This is not coalescing because we want to keep each range logically separate.
|
||||||
|
wait(krmSetRange(tr, blobRangeKeys.begin, range, value));
|
||||||
|
wait(tr->commit());
|
||||||
|
printf("Successfully updated blob range [%s - %s) to %s\n",
|
||||||
|
range.begin.printable().c_str(),
|
||||||
|
range.end.printable().c_str(),
|
||||||
|
value.printable().c_str());
|
||||||
|
return true;
|
||||||
|
} catch (Error& e) {
|
||||||
|
wait(tr->onError(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> DatabaseContext::blobbifyRange(KeyRange range) {
|
||||||
|
return setBlobRangeActor(Reference<DatabaseContext>::addRef(this), range, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> DatabaseContext::unblobbifyRange(KeyRange range) {
|
||||||
|
return setBlobRangeActor(Reference<DatabaseContext>::addRef(this), range, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
ACTOR Future<Standalone<VectorRef<KeyRangeRef>>> listBlobbifiedRangesActor(Reference<DatabaseContext> cx,
|
||||||
|
KeyRange range,
|
||||||
|
int rangeLimit) {
|
||||||
|
state Database db(cx);
|
||||||
|
state Reference<ReadYourWritesTransaction> tr = makeReference<ReadYourWritesTransaction>(db);
|
||||||
|
state Standalone<VectorRef<KeyRangeRef>> blobRanges;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
try {
|
||||||
|
tr->setOption(FDBTransactionOptions::ACCESS_SYSTEM_KEYS);
|
||||||
|
|
||||||
|
state RangeResult results = wait(krmGetRanges(tr, blobRangeKeys.begin, range, 2 * rangeLimit + 2));
|
||||||
|
|
||||||
|
blobRanges.arena().dependsOn(results.arena());
|
||||||
|
for (int i = 0; i < results.size() - 1; i++) {
|
||||||
|
if (results[i].value == LiteralStringRef("1")) {
|
||||||
|
blobRanges.push_back(blobRanges.arena(), KeyRangeRef(results[i].value, results[i + 1].value));
|
||||||
|
}
|
||||||
|
if (blobRanges.size() == rangeLimit) {
|
||||||
|
return blobRanges;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return blobRanges;
|
||||||
|
} catch (Error& e) {
|
||||||
|
wait(tr->onError(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Standalone<VectorRef<KeyRangeRef>>> DatabaseContext::listBlobbifiedRanges(KeyRange range, int rowLimit) {
|
||||||
|
return listBlobbifiedRangesActor(Reference<DatabaseContext>::addRef(this), range, rowLimit);
|
||||||
|
}
|
||||||
|
|
||||||
int64_t getMaxKeySize(KeyRef const& key) {
|
int64_t getMaxKeySize(KeyRef const& key) {
|
||||||
return getMaxWriteKeySize(key, true);
|
return getMaxWriteKeySize(key, true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1783,7 +1783,8 @@ Future<Standalone<VectorRef<KeyRef>>> ReadYourWritesTransaction::getRangeSplitPo
|
||||||
return waitOrError(tr.getRangeSplitPoints(range, chunkSize), resetPromise.getFuture());
|
return waitOrError(tr.getRangeSplitPoints(range, chunkSize), resetPromise.getFuture());
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Standalone<VectorRef<KeyRangeRef>>> ReadYourWritesTransaction::getBlobGranuleRanges(const KeyRange& range) {
|
Future<Standalone<VectorRef<KeyRangeRef>>> ReadYourWritesTransaction::getBlobGranuleRanges(const KeyRange& range,
|
||||||
|
int rangeLimit) {
|
||||||
if (checkUsedDuringCommit()) {
|
if (checkUsedDuringCommit()) {
|
||||||
return used_during_commit();
|
return used_during_commit();
|
||||||
}
|
}
|
||||||
|
@ -1794,7 +1795,7 @@ Future<Standalone<VectorRef<KeyRangeRef>>> ReadYourWritesTransaction::getBlobGra
|
||||||
if (range.begin > maxKey || range.end > maxKey)
|
if (range.begin > maxKey || range.end > maxKey)
|
||||||
return key_outside_legal_range();
|
return key_outside_legal_range();
|
||||||
|
|
||||||
return waitOrError(tr.getBlobGranuleRanges(range), resetPromise.getFuture());
|
return waitOrError(tr.getBlobGranuleRanges(range, rangeLimit), resetPromise.getFuture());
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Standalone<VectorRef<BlobGranuleChunkRef>>> ReadYourWritesTransaction::readBlobGranules(
|
Future<Standalone<VectorRef<BlobGranuleChunkRef>>> ReadYourWritesTransaction::readBlobGranules(
|
||||||
|
|
|
@ -1331,6 +1331,9 @@ int64_t decodeBlobManagerEpochValue(ValueRef const& value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// blob granule data
|
// blob granule data
|
||||||
|
const KeyRef blobRangeActive = LiteralStringRef("1");
|
||||||
|
const KeyRef blobRangeInactive = LiteralStringRef("0");
|
||||||
|
|
||||||
const KeyRangeRef blobGranuleFileKeys(LiteralStringRef("\xff\x02/bgf/"), LiteralStringRef("\xff\x02/bgf0"));
|
const KeyRangeRef blobGranuleFileKeys(LiteralStringRef("\xff\x02/bgf/"), LiteralStringRef("\xff\x02/bgf0"));
|
||||||
const KeyRangeRef blobGranuleMappingKeys(LiteralStringRef("\xff\x02/bgm/"), LiteralStringRef("\xff\x02/bgm0"));
|
const KeyRangeRef blobGranuleMappingKeys(LiteralStringRef("\xff\x02/bgm/"), LiteralStringRef("\xff\x02/bgm0"));
|
||||||
const KeyRangeRef blobGranuleLockKeys(LiteralStringRef("\xff\x02/bgl/"), LiteralStringRef("\xff\x02/bgl0"));
|
const KeyRangeRef blobGranuleLockKeys(LiteralStringRef("\xff\x02/bgl/"), LiteralStringRef("\xff\x02/bgl0"));
|
||||||
|
|
|
@ -144,6 +144,32 @@ ThreadFuture<Void> ThreadSafeDatabase::waitPurgeGranulesComplete(const KeyRef& p
|
||||||
return onMainThread([db, key]() -> Future<Void> { return db->waitPurgeGranulesComplete(key); });
|
return onMainThread([db, key]() -> Future<Void> { return db->waitPurgeGranulesComplete(key); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ThreadFuture<bool> ThreadSafeDatabase::blobbifyRange(const KeyRangeRef& keyRange) {
|
||||||
|
DatabaseContext* db = this->db;
|
||||||
|
KeyRange range = keyRange;
|
||||||
|
return onMainThread([=]() -> Future<bool> { return db->blobbifyRange(range); });
|
||||||
|
}
|
||||||
|
|
||||||
|
ThreadFuture<bool> ThreadSafeDatabase::unblobbifyRange(const KeyRangeRef& keyRange) {
|
||||||
|
DatabaseContext* db = this->db;
|
||||||
|
KeyRange range = keyRange;
|
||||||
|
return onMainThread([=]() -> Future<bool> { return db->blobbifyRange(range); });
|
||||||
|
}
|
||||||
|
|
||||||
|
ThreadFuture<Standalone<VectorRef<KeyRangeRef>>> ThreadSafeDatabase::listBlobbifiedRanges(const KeyRangeRef& keyRange,
|
||||||
|
int rangeLimit) {
|
||||||
|
DatabaseContext* db = this->db;
|
||||||
|
KeyRange range = keyRange;
|
||||||
|
return onMainThread(
|
||||||
|
[=]() -> Future<Standalone<VectorRef<KeyRangeRef>>> { return db->listBlobbifiedRanges(range, rangeLimit); });
|
||||||
|
}
|
||||||
|
|
||||||
|
ThreadFuture<Version> ThreadSafeDatabase::verifyBlobRange(const KeyRangeRef& keyRange, Optional<Version> version) {
|
||||||
|
DatabaseContext* db = this->db;
|
||||||
|
KeyRange range = keyRange;
|
||||||
|
return onMainThread([=]() -> Future<Version> { return db->verifyBlobRange(range, version); });
|
||||||
|
}
|
||||||
|
|
||||||
ThreadSafeDatabase::ThreadSafeDatabase(ConnectionRecordType connectionRecordType,
|
ThreadSafeDatabase::ThreadSafeDatabase(ConnectionRecordType connectionRecordType,
|
||||||
std::string connectionRecordString,
|
std::string connectionRecordString,
|
||||||
int apiVersion) {
|
int apiVersion) {
|
||||||
|
@ -359,13 +385,14 @@ ThreadFuture<Standalone<VectorRef<const char*>>> ThreadSafeTransaction::getAddre
|
||||||
}
|
}
|
||||||
|
|
||||||
ThreadFuture<Standalone<VectorRef<KeyRangeRef>>> ThreadSafeTransaction::getBlobGranuleRanges(
|
ThreadFuture<Standalone<VectorRef<KeyRangeRef>>> ThreadSafeTransaction::getBlobGranuleRanges(
|
||||||
const KeyRangeRef& keyRange) {
|
const KeyRangeRef& keyRange,
|
||||||
|
int rangeLimit) {
|
||||||
ISingleThreadTransaction* tr = this->tr;
|
ISingleThreadTransaction* tr = this->tr;
|
||||||
KeyRange r = keyRange;
|
KeyRange r = keyRange;
|
||||||
|
|
||||||
return onMainThread([tr, r]() -> Future<Standalone<VectorRef<KeyRangeRef>>> {
|
return onMainThread([=]() -> Future<Standalone<VectorRef<KeyRangeRef>>> {
|
||||||
tr->checkDeferredError();
|
tr->checkDeferredError();
|
||||||
return tr->getBlobGranuleRanges(r);
|
return tr->getBlobGranuleRanges(r, rangeLimit);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -378,12 +378,18 @@ public:
|
||||||
Future<OverlappingChangeFeedsInfo> getOverlappingChangeFeeds(KeyRangeRef ranges, Version minVersion);
|
Future<OverlappingChangeFeedsInfo> getOverlappingChangeFeeds(KeyRangeRef ranges, Version minVersion);
|
||||||
Future<Void> popChangeFeedMutations(Key rangeID, Version version);
|
Future<Void> popChangeFeedMutations(Key rangeID, Version version);
|
||||||
|
|
||||||
|
// BlobGranule API.
|
||||||
Future<Key> purgeBlobGranules(KeyRange keyRange,
|
Future<Key> purgeBlobGranules(KeyRange keyRange,
|
||||||
Version purgeVersion,
|
Version purgeVersion,
|
||||||
Optional<TenantName> tenant,
|
Optional<TenantName> tenant,
|
||||||
bool force = false);
|
bool force = false);
|
||||||
Future<Void> waitPurgeGranulesComplete(Key purgeKey);
|
Future<Void> waitPurgeGranulesComplete(Key purgeKey);
|
||||||
|
|
||||||
|
Future<bool> blobbifyRange(KeyRange range);
|
||||||
|
Future<bool> unblobbifyRange(KeyRange range);
|
||||||
|
Future<Standalone<VectorRef<KeyRangeRef>>> listBlobbifiedRanges(KeyRange range, int rangeLimit);
|
||||||
|
Future<Version> verifyBlobRange(const KeyRange& range, Optional<Version> version);
|
||||||
|
|
||||||
// private:
|
// private:
|
||||||
explicit DatabaseContext(Reference<AsyncVar<Reference<IClusterConnectionRecord>>> connectionRecord,
|
explicit DatabaseContext(Reference<AsyncVar<Reference<IClusterConnectionRecord>>> connectionRecord,
|
||||||
Reference<AsyncVar<ClientDBInfo>> clientDBInfo,
|
Reference<AsyncVar<ClientDBInfo>> clientDBInfo,
|
||||||
|
|
|
@ -78,7 +78,8 @@ public:
|
||||||
virtual ThreadFuture<Standalone<VectorRef<KeyRef>>> getRangeSplitPoints(const KeyRangeRef& range,
|
virtual ThreadFuture<Standalone<VectorRef<KeyRef>>> getRangeSplitPoints(const KeyRangeRef& range,
|
||||||
int64_t chunkSize) = 0;
|
int64_t chunkSize) = 0;
|
||||||
|
|
||||||
virtual ThreadFuture<Standalone<VectorRef<KeyRangeRef>>> getBlobGranuleRanges(const KeyRangeRef& keyRange) = 0;
|
virtual ThreadFuture<Standalone<VectorRef<KeyRangeRef>>> getBlobGranuleRanges(const KeyRangeRef& keyRange,
|
||||||
|
int rowLimit) = 0;
|
||||||
|
|
||||||
virtual ThreadResult<RangeResult> readBlobGranules(const KeyRangeRef& keyRange,
|
virtual ThreadResult<RangeResult> readBlobGranules(const KeyRangeRef& keyRange,
|
||||||
Version beginVersion,
|
Version beginVersion,
|
||||||
|
@ -172,6 +173,13 @@ public:
|
||||||
virtual ThreadFuture<Key> purgeBlobGranules(const KeyRangeRef& keyRange, Version purgeVersion, bool force) = 0;
|
virtual ThreadFuture<Key> purgeBlobGranules(const KeyRangeRef& keyRange, Version purgeVersion, bool force) = 0;
|
||||||
virtual ThreadFuture<Void> waitPurgeGranulesComplete(const KeyRef& purgeKey) = 0;
|
virtual ThreadFuture<Void> waitPurgeGranulesComplete(const KeyRef& purgeKey) = 0;
|
||||||
|
|
||||||
|
virtual ThreadFuture<bool> blobbifyRange(const KeyRangeRef& keyRange) = 0;
|
||||||
|
virtual ThreadFuture<bool> unblobbifyRange(const KeyRangeRef& keyRange) = 0;
|
||||||
|
virtual ThreadFuture<Standalone<VectorRef<KeyRangeRef>>> listBlobbifiedRanges(const KeyRangeRef& keyRange,
|
||||||
|
int rangeLimit) = 0;
|
||||||
|
|
||||||
|
virtual ThreadFuture<Version> verifyBlobRange(const KeyRangeRef& keyRange, Optional<Version> version) = 0;
|
||||||
|
|
||||||
// Interface to manage shared state across multiple connections to the same Database
|
// Interface to manage shared state across multiple connections to the same Database
|
||||||
virtual ThreadFuture<DatabaseSharedState*> createSharedState() = 0;
|
virtual ThreadFuture<DatabaseSharedState*> createSharedState() = 0;
|
||||||
virtual void setSharedState(DatabaseSharedState* p) = 0;
|
virtual void setSharedState(DatabaseSharedState* p) = 0;
|
||||||
|
|
|
@ -55,7 +55,7 @@ public:
|
||||||
Future<Standalone<VectorRef<KeyRef>>> getRangeSplitPoints(KeyRange const& range, int64_t chunkSize) override {
|
Future<Standalone<VectorRef<KeyRef>>> getRangeSplitPoints(KeyRange const& range, int64_t chunkSize) override {
|
||||||
throw client_invalid_operation();
|
throw client_invalid_operation();
|
||||||
}
|
}
|
||||||
Future<Standalone<VectorRef<KeyRangeRef>>> getBlobGranuleRanges(KeyRange const& range) override {
|
Future<Standalone<VectorRef<KeyRangeRef>>> getBlobGranuleRanges(KeyRange const& range, int rowLimit) override {
|
||||||
throw client_invalid_operation();
|
throw client_invalid_operation();
|
||||||
}
|
}
|
||||||
Future<Standalone<VectorRef<BlobGranuleChunkRef>>> readBlobGranules(KeyRange const& range,
|
Future<Standalone<VectorRef<BlobGranuleChunkRef>>> readBlobGranules(KeyRange const& range,
|
||||||
|
|
|
@ -80,7 +80,7 @@ public:
|
||||||
virtual Future<Standalone<VectorRef<const char*>>> getAddressesForKey(Key const& key) = 0;
|
virtual Future<Standalone<VectorRef<const char*>>> getAddressesForKey(Key const& key) = 0;
|
||||||
virtual Future<Standalone<VectorRef<KeyRef>>> getRangeSplitPoints(KeyRange const& range, int64_t chunkSize) = 0;
|
virtual Future<Standalone<VectorRef<KeyRef>>> getRangeSplitPoints(KeyRange const& range, int64_t chunkSize) = 0;
|
||||||
virtual Future<int64_t> getEstimatedRangeSizeBytes(KeyRange const& keys) = 0;
|
virtual Future<int64_t> getEstimatedRangeSizeBytes(KeyRange const& keys) = 0;
|
||||||
virtual Future<Standalone<VectorRef<KeyRangeRef>>> getBlobGranuleRanges(KeyRange const& range) = 0;
|
virtual Future<Standalone<VectorRef<KeyRangeRef>>> getBlobGranuleRanges(KeyRange const& range, int rangeLimit) = 0;
|
||||||
virtual Future<Standalone<VectorRef<BlobGranuleChunkRef>>> readBlobGranules(KeyRange const& range,
|
virtual Future<Standalone<VectorRef<BlobGranuleChunkRef>>> readBlobGranules(KeyRange const& range,
|
||||||
Version begin,
|
Version begin,
|
||||||
Optional<Version> readVersion,
|
Optional<Version> readVersion,
|
||||||
|
|
|
@ -171,6 +171,32 @@ struct FdbCApi : public ThreadSafeReferenceCounted<FdbCApi> {
|
||||||
uint8_t const* purge_key_name,
|
uint8_t const* purge_key_name,
|
||||||
int purge_key_name_length);
|
int purge_key_name_length);
|
||||||
|
|
||||||
|
FDBFuture* (*databaseBlobbifyRange)(FDBDatabase* db,
|
||||||
|
uint8_t const* begin_key_name,
|
||||||
|
int begin_key_name_length,
|
||||||
|
uint8_t const* end_key_name,
|
||||||
|
int end_key_name_length);
|
||||||
|
|
||||||
|
FDBFuture* (*databaseUnblobbifyRange)(FDBDatabase* db,
|
||||||
|
uint8_t const* begin_key_name,
|
||||||
|
int begin_key_name_length,
|
||||||
|
uint8_t const* end_key_name,
|
||||||
|
int end_key_name_length);
|
||||||
|
|
||||||
|
FDBFuture* (*databaseListBlobbifiedRanges)(FDBDatabase* db,
|
||||||
|
uint8_t const* begin_key_name,
|
||||||
|
int begin_key_name_length,
|
||||||
|
uint8_t const* end_key_name,
|
||||||
|
int end_key_name_length,
|
||||||
|
int rangeLimit);
|
||||||
|
|
||||||
|
FDBFuture* (*databaseVerifyBlobRange)(FDBDatabase* db,
|
||||||
|
uint8_t const* begin_key_name,
|
||||||
|
int begin_key_name_length,
|
||||||
|
uint8_t const* end_key_name,
|
||||||
|
int end_key_name_length,
|
||||||
|
Optional<Version> version);
|
||||||
|
|
||||||
// Tenant
|
// Tenant
|
||||||
fdb_error_t (*tenantCreateTransaction)(FDBTenant* tenant, FDBTransaction** outTransaction);
|
fdb_error_t (*tenantCreateTransaction)(FDBTenant* tenant, FDBTransaction** outTransaction);
|
||||||
|
|
||||||
|
@ -276,7 +302,8 @@ struct FdbCApi : public ThreadSafeReferenceCounted<FdbCApi> {
|
||||||
uint8_t const* begin_key_name,
|
uint8_t const* begin_key_name,
|
||||||
int begin_key_name_length,
|
int begin_key_name_length,
|
||||||
uint8_t const* end_key_name,
|
uint8_t const* end_key_name,
|
||||||
int end_key_name_length);
|
int end_key_name_length,
|
||||||
|
int rangeLimit);
|
||||||
|
|
||||||
FDBResult* (*transactionReadBlobGranules)(FDBTransaction* db,
|
FDBResult* (*transactionReadBlobGranules)(FDBTransaction* db,
|
||||||
uint8_t const* begin_key_name,
|
uint8_t const* begin_key_name,
|
||||||
|
@ -376,7 +403,8 @@ public:
|
||||||
ThreadFuture<int64_t> getEstimatedRangeSizeBytes(const KeyRangeRef& keys) override;
|
ThreadFuture<int64_t> getEstimatedRangeSizeBytes(const KeyRangeRef& keys) override;
|
||||||
ThreadFuture<Standalone<VectorRef<KeyRef>>> getRangeSplitPoints(const KeyRangeRef& range,
|
ThreadFuture<Standalone<VectorRef<KeyRef>>> getRangeSplitPoints(const KeyRangeRef& range,
|
||||||
int64_t chunkSize) override;
|
int64_t chunkSize) override;
|
||||||
ThreadFuture<Standalone<VectorRef<KeyRangeRef>>> getBlobGranuleRanges(const KeyRangeRef& keyRange) override;
|
ThreadFuture<Standalone<VectorRef<KeyRangeRef>>> getBlobGranuleRanges(const KeyRangeRef& keyRange,
|
||||||
|
int rangeLimit) override;
|
||||||
|
|
||||||
ThreadResult<RangeResult> readBlobGranules(const KeyRangeRef& keyRange,
|
ThreadResult<RangeResult> readBlobGranules(const KeyRangeRef& keyRange,
|
||||||
Version beginVersion,
|
Version beginVersion,
|
||||||
|
@ -476,6 +504,12 @@ public:
|
||||||
ThreadFuture<Key> purgeBlobGranules(const KeyRangeRef& keyRange, Version purgeVersion, bool force) override;
|
ThreadFuture<Key> purgeBlobGranules(const KeyRangeRef& keyRange, Version purgeVersion, bool force) override;
|
||||||
ThreadFuture<Void> waitPurgeGranulesComplete(const KeyRef& purgeKey) override;
|
ThreadFuture<Void> waitPurgeGranulesComplete(const KeyRef& purgeKey) override;
|
||||||
|
|
||||||
|
ThreadFuture<bool> blobbifyRange(const KeyRangeRef& keyRange) override;
|
||||||
|
ThreadFuture<bool> unblobbifyRange(const KeyRangeRef& keyRange) override;
|
||||||
|
ThreadFuture<Standalone<VectorRef<KeyRangeRef>>> listBlobbifiedRanges(const KeyRangeRef& keyRange,
|
||||||
|
int rangeLimit) override;
|
||||||
|
ThreadFuture<Version> verifyBlobRange(const KeyRangeRef& keyRange, Optional<Version> version) override;
|
||||||
|
|
||||||
ThreadFuture<DatabaseSharedState*> createSharedState() override;
|
ThreadFuture<DatabaseSharedState*> createSharedState() override;
|
||||||
void setSharedState(DatabaseSharedState* p) override;
|
void setSharedState(DatabaseSharedState* p) override;
|
||||||
|
|
||||||
|
@ -574,7 +608,8 @@ public:
|
||||||
|
|
||||||
ThreadFuture<Standalone<VectorRef<KeyRef>>> getRangeSplitPoints(const KeyRangeRef& range,
|
ThreadFuture<Standalone<VectorRef<KeyRef>>> getRangeSplitPoints(const KeyRangeRef& range,
|
||||||
int64_t chunkSize) override;
|
int64_t chunkSize) override;
|
||||||
ThreadFuture<Standalone<VectorRef<KeyRangeRef>>> getBlobGranuleRanges(const KeyRangeRef& keyRange) override;
|
ThreadFuture<Standalone<VectorRef<KeyRangeRef>>> getBlobGranuleRanges(const KeyRangeRef& keyRange,
|
||||||
|
int rangeLimit) override;
|
||||||
|
|
||||||
ThreadResult<RangeResult> readBlobGranules(const KeyRangeRef& keyRange,
|
ThreadResult<RangeResult> readBlobGranules(const KeyRangeRef& keyRange,
|
||||||
Version beginVersion,
|
Version beginVersion,
|
||||||
|
@ -817,6 +852,12 @@ public:
|
||||||
ThreadFuture<Key> purgeBlobGranules(const KeyRangeRef& keyRange, Version purgeVersion, bool force) override;
|
ThreadFuture<Key> purgeBlobGranules(const KeyRangeRef& keyRange, Version purgeVersion, bool force) override;
|
||||||
ThreadFuture<Void> waitPurgeGranulesComplete(const KeyRef& purgeKey) override;
|
ThreadFuture<Void> waitPurgeGranulesComplete(const KeyRef& purgeKey) override;
|
||||||
|
|
||||||
|
ThreadFuture<bool> blobbifyRange(const KeyRangeRef& keyRange) override;
|
||||||
|
ThreadFuture<bool> unblobbifyRange(const KeyRangeRef& keyRange) override;
|
||||||
|
ThreadFuture<Standalone<VectorRef<KeyRangeRef>>> listBlobbifiedRanges(const KeyRangeRef& keyRange,
|
||||||
|
int rangeLimit) override;
|
||||||
|
ThreadFuture<Version> verifyBlobRange(const KeyRangeRef& keyRange, Optional<Version> version) override;
|
||||||
|
|
||||||
ThreadFuture<DatabaseSharedState*> createSharedState() override;
|
ThreadFuture<DatabaseSharedState*> createSharedState() override;
|
||||||
void setSharedState(DatabaseSharedState* p) override;
|
void setSharedState(DatabaseSharedState* p) override;
|
||||||
|
|
||||||
|
|
|
@ -415,7 +415,7 @@ public:
|
||||||
// The returned list would still be in form of [keys.begin, splitPoint1, splitPoint2, ... , keys.end]
|
// The returned list would still be in form of [keys.begin, splitPoint1, splitPoint2, ... , keys.end]
|
||||||
Future<Standalone<VectorRef<KeyRef>>> getRangeSplitPoints(KeyRange const& keys, int64_t chunkSize);
|
Future<Standalone<VectorRef<KeyRef>>> getRangeSplitPoints(KeyRange const& keys, int64_t chunkSize);
|
||||||
|
|
||||||
Future<Standalone<VectorRef<KeyRangeRef>>> getBlobGranuleRanges(const KeyRange& range);
|
Future<Standalone<VectorRef<KeyRangeRef>>> getBlobGranuleRanges(const KeyRange& range, int rangeLimit);
|
||||||
Future<Standalone<VectorRef<BlobGranuleChunkRef>>> readBlobGranules(const KeyRange& range,
|
Future<Standalone<VectorRef<BlobGranuleChunkRef>>> readBlobGranules(const KeyRange& range,
|
||||||
Version begin,
|
Version begin,
|
||||||
Optional<Version> readVersion,
|
Optional<Version> readVersion,
|
||||||
|
|
|
@ -121,7 +121,7 @@ public:
|
||||||
Future<Standalone<VectorRef<KeyRef>>> getRangeSplitPoints(const KeyRange& range, int64_t chunkSize) override;
|
Future<Standalone<VectorRef<KeyRef>>> getRangeSplitPoints(const KeyRange& range, int64_t chunkSize) override;
|
||||||
Future<int64_t> getEstimatedRangeSizeBytes(const KeyRange& keys) override;
|
Future<int64_t> getEstimatedRangeSizeBytes(const KeyRange& keys) override;
|
||||||
|
|
||||||
Future<Standalone<VectorRef<KeyRangeRef>>> getBlobGranuleRanges(const KeyRange& range) override;
|
Future<Standalone<VectorRef<KeyRangeRef>>> getBlobGranuleRanges(const KeyRange& range, int rangeLimit) override;
|
||||||
Future<Standalone<VectorRef<BlobGranuleChunkRef>>> readBlobGranules(const KeyRange& range,
|
Future<Standalone<VectorRef<BlobGranuleChunkRef>>> readBlobGranules(const KeyRange& range,
|
||||||
Version begin,
|
Version begin,
|
||||||
Optional<Version> readVersion,
|
Optional<Version> readVersion,
|
||||||
|
|
|
@ -594,6 +594,8 @@ const Value blobManagerEpochValueFor(int64_t epoch);
|
||||||
int64_t decodeBlobManagerEpochValue(ValueRef const& value);
|
int64_t decodeBlobManagerEpochValue(ValueRef const& value);
|
||||||
|
|
||||||
// blob granule keys
|
// blob granule keys
|
||||||
|
extern const StringRef blobRangeActive;
|
||||||
|
extern const StringRef blobRangeInactive;
|
||||||
|
|
||||||
extern const uint8_t BG_FILE_TYPE_DELTA;
|
extern const uint8_t BG_FILE_TYPE_DELTA;
|
||||||
extern const uint8_t BG_FILE_TYPE_SNAPSHOT;
|
extern const uint8_t BG_FILE_TYPE_SNAPSHOT;
|
||||||
|
|
|
@ -62,6 +62,13 @@ public:
|
||||||
ThreadFuture<Key> purgeBlobGranules(const KeyRangeRef& keyRange, Version purgeVersion, bool force) override;
|
ThreadFuture<Key> purgeBlobGranules(const KeyRangeRef& keyRange, Version purgeVersion, bool force) override;
|
||||||
ThreadFuture<Void> waitPurgeGranulesComplete(const KeyRef& purgeKey) override;
|
ThreadFuture<Void> waitPurgeGranulesComplete(const KeyRef& purgeKey) override;
|
||||||
|
|
||||||
|
ThreadFuture<bool> blobbifyRange(const KeyRangeRef& keyRange) override;
|
||||||
|
ThreadFuture<bool> unblobbifyRange(const KeyRangeRef& keyRange) override;
|
||||||
|
ThreadFuture<Standalone<VectorRef<KeyRangeRef>>> listBlobbifiedRanges(const KeyRangeRef& keyRange,
|
||||||
|
int rangeLimit) override;
|
||||||
|
|
||||||
|
ThreadFuture<Version> verifyBlobRange(const KeyRangeRef& keyRange, Optional<Version> version) override;
|
||||||
|
|
||||||
ThreadFuture<DatabaseSharedState*> createSharedState() override;
|
ThreadFuture<DatabaseSharedState*> createSharedState() override;
|
||||||
void setSharedState(DatabaseSharedState* p) override;
|
void setSharedState(DatabaseSharedState* p) override;
|
||||||
|
|
||||||
|
@ -149,7 +156,8 @@ public:
|
||||||
ThreadFuture<Standalone<VectorRef<KeyRef>>> getRangeSplitPoints(const KeyRangeRef& range,
|
ThreadFuture<Standalone<VectorRef<KeyRef>>> getRangeSplitPoints(const KeyRangeRef& range,
|
||||||
int64_t chunkSize) override;
|
int64_t chunkSize) override;
|
||||||
|
|
||||||
ThreadFuture<Standalone<VectorRef<KeyRangeRef>>> getBlobGranuleRanges(const KeyRangeRef& keyRange) override;
|
ThreadFuture<Standalone<VectorRef<KeyRangeRef>>> getBlobGranuleRanges(const KeyRangeRef& keyRange,
|
||||||
|
int rangeLimit) override;
|
||||||
|
|
||||||
ThreadResult<RangeResult> readBlobGranules(const KeyRangeRef& keyRange,
|
ThreadResult<RangeResult> readBlobGranules(const KeyRangeRef& keyRange,
|
||||||
Version beginVersion,
|
Version beginVersion,
|
||||||
|
|
|
@ -189,7 +189,7 @@ ACTOR Future<Void> clearAndAwaitMerge(Database cx, KeyRange range) {
|
||||||
state int reClearInterval = 1; // do quadratic backoff on clear rate, b/c large keys can keep it not write-cold
|
state int reClearInterval = 1; // do quadratic backoff on clear rate, b/c large keys can keep it not write-cold
|
||||||
loop {
|
loop {
|
||||||
try {
|
try {
|
||||||
Standalone<VectorRef<KeyRangeRef>> ranges = wait(tr.getBlobGranuleRanges(range));
|
Standalone<VectorRef<KeyRangeRef>> ranges = wait(tr.getBlobGranuleRanges(range, 2));
|
||||||
if (ranges.size() == 1) {
|
if (ranges.size() == 1) {
|
||||||
return Void();
|
return Void();
|
||||||
}
|
}
|
||||||
|
|
|
@ -130,7 +130,7 @@ void updateClientBlobRanges(KeyRangeMap<bool>* knownBlobRanges,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
bool active = dbBlobRanges[i].value == LiteralStringRef("1");
|
bool active = dbBlobRanges[i].value == blobRangeActive;
|
||||||
if (active) {
|
if (active) {
|
||||||
if (BM_DEBUG) {
|
if (BM_DEBUG) {
|
||||||
fmt::print("BM sees client range [{0} - {1})\n",
|
fmt::print("BM sees client range [{0} - {1})\n",
|
||||||
|
@ -1282,7 +1282,7 @@ ACTOR Future<Void> monitorClientRanges(Reference<BlobManagerData> bmData) {
|
||||||
needToCoalesce = false;
|
needToCoalesce = false;
|
||||||
|
|
||||||
for (int i = 0; i < results.size() - 1; i++) {
|
for (int i = 0; i < results.size() - 1; i++) {
|
||||||
bool active = results[i].value == LiteralStringRef("1");
|
bool active = results[i].value == blobRangeActive;
|
||||||
bmData->knownBlobRanges.insert(KeyRangeRef(results[i].key, results[i + 1].key), active);
|
bmData->knownBlobRanges.insert(KeyRangeRef(results[i].key, results[i + 1].key), active);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5073,9 +5073,6 @@ TEST_CASE("/blobmanager/updateranges") {
|
||||||
VectorRef<KeyRangeRef> added;
|
VectorRef<KeyRangeRef> added;
|
||||||
VectorRef<KeyRangeRef> removed;
|
VectorRef<KeyRangeRef> removed;
|
||||||
|
|
||||||
StringRef active = LiteralStringRef("1");
|
|
||||||
StringRef inactive = StringRef();
|
|
||||||
|
|
||||||
RangeResult dbDataEmpty;
|
RangeResult dbDataEmpty;
|
||||||
std::vector<std::pair<KeyRangeRef, bool>> kbrRanges;
|
std::vector<std::pair<KeyRangeRef, bool>> kbrRanges;
|
||||||
|
|
||||||
|
@ -5086,34 +5083,34 @@ TEST_CASE("/blobmanager/updateranges") {
|
||||||
|
|
||||||
// db data setup
|
// db data setup
|
||||||
RangeResult dbDataAB;
|
RangeResult dbDataAB;
|
||||||
dbDataAB.emplace_back(ar, keyA, active);
|
dbDataAB.emplace_back(ar, keyA, blobRangeActive);
|
||||||
dbDataAB.emplace_back(ar, keyB, inactive);
|
dbDataAB.emplace_back(ar, keyB, blobRangeInactive);
|
||||||
|
|
||||||
RangeResult dbDataAC;
|
RangeResult dbDataAC;
|
||||||
dbDataAC.emplace_back(ar, keyA, active);
|
dbDataAC.emplace_back(ar, keyA, blobRangeActive);
|
||||||
dbDataAC.emplace_back(ar, keyC, inactive);
|
dbDataAC.emplace_back(ar, keyC, blobRangeInactive);
|
||||||
|
|
||||||
RangeResult dbDataAD;
|
RangeResult dbDataAD;
|
||||||
dbDataAD.emplace_back(ar, keyA, active);
|
dbDataAD.emplace_back(ar, keyA, blobRangeActive);
|
||||||
dbDataAD.emplace_back(ar, keyD, inactive);
|
dbDataAD.emplace_back(ar, keyD, blobRangeInactive);
|
||||||
|
|
||||||
RangeResult dbDataBC;
|
RangeResult dbDataBC;
|
||||||
dbDataBC.emplace_back(ar, keyB, active);
|
dbDataBC.emplace_back(ar, keyB, blobRangeActive);
|
||||||
dbDataBC.emplace_back(ar, keyC, inactive);
|
dbDataBC.emplace_back(ar, keyC, blobRangeInactive);
|
||||||
|
|
||||||
RangeResult dbDataBD;
|
RangeResult dbDataBD;
|
||||||
dbDataBD.emplace_back(ar, keyB, active);
|
dbDataBD.emplace_back(ar, keyB, blobRangeActive);
|
||||||
dbDataBD.emplace_back(ar, keyD, inactive);
|
dbDataBD.emplace_back(ar, keyD, blobRangeInactive);
|
||||||
|
|
||||||
RangeResult dbDataCD;
|
RangeResult dbDataCD;
|
||||||
dbDataCD.emplace_back(ar, keyC, active);
|
dbDataCD.emplace_back(ar, keyC, blobRangeActive);
|
||||||
dbDataCD.emplace_back(ar, keyD, inactive);
|
dbDataCD.emplace_back(ar, keyD, blobRangeInactive);
|
||||||
|
|
||||||
RangeResult dbDataAB_CD;
|
RangeResult dbDataAB_CD;
|
||||||
dbDataAB_CD.emplace_back(ar, keyA, active);
|
dbDataAB_CD.emplace_back(ar, keyA, blobRangeActive);
|
||||||
dbDataAB_CD.emplace_back(ar, keyB, inactive);
|
dbDataAB_CD.emplace_back(ar, keyB, blobRangeInactive);
|
||||||
dbDataAB_CD.emplace_back(ar, keyC, active);
|
dbDataAB_CD.emplace_back(ar, keyC, blobRangeActive);
|
||||||
dbDataAB_CD.emplace_back(ar, keyD, inactive);
|
dbDataAB_CD.emplace_back(ar, keyD, blobRangeInactive);
|
||||||
|
|
||||||
// key ranges setup
|
// key ranges setup
|
||||||
KeyRangeRef rangeAB = KeyRangeRef(keyA, keyB);
|
KeyRangeRef rangeAB = KeyRangeRef(keyA, keyB);
|
||||||
|
|
|
@ -230,27 +230,6 @@ struct BlobGranuleCorrectnessWorkload : TestWorkload {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ACTOR Future<Void> setUpBlobRange(Database cx, KeyRange keyRange) {
|
|
||||||
state Reference<ReadYourWritesTransaction> tr = makeReference<ReadYourWritesTransaction>(cx);
|
|
||||||
loop {
|
|
||||||
try {
|
|
||||||
tr->setOption(FDBTransactionOptions::ACCESS_SYSTEM_KEYS);
|
|
||||||
tr->setOption(FDBTransactionOptions::PRIORITY_SYSTEM_IMMEDIATE);
|
|
||||||
tr->set(blobRangeChangeKey, deterministicRandom()->randomUniqueID().toString());
|
|
||||||
wait(krmSetRange(tr, blobRangeKeys.begin, keyRange, LiteralStringRef("1")));
|
|
||||||
wait(tr->commit());
|
|
||||||
if (BGW_DEBUG) {
|
|
||||||
fmt::print("Successfully set up blob granule range for tenant range [{0} - {1})\n",
|
|
||||||
keyRange.begin.printable(),
|
|
||||||
keyRange.end.printable());
|
|
||||||
}
|
|
||||||
return Void();
|
|
||||||
} catch (Error& e) {
|
|
||||||
wait(tr->onError(e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ACTOR Future<TenantMapEntry> setUpTenant(Database cx, TenantName name) {
|
ACTOR Future<TenantMapEntry> setUpTenant(Database cx, TenantName name) {
|
||||||
if (BGW_DEBUG) {
|
if (BGW_DEBUG) {
|
||||||
fmt::print("Setting up blob granule range for tenant {0}\n", name.printable());
|
fmt::print("Setting up blob granule range for tenant {0}\n", name.printable());
|
||||||
|
@ -291,7 +270,8 @@ struct BlobGranuleCorrectnessWorkload : TestWorkload {
|
||||||
self->directories[directoryIdx]->directoryRange =
|
self->directories[directoryIdx]->directoryRange =
|
||||||
KeyRangeRef(tenantEntry.prefix, tenantEntry.prefix.withSuffix(normalKeys.end));
|
KeyRangeRef(tenantEntry.prefix, tenantEntry.prefix.withSuffix(normalKeys.end));
|
||||||
tenants.push_back({ self->directories[directoryIdx]->tenantName, tenantEntry });
|
tenants.push_back({ self->directories[directoryIdx]->tenantName, tenantEntry });
|
||||||
wait(self->setUpBlobRange(cx, self->directories[directoryIdx]->directoryRange));
|
bool _success = wait(cx->blobbifyRange(self->directories[directoryIdx]->directoryRange));
|
||||||
|
ASSERT(_success);
|
||||||
}
|
}
|
||||||
tenantData.addTenants(tenants);
|
tenantData.addTenants(tenants);
|
||||||
|
|
||||||
|
@ -911,8 +891,8 @@ struct BlobGranuleCorrectnessWorkload : TestWorkload {
|
||||||
loop {
|
loop {
|
||||||
state Transaction tr(cx, threadData->tenantName);
|
state Transaction tr(cx, threadData->tenantName);
|
||||||
try {
|
try {
|
||||||
Standalone<VectorRef<KeyRangeRef>> ranges = wait(tr.getBlobGranuleRanges(normalKeys));
|
Standalone<VectorRef<KeyRangeRef>> ranges = wait(tr.getBlobGranuleRanges(normalKeys, 1000000));
|
||||||
ASSERT(ranges.size() >= 1);
|
ASSERT(ranges.size() >= 1 && ranges.size() < 1000000);
|
||||||
ASSERT(ranges.front().begin == normalKeys.begin);
|
ASSERT(ranges.front().begin == normalKeys.begin);
|
||||||
ASSERT(ranges.back().end == normalKeys.end);
|
ASSERT(ranges.back().end == normalKeys.end);
|
||||||
for (int i = 0; i < ranges.size() - 1; i++) {
|
for (int i = 0; i < ranges.size() - 1; i++) {
|
||||||
|
|
|
@ -175,7 +175,7 @@ struct BlobGranuleVerifierWorkload : TestWorkload {
|
||||||
state Transaction tr(cx);
|
state Transaction tr(cx);
|
||||||
loop {
|
loop {
|
||||||
try {
|
try {
|
||||||
Standalone<VectorRef<KeyRangeRef>> allGranules = wait(tr.getBlobGranuleRanges(normalKeys));
|
Standalone<VectorRef<KeyRangeRef>> allGranules = wait(tr.getBlobGranuleRanges(normalKeys, 1000000));
|
||||||
self->granuleRanges.set(allGranules);
|
self->granuleRanges.set(allGranules);
|
||||||
break;
|
break;
|
||||||
} catch (Error& e) {
|
} catch (Error& e) {
|
||||||
|
|
Loading…
Reference in New Issue