Merge blueprints-ramcloud-graph into ONOS code
diff --git a/src/main/cpp/edu_stanford_ramcloud_JRamCloud.cc b/src/main/cpp/edu_stanford_ramcloud_JRamCloud.cc
new file mode 100755
index 0000000..fc93cb4
--- /dev/null
+++ b/src/main/cpp/edu_stanford_ramcloud_JRamCloud.cc
@@ -0,0 +1,766 @@
+/* Copyright (c) 2013 Stanford University
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <RamCloud.h>
+#include <TableEnumerator.h>
+#include <Object.h>
+#include "edu_stanford_ramcloud_JRamCloud.h"
+#include "edu_stanford_ramcloud_JRamCloud_TableEnumerator.h"
+
+using namespace RAMCloud;
+
+/// Our JRamCloud java library is packaged under "edu.stanford.ramcloud".
+/// We will need this when using FindClass, etc.
+#define PACKAGE_PATH "edu/stanford/ramcloud/"
+
+#define check_null(var, msg) \
+ if (var == NULL) { \
+ throw Exception(HERE, "JRamCloud: NULL returned: " msg "\n"); \
+ }
+
+/**
+ * This class provides a simple means of extracting C-style strings
+ * from a jstring and cleans up when the destructor is called. This
+ * avoids having to manually do the annoying GetStringUTFChars /
+ * ReleaseStringUTFChars dance.
+ */
+class JStringGetter {
+ public:
+ JStringGetter(JNIEnv* env, jstring jString)
+ : env(env)
+ , jString(jString)
+ , string(env->GetStringUTFChars(jString, 0))
+ {
+ check_null(string, "GetStringUTFChars failed");
+ }
+
+ ~JStringGetter()
+ {
+ if (string != NULL)
+ env->ReleaseStringUTFChars(jString, string);
+ }
+
+ private:
+ JNIEnv* env;
+ jstring jString;
+
+ public:
+ const char* const string;
+};
+
+/**
+ * This class provides a simple means of accessing jbyteArrays as
+ * C-style void* buffers and cleans up when the destructor is called.
+ * This avoids having to manually do the annoying GetByteArrayElements /
+ * ReleaseByteArrayElements dance.
+ */
+class JByteArrayGetter {
+ public:
+ JByteArrayGetter(JNIEnv* env, jbyteArray jByteArray)
+ : env(env)
+ , jByteArray(jByteArray)
+ , pointer(static_cast<void*>(env->GetByteArrayElements(jByteArray, 0)))
+ , length(env->GetArrayLength(jByteArray))
+ {
+ check_null(pointer, "GetByteArrayElements failed");
+ }
+
+ ~JByteArrayGetter()
+ {
+ if (pointer != NULL) {
+ env->ReleaseByteArrayElements(jByteArray,
+ reinterpret_cast<jbyte*>(pointer),
+ 0);
+ }
+ }
+
+ private:
+ JNIEnv* env;
+ jbyteArray jByteArray;
+
+ public:
+ void* const pointer;
+ const jsize length;
+};
+
+class JByteArrayReference {
+ public:
+ JByteArrayReference(JNIEnv* env, jbyteArray jByteArray)
+ : env(env)
+ , jByteArray(jByteArray)
+ , pointer(static_cast<const void*>(env->GetByteArrayElements(jByteArray, 0)))
+ , length(env->GetArrayLength(jByteArray))
+ {
+ check_null(pointer, "GetByteArrayElements failed");
+ }
+
+ ~JByteArrayReference()
+ {
+ if (pointer != NULL) {
+ env->ReleaseByteArrayElements(jByteArray,
+ (jbyte*)pointer,
+ JNI_ABORT);
+ }
+ }
+
+ private:
+ JNIEnv* env;
+ jbyteArray jByteArray;
+
+ public:
+ const void* const pointer;
+ const jsize length;
+};
+
+static RamCloud*
+getRamCloud(JNIEnv* env, jobject jRamCloud)
+{
+ const static jclass cls = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud"));
+ const static jfieldID fieldId = env->GetFieldID(cls, "ramcloudObjectPointer", "J");
+ return reinterpret_cast<RamCloud*>(env->GetLongField(jRamCloud, fieldId));
+}
+
+static TableEnumerator*
+getTableEnumerator(JNIEnv* env, jobject jTableEnumerator)
+{
+ const static jclass cls = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$TableEnumerator"));
+ const static jfieldID fieldId = env->GetFieldID(cls, "tableEnumeratorObjectPointer", "J");
+ return reinterpret_cast<TableEnumerator*>(env->GetLongField(jTableEnumerator, fieldId));
+}
+
+static void
+createException(JNIEnv* env, jobject jRamCloud, const char* name)
+{
+ // Need to specify the full class name, including the package. To make it
+ // slightly more complicated, our exceptions are nested under the JRamCloud
+ // class.
+ string fullName = PACKAGE_PATH;
+ fullName += "JRamCloud$";
+ fullName += name;
+
+ // This would be much easier if we didn't make our Exception classes nested
+ // under JRamCloud since env->ThrowNew() could be used instead. The problem
+ // is that ThrowNew assumes a particular method signature that happens to
+ // be incompatible with the nested classes' signatures.
+ jclass cls = env->FindClass(fullName.c_str());
+ check_null(cls, "FindClass failed");
+
+ jmethodID methodId = env->GetMethodID(cls,
+ "<init>",
+ "(L" PACKAGE_PATH "JRamCloud;Ljava/lang/String;)V");
+ check_null(methodId, "GetMethodID failed");
+
+ jstring jString = env->NewStringUTF("");
+ check_null(jString, "NewStringUTF failed");
+
+ jthrowable exception = reinterpret_cast<jthrowable>(
+ env->NewObject(cls, methodId, jRamCloud, jString));
+ check_null(exception, "NewObject failed");
+
+ env->Throw(exception);
+}
+
+/**
+ * This macro is used to catch C++ exceptions and convert them into Java
+ * exceptions. Be sure to wrap the individual RamCloud:: calls in try blocks,
+ * rather than the entire methods, since doing so with functions that return
+ * non-void is a bad idea with undefined(?) behaviour.
+ *
+ * _returnValue is the value that should be returned from the JNI function
+ * when an exception is caught and generated in Java. As far as I can tell,
+ * the exception fires immediately upon returning from the JNI method. I
+ * don't think anything else would make sense, but the JNI docs kind of
+ * suck.
+ */
+#define EXCEPTION_CATCHER(_returnValue) \
+ catch (TableDoesntExistException& e) { \
+ createException(env, jRamCloud, "TableDoesntExistException"); \
+ return _returnValue; \
+ } catch (ObjectDoesntExistException& e) { \
+ createException(env, jRamCloud, "ObjectDoesntExistException"); \
+ return _returnValue; \
+ } catch (ObjectExistsException& e) { \
+ createException(env, jRamCloud, "ObjectExistsException"); \
+ return _returnValue; \
+ } catch (WrongVersionException& e) { \
+ createException(env, jRamCloud, "WrongVersionException"); \
+ return _returnValue; \
+ } catch (RejectRulesException& e) { \
+ createException(env, jRamCloud, "RejectRulesException"); \
+ return _returnValue; \
+ } catch (InvalidObjectException& e) { \
+ createException(env, jRamCloud, "InvalidObjectException"); \
+ return _returnValue; \
+ }
+
+/*
+ * Class: edu_stanford_ramcloud_JRamCloud
+ * Method: connect
+ * Signature: (Ljava/lang/String;)J
+ */
+JNIEXPORT jlong
+JNICALL Java_edu_stanford_ramcloud_JRamCloud_connect(JNIEnv *env,
+ jclass jRamCloud,
+ jstring coordinatorLocator)
+{
+ JStringGetter locator(env, coordinatorLocator);
+ RamCloud* ramcloud = NULL;
+ try {
+ ramcloud = new RamCloud(locator.string);
+ } EXCEPTION_CATCHER(NULL);
+ return reinterpret_cast<jlong>(ramcloud);
+}
+
+/*
+ * Class: edu_stanford_ramcloud_JRamCloud
+ * Method: disconnect
+ * Signature: (J)V
+ */
+JNIEXPORT void
+JNICALL Java_edu_stanford_ramcloud_JRamCloud_disconnect(JNIEnv *env,
+ jclass jRamCloud,
+ jlong ramcloudObjectPointer)
+{
+ delete reinterpret_cast<RamCloud*>(ramcloudObjectPointer);
+}
+
+/*
+ * Class: edu_stanford_ramcloud_JRamCloud
+ * Method: createTable
+ * Signature: (Ljava/lang/String;)I
+ */
+JNIEXPORT jlong
+JNICALL Java_edu_stanford_ramcloud_JRamCloud_createTable__Ljava_lang_String_2(JNIEnv *env,
+ jobject jRamCloud,
+ jstring jTableName)
+{
+ return Java_edu_stanford_ramcloud_JRamCloud_createTable__Ljava_lang_String_2I(env,
+ jRamCloud,
+ jTableName,
+ 1);
+}
+
+/*
+ * Class: edu_stanford_ramcloud_JRamCloud
+ * Method: createTable
+ * Signature: (Ljava/lang/String;I)I
+ */
+JNIEXPORT jlong
+JNICALL Java_edu_stanford_ramcloud_JRamCloud_createTable__Ljava_lang_String_2I(JNIEnv *env,
+ jobject jRamCloud,
+ jstring jTableName,
+ jint jServerSpan)
+{
+ RamCloud* ramcloud = getRamCloud(env, jRamCloud);
+ JStringGetter tableName(env, jTableName);
+ uint64_t tableId;
+ try {
+ tableId = ramcloud->createTable(tableName.string, jServerSpan);
+ } EXCEPTION_CATCHER(-1);
+ return static_cast<jlong>(tableId);
+}
+
+/*
+ * Class: edu_stanford_ramcloud_JRamCloud
+ * Method: dropTable
+ * Signature: (Ljava/lang/String;)I
+ */
+JNIEXPORT void
+JNICALL Java_edu_stanford_ramcloud_JRamCloud_dropTable(JNIEnv *env,
+ jobject jRamCloud,
+ jstring jTableName)
+{
+ RamCloud* ramcloud = getRamCloud(env, jRamCloud);
+ JStringGetter tableName(env, jTableName);
+ try {
+ ramcloud->dropTable(tableName.string);
+ } EXCEPTION_CATCHER();
+}
+
+/*
+ * Class: edu_stanford_ramcloud_JRamCloud
+ * Method: getTableId
+ * Signature: (Ljava/lang/String;)J
+ */
+JNIEXPORT jlong
+JNICALL Java_edu_stanford_ramcloud_JRamCloud_getTableId(JNIEnv *env,
+ jobject jRamCloud,
+ jstring jTableName)
+{
+ RamCloud* ramcloud = getRamCloud(env, jRamCloud);
+ JStringGetter tableName(env, jTableName);
+ uint64_t tableId;
+ try {
+ tableId = ramcloud->getTableId(tableName.string);
+ } EXCEPTION_CATCHER(-1);
+ return tableId;
+}
+
+/*
+ * Class: edu_stanford_ramcloud_JRamCloud
+ * Method: read
+ * Signature: (J[B)LJRamCloud/Object;
+ */
+JNIEXPORT jobject
+JNICALL Java_edu_stanford_ramcloud_JRamCloud_read__J_3B(JNIEnv *env,
+ jobject jRamCloud,
+ jlong jTableId,
+ jbyteArray jKey)
+{
+ RamCloud* ramcloud = getRamCloud(env, jRamCloud);
+ JByteArrayReference key(env, jKey);
+
+ Buffer buffer;
+ uint64_t version;
+ try {
+ ramcloud->read(jTableId, key.pointer, key.length, &buffer, NULL, &version);
+ } EXCEPTION_CATCHER(NULL);
+
+ jbyteArray jValue = env->NewByteArray(buffer.getTotalLength());
+ check_null(jValue, "NewByteArray failed");
+ JByteArrayGetter value(env, jValue);
+ buffer.copy(0, buffer.getTotalLength(), value.pointer);
+
+ // Note that using 'javap -s' on the class file will print out the method
+ // signatures (the third argument to GetMethodID).
+ const static jclass cls = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$Object"));
+ check_null(cls, "FindClass failed");
+
+ const static jmethodID methodId = env->GetMethodID(cls,
+ "<init>",
+ "(L" PACKAGE_PATH "JRamCloud;[B[BJ)V");
+ check_null(methodId, "GetMethodID failed");
+
+ return env->NewObject(cls,
+ methodId,
+ jRamCloud,
+ jKey,
+ jValue,
+ static_cast<jlong>(version));
+}
+
+/*
+ * Class: edu_stanford_ramcloud_JRamCloud
+ * Method: read
+ * Signature: (J[BLJRamCloud/RejectRules;)LJRamCloud/Object;
+ */
+JNIEXPORT jobject
+JNICALL Java_edu_stanford_ramcloud_JRamCloud_read__J_3BLJRamCloud_RejectRules_2(JNIEnv *env,
+ jobject jRamCloud,
+ jlong jTableId,
+ jbyteArray jKey,
+ jobject jRejectRules)
+{
+ // XXX-- implement me by generalising the other read() method.
+ return NULL;
+}
+
+/*
+ * Class: edu_stanford_ramcloud_JRamCloud
+ * Method: multiRead
+ * Signature: ([Ledu/stanford/ramcloud/JRamCloud$multiReadObject;I)[Ledu/stanford/ramcloud/JRamCloud$Object;
+ */
+JNIEXPORT jobjectArray
+JNICALL Java_edu_stanford_ramcloud_JRamCloud_multiRead(JNIEnv *env,
+ jobject jRamCloud,
+ jobjectArray jmultiReadArray){
+
+ RamCloud* ramcloud = getRamCloud(env, jRamCloud);
+ const jint requestNum = env->GetArrayLength(jmultiReadArray);
+ MultiReadObject objects[requestNum];
+ Tub<Buffer> values[requestNum];
+ jbyteArray jKey[requestNum];
+ MultiReadObject* requests[requestNum];
+
+ const static jclass jc_multiReadObject = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$multiReadObject"));
+ const static jfieldID jf_tableId = env->GetFieldID(jc_multiReadObject, "tableId", "J");
+ const static jfieldID jf_key = env->GetFieldID(jc_multiReadObject, "key", "[B");
+
+ for (int i = 0 ; i < requestNum ; i++){
+ jobject obj = env->GetObjectArrayElement(jmultiReadArray, i);
+ check_null(obj, "GetObjectArrayElement failed");
+ jlong jTableId = env->GetLongField(obj, jf_tableId);
+
+ jKey[i] = (jbyteArray)env->GetObjectField(obj, jf_key);
+
+ jbyte* data = env->GetByteArrayElements(jKey[i], NULL);
+ check_null(data, "GetByteArrayElements failed");
+
+ objects[i].tableId = jTableId;
+ objects[i].key = data;
+ objects[i].keyLength = env->GetArrayLength(jKey[i]);
+ objects[i].value = &values[i];
+ requests[i] = &objects[i];
+ }
+
+ try {
+ ramcloud->multiRead(requests, requestNum);
+ } EXCEPTION_CATCHER(NULL);
+
+ const static jclass jc_RcObject = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$Object"));
+ check_null(jc_RcObject, "FindClass failed");
+ const static jmethodID jm_init = env->GetMethodID(jc_RcObject,
+ "<init>",
+ "(L" PACKAGE_PATH "JRamCloud;[B[BJ)V");
+
+ jobjectArray outJNIArray = env->NewObjectArray(requestNum, jc_RcObject , NULL);
+ check_null(outJNIArray, "NewObjectArray failed");
+
+ for (int i = 0 ; i < requestNum ; i++) {
+ if (objects[i].status == 0) {
+ jbyteArray jValue = env->NewByteArray(values[i].get()->getTotalLength());
+ check_null(jValue, "NewByteArray failed");
+ JByteArrayGetter value(env, jValue);
+ values[i].get()->copy(0, values[i].get()->getTotalLength(), value.pointer);
+ jobject obj = env->NewObject(jc_RcObject, jm_init, jRamCloud, jKey[i], jValue);
+ check_null(obj, "NewObject failed");
+ env->SetObjectArrayElement(outJNIArray, i, obj);
+ }
+ // keys are read only so no need to copy back to Java side: JNI_ABORT
+ env->ReleaseByteArrayElements(jKey[i], (jbyte *) objects[i].key, JNI_ABORT);
+ }
+ return outJNIArray;
+}
+
+
+/*
+ * Class: edu_stanford_ramcloud_JRamCloud
+ * Method: remove
+ * Signature: (J[B)J
+ */
+JNIEXPORT jlong
+JNICALL Java_edu_stanford_ramcloud_JRamCloud_remove__J_3B(JNIEnv *env,
+ jobject jRamCloud,
+ jlong jTableId,
+ jbyteArray jKey)
+{
+ RamCloud* ramcloud = getRamCloud(env, jRamCloud);
+ JByteArrayReference key(env, jKey);
+ uint64_t version;
+ try {
+ ramcloud->remove(jTableId, key.pointer, key.length, NULL, &version);
+ } EXCEPTION_CATCHER(-1);
+ return static_cast<jlong>(version);
+}
+
+/*
+ * Class: edu_stanford_ramcloud_JRamCloud
+ * Method: remove
+ * Signature: (J[BLJRamCloud/RejectRules;)J
+ */
+JNIEXPORT jlong
+JNICALL Java_edu_stanford_ramcloud_JRamCloud_remove__J_3BLJRamCloud_RejectRules_2(JNIEnv *env,
+ jobject jRamCloud,
+ jlong jTableId,
+ jbyteArray jKey,
+ jobject jRejectRules)
+{
+ // XXX- handle RejectRules
+ RamCloud* ramcloud = getRamCloud(env, jRamCloud);
+ JByteArrayReference key(env, jKey);
+ uint64_t version;
+ try {
+ ramcloud->remove(jTableId, key.pointer, key.length, NULL, &version);
+ } EXCEPTION_CATCHER(-1);
+ return static_cast<jlong>(version);
+}
+
+/*
+ * Class: edu_stanford_ramcloud_JRamCloud
+ * Method: write
+ * Signature: (J[B[B)J
+ */
+JNIEXPORT jlong
+JNICALL Java_edu_stanford_ramcloud_JRamCloud_write__J_3B_3B(JNIEnv *env,
+ jobject jRamCloud,
+ jlong jTableId,
+ jbyteArray jKey,
+ jbyteArray jValue)
+{
+ RamCloud* ramcloud = getRamCloud(env, jRamCloud);
+ JByteArrayReference key(env, jKey);
+ JByteArrayGetter value(env, jValue);
+ uint64_t version;
+ try {
+ ramcloud->write(jTableId,
+ key.pointer, key.length,
+ value.pointer, value.length,
+ NULL,
+ &version);
+ } EXCEPTION_CATCHER(-1);
+ return static_cast<jlong>(version);
+}
+
+/*
+ * Class: edu_stanford_ramcloud_JRamCloud
+ * Method: write
+ * Signature: (J[B[BLJRamCloud/RejectRules;)J
+ */
+JNIEXPORT jlong
+JNICALL Java_edu_stanford_ramcloud_JRamCloud_write__J_3B_3BLJRamCloud_RejectRules_2(JNIEnv *env,
+ jobject jRamCloud,
+ jlong jTableId,
+ jbyteArray jKey,
+ jbyteArray jValue,
+ jobject jRejectRules)
+{
+ // XXX- handle RejectRules
+ RamCloud* ramcloud = getRamCloud(env, jRamCloud);
+ JByteArrayReference key(env, jKey);
+ JByteArrayGetter value(env, jValue);
+ RejectRules rules;
+ jclass ruleClass = env->GetObjectClass(jRejectRules);
+ jfieldID fid = env->GetFieldID(ruleClass, "doesntExist", "Z");
+ rules.doesntExist = (uint8_t) env->GetBooleanField(jRejectRules, fid);
+
+ fid = env->GetFieldID(ruleClass, "exists", "Z");
+ rules.exists = (uint8_t) env->GetBooleanField(jRejectRules, fid);
+
+ fid = env->GetFieldID(ruleClass, "givenVersion", "J");
+ rules.givenVersion = env->GetLongField(jRejectRules, fid);
+
+ fid = env->GetFieldID(ruleClass, "versionLeGiven", "Z");
+ rules.versionLeGiven = (uint8_t) env->GetBooleanField(jRejectRules, fid);
+
+ fid = env->GetFieldID(ruleClass, "versionNeGiven", "Z");
+ rules.versionNeGiven = (uint8_t) env->GetBooleanField(jRejectRules, fid);
+
+ uint64_t version;
+ try {
+ ramcloud->write(jTableId,
+ key.pointer, key.length,
+ value.pointer, value.length,
+ &rules,
+ &version);
+ }
+ EXCEPTION_CATCHER(-1);
+ return static_cast<jlong> (version);
+}
+
+JNIEXPORT jlong
+JNICALL Java_edu_stanford_ramcloud_JRamCloud_writeRule(JNIEnv *env,
+ jobject jRamCloud,
+ jlong jTableId,
+ jbyteArray jKey,
+ jbyteArray jValue,
+ jobject jRejectRules) {
+ RamCloud* ramcloud = getRamCloud(env, jRamCloud);
+ JByteArrayReference key(env, jKey);
+ JByteArrayGetter value(env, jValue);
+ uint64_t version;
+ RejectRules rules = {};
+ const static jclass jc_RejectRules = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$RejectRules"));
+
+ const static jfieldID jf_doesntExist = env->GetFieldID(jc_RejectRules, "doesntExist", "Z");
+ check_null(jf_doesntExist, "doesentExist field id is null");
+ jboolean ruleBool;
+ ruleBool = env->GetBooleanField(jRejectRules, jf_doesntExist);
+ rules.doesntExist = ruleBool ? 1 : 0;
+
+ const static jfieldID jf_exists = env->GetFieldID(jc_RejectRules, "exists", "Z");
+ check_null(jf_exists, "exists field id is null");
+ ruleBool = env->GetBooleanField(jRejectRules, jf_exists);
+ rules.exists = ruleBool ? 1 : 0;
+
+ const static jfieldID jf_givenVersion = env->GetFieldID(jc_RejectRules, "givenVersion", "J");
+ check_null(jf_givenVersion, "givenVersion field id is null");
+ rules.givenVersion = env->GetLongField(jRejectRules, jf_givenVersion);
+
+ const static jfieldID jf_versionLeGiven = env->GetFieldID(jc_RejectRules, "versionLeGiven", "Z");
+ check_null(jf_versionLeGiven, "versionLeGiven field id is null");
+ ruleBool = env->GetBooleanField(jRejectRules, jf_versionLeGiven);
+ rules.versionLeGiven = ruleBool ? 1 : 0;
+
+ const static jfieldID jf_versionNeGiven = env->GetFieldID(jc_RejectRules, "versionNeGiven", "Z");
+ check_null(jf_versionNeGiven, "versionNeGiven field id is null");
+ ruleBool = env->GetBooleanField(jRejectRules, jf_versionNeGiven);
+ rules.versionNeGiven = ruleBool ? 1 : 0;
+ try {
+ ramcloud->write(jTableId,
+ key.pointer, key.length,
+ value.pointer, value.length,
+ &rules,
+ &version);
+ }
+ EXCEPTION_CATCHER(-1);
+ return static_cast<jlong> (version);
+}
+
+/*
+ * Class: edu_stanford_ramcloud_JRamCloud_TableEnumerator
+ * Method: init
+ * Signature: (J)V
+ */
+JNIEXPORT jlong JNICALL Java_edu_stanford_ramcloud_JRamCloud_00024TableEnumerator_init(JNIEnv *env,
+ jobject jTableEnumerator,
+ jlong jTableId)
+{
+ const static jclass cls = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$TableEnumerator"));
+ const static jfieldID fieldId = env->GetFieldID(cls, "ramCloudObjectPointer", "J");
+ RamCloud* ramcloud = reinterpret_cast<RamCloud*>(env->GetLongField(jTableEnumerator, fieldId));
+
+ return reinterpret_cast<jlong>(new TableEnumerator(*ramcloud, jTableId));
+}
+
+/*
+ * Class: edu_stanford_ramcloud_JRamCloud_TableEnumerator
+ * Method: hasNext
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL Java_edu_stanford_ramcloud_JRamCloud_00024TableEnumerator_hasNext( JNIEnv *env,
+ jobject jTableEnumerator)
+{
+ TableEnumerator* tableEnum = getTableEnumerator(env, jTableEnumerator);
+ return static_cast<jboolean>(tableEnum->hasNext());
+}
+
+/*
+ * Class: edu_stanford_ramcloud_JRamCloud_TableEnumerator
+ * Method: next
+ * Signature: ()Ledu/stanford/ramcloud/JRamCloud/Object;
+ */
+JNIEXPORT jobject JNICALL Java_edu_stanford_ramcloud_JRamCloud_00024TableEnumerator_next( JNIEnv *env,
+ jobject jTableEnumerator)
+{
+ TableEnumerator* tableEnum = getTableEnumerator(env, jTableEnumerator);
+
+ if(tableEnum->hasNext())
+ {
+ uint32_t size = 0;
+ const void* buffer = 0;
+ uint64_t version = 0;
+
+ tableEnum->next(&size, &buffer);
+ Object object(buffer, size);
+
+ jbyteArray jKey = env->NewByteArray(object.getKeyLength());
+ jbyteArray jValue = env->NewByteArray(object.getDataLength());
+
+ JByteArrayGetter key(env, jKey);
+ JByteArrayGetter value(env, jValue);
+
+ memcpy(key.pointer, object.getKey(), object.getKeyLength());
+ memcpy(value.pointer, object.getData(), object.getDataLength());
+
+ version = object.getVersion();
+
+ const static jclass cls = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$Object"));
+ check_null(cls, "FindClass failed");
+ const static jmethodID methodId = env->GetMethodID(cls,
+ "<init>",
+ "(L" PACKAGE_PATH "JRamCloud;[B[BJ)V");
+ check_null(methodId, "GetMethodID failed");
+ return env->NewObject(cls,
+ methodId,
+ jTableEnumerator,
+ jKey,
+ jValue,
+ static_cast<jlong>(version));
+ } else
+ return NULL;
+}
+
+/*
+ * Class: edu_stanford_ramcloud_JRamCloud
+ * Method: multiWrite
+ * Signature: ([Ledu/stanford/ramcloud/JRamCloud/MultiWriteObject;)[Ledu/stanford/ramcloud/JRamCloud/MultiWriteRspObject;
+ */
+JNIEXPORT jobjectArray JNICALL Java_edu_stanford_ramcloud_JRamCloud_multiWrite(JNIEnv *env, jobject jRamCloud, jobjectArray jmultiWriteArray) {
+ jint requestNum = env->GetArrayLength(jmultiWriteArray);
+ RamCloud* ramcloud = getRamCloud(env, jRamCloud);
+ Tub<MultiWriteObject> objects[requestNum];
+ MultiWriteObject *requests[requestNum];
+ RejectRules rules[requestNum];
+ jbyteArray jKey[requestNum];
+ jbyteArray jValue[requestNum];
+
+ const static jclass jc_multiWriteObject = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$MultiWriteObject"));
+ const static jclass jc_RejectRules = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$RejectRules"));
+ const static jfieldID jf_tableId = env->GetFieldID(jc_multiWriteObject, "tableId", "J");
+ const static jfieldID jf_key = env->GetFieldID(jc_multiWriteObject, "key", "[B");
+ const static jfieldID jf_value = env->GetFieldID(jc_multiWriteObject, "value", "[B");
+ const static jfieldID jf_reject_rules = env->GetFieldID(jc_multiWriteObject, "rules", "L" PACKAGE_PATH "JRamCloud$RejectRules;");
+
+ const static jfieldID jf_doesntExist = env->GetFieldID(jc_RejectRules, "doesntExist", "Z");
+ check_null(jf_doesntExist, "doesentExist field id is null");
+ const static jfieldID jf_exists = env->GetFieldID(jc_RejectRules, "exists", "Z");
+ check_null(jf_exists, "exists field id is null");
+ const static jfieldID jf_givenVersion = env->GetFieldID(jc_RejectRules, "givenVersion", "J");
+ check_null(jf_givenVersion, "givenVersion field id is null");
+ const static jfieldID jf_versionLeGiven = env->GetFieldID(jc_RejectRules, "versionLeGiven", "Z");
+ check_null(jf_versionLeGiven, "versionLeGiven field id is null");
+ const static jfieldID jf_versionNeGiven = env->GetFieldID(jc_RejectRules, "versionNeGiven", "Z");
+ check_null(jf_versionNeGiven, "versionNeGiven field id is null");
+
+ for (int i = 0; i < requestNum; i++) {
+ jobject obj = env->GetObjectArrayElement(jmultiWriteArray, i);
+ check_null(obj, "multi write GetObjectArrayElement failed");
+
+ uint64_t tableId = env->GetLongField(obj, jf_tableId);
+
+ jKey[i] = (jbyteArray)env->GetObjectField(obj, jf_key);
+ jbyte* keyData = env->GetByteArrayElements(jKey[i], NULL);
+ uint16_t keyLength = env->GetArrayLength(jKey[i]);
+
+ jValue[i] = (jbyteArray)env->GetObjectField(obj, jf_value);
+ jbyte* valueData = env->GetByteArrayElements(jValue[i], NULL);
+ uint32_t valueLength = env->GetArrayLength(jValue[i]);
+
+ jobject jRejectRules = env->GetObjectField(obj, jf_reject_rules);
+ rules[i] = {};
+
+ if (jRejectRules != NULL) {
+ jboolean ruleBool;
+
+ ruleBool = env->GetBooleanField(jRejectRules, jf_doesntExist);
+ rules[i].doesntExist = ruleBool ? 1 : 0;
+
+ ruleBool = env->GetBooleanField(jRejectRules, jf_exists);
+ rules[i].exists = ruleBool ? 1 : 0;
+
+ rules[i].givenVersion = env->GetLongField(jRejectRules, jf_givenVersion);
+
+ ruleBool = env->GetBooleanField(jRejectRules, jf_versionLeGiven);
+ rules[i].versionLeGiven = ruleBool ? 1 : 0;
+
+ ruleBool = env->GetBooleanField(jRejectRules, jf_versionNeGiven);
+ rules[i].versionNeGiven = ruleBool ? 1 : 0;
+ }
+ objects[i].construct(tableId, keyData, keyLength, valueData, valueLength, &rules[i]);
+ requests[i] = objects[i].get();
+ }
+ try {
+ ramcloud->multiWrite(requests, requestNum);
+ } EXCEPTION_CATCHER(NULL);
+
+ const static jclass jc_RcObject = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$MultiWriteRspObject"));
+ check_null(jc_RcObject, "FindClass failed");
+ const static jmethodID jm_init = env->GetMethodID(jc_RcObject,
+ "<init>",
+ "(L" PACKAGE_PATH "JRamCloud;IJ)V");
+
+ jobjectArray outJNIArray = env->NewObjectArray(requestNum, jc_RcObject , NULL);
+ check_null(outJNIArray, "NewObjectArray failed");
+
+ for (int i = 0 ; i < requestNum ; i++) {
+ jobject obj = env->NewObject(jc_RcObject, jm_init, jRamCloud, objects[i]->status, objects[i]->version);
+ check_null(obj, "NewObject failed");
+ env->SetObjectArrayElement(outJNIArray, i, obj);
+ env->ReleaseByteArrayElements(jKey[i], (jbyte *)requests[i]->key, JNI_ABORT);
+ env->ReleaseByteArrayElements(jValue[i], (jbyte *)requests[i]->value, JNI_ABORT);
+ objects[i].destroy();
+ }
+ return outJNIArray;
+}