/* * fdbJNI.cpp * * This source file is part of the FoundationDB open source project * * Copyright 2013-2022 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. */ #include #include #include #include "com_apple_foundationdb_FDB.h" #include "com_apple_foundationdb_FDBDatabase.h" #include "com_apple_foundationdb_FDBTenant.h" #include "com_apple_foundationdb_FDBTransaction.h" #include "com_apple_foundationdb_FutureBool.h" #include "com_apple_foundationdb_FutureInt64.h" #include "com_apple_foundationdb_FutureKey.h" #include "com_apple_foundationdb_FutureKeyArray.h" #include "com_apple_foundationdb_FutureKeyRangeArray.h" #include "com_apple_foundationdb_FutureResult.h" #include "com_apple_foundationdb_FutureResults.h" #include "com_apple_foundationdb_FutureStrings.h" #include "com_apple_foundationdb_NativeFuture.h" #define FDB_API_VERSION 720 #include #define JNI_NULL nullptr #if defined(__GNUG__) #undef JNIEXPORT #define JNIEXPORT __attribute__((visibility("default"))) #endif static JavaVM* g_jvm = nullptr; static thread_local JNIEnv* g_thread_jenv = nullptr; // Defined for the network thread once it is running, and for any thread that has called registerCallback static thread_local jmethodID g_IFutureCallback_call_methodID = JNI_NULL; static thread_local bool is_external = false; static jclass range_result_summary_class; static jclass range_result_class; static jclass mapped_range_result_class; static jclass mapped_key_value_class; static jclass string_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 keyrange_init; static jmethodID keyrange_array_result_init; static jmethodID range_result_init; static jmethodID mapped_range_result_init; static jmethodID mapped_key_value_from_bytes; static jmethodID range_result_summary_init; void detachIfExternalThread(void* ignore) { if (is_external && g_thread_jenv != nullptr) { g_thread_jenv = nullptr; g_IFutureCallback_call_methodID = JNI_NULL; g_jvm->DetachCurrentThread(); } } void throwOutOfMem(JNIEnv* jenv) { const char* className = "java/lang/OutOfMemoryError"; jclass illegalArgClass = jenv->FindClass(className); if (jenv->ExceptionOccurred()) return; if (jenv->ThrowNew(illegalArgClass, nullptr) != 0) { if (!jenv->ExceptionOccurred()) { jenv->FatalError("Could not throw OutOfMemoryError"); } else { // This means that an exception is pending. We do not know what it is, but are sure // that control flow will include throwing that exception into the calling Java code. } } } static jthrowable getThrowable(JNIEnv* jenv, fdb_error_t e, const char* msg = nullptr) { jclass excepClass = jenv->FindClass("com/apple/foundationdb/FDBException"); if (jenv->ExceptionOccurred()) return JNI_NULL; jmethodID excepCtor = jenv->GetMethodID(excepClass, "", "(Ljava/lang/String;I)V"); if (jenv->ExceptionOccurred()) return JNI_NULL; const char* fdb_message = msg ? msg : fdb_get_error(e); jstring m = jenv->NewStringUTF(fdb_message); if (jenv->ExceptionOccurred()) return JNI_NULL; jthrowable t = (jthrowable)jenv->NewObject(excepClass, excepCtor, m, e); if (jenv->ExceptionOccurred()) return JNI_NULL; return t; } void throwNamedException(JNIEnv* jenv, const char* class_full_name, const char* message) { jclass exceptionClass = jenv->FindClass(class_full_name); if (jenv->ExceptionOccurred()) return; if (jenv->ThrowNew(exceptionClass, message) != 0) { if (jenv->ExceptionOccurred()) return; jenv->FatalError("FDB: Error throwing exception"); } } void throwRuntimeEx(JNIEnv* jenv, const char* message) { throwNamedException(jenv, "java/lang/RuntimeException", message); } void throwParamNotNull(JNIEnv* jenv) { throwNamedException(jenv, "java/lang/IllegalArgumentException", "Argument cannot be null"); } #ifdef __cplusplus extern "C" { #endif // If the methods are not found, exceptions are thrown and this will return false. // Returns TRUE on success, false otherwise. static bool findCallbackMethods(JNIEnv* jenv) { jclass cls = jenv->FindClass("java/lang/Runnable"); if (jenv->ExceptionOccurred()) return false; g_IFutureCallback_call_methodID = jenv->GetMethodID(cls, "run", "()V"); if (jenv->ExceptionOccurred()) return false; return true; } static void callCallback(FDBFuture* f, void* data) { if (g_thread_jenv == nullptr) { // We are on an external thread and must attach to the JVM. // The shutdown hook will later detach this thread. is_external = true; if (g_jvm != nullptr && g_jvm->AttachCurrentThreadAsDaemon((void**)&g_thread_jenv, nullptr) == JNI_OK) { if (!findCallbackMethods(g_thread_jenv)) { g_thread_jenv->FatalError("FDB: Could not find callback method.\n"); } } else { // Can't call FatalError, because we don't have a pointer to the jenv... // There will be a segmentation fault from the attempt to call the callback method. fprintf(stderr, "FDB: Could not attach external client thread to the JVM as daemon.\n"); } } jobject callback = (jobject)data; g_thread_jenv->CallVoidMethod(callback, g_IFutureCallback_call_methodID); g_thread_jenv->DeleteGlobalRef(callback); } // Attempts to throw 't', attempts to shut down the JVM if this fails. void safeThrow(JNIEnv* jenv, jthrowable t) { if (jenv->Throw(t) != 0) { jenv->FatalError("FDB: Unable to throw exception"); } } JNIEXPORT void JNICALL Java_com_apple_foundationdb_NativeFuture_Future_1registerCallback(JNIEnv* jenv, jobject cls, jlong future, jobject callback) { // SOMEDAY: Do this on module load instead. Can we cache method ids across threads? if (!g_IFutureCallback_call_methodID) { if (!findCallbackMethods(jenv)) { return; } } if (!future || !callback) { throwParamNotNull(jenv); return; } FDBFuture* f = (FDBFuture*)future; // This is documented as not throwing, but simply returning null on OOM. // As belt and suspenders, we will check for pending exceptions and then, // if there are none and the result is null, we'll throw our own OOM. callback = jenv->NewGlobalRef(callback); if (!callback) { if (!jenv->ExceptionOccurred()) throwOutOfMem(jenv); return; } // Here we cache a thread-local reference to jenv g_thread_jenv = jenv; fdb_error_t err = fdb_future_set_callback(f, &callCallback, callback); if (err) { jenv->DeleteGlobalRef(callback); safeThrow(jenv, getThrowable(jenv, err)); } } JNIEXPORT void JNICALL Java_com_apple_foundationdb_NativeFuture_Future_1blockUntilReady(JNIEnv* jenv, jobject, jlong future) { if (!future) { throwParamNotNull(jenv); return; } FDBFuture* sav = (FDBFuture*)future; fdb_error_t err = fdb_future_block_until_ready(sav); if (err) safeThrow(jenv, getThrowable(jenv, err)); } JNIEXPORT jthrowable JNICALL Java_com_apple_foundationdb_NativeFuture_Future_1getError(JNIEnv* jenv, jobject, jlong future) { if (!future) { throwParamNotNull(jenv); return JNI_NULL; } FDBFuture* sav = (FDBFuture*)future; fdb_error_t err = fdb_future_get_error(sav); if (err) return getThrowable(jenv, err); else return JNI_NULL; } JNIEXPORT jboolean JNICALL Java_com_apple_foundationdb_NativeFuture_Future_1isReady(JNIEnv* jenv, jobject, jlong future) { if (!future) { throwParamNotNull(jenv); return JNI_FALSE; } FDBFuture* var = (FDBFuture*)future; return (jboolean)fdb_future_is_ready(var); } JNIEXPORT void JNICALL Java_com_apple_foundationdb_NativeFuture_Future_1dispose(JNIEnv* jenv, jobject, jlong future) { if (!future) { throwParamNotNull(jenv); return; } FDBFuture* var = (FDBFuture*)future; fdb_future_destroy(var); } JNIEXPORT void JNICALL Java_com_apple_foundationdb_NativeFuture_Future_1cancel(JNIEnv* jenv, jobject, jlong future) { if (!future) { throwParamNotNull(jenv); return; } FDBFuture* var = (FDBFuture*)future; fdb_future_cancel(var); } JNIEXPORT void JNICALL Java_com_apple_foundationdb_NativeFuture_Future_1releaseMemory(JNIEnv* jenv, jobject, jlong future) { if (!future) { throwParamNotNull(jenv); return; } FDBFuture* var = (FDBFuture*)future; 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) { if (!future) { throwParamNotNull(jenv); return 0; } FDBFuture* f = (FDBFuture*)future; int64_t value = 0; fdb_error_t err = fdb_future_get_int64(f, &value); if (err) { safeThrow(jenv, getThrowable(jenv, err)); return 0; } return (jlong)value; } JNIEXPORT jobjectArray JNICALL Java_com_apple_foundationdb_FutureStrings_FutureStrings_1get(JNIEnv* jenv, jobject, jlong future) { if (!future) { throwParamNotNull(jenv); return JNI_NULL; } FDBFuture* f = (FDBFuture*)future; const char** strings; int count; fdb_error_t err = fdb_future_get_string_array(f, &strings, &count); if (err) { safeThrow(jenv, getThrowable(jenv, err)); return JNI_NULL; } if (jenv->ExceptionOccurred()) return JNI_NULL; jobjectArray arr = jenv->NewObjectArray(count, string_class, JNI_NULL); if (!arr) { if (!jenv->ExceptionOccurred()) throwOutOfMem(jenv); return JNI_NULL; } for (int i = 0; i < count; i++) { jstring str = jenv->NewStringUTF(strings[i]); if (!str) { if (!jenv->ExceptionOccurred()) throwOutOfMem(jenv); return JNI_NULL; } jenv->SetObjectArrayElement(arr, i, str); if (jenv->ExceptionOccurred()) return JNI_NULL; } return arr; } JNIEXPORT jobject JNICALL Java_com_apple_foundationdb_FutureKeyArray_FutureKeyArray_1get(JNIEnv* jenv, jobject, jlong future) { if (!future) { throwParamNotNull(jenv); return JNI_NULL; } FDBFuture* f = (FDBFuture*)future; const FDBKey* ks; int count; fdb_error_t err = fdb_future_get_key_array(f, &ks, &count); if (err) { safeThrow(jenv, getThrowable(jenv, err)); return JNI_NULL; } int totalKeySize = 0; for (int i = 0; i < count; i++) { totalKeySize += ks[i].key_length; } jbyteArray keyArray = jenv->NewByteArray(totalKeySize); if (!keyArray) { if (!jenv->ExceptionOccurred()) throwOutOfMem(jenv); return JNI_NULL; } uint8_t* keys_barr = (uint8_t*)jenv->GetByteArrayElements(keyArray, JNI_NULL); if (!keys_barr) { throwRuntimeEx(jenv, "Error getting handle to native resources"); return JNI_NULL; } jintArray lengthArray = jenv->NewIntArray(count); if (!lengthArray) { if (!jenv->ExceptionOccurred()) throwOutOfMem(jenv); jenv->ReleaseByteArrayElements(keyArray, (jbyte*)keys_barr, 0); return JNI_NULL; } jint* length_barr = jenv->GetIntArrayElements(lengthArray, JNI_NULL); if (!length_barr) { if (!jenv->ExceptionOccurred()) throwOutOfMem(jenv); jenv->ReleaseByteArrayElements(keyArray, (jbyte*)keys_barr, 0); return JNI_NULL; } int offset = 0; for (int i = 0; i < count; i++) { memcpy(keys_barr + offset, ks[i].key, ks[i].key_length); length_barr[i] = ks[i].key_length; offset += ks[i].key_length; } jenv->ReleaseByteArrayElements(keyArray, (jbyte*)keys_barr, 0); jenv->ReleaseIntArrayElements(lengthArray, length_barr, 0); jobject result = jenv->NewObject(key_array_result_class, key_array_result_init, keyArray, lengthArray); if (jenv->ExceptionOccurred()) return JNI_NULL; 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 JNIEXPORT jobject JNICALL Java_com_apple_foundationdb_FutureResults_FutureResults_1get(JNIEnv* jenv, jobject, jlong future) { if (!future) { throwParamNotNull(jenv); return JNI_NULL; } FDBFuture* f = (FDBFuture*)future; const FDBKeyValue* kvs; int count; fdb_bool_t more; fdb_error_t err = fdb_future_get_keyvalue_array(f, &kvs, &count, &more); if (err) { safeThrow(jenv, getThrowable(jenv, err)); return JNI_NULL; } int totalKeyValueSize = 0; for (int i = 0; i < count; i++) { totalKeyValueSize += kvs[i].key_length + kvs[i].value_length; } jbyteArray keyValueArray = jenv->NewByteArray(totalKeyValueSize); if (!keyValueArray) { if (!jenv->ExceptionOccurred()) throwOutOfMem(jenv); return JNI_NULL; } uint8_t* keyvalues_barr = (uint8_t*)jenv->GetByteArrayElements(keyValueArray, JNI_NULL); if (!keyvalues_barr) { throwRuntimeEx(jenv, "Error getting handle to native resources"); return JNI_NULL; } jintArray lengthArray = jenv->NewIntArray(count * 2); if (!lengthArray) { if (!jenv->ExceptionOccurred()) throwOutOfMem(jenv); jenv->ReleaseByteArrayElements(keyValueArray, (jbyte*)keyvalues_barr, 0); return JNI_NULL; } jint* length_barr = jenv->GetIntArrayElements(lengthArray, JNI_NULL); if (!length_barr) { if (!jenv->ExceptionOccurred()) throwOutOfMem(jenv); jenv->ReleaseByteArrayElements(keyValueArray, (jbyte*)keyvalues_barr, 0); return JNI_NULL; } int offset = 0; for (int i = 0; i < count; i++) { memcpy(keyvalues_barr + offset, kvs[i].key, kvs[i].key_length); length_barr[i * 2] = kvs[i].key_length; offset += kvs[i].key_length; memcpy(keyvalues_barr + offset, kvs[i].value, kvs[i].value_length); length_barr[(i * 2) + 1] = kvs[i].value_length; offset += kvs[i].value_length; } jenv->ReleaseByteArrayElements(keyValueArray, (jbyte*)keyvalues_barr, 0); jenv->ReleaseIntArrayElements(lengthArray, length_barr, 0); jobject result = jenv->NewObject(range_result_class, range_result_init, keyValueArray, lengthArray, (jboolean)more); if (jenv->ExceptionOccurred()) return JNI_NULL; return result; } class ExecuteOnLeave { std::function func; public: explicit ExecuteOnLeave(std::function func) : func(func) {} ~ExecuteOnLeave() { func(); } }; void cpBytesAndLengthInner(uint8_t*& pByte, jint*& pLength, const uint8_t* data, const int& length) { *pLength = length; pLength++; memcpy(pByte, data, length); pByte += length; } void cpBytesAndLength(uint8_t*& pByte, jint*& pLength, const FDBKey& key) { cpBytesAndLengthInner(pByte, pLength, key.key, key.key_length); } JNIEXPORT jobject JNICALL Java_com_apple_foundationdb_FutureMappedResults_FutureMappedResults_1get(JNIEnv* jenv, jobject, jlong future) { if (!future) { throwParamNotNull(jenv); return JNI_NULL; } FDBFuture* f = (FDBFuture*)future; const FDBMappedKeyValue* kvms; int count; fdb_bool_t more; fdb_error_t err = fdb_future_get_mappedkeyvalue_array(f, &kvms, &count, &more); if (err) { safeThrow(jenv, getThrowable(jenv, err)); return JNI_NULL; } jobjectArray mrr_values = jenv->NewObjectArray(count, mapped_key_value_class, NULL); if (!mrr_values) { if (!jenv->ExceptionOccurred()) throwOutOfMem(jenv); return JNI_NULL; } for (int i = 0; i < count; i++) { FDBMappedKeyValue kvm = kvms[i]; int kvm_count = kvm.getRange.m_size; // now it has 4 field, key, value, getRange.begin, getRange.end // this needs to change if FDBMappedKeyValue definition is changed. const int totalFieldFDBMappedKeyValue = 4; const int totalLengths = totalFieldFDBMappedKeyValue + kvm_count * 2; int totalBytes = kvm.key.key_length + kvm.value.key_length + kvm.getRange.begin.key.key_length + kvm.getRange.end.key.key_length; for (int i = 0; i < kvm_count; i++) { auto kv = kvm.getRange.data[i]; totalBytes += kv.key_length + kv.value_length; } jbyteArray bytesArray = jenv->NewByteArray(totalBytes); if (!bytesArray) { if (!jenv->ExceptionOccurred()) throwOutOfMem(jenv); return JNI_NULL; } jintArray lengthArray = jenv->NewIntArray(totalLengths); if (!lengthArray) { if (!jenv->ExceptionOccurred()) throwOutOfMem(jenv); return JNI_NULL; } uint8_t* bytes_barr = (uint8_t*)jenv->GetByteArrayElements(bytesArray, JNI_NULL); if (!bytes_barr) { throwRuntimeEx(jenv, "Error getting handle to native resources"); return JNI_NULL; } { ExecuteOnLeave e([&]() { jenv->ReleaseByteArrayElements(bytesArray, (jbyte*)bytes_barr, 0); }); jint* length_barr = jenv->GetIntArrayElements(lengthArray, JNI_NULL); if (!length_barr) { if (!jenv->ExceptionOccurred()) throwOutOfMem(jenv); return JNI_NULL; } { ExecuteOnLeave e([&]() { jenv->ReleaseIntArrayElements(lengthArray, length_barr, 0); }); uint8_t* pByte = bytes_barr; jint* pLength = length_barr; cpBytesAndLength(pByte, pLength, kvm.key); cpBytesAndLength(pByte, pLength, kvm.value); cpBytesAndLength(pByte, pLength, kvm.getRange.begin.key); cpBytesAndLength(pByte, pLength, kvm.getRange.end.key); for (int kvm_i = 0; kvm_i < kvm_count; kvm_i++) { auto kv = kvm.getRange.data[kvm_i]; cpBytesAndLengthInner(pByte, pLength, kv.key, kv.key_length); cpBytesAndLengthInner(pByte, pLength, kv.value, kv.value_length); } } } // After native arrays are released // call public static method MappedKeyValue::fromBytes() jobject mkv = jenv->CallStaticObjectMethod( mapped_key_value_class, mapped_key_value_from_bytes, (jbyteArray)bytesArray, (jintArray)lengthArray); if (jenv->ExceptionOccurred()) return JNI_NULL; jenv->SetObjectArrayElement(mrr_values, i, mkv); if (jenv->ExceptionOccurred()) return JNI_NULL; } jobject mrr = jenv->NewObject(mapped_range_result_class, mapped_range_result_init, mrr_values, (jboolean)more); if (jenv->ExceptionOccurred()) return JNI_NULL; return mrr; } // SOMEDAY: explore doing this more efficiently with Direct ByteBuffers JNIEXPORT jbyteArray JNICALL Java_com_apple_foundationdb_FutureResult_FutureResult_1get(JNIEnv* jenv, jobject, jlong future) { if (!future) { throwParamNotNull(jenv); return JNI_NULL; } FDBFuture* f = (FDBFuture*)future; fdb_bool_t present; const uint8_t* value; int length; fdb_error_t err = fdb_future_get_value(f, &present, &value, &length); if (err) { safeThrow(jenv, getThrowable(jenv, err)); return JNI_NULL; } if (!present) return JNI_NULL; jbyteArray result = jenv->NewByteArray(length); if (!result) { if (!jenv->ExceptionOccurred()) throwOutOfMem(jenv); return JNI_NULL; } jenv->SetByteArrayRegion(result, 0, length, (const jbyte*)value); return result; } JNIEXPORT jbyteArray JNICALL Java_com_apple_foundationdb_FutureKey_FutureKey_1get(JNIEnv* jenv, jobject, jlong future) { if (!future) { throwParamNotNull(jenv); return JNI_NULL; } FDBFuture* f = (FDBFuture*)future; const uint8_t* value; int length; fdb_error_t err = fdb_future_get_key(f, &value, &length); if (err) { safeThrow(jenv, getThrowable(jenv, err)); return JNI_NULL; } jbyteArray result = jenv->NewByteArray(length); if (!result) { if (!jenv->ExceptionOccurred()) throwOutOfMem(jenv); return JNI_NULL; } jenv->SetByteArrayRegion(result, 0, length, (const jbyte*)value); return result; } JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBDatabase_Database_1openTenant(JNIEnv* jenv, jobject, jlong dbPtr, jbyteArray tenantNameBytes) { if (!dbPtr || !tenantNameBytes) { throwParamNotNull(jenv); return 0; } FDBDatabase* database = (FDBDatabase*)dbPtr; FDBTenant* tenant; uint8_t* barr = (uint8_t*)jenv->GetByteArrayElements(tenantNameBytes, JNI_NULL); if (!barr) { if (!jenv->ExceptionOccurred()) throwRuntimeEx(jenv, "Error getting handle to native resources"); return 0; } fdb_error_t err = fdb_database_open_tenant(database, barr, jenv->GetArrayLength(tenantNameBytes), &tenant); if (err) { safeThrow(jenv, getThrowable(jenv, err)); return 0; } jenv->ReleaseByteArrayElements(tenantNameBytes, (jbyte*)barr, JNI_ABORT); return (jlong)tenant; } JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBDatabase_Database_1createTransaction(JNIEnv* jenv, jobject, jlong dbPtr) { if (!dbPtr) { throwParamNotNull(jenv); return 0; } FDBDatabase* database = (FDBDatabase*)dbPtr; FDBTransaction* tr; fdb_error_t err = fdb_database_create_transaction(database, &tr); if (err) { safeThrow(jenv, getThrowable(jenv, err)); return 0; } return (jlong)tr; } JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDBDatabase_Database_1dispose(JNIEnv* jenv, jobject, jlong dPtr) { if (!dPtr) { throwParamNotNull(jenv); return; } fdb_database_destroy((FDBDatabase*)dPtr); } JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDBDatabase_Database_1setOption(JNIEnv* jenv, jobject, jlong dPtr, jint code, jbyteArray value) { if (!dPtr) { throwParamNotNull(jenv); return; } FDBDatabase* c = (FDBDatabase*)dPtr; uint8_t* barr = nullptr; int size = 0; if (value != JNI_NULL) { barr = (uint8_t*)jenv->GetByteArrayElements(value, JNI_NULL); if (!barr) { throwRuntimeEx(jenv, "Error getting handle to native resources"); return; } size = jenv->GetArrayLength(value); } fdb_error_t err = fdb_database_set_option(c, (FDBDatabaseOption)code, barr, size); if (value != JNI_NULL) jenv->ReleaseByteArrayElements(value, (jbyte*)barr, JNI_ABORT); if (err) { safeThrow(jenv, getThrowable(jenv, err)); } } // Get network thread busyness (updated every 1s) // A value of 0 indicates that the client is more or less idle // A value of 1 (or more) indicates that the client is saturated JNIEXPORT jdouble JNICALL Java_com_apple_foundationdb_FDBDatabase_Database_1getMainThreadBusyness(JNIEnv* jenv, jobject, jlong dbPtr) { if (!dbPtr) { throwParamNotNull(jenv); return 0; } FDBDatabase* database = (FDBDatabase*)dbPtr; return (jdouble)fdb_database_get_main_thread_busyness(database); } JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBDatabase_Database_1purgeBlobGranules(JNIEnv* jenv, jobject, jlong dbPtr, jbyteArray beginKeyBytes, jbyteArray endKeyBytes, jlong purgeVersion, jboolean force) { 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_purge_blob_granules(database, beginKeyArr, jenv->GetArrayLength(beginKeyBytes), endKeyArr, jenv->GetArrayLength(endKeyBytes), purgeVersion, (fdb_bool_t)force); 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_1waitPurgeGranulesComplete(JNIEnv* jenv, jobject, jlong dbPtr, jbyteArray purgeKeyBytes) { if (!dbPtr || !purgeKeyBytes) { throwParamNotNull(jenv); return 0; } FDBDatabase* database = (FDBDatabase*)dbPtr; uint8_t* purgeKeyArr = (uint8_t*)jenv->GetByteArrayElements(purgeKeyBytes, JNI_NULL); if (!purgeKeyArr) { if (!jenv->ExceptionOccurred()) throwRuntimeEx(jenv, "Error getting handle to native resources"); return 0; } FDBFuture* f = fdb_database_wait_purge_granules_complete(database, purgeKeyArr, jenv->GetArrayLength(purgeKeyBytes)); jenv->ReleaseByteArrayElements(purgeKeyBytes, (jbyte*)purgeKeyArr, JNI_ABORT); 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_verify_blob_range( 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, jobject, jint predicate, jint code) { return (jboolean)fdb_error_predicate(predicate, code); } JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDB_Database_1create(JNIEnv* jenv, jobject, jstring clusterFileName) { const char* fileName = nullptr; if (clusterFileName != JNI_NULL) { fileName = jenv->GetStringUTFChars(clusterFileName, JNI_NULL); if (jenv->ExceptionOccurred()) { return 0; } } FDBDatabase* db; fdb_error_t err = fdb_create_database(fileName, &db); if (clusterFileName != JNI_NULL) { jenv->ReleaseStringUTFChars(clusterFileName, fileName); } if (err) { safeThrow(jenv, getThrowable(jenv, err)); return 0; } return (jlong)db; } JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBTenant_Tenant_1createTransaction(JNIEnv* jenv, jobject, jlong tPtr) { if (!tPtr) { throwParamNotNull(jenv); return 0; } FDBTenant* tenant = (FDBTenant*)tPtr; FDBTransaction* tr; fdb_error_t err = fdb_tenant_create_transaction(tenant, &tr); if (err) { safeThrow(jenv, getThrowable(jenv, err)); return 0; } return (jlong)tr; } JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDBTenant_Tenant_1dispose(JNIEnv* jenv, jobject, jlong tPtr) { if (!tPtr) { throwParamNotNull(jenv); return; } fdb_tenant_destroy((FDBTenant*)tPtr); } JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBTenant_Tenant_1purgeBlobGranules(JNIEnv* jenv, jobject, jlong tPtr, jbyteArray beginKeyBytes, jbyteArray endKeyBytes, jlong purgeVersion, jboolean force) { if (!tPtr || !beginKeyBytes || !endKeyBytes) { throwParamNotNull(jenv); return 0; } FDBTenant* tenant = (FDBTenant*)tPtr; 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_tenant_purge_blob_granules(tenant, beginKeyArr, jenv->GetArrayLength(beginKeyBytes), endKeyArr, jenv->GetArrayLength(endKeyBytes), purgeVersion, (fdb_bool_t)force); jenv->ReleaseByteArrayElements(beginKeyBytes, (jbyte*)beginKeyArr, JNI_ABORT); jenv->ReleaseByteArrayElements(endKeyBytes, (jbyte*)endKeyArr, JNI_ABORT); return (jlong)f; } JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBTenant_Tenant_1waitPurgeGranulesComplete(JNIEnv* jenv, jobject, jlong tPtr, jbyteArray purgeKeyBytes) { if (!tPtr || !purgeKeyBytes) { throwParamNotNull(jenv); return 0; } FDBTenant* tenant = (FDBTenant*)tPtr; uint8_t* purgeKeyArr = (uint8_t*)jenv->GetByteArrayElements(purgeKeyBytes, JNI_NULL); if (!purgeKeyArr) { if (!jenv->ExceptionOccurred()) throwRuntimeEx(jenv, "Error getting handle to native resources"); return 0; } FDBFuture* f = fdb_tenant_wait_purge_granules_complete(tenant, purgeKeyArr, jenv->GetArrayLength(purgeKeyBytes)); jenv->ReleaseByteArrayElements(purgeKeyBytes, (jbyte*)purgeKeyArr, JNI_ABORT); return (jlong)f; } JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBTenant_Tenant_1blobbifyRange(JNIEnv* jenv, jobject, jlong tPtr, jbyteArray beginKeyBytes, jbyteArray endKeyBytes) { if (!tPtr || !beginKeyBytes || !endKeyBytes) { throwParamNotNull(jenv); return 0; } FDBTenant* tenant = (FDBTenant*)tPtr; 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_tenant_blobbify_range( tenant, 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_FDBTenant_Tenant_1unblobbifyRange(JNIEnv* jenv, jobject, jlong tPtr, jbyteArray beginKeyBytes, jbyteArray endKeyBytes) { if (!tPtr || !beginKeyBytes || !endKeyBytes) { throwParamNotNull(jenv); return 0; } FDBTenant* tenant = (FDBTenant*)tPtr; 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_tenant_unblobbify_range( tenant, 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_FDBTenant_Tenant_1listBlobbifiedRanges(JNIEnv* jenv, jobject, jlong tPtr, jbyteArray beginKeyBytes, jbyteArray endKeyBytes, jint rangeLimit) { if (!tPtr || !beginKeyBytes || !endKeyBytes) { throwParamNotNull(jenv); return 0; } FDBTenant* tenant = (FDBTenant*)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_tenant_list_blobbified_ranges( tenant, 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_FDBTenant_Tenant_1verifyBlobRange(JNIEnv* jenv, jobject, jlong tPtr, jbyteArray beginKeyBytes, jbyteArray endKeyBytes, jlong version) { if (!tPtr || !beginKeyBytes || !endKeyBytes) { throwParamNotNull(jenv); return 0; } FDBTenant* tenant = (FDBTenant*)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_tenant_verify_blob_range( tenant, 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 jlong JNICALL Java_com_apple_foundationdb_FDBTenant_Tenant_1getId(JNIEnv* jenv, jobject, jlong tPtr) { if (!tPtr) { throwParamNotNull(jenv); return 0; } FDBTenant* tenant = (FDBTenant*)tPtr; FDBFuture* f = fdb_tenant_get_id(tenant); return (jlong)f; } JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1setVersion(JNIEnv* jenv, jobject, jlong tPtr, jlong version) { if (!tPtr) { throwParamNotNull(jenv); return; } FDBTransaction* tr = (FDBTransaction*)tPtr; fdb_transaction_set_read_version(tr, version); } JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1getReadVersion(JNIEnv* jenv, jobject, jlong tPtr) { if (!tPtr) { throwParamNotNull(jenv); return 0; } FDBTransaction* tr = (FDBTransaction*)tPtr; FDBFuture* f = fdb_transaction_get_read_version(tr); return (jlong)f; } JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1get(JNIEnv* jenv, jobject, jlong tPtr, jbyteArray keyBytes, jboolean snapshot) { if (!tPtr || !keyBytes) { throwParamNotNull(jenv); return 0; } FDBTransaction* tr = (FDBTransaction*)tPtr; uint8_t* barr = (uint8_t*)jenv->GetByteArrayElements(keyBytes, JNI_NULL); if (!barr) { if (!jenv->ExceptionOccurred()) throwRuntimeEx(jenv, "Error getting handle to native resources"); return 0; } FDBFuture* f = fdb_transaction_get(tr, barr, jenv->GetArrayLength(keyBytes), (fdb_bool_t)snapshot); jenv->ReleaseByteArrayElements(keyBytes, (jbyte*)barr, JNI_ABORT); return (jlong)f; } JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1getKey(JNIEnv* jenv, jobject, jlong tPtr, jbyteArray keyBytes, jboolean orEqual, jint offset, jboolean snapshot) { if (!tPtr || !keyBytes) { throwParamNotNull(jenv); return 0; } FDBTransaction* tr = (FDBTransaction*)tPtr; uint8_t* barr = (uint8_t*)jenv->GetByteArrayElements(keyBytes, JNI_NULL); if (!barr) { if (!jenv->ExceptionOccurred()) throwRuntimeEx(jenv, "Error getting handle to native resources"); return 0; } FDBFuture* f = fdb_transaction_get_key(tr, barr, jenv->GetArrayLength(keyBytes), orEqual, offset, (fdb_bool_t)snapshot); jenv->ReleaseByteArrayElements(keyBytes, (jbyte*)barr, JNI_ABORT); return (jlong)f; } JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1getRange(JNIEnv* jenv, jobject, jlong tPtr, jbyteArray keyBeginBytes, jboolean orEqualBegin, jint offsetBegin, jbyteArray keyEndBytes, jboolean orEqualEnd, jint offsetEnd, jint rowLimit, jint targetBytes, jint streamingMode, jint iteration, jboolean snapshot, jboolean reverse) { if (!tPtr || !keyBeginBytes || !keyEndBytes) { throwParamNotNull(jenv); return 0; } FDBTransaction* tr = (FDBTransaction*)tPtr; uint8_t* barrBegin = (uint8_t*)jenv->GetByteArrayElements(keyBeginBytes, JNI_NULL); if (!barrBegin) { if (!jenv->ExceptionOccurred()) throwRuntimeEx(jenv, "Error getting handle to native resources"); return 0; } uint8_t* barrEnd = (uint8_t*)jenv->GetByteArrayElements(keyEndBytes, JNI_NULL); if (!barrEnd) { jenv->ReleaseByteArrayElements(keyBeginBytes, (jbyte*)barrBegin, JNI_ABORT); if (!jenv->ExceptionOccurred()) throwRuntimeEx(jenv, "Error getting handle to native resources"); return 0; } FDBFuture* f = fdb_transaction_get_range(tr, barrBegin, jenv->GetArrayLength(keyBeginBytes), orEqualBegin, offsetBegin, barrEnd, jenv->GetArrayLength(keyEndBytes), orEqualEnd, offsetEnd, rowLimit, targetBytes, (FDBStreamingMode)streamingMode, iteration, snapshot, reverse); jenv->ReleaseByteArrayElements(keyBeginBytes, (jbyte*)barrBegin, JNI_ABORT); jenv->ReleaseByteArrayElements(keyEndBytes, (jbyte*)barrEnd, JNI_ABORT); return (jlong)f; } JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1getMappedRange(JNIEnv* jenv, jobject, jlong tPtr, jbyteArray keyBeginBytes, jboolean orEqualBegin, jint offsetBegin, jbyteArray keyEndBytes, jboolean orEqualEnd, jint offsetEnd, jbyteArray mapperBytes, jint rowLimit, jint targetBytes, jint streamingMode, jint iteration, jint matchIndex, jboolean snapshot, jboolean reverse) { if (!tPtr || !keyBeginBytes || !keyEndBytes || !mapperBytes) { throwParamNotNull(jenv); return 0; } FDBTransaction* tr = (FDBTransaction*)tPtr; uint8_t* barrBegin = (uint8_t*)jenv->GetByteArrayElements(keyBeginBytes, JNI_NULL); if (!barrBegin) { if (!jenv->ExceptionOccurred()) throwRuntimeEx(jenv, "Error getting handle to native resources"); return 0; } uint8_t* barrEnd = (uint8_t*)jenv->GetByteArrayElements(keyEndBytes, JNI_NULL); if (!barrEnd) { jenv->ReleaseByteArrayElements(keyBeginBytes, (jbyte*)barrBegin, JNI_ABORT); if (!jenv->ExceptionOccurred()) throwRuntimeEx(jenv, "Error getting handle to native resources"); return 0; } uint8_t* barrMapper = (uint8_t*)jenv->GetByteArrayElements(mapperBytes, JNI_NULL); if (!barrMapper) { jenv->ReleaseByteArrayElements(keyBeginBytes, (jbyte*)barrBegin, JNI_ABORT); jenv->ReleaseByteArrayElements(keyEndBytes, (jbyte*)barrEnd, JNI_ABORT); if (!jenv->ExceptionOccurred()) throwRuntimeEx(jenv, "Error getting handle to native resources"); return 0; } FDBFuture* f = fdb_transaction_get_mapped_range(tr, barrBegin, jenv->GetArrayLength(keyBeginBytes), orEqualBegin, offsetBegin, barrEnd, jenv->GetArrayLength(keyEndBytes), orEqualEnd, offsetEnd, barrMapper, jenv->GetArrayLength(mapperBytes), rowLimit, targetBytes, (FDBStreamingMode)streamingMode, iteration, matchIndex, snapshot, reverse); jenv->ReleaseByteArrayElements(keyBeginBytes, (jbyte*)barrBegin, JNI_ABORT); jenv->ReleaseByteArrayElements(keyEndBytes, (jbyte*)barrEnd, JNI_ABORT); jenv->ReleaseByteArrayElements(mapperBytes, (jbyte*)barrMapper, JNI_ABORT); return (jlong)f; } JNIEXPORT void JNICALL Java_com_apple_foundationdb_FutureResults_FutureResults_1getDirect(JNIEnv* jenv, jobject, jlong future, jobject jbuffer, jint bufferCapacity) { if (!future) { throwParamNotNull(jenv); return; } uint8_t* buffer = (uint8_t*)jenv->GetDirectBufferAddress(jbuffer); if (!buffer) { if (!jenv->ExceptionOccurred()) throwRuntimeEx(jenv, "Error getting handle to native resources"); return; } FDBFuture* f = (FDBFuture*)future; const FDBKeyValue* kvs; int count; fdb_bool_t more; fdb_error_t err = fdb_future_get_keyvalue_array(f, &kvs, &count, &more); if (err) { safeThrow(jenv, getThrowable(jenv, err)); return; } // Capacity for Metadata+Keys+Values // => sizeof(jint) for total key/value pairs // => sizeof(jint) to store more flag // => sizeof(jint) to store key length per KV pair // => sizeof(jint) to store value length per KV pair int totalCapacityNeeded = 2 * sizeof(jint); for (int i = 0; i < count; i++) { totalCapacityNeeded += kvs[i].key_length + kvs[i].value_length + 2 * sizeof(jint); if (bufferCapacity < totalCapacityNeeded) { count = i; /* Only fit first `i` K/V pairs */ more = true; break; } } int offset = 0; // First copy RangeResultSummary, i.e. [keyCount, more] memcpy(buffer + offset, &count, sizeof(jint)); offset += sizeof(jint); memcpy(buffer + offset, &more, sizeof(jint)); offset += sizeof(jint); for (int i = 0; i < count; i++) { memcpy(buffer + offset, &kvs[i].key_length, sizeof(jint)); memcpy(buffer + offset + sizeof(jint), &kvs[i].value_length, sizeof(jint)); offset += 2 * sizeof(jint); memcpy(buffer + offset, kvs[i].key, kvs[i].key_length); offset += kvs[i].key_length; memcpy(buffer + offset, kvs[i].value, kvs[i].value_length); offset += kvs[i].value_length; } } void memcpyStringInner(uint8_t* buffer, int& offset, const uint8_t* data, const int& length) { memcpy(buffer + offset, &length, sizeof(jint)); offset += sizeof(jint); memcpy(buffer + offset, data, length); offset += length; } void memcpyString(uint8_t* buffer, int& offset, const FDBKey& key) { memcpyStringInner(buffer, offset, key.key, key.key_length); } JNIEXPORT void JNICALL Java_com_apple_foundationdb_FutureMappedResults_FutureMappedResults_1getDirect(JNIEnv* jenv, jobject, jlong future, jobject jbuffer, jint bufferCapacity) { if (!future) { throwParamNotNull(jenv); return; } uint8_t* buffer = (uint8_t*)jenv->GetDirectBufferAddress(jbuffer); if (!buffer) { if (!jenv->ExceptionOccurred()) throwRuntimeEx(jenv, "Error getting handle to native resources"); return; } FDBFuture* f = (FDBFuture*)future; const FDBMappedKeyValue* kvms; int count; fdb_bool_t more; fdb_error_t err = fdb_future_get_mappedkeyvalue_array(f, &kvms, &count, &more); if (err) { safeThrow(jenv, getThrowable(jenv, err)); return; } int totalCapacityNeeded = 2 * sizeof(jint); for (int i = 0; i < count; i++) { const FDBMappedKeyValue& kvm = kvms[i]; totalCapacityNeeded += kvm.key.key_length + kvm.value.key_length + kvm.getRange.begin.key.key_length + kvm.getRange.end.key.key_length + 5 * sizeof(jint); // Besides the 4 lengths above, also one for kvm_count. int kvm_count = kvm.getRange.m_size; for (int i = 0; i < kvm_count; i++) { auto kv = kvm.getRange.data[i]; totalCapacityNeeded += kv.key_length + kv.value_length + 2 * sizeof(jint); } if (bufferCapacity < totalCapacityNeeded) { count = i; /* Only fit first `i` K/V pairs */ more = true; break; } } int offset = 0; // First copy RangeResultSummary, i.e. [keyCount, more] memcpy(buffer + offset, &count, sizeof(jint)); offset += sizeof(jint); memcpy(buffer + offset, &more, sizeof(jint)); offset += sizeof(jint); for (int i = 0; i < count; i++) { const FDBMappedKeyValue& kvm = kvms[i]; memcpyString(buffer, offset, kvm.key); memcpyString(buffer, offset, kvm.value); memcpyString(buffer, offset, kvm.getRange.begin.key); memcpyString(buffer, offset, kvm.getRange.end.key); int kvm_count = kvm.getRange.m_size; memcpy(buffer + offset, &kvm_count, sizeof(jint)); offset += sizeof(jint); for (int i = 0; i < kvm_count; i++) { auto kv = kvm.getRange.data[i]; memcpyStringInner(buffer, offset, kv.key, kv.key_length); memcpyStringInner(buffer, offset, kv.value, kv.value_length); } } } JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1getEstimatedRangeSizeBytes(JNIEnv* jenv, jobject, jlong tPtr, jbyteArray beginKeyBytes, jbyteArray endKeyBytes) { if (!tPtr || !beginKeyBytes || !endKeyBytes) { 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_estimated_range_size_bytes( tr, startKey, jenv->GetArrayLength(beginKeyBytes), endKey, jenv->GetArrayLength(endKeyBytes)); jenv->ReleaseByteArrayElements(beginKeyBytes, (jbyte*)startKey, JNI_ABORT); jenv->ReleaseByteArrayElements(endKeyBytes, (jbyte*)endKey, JNI_ABORT); return (jlong)f; } JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1getRangeSplitPoints(JNIEnv* jenv, jobject, jlong tPtr, jbyteArray beginKeyBytes, jbyteArray endKeyBytes, jlong chunkSize) { if (!tPtr || !beginKeyBytes || !endKeyBytes) { 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_range_split_points( tr, startKey, jenv->GetArrayLength(beginKeyBytes), endKey, jenv->GetArrayLength(endKeyBytes), chunkSize); jenv->ReleaseByteArrayElements(beginKeyBytes, (jbyte*)startKey, JNI_ABORT); jenv->ReleaseByteArrayElements(endKeyBytes, (jbyte*)endKey, JNI_ABORT); 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, jobject, jlong tPtr, jbyteArray keyBytes, jbyteArray valueBytes) { if (!tPtr || !keyBytes || !valueBytes) { throwParamNotNull(jenv); return; } FDBTransaction* tr = (FDBTransaction*)tPtr; uint8_t* barrKey = (uint8_t*)jenv->GetByteArrayElements(keyBytes, JNI_NULL); if (!barrKey) { if (!jenv->ExceptionOccurred()) throwRuntimeEx(jenv, "Error getting handle to native resources"); return; } uint8_t* barrValue = (uint8_t*)jenv->GetByteArrayElements(valueBytes, JNI_NULL); if (!barrValue) { jenv->ReleaseByteArrayElements(keyBytes, (jbyte*)barrKey, JNI_ABORT); if (!jenv->ExceptionOccurred()) throwRuntimeEx(jenv, "Error getting handle to native resources"); return; } fdb_transaction_set(tr, barrKey, jenv->GetArrayLength(keyBytes), barrValue, jenv->GetArrayLength(valueBytes)); jenv->ReleaseByteArrayElements(keyBytes, (jbyte*)barrKey, JNI_ABORT); jenv->ReleaseByteArrayElements(valueBytes, (jbyte*)barrValue, JNI_ABORT); } JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1clear__J_3B(JNIEnv* jenv, jobject, jlong tPtr, jbyteArray keyBytes) { if (!tPtr || !keyBytes) { throwParamNotNull(jenv); return; } FDBTransaction* tr = (FDBTransaction*)tPtr; uint8_t* barr = (uint8_t*)jenv->GetByteArrayElements(keyBytes, JNI_NULL); if (!barr) { if (!jenv->ExceptionOccurred()) throwRuntimeEx(jenv, "Error getting handle to native resources"); return; } fdb_transaction_clear(tr, barr, jenv->GetArrayLength(keyBytes)); jenv->ReleaseByteArrayElements(keyBytes, (jbyte*)barr, JNI_ABORT); } JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1clear__J_3B_3B(JNIEnv* jenv, jobject, jlong tPtr, jbyteArray keyBeginBytes, jbyteArray keyEndBytes) { if (!tPtr || !keyBeginBytes || !keyEndBytes) { throwParamNotNull(jenv); return; } FDBTransaction* tr = (FDBTransaction*)tPtr; uint8_t* barrKeyBegin = (uint8_t*)jenv->GetByteArrayElements(keyBeginBytes, JNI_NULL); if (!barrKeyBegin) { if (!jenv->ExceptionOccurred()) throwRuntimeEx(jenv, "Error getting handle to native resources"); return; } uint8_t* barrKeyEnd = (uint8_t*)jenv->GetByteArrayElements(keyEndBytes, JNI_NULL); if (!barrKeyEnd) { jenv->ReleaseByteArrayElements(keyBeginBytes, (jbyte*)barrKeyBegin, JNI_ABORT); if (!jenv->ExceptionOccurred()) throwRuntimeEx(jenv, "Error getting handle to native resources"); return; } fdb_transaction_clear_range( tr, barrKeyBegin, jenv->GetArrayLength(keyBeginBytes), barrKeyEnd, jenv->GetArrayLength(keyEndBytes)); jenv->ReleaseByteArrayElements(keyBeginBytes, (jbyte*)barrKeyBegin, JNI_ABORT); jenv->ReleaseByteArrayElements(keyEndBytes, (jbyte*)barrKeyEnd, JNI_ABORT); } JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1mutate(JNIEnv* jenv, jobject, jlong tPtr, jint code, jbyteArray key, jbyteArray value) { if (!tPtr || !key || !value) { throwParamNotNull(jenv); return; } FDBTransaction* tr = (FDBTransaction*)tPtr; uint8_t* barrKey = (uint8_t*)jenv->GetByteArrayElements(key, JNI_NULL); if (!barrKey) { if (!jenv->ExceptionOccurred()) throwRuntimeEx(jenv, "Error getting handle to native resources"); return; } uint8_t* barrValue = (uint8_t*)jenv->GetByteArrayElements(value, JNI_NULL); if (!barrValue) { jenv->ReleaseByteArrayElements(key, (jbyte*)barrKey, JNI_ABORT); if (!jenv->ExceptionOccurred()) throwRuntimeEx(jenv, "Error getting handle to native resources"); return; } fdb_transaction_atomic_op( tr, barrKey, jenv->GetArrayLength(key), barrValue, jenv->GetArrayLength(value), (FDBMutationType)code); jenv->ReleaseByteArrayElements(key, (jbyte*)barrKey, JNI_ABORT); jenv->ReleaseByteArrayElements(value, (jbyte*)barrValue, JNI_ABORT); } JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1commit(JNIEnv* jenv, jobject, jlong tPtr) { if (!tPtr) { throwParamNotNull(jenv); return 0; } FDBTransaction* tr = (FDBTransaction*)tPtr; FDBFuture* f = fdb_transaction_commit(tr); return (jlong)f; } JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1setOption(JNIEnv* jenv, jobject, jlong tPtr, jint code, jbyteArray value) { if (!tPtr) { throwParamNotNull(jenv); return; } FDBTransaction* tr = (FDBTransaction*)tPtr; uint8_t* barr = nullptr; int size = 0; if (value != JNI_NULL) { barr = (uint8_t*)jenv->GetByteArrayElements(value, JNI_NULL); if (!barr) { if (!jenv->ExceptionOccurred()) throwRuntimeEx(jenv, "Error getting handle to native resources"); return; } size = jenv->GetArrayLength(value); } fdb_error_t err = fdb_transaction_set_option(tr, (FDBTransactionOption)code, barr, size); if (value != JNI_NULL) jenv->ReleaseByteArrayElements(value, (jbyte*)barr, JNI_ABORT); if (err) { safeThrow(jenv, getThrowable(jenv, err)); } } JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1getCommittedVersion(JNIEnv* jenv, jobject, jlong tPtr) { if (!tPtr) { throwParamNotNull(jenv); return 0; } FDBTransaction* tr = (FDBTransaction*)tPtr; int64_t version; fdb_error_t err = fdb_transaction_get_committed_version(tr, &version); if (err) { safeThrow(jenv, getThrowable(jenv, err)); return 0; } return (jlong)version; } JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1getApproximateSize(JNIEnv* jenv, jobject, jlong tPtr) { if (!tPtr) { throwParamNotNull(jenv); return 0; } FDBFuture* f = fdb_transaction_get_approximate_size((FDBTransaction*)tPtr); return (jlong)f; } JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1getVersionstamp(JNIEnv* jenv, jobject, jlong tPtr) { if (!tPtr) { throwParamNotNull(jenv); return 0; } FDBTransaction* tr = (FDBTransaction*)tPtr; FDBFuture* f = fdb_transaction_get_versionstamp(tr); return (jlong)f; } JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1getKeyLocations(JNIEnv* jenv, jobject, jlong tPtr, jbyteArray key) { if (!tPtr || !key) { throwParamNotNull(jenv); return 0; } FDBTransaction* tr = (FDBTransaction*)tPtr; uint8_t* barr = (uint8_t*)jenv->GetByteArrayElements(key, JNI_NULL); if (!barr) { if (!jenv->ExceptionOccurred()) throwRuntimeEx(jenv, "Error getting handle to native resources"); return 0; } int size = jenv->GetArrayLength(key); FDBFuture* f = fdb_transaction_get_addresses_for_key(tr, barr, size); jenv->ReleaseByteArrayElements(key, (jbyte*)barr, JNI_ABORT); return (jlong)f; } JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1onError(JNIEnv* jenv, jobject, jlong tPtr, jint errorCode) { if (!tPtr) { throwParamNotNull(jenv); return 0; } FDBTransaction* tr = (FDBTransaction*)tPtr; FDBFuture* f = fdb_transaction_on_error(tr, (fdb_error_t)errorCode); return (jlong)f; } JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1dispose(JNIEnv* jenv, jobject, jlong tPtr) { if (!tPtr) { throwParamNotNull(jenv); return; } fdb_transaction_destroy((FDBTransaction*)tPtr); } JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1reset(JNIEnv* jenv, jobject, jlong tPtr) { if (!tPtr) { throwParamNotNull(jenv); return; } fdb_transaction_reset((FDBTransaction*)tPtr); } JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1watch(JNIEnv* jenv, jobject, jlong tPtr, jbyteArray key) { if (!tPtr || !key) { throwParamNotNull(jenv); return 0; } FDBTransaction* tr = (FDBTransaction*)tPtr; uint8_t* barr = (uint8_t*)jenv->GetByteArrayElements(key, JNI_NULL); if (!barr) { if (!jenv->ExceptionOccurred()) throwRuntimeEx(jenv, "Error getting handle to native resources"); return 0; } int size = jenv->GetArrayLength(key); FDBFuture* f = fdb_transaction_watch(tr, barr, size); jenv->ReleaseByteArrayElements(key, (jbyte*)barr, JNI_ABORT); return (jlong)f; } JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1cancel(JNIEnv* jenv, jobject, jlong tPtr) { if (!tPtr) { throwParamNotNull(jenv); return; } fdb_transaction_cancel((FDBTransaction*)tPtr); } JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1addConflictRange(JNIEnv* jenv, jobject, jlong tPtr, jbyteArray keyBegin, jbyteArray keyEnd, jint conflictType) { if (!tPtr || !keyBegin || !keyEnd) { throwParamNotNull(jenv); return; } FDBTransaction* tr = (FDBTransaction*)tPtr; uint8_t* begin_barr = (uint8_t*)jenv->GetByteArrayElements(keyBegin, JNI_NULL); if (!begin_barr) { if (!jenv->ExceptionOccurred()) throwRuntimeEx(jenv, "Error getting handle to native resources"); return; } int begin_size = jenv->GetArrayLength(keyBegin); uint8_t* end_barr = (uint8_t*)jenv->GetByteArrayElements(keyEnd, JNI_NULL); if (!end_barr) { jenv->ReleaseByteArrayElements(keyBegin, (jbyte*)begin_barr, JNI_ABORT); if (!jenv->ExceptionOccurred()) throwRuntimeEx(jenv, "Error getting handle to native resources"); return; } int end_size = jenv->GetArrayLength(keyEnd); fdb_error_t err = fdb_transaction_add_conflict_range( tr, begin_barr, begin_size, end_barr, end_size, (FDBConflictRangeType)conflictType); jenv->ReleaseByteArrayElements(keyBegin, (jbyte*)begin_barr, JNI_ABORT); jenv->ReleaseByteArrayElements(keyEnd, (jbyte*)end_barr, JNI_ABORT); if (err) { safeThrow(jenv, getThrowable(jenv, err)); } } JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDB_Select_1API_1version(JNIEnv* jenv, jclass, jint version) { fdb_error_t err = fdb_select_api_version((int)version); if (err) { if (err == 2203) { int maxSupportedVersion = fdb_get_max_api_version(); char errorStr[1024]; if (FDB_API_VERSION > maxSupportedVersion) { snprintf(errorStr, sizeof(errorStr), "This version of the FoundationDB Java binding is not supported by the installed " "FoundationDB C library. The binding requires a library that supports API version " "%d, but the installed library supports a maximum version of %d.", FDB_API_VERSION, maxSupportedVersion); } else { snprintf(errorStr, sizeof(errorStr), "API version %d is not supported by the installed FoundationDB C library.", version); } safeThrow(jenv, getThrowable(jenv, err, errorStr)); } else { safeThrow(jenv, getThrowable(jenv, err)); } } } JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDB_Network_1setOption(JNIEnv* jenv, jobject, jint code, jbyteArray value) { uint8_t* barr = nullptr; int size = 0; if (value != JNI_NULL) { barr = (uint8_t*)jenv->GetByteArrayElements(value, JNI_NULL); if (!barr) { if (!jenv->ExceptionOccurred()) throwRuntimeEx(jenv, "Error getting handle to native resources"); return; } size = jenv->GetArrayLength(value); } fdb_error_t err = fdb_network_set_option((FDBNetworkOption)code, barr, size); if (value != JNI_NULL) jenv->ReleaseByteArrayElements(value, (jbyte*)barr, JNI_ABORT); if (err) { safeThrow(jenv, getThrowable(jenv, err)); } } JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDB_Network_1setup(JNIEnv* jenv, jobject) { fdb_error_t err = fdb_setup_network(); if (err) { safeThrow(jenv, getThrowable(jenv, err)); } } JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDB_Network_1run(JNIEnv* jenv, jobject) { // initialize things for the callbacks on the network thread g_thread_jenv = jenv; if (!g_IFutureCallback_call_methodID) { if (!findCallbackMethods(jenv)) return; } fdb_error_t hookErr = fdb_add_network_thread_completion_hook(&detachIfExternalThread, nullptr); if (hookErr) { safeThrow(jenv, getThrowable(jenv, hookErr)); } fdb_error_t err = fdb_run_network(); if (err) { safeThrow(jenv, getThrowable(jenv, err)); } } JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDB_Network_1stop(JNIEnv* jenv, jobject) { fdb_error_t err = fdb_stop_network(); if (err) { safeThrow(jenv, getThrowable(jenv, err)); } } jint JNI_OnLoad(JavaVM* vm, void* reserved) { JNIEnv* env; g_jvm = vm; if (vm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK) { return JNI_ERR; } else { jclass local_range_result_class = env->FindClass("com/apple/foundationdb/RangeResult"); range_result_init = env->GetMethodID(local_range_result_class, "", "([B[IZ)V"); range_result_class = (jclass)(env)->NewGlobalRef(local_range_result_class); jclass local_mapped_range_result_class = env->FindClass("com/apple/foundationdb/MappedRangeResult"); mapped_range_result_init = env->GetMethodID(local_mapped_range_result_class, "", "([Lcom/apple/foundationdb/MappedKeyValue;Z)V"); mapped_range_result_class = (jclass)(env)->NewGlobalRef(local_mapped_range_result_class); jclass local_mapped_key_value_class = env->FindClass("com/apple/foundationdb/MappedKeyValue"); mapped_key_value_from_bytes = env->GetStaticMethodID( local_mapped_key_value_class, "fromBytes", "([B[I)Lcom/apple/foundationdb/MappedKeyValue;"); mapped_key_value_class = (jclass)(env)->NewGlobalRef(local_mapped_key_value_class); jclass local_key_array_result_class = env->FindClass("com/apple/foundationdb/KeyArrayResult"); key_array_result_init = env->GetMethodID(local_key_array_result_class, "", "([B[I)V"); 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, "", "([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, "", "([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"); range_result_summary_init = env->GetMethodID(local_range_result_summary_class, "", "([BIZ)V"); range_result_summary_class = (jclass)(env)->NewGlobalRef(local_range_result_summary_class); jclass local_string_class = env->FindClass("java/lang/String"); string_class = (jclass)(env)->NewGlobalRef(local_string_class); return JNI_VERSION_1_6; } } // Is automatically called once the Classloader is destroyed void JNI_OnUnload(JavaVM* vm, void* reserved) { JNIEnv* env; if (vm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK) { return; } else { // delete global references so the GC can collect them if (range_result_summary_class != JNI_NULL) { env->DeleteGlobalRef(range_result_summary_class); } if (range_result_class != JNI_NULL) { 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) { env->DeleteGlobalRef(mapped_range_result_class); } if (mapped_key_value_class != JNI_NULL) { env->DeleteGlobalRef(mapped_key_value_class); } if (string_class != JNI_NULL) { env->DeleteGlobalRef(string_class); } } } #ifdef __cplusplus } #endif