blob: fe61007e4208ca2625c0661d19433d88efc0bfb8 [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"
20#include "edu_stanford_ramcloud_JRamCloud_TableEnumerator.h"
21
22using namespace RAMCloud;
23
24/// Our JRamCloud java library is packaged under "edu.stanford.ramcloud".
25/// We will need this when using FindClass, etc.
26#define PACKAGE_PATH "edu/stanford/ramcloud/"
27
28#define check_null(var, msg) \
29 if (var == NULL) { \
30 throw Exception(HERE, "JRamCloud: NULL returned: " msg "\n"); \
31 }
32
33/**
34 * This class provides a simple means of extracting C-style strings
35 * from a jstring and cleans up when the destructor is called. This
36 * avoids having to manually do the annoying GetStringUTFChars /
37 * ReleaseStringUTFChars dance.
38 */
39class JStringGetter {
40 public:
41 JStringGetter(JNIEnv* env, jstring jString)
42 : env(env)
43 , jString(jString)
44 , string(env->GetStringUTFChars(jString, 0))
45 {
46 check_null(string, "GetStringUTFChars failed");
47 }
48
49 ~JStringGetter()
50 {
51 if (string != NULL)
52 env->ReleaseStringUTFChars(jString, string);
53 }
54
55 private:
56 JNIEnv* env;
57 jstring jString;
58
59 public:
60 const char* const string;
61};
62
63/**
64 * This class provides a simple means of accessing jbyteArrays as
65 * C-style void* buffers and cleans up when the destructor is called.
66 * This avoids having to manually do the annoying GetByteArrayElements /
67 * ReleaseByteArrayElements dance.
68 */
69class JByteArrayGetter {
70 public:
71 JByteArrayGetter(JNIEnv* env, jbyteArray jByteArray)
72 : env(env)
73 , jByteArray(jByteArray)
74 , pointer(static_cast<void*>(env->GetByteArrayElements(jByteArray, 0)))
75 , length(env->GetArrayLength(jByteArray))
76 {
77 check_null(pointer, "GetByteArrayElements failed");
78 }
79
80 ~JByteArrayGetter()
81 {
82 if (pointer != NULL) {
83 env->ReleaseByteArrayElements(jByteArray,
84 reinterpret_cast<jbyte*>(pointer),
85 0);
86 }
87 }
88
89 private:
90 JNIEnv* env;
91 jbyteArray jByteArray;
92
93 public:
94 void* const pointer;
95 const jsize length;
96};
97
98class JByteArrayReference {
99 public:
100 JByteArrayReference(JNIEnv* env, jbyteArray jByteArray)
101 : env(env)
102 , jByteArray(jByteArray)
103 , pointer(static_cast<const void*>(env->GetByteArrayElements(jByteArray, 0)))
104 , length(env->GetArrayLength(jByteArray))
105 {
106 check_null(pointer, "GetByteArrayElements failed");
107 }
108
109 ~JByteArrayReference()
110 {
111 if (pointer != NULL) {
112 env->ReleaseByteArrayElements(jByteArray,
113 (jbyte*)pointer,
114 JNI_ABORT);
115 }
116 }
117
118 private:
119 JNIEnv* env;
120 jbyteArray jByteArray;
121
122 public:
123 const void* const pointer;
124 const jsize length;
125};
126
127static RamCloud*
128getRamCloud(JNIEnv* env, jobject jRamCloud)
129{
130 const static jclass cls = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud"));
131 const static jfieldID fieldId = env->GetFieldID(cls, "ramcloudObjectPointer", "J");
132 return reinterpret_cast<RamCloud*>(env->GetLongField(jRamCloud, fieldId));
133}
134
135static TableEnumerator*
136getTableEnumerator(JNIEnv* env, jobject jTableEnumerator)
137{
138 const static jclass cls = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$TableEnumerator"));
139 const static jfieldID fieldId = env->GetFieldID(cls, "tableEnumeratorObjectPointer", "J");
140 return reinterpret_cast<TableEnumerator*>(env->GetLongField(jTableEnumerator, fieldId));
141}
142
143static void
144createException(JNIEnv* env, jobject jRamCloud, const char* name)
145{
146 // Need to specify the full class name, including the package. To make it
147 // slightly more complicated, our exceptions are nested under the JRamCloud
148 // class.
149 string fullName = PACKAGE_PATH;
150 fullName += "JRamCloud$";
151 fullName += name;
152
153 // This would be much easier if we didn't make our Exception classes nested
154 // under JRamCloud since env->ThrowNew() could be used instead. The problem
155 // is that ThrowNew assumes a particular method signature that happens to
156 // be incompatible with the nested classes' signatures.
157 jclass cls = env->FindClass(fullName.c_str());
158 check_null(cls, "FindClass failed");
159
160 jmethodID methodId = env->GetMethodID(cls,
161 "<init>",
162 "(L" PACKAGE_PATH "JRamCloud;Ljava/lang/String;)V");
163 check_null(methodId, "GetMethodID failed");
164
165 jstring jString = env->NewStringUTF("");
166 check_null(jString, "NewStringUTF failed");
167
168 jthrowable exception = reinterpret_cast<jthrowable>(
169 env->NewObject(cls, methodId, jRamCloud, jString));
170 check_null(exception, "NewObject failed");
171
172 env->Throw(exception);
173}
174
175/**
176 * This macro is used to catch C++ exceptions and convert them into Java
177 * exceptions. Be sure to wrap the individual RamCloud:: calls in try blocks,
178 * rather than the entire methods, since doing so with functions that return
179 * non-void is a bad idea with undefined(?) behaviour.
180 *
181 * _returnValue is the value that should be returned from the JNI function
182 * when an exception is caught and generated in Java. As far as I can tell,
183 * the exception fires immediately upon returning from the JNI method. I
184 * don't think anything else would make sense, but the JNI docs kind of
185 * suck.
186 */
187#define EXCEPTION_CATCHER(_returnValue) \
188 catch (TableDoesntExistException& e) { \
189 createException(env, jRamCloud, "TableDoesntExistException"); \
190 return _returnValue; \
191 } catch (ObjectDoesntExistException& e) { \
192 createException(env, jRamCloud, "ObjectDoesntExistException"); \
193 return _returnValue; \
194 } catch (ObjectExistsException& e) { \
195 createException(env, jRamCloud, "ObjectExistsException"); \
196 return _returnValue; \
197 } catch (WrongVersionException& e) { \
198 createException(env, jRamCloud, "WrongVersionException"); \
199 return _returnValue; \
200 } catch (RejectRulesException& e) { \
201 createException(env, jRamCloud, "RejectRulesException"); \
202 return _returnValue; \
203 } catch (InvalidObjectException& e) { \
204 createException(env, jRamCloud, "InvalidObjectException"); \
205 return _returnValue; \
206 }
207
208/*
209 * Class: edu_stanford_ramcloud_JRamCloud
210 * Method: connect
211 * Signature: (Ljava/lang/String;)J
212 */
213JNIEXPORT jlong
214JNICALL Java_edu_stanford_ramcloud_JRamCloud_connect(JNIEnv *env,
215 jclass jRamCloud,
216 jstring coordinatorLocator)
217{
218 JStringGetter locator(env, coordinatorLocator);
219 RamCloud* ramcloud = NULL;
220 try {
221 ramcloud = new RamCloud(locator.string);
222 } EXCEPTION_CATCHER(NULL);
223 return reinterpret_cast<jlong>(ramcloud);
224}
225
226/*
227 * Class: edu_stanford_ramcloud_JRamCloud
228 * Method: disconnect
229 * Signature: (J)V
230 */
231JNIEXPORT void
232JNICALL Java_edu_stanford_ramcloud_JRamCloud_disconnect(JNIEnv *env,
233 jclass jRamCloud,
234 jlong ramcloudObjectPointer)
235{
236 delete reinterpret_cast<RamCloud*>(ramcloudObjectPointer);
237}
238
239/*
240 * Class: edu_stanford_ramcloud_JRamCloud
241 * Method: createTable
242 * Signature: (Ljava/lang/String;)I
243 */
244JNIEXPORT jlong
245JNICALL Java_edu_stanford_ramcloud_JRamCloud_createTable__Ljava_lang_String_2(JNIEnv *env,
246 jobject jRamCloud,
247 jstring jTableName)
248{
249 return Java_edu_stanford_ramcloud_JRamCloud_createTable__Ljava_lang_String_2I(env,
250 jRamCloud,
251 jTableName,
252 1);
253}
254
255/*
256 * Class: edu_stanford_ramcloud_JRamCloud
257 * Method: createTable
258 * Signature: (Ljava/lang/String;I)I
259 */
260JNIEXPORT jlong
261JNICALL Java_edu_stanford_ramcloud_JRamCloud_createTable__Ljava_lang_String_2I(JNIEnv *env,
262 jobject jRamCloud,
263 jstring jTableName,
264 jint jServerSpan)
265{
266 RamCloud* ramcloud = getRamCloud(env, jRamCloud);
267 JStringGetter tableName(env, jTableName);
268 uint64_t tableId;
269 try {
270 tableId = ramcloud->createTable(tableName.string, jServerSpan);
271 } EXCEPTION_CATCHER(-1);
272 return static_cast<jlong>(tableId);
273}
274
275/*
276 * Class: edu_stanford_ramcloud_JRamCloud
277 * Method: dropTable
278 * Signature: (Ljava/lang/String;)I
279 */
280JNIEXPORT void
281JNICALL Java_edu_stanford_ramcloud_JRamCloud_dropTable(JNIEnv *env,
282 jobject jRamCloud,
283 jstring jTableName)
284{
285 RamCloud* ramcloud = getRamCloud(env, jRamCloud);
286 JStringGetter tableName(env, jTableName);
287 try {
288 ramcloud->dropTable(tableName.string);
289 } EXCEPTION_CATCHER();
290}
291
292/*
293 * Class: edu_stanford_ramcloud_JRamCloud
294 * Method: getTableId
295 * Signature: (Ljava/lang/String;)J
296 */
297JNIEXPORT jlong
298JNICALL Java_edu_stanford_ramcloud_JRamCloud_getTableId(JNIEnv *env,
299 jobject jRamCloud,
300 jstring jTableName)
301{
302 RamCloud* ramcloud = getRamCloud(env, jRamCloud);
303 JStringGetter tableName(env, jTableName);
304 uint64_t tableId;
305 try {
306 tableId = ramcloud->getTableId(tableName.string);
307 } EXCEPTION_CATCHER(-1);
308 return tableId;
309}
310
311/*
312 * Class: edu_stanford_ramcloud_JRamCloud
313 * Method: read
314 * Signature: (J[B)LJRamCloud/Object;
315 */
316JNIEXPORT jobject
317JNICALL Java_edu_stanford_ramcloud_JRamCloud_read__J_3B(JNIEnv *env,
318 jobject jRamCloud,
319 jlong jTableId,
320 jbyteArray jKey)
321{
322 RamCloud* ramcloud = getRamCloud(env, jRamCloud);
323 JByteArrayReference key(env, jKey);
324
325 Buffer buffer;
326 uint64_t version;
327 try {
328 ramcloud->read(jTableId, key.pointer, key.length, &buffer, NULL, &version);
329 } EXCEPTION_CATCHER(NULL);
330
331 jbyteArray jValue = env->NewByteArray(buffer.getTotalLength());
332 check_null(jValue, "NewByteArray failed");
333 JByteArrayGetter value(env, jValue);
334 buffer.copy(0, buffer.getTotalLength(), value.pointer);
335
336 // Note that using 'javap -s' on the class file will print out the method
337 // signatures (the third argument to GetMethodID).
338 const static jclass cls = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$Object"));
339 check_null(cls, "FindClass failed");
340
341 const static jmethodID methodId = env->GetMethodID(cls,
342 "<init>",
343 "(L" PACKAGE_PATH "JRamCloud;[B[BJ)V");
344 check_null(methodId, "GetMethodID failed");
345
346 return env->NewObject(cls,
347 methodId,
348 jRamCloud,
349 jKey,
350 jValue,
351 static_cast<jlong>(version));
352}
353
354/*
355 * Class: edu_stanford_ramcloud_JRamCloud
356 * Method: read
357 * Signature: (J[BLJRamCloud/RejectRules;)LJRamCloud/Object;
358 */
359JNIEXPORT jobject
360JNICALL Java_edu_stanford_ramcloud_JRamCloud_read__J_3BLJRamCloud_RejectRules_2(JNIEnv *env,
361 jobject jRamCloud,
362 jlong jTableId,
363 jbyteArray jKey,
364 jobject jRejectRules)
365{
366 // XXX-- implement me by generalising the other read() method.
367 return NULL;
368}
369
370/*
371 * Class: edu_stanford_ramcloud_JRamCloud
372 * Method: multiRead
373 * Signature: ([Ledu/stanford/ramcloud/JRamCloud$multiReadObject;I)[Ledu/stanford/ramcloud/JRamCloud$Object;
374 */
375JNIEXPORT jobjectArray
376JNICALL Java_edu_stanford_ramcloud_JRamCloud_multiRead(JNIEnv *env,
377 jobject jRamCloud,
Yoshi Muroi2c170602014-02-15 08:31:28 -0800378 jlongArray jTableId,
379 jobjectArray jKeyData,
380 jshortArray jKeyDataSize,
381 jint jrequestNum){
yoshi28bac132014-01-22 11:00:17 -0800382
383 RamCloud* ramcloud = getRamCloud(env, jRamCloud);
Yoshi Muroi2c170602014-02-15 08:31:28 -0800384 MultiReadObject objects[jrequestNum];
385 Tub<Buffer> values[jrequestNum];
386 jbyteArray jKey[jrequestNum];
387 MultiReadObject* requests[jrequestNum];
yoshi28bac132014-01-22 11:00:17 -0800388
Yoshi Muroi2c170602014-02-15 08:31:28 -0800389 jlong TableId;
390 jshort KeyDataSize;
391 jbyte* data[jrequestNum];
yoshi28bac132014-01-22 11:00:17 -0800392
Yoshi Muroi2c170602014-02-15 08:31:28 -0800393 for (int i = 0 ; i < jrequestNum ; i++){
394 jKey[i] = (jbyteArray)env->GetObjectArrayElement(jKeyData, i);
yoshi28bac132014-01-22 11:00:17 -0800395
Yoshi Muroi2c170602014-02-15 08:31:28 -0800396 env->GetShortArrayRegion(jKeyDataSize, i, 1, &KeyDataSize);
yoshi28bac132014-01-22 11:00:17 -0800397
Yoshi Muroi2c170602014-02-15 08:31:28 -0800398 data[i] = (jbyte *) malloc(KeyDataSize);
399 env->GetByteArrayRegion(jKey[i], 0, KeyDataSize, data[i]);
yoshi28bac132014-01-22 11:00:17 -0800400
Yoshi Muroi2c170602014-02-15 08:31:28 -0800401 env->GetLongArrayRegion(jTableId, i, 1, &TableId);
402 objects[i].tableId = TableId;
403 objects[i].key = data[i];
404 objects[i].keyLength = KeyDataSize;
yoshi28bac132014-01-22 11:00:17 -0800405 objects[i].value = &values[i];
406 requests[i] = &objects[i];
407 }
408
409 try {
Yoshi Muroi2c170602014-02-15 08:31:28 -0800410 ramcloud->multiRead(requests, jrequestNum);
yoshi28bac132014-01-22 11:00:17 -0800411 } EXCEPTION_CATCHER(NULL);
412
413 const static jclass jc_RcObject = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$Object"));
414 check_null(jc_RcObject, "FindClass failed");
415 const static jmethodID jm_init = env->GetMethodID(jc_RcObject,
416 "<init>",
417 "(L" PACKAGE_PATH "JRamCloud;[B[BJ)V");
418
Yoshi Muroi2c170602014-02-15 08:31:28 -0800419 jobjectArray outJNIArray = env->NewObjectArray(jrequestNum, jc_RcObject , NULL);
yoshi28bac132014-01-22 11:00:17 -0800420 check_null(outJNIArray, "NewObjectArray failed");
421
Yoshi Muroi2c170602014-02-15 08:31:28 -0800422 for (int i = 0 ; i < jrequestNum ; i++) {
yoshi28bac132014-01-22 11:00:17 -0800423 if (objects[i].status == 0) {
424 jbyteArray jValue = env->NewByteArray(values[i].get()->getTotalLength());
425 check_null(jValue, "NewByteArray failed");
426 JByteArrayGetter value(env, jValue);
427 values[i].get()->copy(0, values[i].get()->getTotalLength(), value.pointer);
428 jobject obj = env->NewObject(jc_RcObject, jm_init, jRamCloud, jKey[i], jValue);
429 check_null(obj, "NewObject failed");
430 env->SetObjectArrayElement(outJNIArray, i, obj);
431 }
Yoshi Muroi2c170602014-02-15 08:31:28 -0800432 free(data[i]);
yoshi28bac132014-01-22 11:00:17 -0800433 }
434 return outJNIArray;
435}
436
437
438/*
439 * Class: edu_stanford_ramcloud_JRamCloud
440 * Method: remove
441 * Signature: (J[B)J
442 */
443JNIEXPORT jlong
444JNICALL Java_edu_stanford_ramcloud_JRamCloud_remove__J_3B(JNIEnv *env,
445 jobject jRamCloud,
446 jlong jTableId,
447 jbyteArray jKey)
448{
449 RamCloud* ramcloud = getRamCloud(env, jRamCloud);
450 JByteArrayReference key(env, jKey);
451 uint64_t version;
452 try {
453 ramcloud->remove(jTableId, key.pointer, key.length, NULL, &version);
454 } EXCEPTION_CATCHER(-1);
455 return static_cast<jlong>(version);
456}
457
Yuta HIGUCHI9402dab2014-01-30 19:54:31 -0800458
459// Workaround for javah generating incorrect signature for inner class
460// 00024 is an escaped signature for $ character
461#ifdef __cplusplus
462extern "C" {
463#endif
464JNIEXPORT jlong JNICALL Java_edu_stanford_ramcloud_JRamCloud_remove__J_3BLedu_stanford_ramcloud_JRamCloud_00024RejectRules_2
465 (JNIEnv *, jobject, jlong, jbyteArray, jobject);
466#ifdef __cplusplus
467}
468#endif
469
yoshi28bac132014-01-22 11:00:17 -0800470/*
471 * Class: edu_stanford_ramcloud_JRamCloud
472 * Method: remove
Yuta HIGUCHI9402dab2014-01-30 19:54:31 -0800473 * Signature: (J[BLedu/stanford/ramcloud/JRamCloud/$RejectRules;)J
yoshi28bac132014-01-22 11:00:17 -0800474 */
475JNIEXPORT jlong
Yuta HIGUCHI9402dab2014-01-30 19:54:31 -0800476JNICALL Java_edu_stanford_ramcloud_JRamCloud_remove__J_3BLedu_stanford_ramcloud_JRamCloud_00024RejectRules_2(JNIEnv *env,
yoshi28bac132014-01-22 11:00:17 -0800477 jobject jRamCloud,
478 jlong jTableId,
479 jbyteArray jKey,
480 jobject jRejectRules)
481{
482 // XXX- handle RejectRules
483 RamCloud* ramcloud = getRamCloud(env, jRamCloud);
484 JByteArrayReference key(env, jKey);
485 uint64_t version;
486 try {
487 ramcloud->remove(jTableId, key.pointer, key.length, NULL, &version);
488 } EXCEPTION_CATCHER(-1);
489 return static_cast<jlong>(version);
490}
491
492/*
493 * Class: edu_stanford_ramcloud_JRamCloud
494 * Method: write
495 * Signature: (J[B[B)J
496 */
497JNIEXPORT jlong
498JNICALL Java_edu_stanford_ramcloud_JRamCloud_write__J_3B_3B(JNIEnv *env,
499 jobject jRamCloud,
500 jlong jTableId,
501 jbyteArray jKey,
502 jbyteArray jValue)
503{
504 RamCloud* ramcloud = getRamCloud(env, jRamCloud);
505 JByteArrayReference key(env, jKey);
506 JByteArrayGetter value(env, jValue);
507 uint64_t version;
508 try {
509 ramcloud->write(jTableId,
510 key.pointer, key.length,
511 value.pointer, value.length,
512 NULL,
513 &version);
514 } EXCEPTION_CATCHER(-1);
515 return static_cast<jlong>(version);
516}
517
518/*
519 * Class: edu_stanford_ramcloud_JRamCloud
520 * Method: write
521 * Signature: (J[B[BLJRamCloud/RejectRules;)J
522 */
523JNIEXPORT jlong
524JNICALL Java_edu_stanford_ramcloud_JRamCloud_write__J_3B_3BLJRamCloud_RejectRules_2(JNIEnv *env,
525 jobject jRamCloud,
526 jlong jTableId,
527 jbyteArray jKey,
528 jbyteArray jValue,
529 jobject jRejectRules)
530{
531 // XXX- handle RejectRules
532 RamCloud* ramcloud = getRamCloud(env, jRamCloud);
533 JByteArrayReference key(env, jKey);
534 JByteArrayGetter value(env, jValue);
535 RejectRules rules;
536 jclass ruleClass = env->GetObjectClass(jRejectRules);
537 jfieldID fid = env->GetFieldID(ruleClass, "doesntExist", "Z");
538 rules.doesntExist = (uint8_t) env->GetBooleanField(jRejectRules, fid);
539
540 fid = env->GetFieldID(ruleClass, "exists", "Z");
541 rules.exists = (uint8_t) env->GetBooleanField(jRejectRules, fid);
542
543 fid = env->GetFieldID(ruleClass, "givenVersion", "J");
544 rules.givenVersion = env->GetLongField(jRejectRules, fid);
545
546 fid = env->GetFieldID(ruleClass, "versionLeGiven", "Z");
547 rules.versionLeGiven = (uint8_t) env->GetBooleanField(jRejectRules, fid);
548
549 fid = env->GetFieldID(ruleClass, "versionNeGiven", "Z");
550 rules.versionNeGiven = (uint8_t) env->GetBooleanField(jRejectRules, fid);
551
552 uint64_t version;
553 try {
554 ramcloud->write(jTableId,
555 key.pointer, key.length,
556 value.pointer, value.length,
557 &rules,
558 &version);
559 }
560 EXCEPTION_CATCHER(-1);
561 return static_cast<jlong> (version);
562}
563
564JNIEXPORT jlong
565JNICALL Java_edu_stanford_ramcloud_JRamCloud_writeRule(JNIEnv *env,
566 jobject jRamCloud,
567 jlong jTableId,
568 jbyteArray jKey,
569 jbyteArray jValue,
570 jobject jRejectRules) {
571 RamCloud* ramcloud = getRamCloud(env, jRamCloud);
572 JByteArrayReference key(env, jKey);
573 JByteArrayGetter value(env, jValue);
574 uint64_t version;
575 RejectRules rules = {};
576 const static jclass jc_RejectRules = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$RejectRules"));
577
578 const static jfieldID jf_doesntExist = env->GetFieldID(jc_RejectRules, "doesntExist", "Z");
579 check_null(jf_doesntExist, "doesentExist field id is null");
580 jboolean ruleBool;
581 ruleBool = env->GetBooleanField(jRejectRules, jf_doesntExist);
582 rules.doesntExist = ruleBool ? 1 : 0;
583
584 const static jfieldID jf_exists = env->GetFieldID(jc_RejectRules, "exists", "Z");
585 check_null(jf_exists, "exists field id is null");
586 ruleBool = env->GetBooleanField(jRejectRules, jf_exists);
587 rules.exists = ruleBool ? 1 : 0;
588
589 const static jfieldID jf_givenVersion = env->GetFieldID(jc_RejectRules, "givenVersion", "J");
590 check_null(jf_givenVersion, "givenVersion field id is null");
591 rules.givenVersion = env->GetLongField(jRejectRules, jf_givenVersion);
592
593 const static jfieldID jf_versionLeGiven = env->GetFieldID(jc_RejectRules, "versionLeGiven", "Z");
594 check_null(jf_versionLeGiven, "versionLeGiven field id is null");
595 ruleBool = env->GetBooleanField(jRejectRules, jf_versionLeGiven);
596 rules.versionLeGiven = ruleBool ? 1 : 0;
597
598 const static jfieldID jf_versionNeGiven = env->GetFieldID(jc_RejectRules, "versionNeGiven", "Z");
599 check_null(jf_versionNeGiven, "versionNeGiven field id is null");
600 ruleBool = env->GetBooleanField(jRejectRules, jf_versionNeGiven);
601 rules.versionNeGiven = ruleBool ? 1 : 0;
602 try {
603 ramcloud->write(jTableId,
604 key.pointer, key.length,
605 value.pointer, value.length,
606 &rules,
607 &version);
608 }
609 EXCEPTION_CATCHER(-1);
610 return static_cast<jlong> (version);
611}
612
613/*
614 * Class: edu_stanford_ramcloud_JRamCloud_TableEnumerator
615 * Method: init
616 * Signature: (J)V
617 */
618JNIEXPORT jlong JNICALL Java_edu_stanford_ramcloud_JRamCloud_00024TableEnumerator_init(JNIEnv *env,
619 jobject jTableEnumerator,
620 jlong jTableId)
621{
622 const static jclass cls = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$TableEnumerator"));
623 const static jfieldID fieldId = env->GetFieldID(cls, "ramCloudObjectPointer", "J");
624 RamCloud* ramcloud = reinterpret_cast<RamCloud*>(env->GetLongField(jTableEnumerator, fieldId));
625
626 return reinterpret_cast<jlong>(new TableEnumerator(*ramcloud, jTableId));
627}
628
629/*
630 * Class: edu_stanford_ramcloud_JRamCloud_TableEnumerator
631 * Method: hasNext
632 * Signature: ()Z
633 */
634JNIEXPORT jboolean JNICALL Java_edu_stanford_ramcloud_JRamCloud_00024TableEnumerator_hasNext( JNIEnv *env,
635 jobject jTableEnumerator)
636{
637 TableEnumerator* tableEnum = getTableEnumerator(env, jTableEnumerator);
638 return static_cast<jboolean>(tableEnum->hasNext());
639}
640
641/*
642 * Class: edu_stanford_ramcloud_JRamCloud_TableEnumerator
643 * Method: next
644 * Signature: ()Ledu/stanford/ramcloud/JRamCloud/Object;
645 */
646JNIEXPORT jobject JNICALL Java_edu_stanford_ramcloud_JRamCloud_00024TableEnumerator_next( JNIEnv *env,
647 jobject jTableEnumerator)
648{
649 TableEnumerator* tableEnum = getTableEnumerator(env, jTableEnumerator);
650
651 if(tableEnum->hasNext())
652 {
653 uint32_t size = 0;
654 const void* buffer = 0;
655 uint64_t version = 0;
656
657 tableEnum->next(&size, &buffer);
658 Object object(buffer, size);
659
660 jbyteArray jKey = env->NewByteArray(object.getKeyLength());
661 jbyteArray jValue = env->NewByteArray(object.getDataLength());
662
663 JByteArrayGetter key(env, jKey);
664 JByteArrayGetter value(env, jValue);
665
666 memcpy(key.pointer, object.getKey(), object.getKeyLength());
667 memcpy(value.pointer, object.getData(), object.getDataLength());
668
669 version = object.getVersion();
670
671 const static jclass cls = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$Object"));
672 check_null(cls, "FindClass failed");
673 const static jmethodID methodId = env->GetMethodID(cls,
674 "<init>",
675 "(L" PACKAGE_PATH "JRamCloud;[B[BJ)V");
676 check_null(methodId, "GetMethodID failed");
677 return env->NewObject(cls,
678 methodId,
679 jTableEnumerator,
680 jKey,
681 jValue,
682 static_cast<jlong>(version));
683 } else
684 return NULL;
685}
686
687/*
688 * Class: edu_stanford_ramcloud_JRamCloud
689 * Method: multiWrite
690 * Signature: ([Ledu/stanford/ramcloud/JRamCloud/MultiWriteObject;)[Ledu/stanford/ramcloud/JRamCloud/MultiWriteRspObject;
691 */
692JNIEXPORT jobjectArray JNICALL Java_edu_stanford_ramcloud_JRamCloud_multiWrite(JNIEnv *env, jobject jRamCloud, jobjectArray jmultiWriteArray) {
693 jint requestNum = env->GetArrayLength(jmultiWriteArray);
694 RamCloud* ramcloud = getRamCloud(env, jRamCloud);
695 Tub<MultiWriteObject> objects[requestNum];
696 MultiWriteObject *requests[requestNum];
697 RejectRules rules[requestNum];
698 jbyteArray jKey[requestNum];
699 jbyteArray jValue[requestNum];
700
701 const static jclass jc_multiWriteObject = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$MultiWriteObject"));
702 const static jclass jc_RejectRules = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$RejectRules"));
703 const static jfieldID jf_tableId = env->GetFieldID(jc_multiWriteObject, "tableId", "J");
704 const static jfieldID jf_key = env->GetFieldID(jc_multiWriteObject, "key", "[B");
705 const static jfieldID jf_value = env->GetFieldID(jc_multiWriteObject, "value", "[B");
706 const static jfieldID jf_reject_rules = env->GetFieldID(jc_multiWriteObject, "rules", "L" PACKAGE_PATH "JRamCloud$RejectRules;");
707
708 const static jfieldID jf_doesntExist = env->GetFieldID(jc_RejectRules, "doesntExist", "Z");
709 check_null(jf_doesntExist, "doesentExist field id is null");
710 const static jfieldID jf_exists = env->GetFieldID(jc_RejectRules, "exists", "Z");
711 check_null(jf_exists, "exists field id is null");
712 const static jfieldID jf_givenVersion = env->GetFieldID(jc_RejectRules, "givenVersion", "J");
713 check_null(jf_givenVersion, "givenVersion field id is null");
714 const static jfieldID jf_versionLeGiven = env->GetFieldID(jc_RejectRules, "versionLeGiven", "Z");
715 check_null(jf_versionLeGiven, "versionLeGiven field id is null");
716 const static jfieldID jf_versionNeGiven = env->GetFieldID(jc_RejectRules, "versionNeGiven", "Z");
717 check_null(jf_versionNeGiven, "versionNeGiven field id is null");
718
719 for (int i = 0; i < requestNum; i++) {
720 jobject obj = env->GetObjectArrayElement(jmultiWriteArray, i);
721 check_null(obj, "multi write GetObjectArrayElement failed");
722
723 uint64_t tableId = env->GetLongField(obj, jf_tableId);
724
725 jKey[i] = (jbyteArray)env->GetObjectField(obj, jf_key);
726 jbyte* keyData = env->GetByteArrayElements(jKey[i], NULL);
727 uint16_t keyLength = env->GetArrayLength(jKey[i]);
728
729 jValue[i] = (jbyteArray)env->GetObjectField(obj, jf_value);
730 jbyte* valueData = env->GetByteArrayElements(jValue[i], NULL);
731 uint32_t valueLength = env->GetArrayLength(jValue[i]);
732
733 jobject jRejectRules = env->GetObjectField(obj, jf_reject_rules);
734 rules[i] = {};
735
736 if (jRejectRules != NULL) {
737 jboolean ruleBool;
738
739 ruleBool = env->GetBooleanField(jRejectRules, jf_doesntExist);
740 rules[i].doesntExist = ruleBool ? 1 : 0;
741
742 ruleBool = env->GetBooleanField(jRejectRules, jf_exists);
743 rules[i].exists = ruleBool ? 1 : 0;
744
745 rules[i].givenVersion = env->GetLongField(jRejectRules, jf_givenVersion);
746
747 ruleBool = env->GetBooleanField(jRejectRules, jf_versionLeGiven);
748 rules[i].versionLeGiven = ruleBool ? 1 : 0;
749
750 ruleBool = env->GetBooleanField(jRejectRules, jf_versionNeGiven);
751 rules[i].versionNeGiven = ruleBool ? 1 : 0;
752 }
753 objects[i].construct(tableId, keyData, keyLength, valueData, valueLength, &rules[i]);
754 requests[i] = objects[i].get();
755 }
756 try {
757 ramcloud->multiWrite(requests, requestNum);
758 } EXCEPTION_CATCHER(NULL);
759
760 const static jclass jc_RcObject = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$MultiWriteRspObject"));
761 check_null(jc_RcObject, "FindClass failed");
762 const static jmethodID jm_init = env->GetMethodID(jc_RcObject,
763 "<init>",
764 "(L" PACKAGE_PATH "JRamCloud;IJ)V");
765
766 jobjectArray outJNIArray = env->NewObjectArray(requestNum, jc_RcObject , NULL);
767 check_null(outJNIArray, "NewObjectArray failed");
768
769 for (int i = 0 ; i < requestNum ; i++) {
770 jobject obj = env->NewObject(jc_RcObject, jm_init, jRamCloud, objects[i]->status, objects[i]->version);
771 check_null(obj, "NewObject failed");
772 env->SetObjectArrayElement(outJNIArray, i, obj);
773 env->ReleaseByteArrayElements(jKey[i], (jbyte *)requests[i]->key, JNI_ABORT);
774 env->ReleaseByteArrayElements(jValue[i], (jbyte *)requests[i]->value, JNI_ABORT);
775 objects[i].destroy();
776 }
777 return outJNIArray;
778}