blob: 830fd47c69e1d837cd27678846cc75bf859bd47b [file] [log] [blame]
yoshi28bac132014-01-22 11:00:17 -08001/* Copyright (c) 2013 Stanford University
2 *
3 * Permission to use, copy, modify, and distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
6 *
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR
10 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 */
15
16#include <RamCloud.h>
17#include <TableEnumerator.h>
18#include <Object.h>
19#include "edu_stanford_ramcloud_JRamCloud.h"
yoshi28bac132014-01-22 11:00:17 -080020
21using namespace RAMCloud;
22
23/// Our JRamCloud java library is packaged under "edu.stanford.ramcloud".
24/// We will need this when using FindClass, etc.
25#define PACKAGE_PATH "edu/stanford/ramcloud/"
26
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -080027// Java RejectRules flags bit index
28const static int DoesntExist = 1;
29const static int Exists = 1 << 1;
30const static int VersionLeGiven = 1 << 2;
31const static int VersionNeGiven = 1 << 3;
32
yoshi28bac132014-01-22 11:00:17 -080033#define check_null(var, msg) \
34 if (var == NULL) { \
35 throw Exception(HERE, "JRamCloud: NULL returned: " msg "\n"); \
36 }
37
38/**
39 * This class provides a simple means of extracting C-style strings
40 * from a jstring and cleans up when the destructor is called. This
41 * avoids having to manually do the annoying GetStringUTFChars /
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -080042 * ReleaseStringUTFChars dance.
yoshi28bac132014-01-22 11:00:17 -080043 */
44class JStringGetter {
45 public:
46 JStringGetter(JNIEnv* env, jstring jString)
47 : env(env)
48 , jString(jString)
49 , string(env->GetStringUTFChars(jString, 0))
50 {
51 check_null(string, "GetStringUTFChars failed");
52 }
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -080053
yoshi28bac132014-01-22 11:00:17 -080054 ~JStringGetter()
55 {
56 if (string != NULL)
57 env->ReleaseStringUTFChars(jString, string);
58 }
59
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -080060 private:
yoshi28bac132014-01-22 11:00:17 -080061 JNIEnv* env;
62 jstring jString;
63
64 public:
65 const char* const string;
66};
67
68/**
69 * This class provides a simple means of accessing jbyteArrays as
70 * C-style void* buffers and cleans up when the destructor is called.
71 * This avoids having to manually do the annoying GetByteArrayElements /
72 * ReleaseByteArrayElements dance.
73 */
74class JByteArrayGetter {
75 public:
76 JByteArrayGetter(JNIEnv* env, jbyteArray jByteArray)
77 : env(env)
78 , jByteArray(jByteArray)
79 , pointer(static_cast<void*>(env->GetByteArrayElements(jByteArray, 0)))
80 , length(env->GetArrayLength(jByteArray))
81 {
82 check_null(pointer, "GetByteArrayElements failed");
83 }
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -080084
yoshi28bac132014-01-22 11:00:17 -080085 ~JByteArrayGetter()
86 {
87 if (pointer != NULL) {
88 env->ReleaseByteArrayElements(jByteArray,
89 reinterpret_cast<jbyte*>(pointer),
90 0);
91 }
92 }
93
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -080094 private:
yoshi28bac132014-01-22 11:00:17 -080095 JNIEnv* env;
96 jbyteArray jByteArray;
97
98 public:
99 void* const pointer;
100 const jsize length;
101};
102
103class JByteArrayReference {
104 public:
105 JByteArrayReference(JNIEnv* env, jbyteArray jByteArray)
106 : env(env)
107 , jByteArray(jByteArray)
108 , pointer(static_cast<const void*>(env->GetByteArrayElements(jByteArray, 0)))
109 , length(env->GetArrayLength(jByteArray))
110 {
111 check_null(pointer, "GetByteArrayElements failed");
112 }
113
114 ~JByteArrayReference()
115 {
116 if (pointer != NULL) {
117 env->ReleaseByteArrayElements(jByteArray,
118 (jbyte*)pointer,
119 JNI_ABORT);
120 }
121 }
122
123 private:
124 JNIEnv* env;
125 jbyteArray jByteArray;
126
127 public:
128 const void* const pointer;
129 const jsize length;
130};
131
132static RamCloud*
133getRamCloud(JNIEnv* env, jobject jRamCloud)
134{
135 const static jclass cls = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud"));
136 const static jfieldID fieldId = env->GetFieldID(cls, "ramcloudObjectPointer", "J");
137 return reinterpret_cast<RamCloud*>(env->GetLongField(jRamCloud, fieldId));
138}
139
140static TableEnumerator*
141getTableEnumerator(JNIEnv* env, jobject jTableEnumerator)
142{
143 const static jclass cls = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$TableEnumerator"));
144 const static jfieldID fieldId = env->GetFieldID(cls, "tableEnumeratorObjectPointer", "J");
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800145 return reinterpret_cast<TableEnumerator*>(env->GetLongField(jTableEnumerator, fieldId));
yoshi28bac132014-01-22 11:00:17 -0800146}
147
148static void
149createException(JNIEnv* env, jobject jRamCloud, const char* name)
150{
151 // Need to specify the full class name, including the package. To make it
152 // slightly more complicated, our exceptions are nested under the JRamCloud
153 // class.
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800154 string fullName(PACKAGE_PATH "JRamCloud$");
yoshi28bac132014-01-22 11:00:17 -0800155 fullName += name;
156
yoshi28bac132014-01-22 11:00:17 -0800157 jclass cls = env->FindClass(fullName.c_str());
158 check_null(cls, "FindClass failed");
159
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800160 env->ThrowNew(cls, "");
161}
yoshi28bac132014-01-22 11:00:17 -0800162
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800163static void
164setRejectRules(JNIEnv* env, jobject jRejectRules, RejectRules& rules)
165{
166 const static jclass jc_RejectRules = (jclass) env->NewGlobalRef(
167 env->FindClass(PACKAGE_PATH "JRamCloud$RejectRules"));
168 static const jfieldID jf_flags = env->GetFieldID(jc_RejectRules, "flags", "I");
169 check_null(jf_flags, "flags field ID is null");
170 static const jfieldID jf_givenVersion = env->GetFieldID(jc_RejectRules,
171 "givenVersion", "J");
172 check_null(jf_givenVersion, "givenVersion field ID is null");
yoshi28bac132014-01-22 11:00:17 -0800173
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800174 const jint rejectFlag = env->GetIntField(jRejectRules, jf_flags);
175 rules.doesntExist = (rejectFlag & DoesntExist) != 0;
176 rules.exists = (rejectFlag & Exists) != 0;
177 rules.versionLeGiven = (rejectFlag & VersionLeGiven) != 0;
178 rules.versionNeGiven = (rejectFlag & VersionNeGiven) != 0;
179 if (rules.versionLeGiven || rules.versionNeGiven) {
180 rules.givenVersion = env->GetLongField(jRejectRules, jf_givenVersion);
181 }
yoshi28bac132014-01-22 11:00:17 -0800182}
183
184/**
185 * This macro is used to catch C++ exceptions and convert them into Java
186 * exceptions. Be sure to wrap the individual RamCloud:: calls in try blocks,
187 * rather than the entire methods, since doing so with functions that return
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800188 * non-void is a bad idea with undefined(?) behaviour.
yoshi28bac132014-01-22 11:00:17 -0800189 *
190 * _returnValue is the value that should be returned from the JNI function
191 * when an exception is caught and generated in Java. As far as I can tell,
192 * the exception fires immediately upon returning from the JNI method. I
193 * don't think anything else would make sense, but the JNI docs kind of
194 * suck.
195 */
196#define EXCEPTION_CATCHER(_returnValue) \
197 catch (TableDoesntExistException& e) { \
198 createException(env, jRamCloud, "TableDoesntExistException"); \
199 return _returnValue; \
200 } catch (ObjectDoesntExistException& e) { \
201 createException(env, jRamCloud, "ObjectDoesntExistException"); \
202 return _returnValue; \
203 } catch (ObjectExistsException& e) { \
204 createException(env, jRamCloud, "ObjectExistsException"); \
205 return _returnValue; \
206 } catch (WrongVersionException& e) { \
207 createException(env, jRamCloud, "WrongVersionException"); \
208 return _returnValue; \
209 } catch (RejectRulesException& e) { \
210 createException(env, jRamCloud, "RejectRulesException"); \
211 return _returnValue; \
212 } catch (InvalidObjectException& e) { \
213 createException(env, jRamCloud, "InvalidObjectException"); \
214 return _returnValue; \
215 }
216
217/*
218 * Class: edu_stanford_ramcloud_JRamCloud
219 * Method: connect
220 * Signature: (Ljava/lang/String;)J
221 */
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800222JNIEXPORT jlong
yoshi28bac132014-01-22 11:00:17 -0800223JNICALL Java_edu_stanford_ramcloud_JRamCloud_connect(JNIEnv *env,
224 jclass jRamCloud,
225 jstring coordinatorLocator)
226{
227 JStringGetter locator(env, coordinatorLocator);
228 RamCloud* ramcloud = NULL;
229 try {
230 ramcloud = new RamCloud(locator.string);
Yuta HIGUCHI52617722014-03-14 13:36:10 -0700231 } EXCEPTION_CATCHER((jlong)(NULL));
yoshi28bac132014-01-22 11:00:17 -0800232 return reinterpret_cast<jlong>(ramcloud);
233}
234
235/*
236 * Class: edu_stanford_ramcloud_JRamCloud
237 * Method: disconnect
238 * Signature: (J)V
239 */
240JNIEXPORT void
241JNICALL Java_edu_stanford_ramcloud_JRamCloud_disconnect(JNIEnv *env,
242 jclass jRamCloud,
243 jlong ramcloudObjectPointer)
244{
245 delete reinterpret_cast<RamCloud*>(ramcloudObjectPointer);
246}
247
248/*
249 * Class: edu_stanford_ramcloud_JRamCloud
250 * Method: createTable
251 * Signature: (Ljava/lang/String;)I
252 */
253JNIEXPORT jlong
254JNICALL Java_edu_stanford_ramcloud_JRamCloud_createTable__Ljava_lang_String_2(JNIEnv *env,
255 jobject jRamCloud,
256 jstring jTableName)
257{
258 return Java_edu_stanford_ramcloud_JRamCloud_createTable__Ljava_lang_String_2I(env,
259 jRamCloud,
260 jTableName,
261 1);
262}
263
264/*
265 * Class: edu_stanford_ramcloud_JRamCloud
266 * Method: createTable
267 * Signature: (Ljava/lang/String;I)I
268 */
269JNIEXPORT jlong
270JNICALL Java_edu_stanford_ramcloud_JRamCloud_createTable__Ljava_lang_String_2I(JNIEnv *env,
271 jobject jRamCloud,
272 jstring jTableName,
273 jint jServerSpan)
274{
275 RamCloud* ramcloud = getRamCloud(env, jRamCloud);
276 JStringGetter tableName(env, jTableName);
277 uint64_t tableId;
278 try {
279 tableId = ramcloud->createTable(tableName.string, jServerSpan);
280 } EXCEPTION_CATCHER(-1);
281 return static_cast<jlong>(tableId);
282}
283
284/*
285 * Class: edu_stanford_ramcloud_JRamCloud
286 * Method: dropTable
287 * Signature: (Ljava/lang/String;)I
288 */
289JNIEXPORT void
290JNICALL Java_edu_stanford_ramcloud_JRamCloud_dropTable(JNIEnv *env,
291 jobject jRamCloud,
292 jstring jTableName)
293{
294 RamCloud* ramcloud = getRamCloud(env, jRamCloud);
295 JStringGetter tableName(env, jTableName);
296 try {
297 ramcloud->dropTable(tableName.string);
298 } EXCEPTION_CATCHER();
299}
300
301/*
302 * Class: edu_stanford_ramcloud_JRamCloud
303 * Method: getTableId
304 * Signature: (Ljava/lang/String;)J
305 */
306JNIEXPORT jlong
307JNICALL Java_edu_stanford_ramcloud_JRamCloud_getTableId(JNIEnv *env,
308 jobject jRamCloud,
309 jstring jTableName)
310{
311 RamCloud* ramcloud = getRamCloud(env, jRamCloud);
312 JStringGetter tableName(env, jTableName);
313 uint64_t tableId;
314 try {
315 tableId = ramcloud->getTableId(tableName.string);
316 } EXCEPTION_CATCHER(-1);
317 return tableId;
318}
319
320/*
321 * Class: edu_stanford_ramcloud_JRamCloud
322 * Method: read
323 * Signature: (J[B)LJRamCloud/Object;
324 */
325JNIEXPORT jobject
326JNICALL Java_edu_stanford_ramcloud_JRamCloud_read__J_3B(JNIEnv *env,
327 jobject jRamCloud,
328 jlong jTableId,
329 jbyteArray jKey)
330{
331 RamCloud* ramcloud = getRamCloud(env, jRamCloud);
332 JByteArrayReference key(env, jKey);
333
334 Buffer buffer;
335 uint64_t version;
336 try {
337 ramcloud->read(jTableId, key.pointer, key.length, &buffer, NULL, &version);
338 } EXCEPTION_CATCHER(NULL);
339
340 jbyteArray jValue = env->NewByteArray(buffer.getTotalLength());
341 check_null(jValue, "NewByteArray failed");
342 JByteArrayGetter value(env, jValue);
343 buffer.copy(0, buffer.getTotalLength(), value.pointer);
344
345 // Note that using 'javap -s' on the class file will print out the method
346 // signatures (the third argument to GetMethodID).
347 const static jclass cls = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$Object"));
348 check_null(cls, "FindClass failed");
349
350 const static jmethodID methodId = env->GetMethodID(cls,
351 "<init>",
Yoshi Muroie7693b12014-02-19 19:41:17 -0800352 "([B[BJ)V");
yoshi28bac132014-01-22 11:00:17 -0800353 check_null(methodId, "GetMethodID failed");
354
355 return env->NewObject(cls,
356 methodId,
yoshi28bac132014-01-22 11:00:17 -0800357 jKey,
358 jValue,
359 static_cast<jlong>(version));
360}
361
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800362// Workaround for javah generating incorrect signature for inner class
363// 00024 is an escaped signature for $ character
364#ifdef __cplusplus
365extern "C" {
366#endif
367JNIEXPORT jobject JNICALL Java_edu_stanford_ramcloud_JRamCloud_read__J_3BLedu_stanford_ramcloud_JRamCloud_00024RejectRules_2
368 (JNIEnv *, jobject, jlong, jbyteArray, jobject);
369#ifdef __cplusplus
370}
371#endif
372
yoshi28bac132014-01-22 11:00:17 -0800373/*
374 * Class: edu_stanford_ramcloud_JRamCloud
375 * Method: read
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800376 * Signature: (J[BLedu/stanford/ramcloud/JRamCloud/RejectRules;)Ledu/stanford/ramcloud/JRamCloud/Object;
yoshi28bac132014-01-22 11:00:17 -0800377 */
378JNIEXPORT jobject
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800379JNICALL Java_edu_stanford_ramcloud_JRamCloud_read__J_3BLedu_stanford_ramcloud_JRamCloud_00024RejectRules_2(JNIEnv *env,
yoshi28bac132014-01-22 11:00:17 -0800380 jobject jRamCloud,
381 jlong jTableId,
382 jbyteArray jKey,
383 jobject jRejectRules)
384{
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800385 RamCloud* ramcloud = getRamCloud(env, jRamCloud);
386 JByteArrayReference key(env, jKey);
387
388 Buffer buffer;
389 uint64_t version;
390 RejectRules rules = {};
391 setRejectRules(env, jRejectRules, rules);
392
393 try {
394 ramcloud->read(jTableId, key.pointer, key.length, &buffer, &rules, &version);
395 } EXCEPTION_CATCHER(NULL);
396
397 jbyteArray jValue = env->NewByteArray(buffer.getTotalLength());
398 check_null(jValue, "NewByteArray failed");
399 JByteArrayGetter value(env, jValue);
400 buffer.copy(0, buffer.getTotalLength(), value.pointer);
401
402 // Note that using 'javap -s' on the class file will print out the method
403 // signatures (the third argument to GetMethodID).
404 const static jclass cls = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$Object"));
405 check_null(cls, "FindClass failed");
406
407 const static jmethodID methodId = env->GetMethodID(cls,
408 "<init>",
409 "([B[BJ)V");
410 check_null(methodId, "GetMethodID failed");
411
412 return env->NewObject(cls,
413 methodId,
414 jKey,
415 jValue,
416 static_cast<jlong>(version));
yoshi28bac132014-01-22 11:00:17 -0800417}
418
419/*
420 * Class: edu_stanford_ramcloud_JRamCloud
421 * Method: multiRead
422 * Signature: ([Ledu/stanford/ramcloud/JRamCloud$multiReadObject;I)[Ledu/stanford/ramcloud/JRamCloud$Object;
423 */
424JNIEXPORT jobjectArray
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800425JNICALL Java_edu_stanford_ramcloud_JRamCloud_multiRead(JNIEnv *env,
yoshi28bac132014-01-22 11:00:17 -0800426 jobject jRamCloud,
Yoshi Muroi2c170602014-02-15 08:31:28 -0800427 jlongArray jTableId,
428 jobjectArray jKeyData,
Yoshi Muroie7693b12014-02-19 19:41:17 -0800429 jshortArray jKeyLength,
Yoshi Muroi2c170602014-02-15 08:31:28 -0800430 jint jrequestNum){
yoshi28bac132014-01-22 11:00:17 -0800431
432 RamCloud* ramcloud = getRamCloud(env, jRamCloud);
Yoshi Muroi2c170602014-02-15 08:31:28 -0800433 MultiReadObject objects[jrequestNum];
434 Tub<Buffer> values[jrequestNum];
435 jbyteArray jKey[jrequestNum];
436 MultiReadObject* requests[jrequestNum];
yoshi28bac132014-01-22 11:00:17 -0800437
Yoshi Muroie7693b12014-02-19 19:41:17 -0800438 jlong tableId;
439 jshort keyLength;
440 jbyte* keyData[jrequestNum];
yoshi28bac132014-01-22 11:00:17 -0800441
Yoshi Muroi2c170602014-02-15 08:31:28 -0800442 for (int i = 0 ; i < jrequestNum ; i++){
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800443 jKey[i] = (jbyteArray)env->GetObjectArrayElement(jKeyData, i);
yoshi28bac132014-01-22 11:00:17 -0800444
Yoshi Muroie7693b12014-02-19 19:41:17 -0800445 env->GetShortArrayRegion(jKeyLength, i, 1, &keyLength);
yoshi28bac132014-01-22 11:00:17 -0800446
Yoshi Muroie7693b12014-02-19 19:41:17 -0800447 keyData[i] = (jbyte *) malloc(keyLength);
448 env->GetByteArrayRegion(jKey[i], 0, keyLength, keyData[i]);
yoshi28bac132014-01-22 11:00:17 -0800449
Yoshi Muroie7693b12014-02-19 19:41:17 -0800450 env->GetLongArrayRegion(jTableId, i, 1, &tableId);
451 objects[i].tableId = tableId;
452 objects[i].key = keyData[i];
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800453 objects[i].keyLength = keyLength;
yoshi28bac132014-01-22 11:00:17 -0800454 objects[i].value = &values[i];
455 requests[i] = &objects[i];
456 }
457
458 try {
Yoshi Muroi2c170602014-02-15 08:31:28 -0800459 ramcloud->multiRead(requests, jrequestNum);
yoshi28bac132014-01-22 11:00:17 -0800460 } EXCEPTION_CATCHER(NULL);
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800461
yoshi28bac132014-01-22 11:00:17 -0800462 const static jclass jc_RcObject = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$Object"));
463 check_null(jc_RcObject, "FindClass failed");
464 const static jmethodID jm_init = env->GetMethodID(jc_RcObject,
465 "<init>",
Yoshi Muroie7693b12014-02-19 19:41:17 -0800466 "([B[BJ)V");
yoshi28bac132014-01-22 11:00:17 -0800467
Yoshi Muroi2c170602014-02-15 08:31:28 -0800468 jobjectArray outJNIArray = env->NewObjectArray(jrequestNum, jc_RcObject , NULL);
yoshi28bac132014-01-22 11:00:17 -0800469 check_null(outJNIArray, "NewObjectArray failed");
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800470
Yoshi Muroi2c170602014-02-15 08:31:28 -0800471 for (int i = 0 ; i < jrequestNum ; i++) {
yoshi28bac132014-01-22 11:00:17 -0800472 if (objects[i].status == 0) {
473 jbyteArray jValue = env->NewByteArray(values[i].get()->getTotalLength());
474 check_null(jValue, "NewByteArray failed");
475 JByteArrayGetter value(env, jValue);
476 values[i].get()->copy(0, values[i].get()->getTotalLength(), value.pointer);
Yuta HIGUCHI52617722014-03-14 13:36:10 -0700477 jobject obj = env->NewObject(jc_RcObject, jm_init, jKey[i], jValue, (jlong)objects[i].version);
yoshi28bac132014-01-22 11:00:17 -0800478 check_null(obj, "NewObject failed");
479 env->SetObjectArrayElement(outJNIArray, i, obj);
480 }
Yoshi Muroie7693b12014-02-19 19:41:17 -0800481 free(keyData[i]);
yoshi28bac132014-01-22 11:00:17 -0800482 }
483 return outJNIArray;
484}
485
486
487/*
488 * Class: edu_stanford_ramcloud_JRamCloud
489 * Method: remove
490 * Signature: (J[B)J
491 */
492JNIEXPORT jlong
493JNICALL Java_edu_stanford_ramcloud_JRamCloud_remove__J_3B(JNIEnv *env,
494 jobject jRamCloud,
495 jlong jTableId,
496 jbyteArray jKey)
497{
498 RamCloud* ramcloud = getRamCloud(env, jRamCloud);
499 JByteArrayReference key(env, jKey);
500 uint64_t version;
501 try {
502 ramcloud->remove(jTableId, key.pointer, key.length, NULL, &version);
503 } EXCEPTION_CATCHER(-1);
504 return static_cast<jlong>(version);
505}
506
Yuta HIGUCHI9402dab2014-01-30 19:54:31 -0800507
508// Workaround for javah generating incorrect signature for inner class
509// 00024 is an escaped signature for $ character
510#ifdef __cplusplus
511extern "C" {
512#endif
513JNIEXPORT jlong JNICALL Java_edu_stanford_ramcloud_JRamCloud_remove__J_3BLedu_stanford_ramcloud_JRamCloud_00024RejectRules_2
514 (JNIEnv *, jobject, jlong, jbyteArray, jobject);
515#ifdef __cplusplus
516}
517#endif
518
yoshi28bac132014-01-22 11:00:17 -0800519/*
520 * Class: edu_stanford_ramcloud_JRamCloud
521 * Method: remove
Yuta HIGUCHI9402dab2014-01-30 19:54:31 -0800522 * Signature: (J[BLedu/stanford/ramcloud/JRamCloud/$RejectRules;)J
yoshi28bac132014-01-22 11:00:17 -0800523 */
524JNIEXPORT jlong
Yuta HIGUCHI9402dab2014-01-30 19:54:31 -0800525JNICALL Java_edu_stanford_ramcloud_JRamCloud_remove__J_3BLedu_stanford_ramcloud_JRamCloud_00024RejectRules_2(JNIEnv *env,
yoshi28bac132014-01-22 11:00:17 -0800526 jobject jRamCloud,
527 jlong jTableId,
528 jbyteArray jKey,
529 jobject jRejectRules)
530{
yoshi28bac132014-01-22 11:00:17 -0800531 RamCloud* ramcloud = getRamCloud(env, jRamCloud);
532 JByteArrayReference key(env, jKey);
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800533 RejectRules rules = {};
534 setRejectRules(env, jRejectRules, rules);
yoshi28bac132014-01-22 11:00:17 -0800535 uint64_t version;
536 try {
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800537 ramcloud->remove(jTableId, key.pointer, key.length, &rules, &version);
yoshi28bac132014-01-22 11:00:17 -0800538 } EXCEPTION_CATCHER(-1);
539 return static_cast<jlong>(version);
540}
541
542/*
543 * Class: edu_stanford_ramcloud_JRamCloud
544 * Method: write
545 * Signature: (J[B[B)J
546 */
547JNIEXPORT jlong
548JNICALL Java_edu_stanford_ramcloud_JRamCloud_write__J_3B_3B(JNIEnv *env,
549 jobject jRamCloud,
550 jlong jTableId,
551 jbyteArray jKey,
552 jbyteArray jValue)
553{
554 RamCloud* ramcloud = getRamCloud(env, jRamCloud);
555 JByteArrayReference key(env, jKey);
556 JByteArrayGetter value(env, jValue);
557 uint64_t version;
558 try {
559 ramcloud->write(jTableId,
560 key.pointer, key.length,
561 value.pointer, value.length,
562 NULL,
563 &version);
564 } EXCEPTION_CATCHER(-1);
565 return static_cast<jlong>(version);
566}
567
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800568// Workaround for javah generating incorrect signature for inner class
569// 00024 is an escaped signature for $ character
570#ifdef __cplusplus
571extern "C" {
572#endif
573JNIEXPORT jlong JNICALL Java_edu_stanford_ramcloud_JRamCloud_write__J_3B_3BLedu_stanford_ramcloud_JRamCloud_00024RejectRules_2
574 (JNIEnv *, jobject, jlong, jbyteArray, jbyteArray, jobject);
575#ifdef __cplusplus
576}
577#endif
578
yoshi28bac132014-01-22 11:00:17 -0800579/*
580 * Class: edu_stanford_ramcloud_JRamCloud
581 * Method: write
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800582 * Signature: (J[B[BLedu/stanford/ramcloud/JRamCloud/RejectRules;)J
yoshi28bac132014-01-22 11:00:17 -0800583 */
584JNIEXPORT jlong
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800585JNICALL Java_edu_stanford_ramcloud_JRamCloud_write__J_3B_3BLedu_stanford_ramcloud_JRamCloud_00024RejectRules_2(JNIEnv *env,
yoshi28bac132014-01-22 11:00:17 -0800586 jobject jRamCloud,
587 jlong jTableId,
588 jbyteArray jKey,
589 jbyteArray jValue,
590 jobject jRejectRules)
591{
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800592 return Java_edu_stanford_ramcloud_JRamCloud_writeRule(env, jRamCloud, jTableId, jKey, jValue, jRejectRules);
yoshi28bac132014-01-22 11:00:17 -0800593}
594
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800595/*
596 * Class: edu_stanford_ramcloud_JRamCloud
597 * Method: writeRule
598 * Signature: (J[B[BLedu/stanford/ramcloud/JRamCloud/RejectRules;)J
599 */
yoshi28bac132014-01-22 11:00:17 -0800600JNIEXPORT jlong
601JNICALL Java_edu_stanford_ramcloud_JRamCloud_writeRule(JNIEnv *env,
602 jobject jRamCloud,
603 jlong jTableId,
604 jbyteArray jKey,
605 jbyteArray jValue,
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800606 jobject jRejectRules)
607{
yoshi28bac132014-01-22 11:00:17 -0800608 RamCloud* ramcloud = getRamCloud(env, jRamCloud);
609 JByteArrayReference key(env, jKey);
610 JByteArrayGetter value(env, jValue);
yoshi28bac132014-01-22 11:00:17 -0800611 RejectRules rules = {};
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800612 setRejectRules(env, jRejectRules, rules);
613 uint64_t version;
yoshi28bac132014-01-22 11:00:17 -0800614 try {
615 ramcloud->write(jTableId,
616 key.pointer, key.length,
617 value.pointer, value.length,
618 &rules,
619 &version);
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800620 } EXCEPTION_CATCHER(-1);
yoshi28bac132014-01-22 11:00:17 -0800621 return static_cast<jlong> (version);
622}
623
624/*
625 * Class: edu_stanford_ramcloud_JRamCloud_TableEnumerator
626 * Method: init
627 * Signature: (J)V
628 */
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800629JNIEXPORT jlong JNICALL Java_edu_stanford_ramcloud_JRamCloud_00024TableEnumerator_init(JNIEnv *env,
630 jobject jTableEnumerator,
yoshi28bac132014-01-22 11:00:17 -0800631 jlong jTableId)
632{
633 const static jclass cls = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$TableEnumerator"));
634 const static jfieldID fieldId = env->GetFieldID(cls, "ramCloudObjectPointer", "J");
635 RamCloud* ramcloud = reinterpret_cast<RamCloud*>(env->GetLongField(jTableEnumerator, fieldId));
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800636
Yuta HIGUCHIa7ec0732014-03-10 16:01:06 -0700637 return reinterpret_cast<jlong>(new TableEnumerator(*ramcloud, jTableId, false));
yoshi28bac132014-01-22 11:00:17 -0800638}
639
640/*
641 * Class: edu_stanford_ramcloud_JRamCloud_TableEnumerator
642 * Method: hasNext
643 * Signature: ()Z
644 */
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800645JNIEXPORT jboolean JNICALL Java_edu_stanford_ramcloud_JRamCloud_00024TableEnumerator_hasNext( JNIEnv *env,
yoshi28bac132014-01-22 11:00:17 -0800646 jobject jTableEnumerator)
647{
648 TableEnumerator* tableEnum = getTableEnumerator(env, jTableEnumerator);
649 return static_cast<jboolean>(tableEnum->hasNext());
650}
651
652/*
653 * Class: edu_stanford_ramcloud_JRamCloud_TableEnumerator
654 * Method: next
655 * Signature: ()Ledu/stanford/ramcloud/JRamCloud/Object;
656 */
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800657JNIEXPORT jobject JNICALL Java_edu_stanford_ramcloud_JRamCloud_00024TableEnumerator_next( JNIEnv *env,
yoshi28bac132014-01-22 11:00:17 -0800658 jobject jTableEnumerator)
659{
660 TableEnumerator* tableEnum = getTableEnumerator(env, jTableEnumerator);
661
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800662 if (tableEnum->hasNext()) {
yoshi28bac132014-01-22 11:00:17 -0800663 uint32_t size = 0;
664 const void* buffer = 0;
665 uint64_t version = 0;
666
667 tableEnum->next(&size, &buffer);
668 Object object(buffer, size);
669
670 jbyteArray jKey = env->NewByteArray(object.getKeyLength());
671 jbyteArray jValue = env->NewByteArray(object.getDataLength());
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800672
yoshi28bac132014-01-22 11:00:17 -0800673 JByteArrayGetter key(env, jKey);
674 JByteArrayGetter value(env, jValue);
675
676 memcpy(key.pointer, object.getKey(), object.getKeyLength());
677 memcpy(value.pointer, object.getData(), object.getDataLength());
678
679 version = object.getVersion();
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800680
yoshi28bac132014-01-22 11:00:17 -0800681 const static jclass cls = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$Object"));
682 check_null(cls, "FindClass failed");
683 const static jmethodID methodId = env->GetMethodID(cls,
684 "<init>",
Yoshi Muroie7693b12014-02-19 19:41:17 -0800685 "([B[BJ)V");
yoshi28bac132014-01-22 11:00:17 -0800686 check_null(methodId, "GetMethodID failed");
687 return env->NewObject(cls,
688 methodId,
yoshi28bac132014-01-22 11:00:17 -0800689 jKey,
690 jValue,
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800691 static_cast<jlong>(version));
692 } else {
yoshi28bac132014-01-22 11:00:17 -0800693 return NULL;
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800694 }
yoshi28bac132014-01-22 11:00:17 -0800695}
696
697/*
698 * Class: edu_stanford_ramcloud_JRamCloud
Yoshi Muroie7693b12014-02-19 19:41:17 -0800699 * Method: getTableObjects
700 * Signature: (JJ)Ledu/stanford/ramcloud/JRamCloud/TableEnumeratorObject;
701 */
702JNIEXPORT jobject JNICALL Java_edu_stanford_ramcloud_JRamCloud_getTableObjects(JNIEnv *env,
703 jobject jRamCloud,
704 jlong jTableId,
705 jlong jTabletNextHash){
706
707 RamCloud* ramcloud = getRamCloud(env, jRamCloud);
708
Yoshi Muroie7693b12014-02-19 19:41:17 -0800709 const static jclass jc_RcObject = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$Object"));
710 check_null(jc_RcObject, "FindClass failed");
711 const static jmethodID jm_init = env->GetMethodID(jc_RcObject,
712 "<init>",
713 "([B[BJ)V");
714 check_null(jm_init, "GetMethodID failed");
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800715
Yoshi Muroie7693b12014-02-19 19:41:17 -0800716 const static jclass jc_RcTableObject = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$TableEnumeratorObject"));
717 check_null(jc_RcTableObject, "FindClass failed");
718 const static jmethodID jm_TableEnumeratorObject_init = env->GetMethodID(jc_RcTableObject,
719 "<init>",
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800720 "([L" PACKAGE_PATH "JRamCloud$Object;J)V");
Yoshi Muroie7693b12014-02-19 19:41:17 -0800721 check_null(jm_TableEnumeratorObject_init, "GetMethodID failed");
722
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800723
724 Buffer state;
725 Buffer objects;
726 bool done = false;
727
Yoshi Muroie7693b12014-02-19 19:41:17 -0800728 while (true) {
Yuta HIGUCHIa7ec0732014-03-10 16:01:06 -0700729 jTabletNextHash = ramcloud->enumerateTable(jTableId, false, jTabletNextHash, state, objects);
Yoshi Muroie7693b12014-02-19 19:41:17 -0800730 if (objects.getTotalLength() > 0) {
731 break;
732 }
733 if (objects.getTotalLength() == 0 && jTabletNextHash == 0) {
734 done = true;
735 break;
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800736 }
Yoshi Muroie7693b12014-02-19 19:41:17 -0800737 }
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800738
Yoshi Muroie7693b12014-02-19 19:41:17 -0800739 if (done) {
740 return env->NewObject(jc_RcTableObject, jm_TableEnumeratorObject_init, env->NewObjectArray(0, jc_RcObject , NULL), 0);
741 }
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800742
743 int numOfObjects = 0;
744 uint32_t nextOffset = 0;
745 for (numOfObjects = 0; nextOffset < objects.getTotalLength() ; numOfObjects++) {
Yoshi Muroie7693b12014-02-19 19:41:17 -0800746 uint32_t objectSize = *objects.getOffset<uint32_t>(nextOffset);
747 nextOffset += downCast<uint32_t>(sizeof(uint32_t));
748 nextOffset += objectSize;
749 }
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800750
751 jobjectArray outJNIArray = env->NewObjectArray(numOfObjects, jc_RcObject , NULL);
Yoshi Muroie7693b12014-02-19 19:41:17 -0800752 check_null(outJNIArray, "NewObjectArray failed");
753
754 nextOffset = 0;
755 for (int i = 0; nextOffset < objects.getTotalLength() ;i++) {
756 uint32_t objectSize = *objects.getOffset<uint32_t>(nextOffset);
757 nextOffset += downCast<uint32_t>(sizeof(uint32_t));
758
759 const void* blob = objects.getRange(nextOffset, objectSize);
760 nextOffset += objectSize;
761
762 Object object(blob, objectSize);
763
764 jbyteArray jKey = env->NewByteArray(object.getKeyLength());
765 jbyteArray jValue = env->NewByteArray(object.getDataLength());
766
767 JByteArrayGetter key(env, jKey);
768 JByteArrayGetter value(env, jValue);
769
770 memcpy(key.pointer, object.getKey(), object.getKeyLength());
771 memcpy(value.pointer, object.getData(), object.getDataLength());
772
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800773 uint64_t version = object.getVersion();
Yoshi Muroie7693b12014-02-19 19:41:17 -0800774
775 jobject obj = env->NewObject(jc_RcObject, jm_init, jKey, jValue, static_cast<jlong>(version));
776 check_null(obj, "NewObject failed");
777
778 env->SetObjectArrayElement(outJNIArray, i, obj);
779 }
780
781 return env->NewObject(jc_RcTableObject, jm_TableEnumeratorObject_init, outJNIArray, jTabletNextHash);
Yoshi Muroie7693b12014-02-19 19:41:17 -0800782}
783
784/*
785 * Class: edu_stanford_ramcloud_JRamCloud
yoshi28bac132014-01-22 11:00:17 -0800786 * Method: multiWrite
787 * Signature: ([Ledu/stanford/ramcloud/JRamCloud/MultiWriteObject;)[Ledu/stanford/ramcloud/JRamCloud/MultiWriteRspObject;
788 */
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800789JNIEXPORT jobjectArray JNICALL Java_edu_stanford_ramcloud_JRamCloud_multiWrite(JNIEnv *env,
Yoshi Muroie7693b12014-02-19 19:41:17 -0800790 jobject jRamCloud,
791 jlongArray jTableId,
792 jobjectArray jKeyData,
793 jshortArray jKeyLength,
794 jobjectArray jValueData,
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800795 jintArray jValueLength,
Yoshi Muroie7693b12014-02-19 19:41:17 -0800796 jint jrequestNum,
797 jobjectArray jRules ) {
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800798
Yoshi Muroie7693b12014-02-19 19:41:17 -0800799 RamCloud* ramcloud = getRamCloud(env, jRamCloud);
800 Tub<MultiWriteObject> objects[jrequestNum];
801 MultiWriteObject *requests[jrequestNum];
802 RejectRules rules[jrequestNum];
803 jbyteArray jKey[jrequestNum];
804 jbyteArray jValue[jrequestNum];
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800805
Yoshi Muroie7693b12014-02-19 19:41:17 -0800806 jlong tableId;
807 jshort keyLength;
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800808 jint valueLength;
Yoshi Muroie7693b12014-02-19 19:41:17 -0800809 jbyte* keyData[jrequestNum];
810 jbyte* valueData[jrequestNum];
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800811
yoshi28bac132014-01-22 11:00:17 -0800812 const static jclass jc_RejectRules = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$RejectRules"));
yoshi28bac132014-01-22 11:00:17 -0800813
yoshi28bac132014-01-22 11:00:17 -0800814 const static jfieldID jf_givenVersion = env->GetFieldID(jc_RejectRules, "givenVersion", "J");
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800815 check_null(jf_givenVersion, "givenVersion field ID is null");
816
817 const static jfieldID jf_flags = env->GetFieldID(jc_RejectRules, "flags", "I");
818 check_null(jf_flags, "flags field ID is null");
yoshi28bac132014-01-22 11:00:17 -0800819
Yoshi Muroie7693b12014-02-19 19:41:17 -0800820 for (int i = 0; i < jrequestNum; i++) {
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800821 env->GetLongArrayRegion(jTableId, i, 1, &tableId);
yoshi28bac132014-01-22 11:00:17 -0800822
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800823 env->GetShortArrayRegion(jKeyLength, i, 1, &keyLength);
824 jKey[i] = (jbyteArray)env->GetObjectArrayElement(jKeyData, i);
825 keyData[i] = (jbyte *) malloc(keyLength);
826 env->GetByteArrayRegion(jKey[i], 0, keyLength, keyData[i]);
827
828 env->GetIntArrayRegion(jValueLength, i, 1, &valueLength);
Yoshi Muroie7693b12014-02-19 19:41:17 -0800829 jValue[i] = (jbyteArray)env->GetObjectArrayElement(jValueData, i);
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800830 valueData[i] = (jbyte *) malloc(valueLength);
831 env->GetByteArrayRegion(jValue[i], 0, valueLength, valueData[i]);
832
833 jobject jRejectRules = (jbyteArray)env->GetObjectArrayElement(jRules, i);
yoshi28bac132014-01-22 11:00:17 -0800834 rules[i] = {};
835
836 if (jRejectRules != NULL) {
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800837 const jint flags = env->GetIntField(jRejectRules, jf_flags);
yoshi28bac132014-01-22 11:00:17 -0800838
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800839 rules[i].doesntExist = (flags & DoesntExist) != 0;
yoshi28bac132014-01-22 11:00:17 -0800840
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800841 rules[i].exists = (flags & Exists) != 0;
yoshi28bac132014-01-22 11:00:17 -0800842
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800843 rules[i].versionLeGiven = (flags & VersionLeGiven) != 0;
yoshi28bac132014-01-22 11:00:17 -0800844
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800845 rules[i].versionNeGiven = (flags & VersionNeGiven) != 0;
yoshi28bac132014-01-22 11:00:17 -0800846
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800847 if (rules[i].versionLeGiven || rules[i].versionNeGiven) {
848 rules[i].givenVersion = env->GetLongField(jRejectRules, jf_givenVersion);
849 }
yoshi28bac132014-01-22 11:00:17 -0800850 }
Yoshi Muroie7693b12014-02-19 19:41:17 -0800851 objects[i].construct(tableId, keyData[i], keyLength, valueData[i], valueLength, &rules[i]);
yoshi28bac132014-01-22 11:00:17 -0800852 requests[i] = objects[i].get();
853 }
854 try {
Yoshi Muroie7693b12014-02-19 19:41:17 -0800855 ramcloud->multiWrite(requests, jrequestNum);
yoshi28bac132014-01-22 11:00:17 -0800856 } EXCEPTION_CATCHER(NULL);
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800857
yoshi28bac132014-01-22 11:00:17 -0800858 const static jclass jc_RcObject = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$MultiWriteRspObject"));
859 check_null(jc_RcObject, "FindClass failed");
860 const static jmethodID jm_init = env->GetMethodID(jc_RcObject,
861 "<init>",
Yoshi Muroie7693b12014-02-19 19:41:17 -0800862 "(IJ)V");
yoshi28bac132014-01-22 11:00:17 -0800863
Yoshi Muroie7693b12014-02-19 19:41:17 -0800864 jobjectArray outJNIArray = env->NewObjectArray(jrequestNum, jc_RcObject , NULL);
yoshi28bac132014-01-22 11:00:17 -0800865 check_null(outJNIArray, "NewObjectArray failed");
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800866
Yoshi Muroie7693b12014-02-19 19:41:17 -0800867 for (int i = 0 ; i < jrequestNum ; i++) {
868 jobject obj = env->NewObject(jc_RcObject, jm_init, objects[i]->status, objects[i]->version);
yoshi28bac132014-01-22 11:00:17 -0800869 check_null(obj, "NewObject failed");
870 env->SetObjectArrayElement(outJNIArray, i, obj);
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800871 free(keyData[i]);
872 free(valueData[i]);
yoshi28bac132014-01-22 11:00:17 -0800873 objects[i].destroy();
874 }
875 return outJNIArray;
876}