blob: 4694c4e0ae1f5cc5c686a86a63c8a347f038eb17 [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>",
Yoshi Muroie7693b12014-02-19 19:41:17 -0800343 "([B[BJ)V");
yoshi28bac132014-01-22 11:00:17 -0800344 check_null(methodId, "GetMethodID failed");
345
346 return env->NewObject(cls,
347 methodId,
yoshi28bac132014-01-22 11:00:17 -0800348 jKey,
349 jValue,
350 static_cast<jlong>(version));
351}
352
353/*
354 * Class: edu_stanford_ramcloud_JRamCloud
355 * Method: read
356 * Signature: (J[BLJRamCloud/RejectRules;)LJRamCloud/Object;
357 */
358JNIEXPORT jobject
359JNICALL Java_edu_stanford_ramcloud_JRamCloud_read__J_3BLJRamCloud_RejectRules_2(JNIEnv *env,
360 jobject jRamCloud,
361 jlong jTableId,
362 jbyteArray jKey,
363 jobject jRejectRules)
364{
365 // XXX-- implement me by generalising the other read() method.
366 return NULL;
367}
368
369/*
370 * Class: edu_stanford_ramcloud_JRamCloud
371 * Method: multiRead
372 * Signature: ([Ledu/stanford/ramcloud/JRamCloud$multiReadObject;I)[Ledu/stanford/ramcloud/JRamCloud$Object;
373 */
374JNIEXPORT jobjectArray
375JNICALL Java_edu_stanford_ramcloud_JRamCloud_multiRead(JNIEnv *env,
376 jobject jRamCloud,
Yoshi Muroi2c170602014-02-15 08:31:28 -0800377 jlongArray jTableId,
378 jobjectArray jKeyData,
Yoshi Muroie7693b12014-02-19 19:41:17 -0800379 jshortArray jKeyLength,
Yoshi Muroi2c170602014-02-15 08:31:28 -0800380 jint jrequestNum){
yoshi28bac132014-01-22 11:00:17 -0800381
382 RamCloud* ramcloud = getRamCloud(env, jRamCloud);
Yoshi Muroi2c170602014-02-15 08:31:28 -0800383 MultiReadObject objects[jrequestNum];
384 Tub<Buffer> values[jrequestNum];
385 jbyteArray jKey[jrequestNum];
386 MultiReadObject* requests[jrequestNum];
yoshi28bac132014-01-22 11:00:17 -0800387
Yoshi Muroie7693b12014-02-19 19:41:17 -0800388 jlong tableId;
389 jshort keyLength;
390 jbyte* keyData[jrequestNum];
yoshi28bac132014-01-22 11:00:17 -0800391
Yoshi Muroi2c170602014-02-15 08:31:28 -0800392 for (int i = 0 ; i < jrequestNum ; i++){
393 jKey[i] = (jbyteArray)env->GetObjectArrayElement(jKeyData, i);
yoshi28bac132014-01-22 11:00:17 -0800394
Yoshi Muroie7693b12014-02-19 19:41:17 -0800395 env->GetShortArrayRegion(jKeyLength, i, 1, &keyLength);
yoshi28bac132014-01-22 11:00:17 -0800396
Yoshi Muroie7693b12014-02-19 19:41:17 -0800397 keyData[i] = (jbyte *) malloc(keyLength);
398 env->GetByteArrayRegion(jKey[i], 0, keyLength, keyData[i]);
yoshi28bac132014-01-22 11:00:17 -0800399
Yoshi Muroie7693b12014-02-19 19:41:17 -0800400 env->GetLongArrayRegion(jTableId, i, 1, &tableId);
401 objects[i].tableId = tableId;
402 objects[i].key = keyData[i];
403 objects[i].keyLength = keyLength;
yoshi28bac132014-01-22 11:00:17 -0800404 objects[i].value = &values[i];
405 requests[i] = &objects[i];
406 }
407
408 try {
Yoshi Muroi2c170602014-02-15 08:31:28 -0800409 ramcloud->multiRead(requests, jrequestNum);
yoshi28bac132014-01-22 11:00:17 -0800410 } EXCEPTION_CATCHER(NULL);
411
412 const static jclass jc_RcObject = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$Object"));
413 check_null(jc_RcObject, "FindClass failed");
414 const static jmethodID jm_init = env->GetMethodID(jc_RcObject,
415 "<init>",
Yoshi Muroie7693b12014-02-19 19:41:17 -0800416 "([B[BJ)V");
yoshi28bac132014-01-22 11:00:17 -0800417
Yoshi Muroi2c170602014-02-15 08:31:28 -0800418 jobjectArray outJNIArray = env->NewObjectArray(jrequestNum, jc_RcObject , NULL);
yoshi28bac132014-01-22 11:00:17 -0800419 check_null(outJNIArray, "NewObjectArray failed");
420
Yoshi Muroi2c170602014-02-15 08:31:28 -0800421 for (int i = 0 ; i < jrequestNum ; i++) {
yoshi28bac132014-01-22 11:00:17 -0800422 if (objects[i].status == 0) {
423 jbyteArray jValue = env->NewByteArray(values[i].get()->getTotalLength());
424 check_null(jValue, "NewByteArray failed");
425 JByteArrayGetter value(env, jValue);
426 values[i].get()->copy(0, values[i].get()->getTotalLength(), value.pointer);
Yoshi Muroie7693b12014-02-19 19:41:17 -0800427 jobject obj = env->NewObject(jc_RcObject, jm_init, jKey[i], jValue);
yoshi28bac132014-01-22 11:00:17 -0800428 check_null(obj, "NewObject failed");
429 env->SetObjectArrayElement(outJNIArray, i, obj);
430 }
Yoshi Muroie7693b12014-02-19 19:41:17 -0800431 free(keyData[i]);
yoshi28bac132014-01-22 11:00:17 -0800432 }
433 return outJNIArray;
434}
435
436
437/*
438 * Class: edu_stanford_ramcloud_JRamCloud
439 * Method: remove
440 * Signature: (J[B)J
441 */
442JNIEXPORT jlong
443JNICALL Java_edu_stanford_ramcloud_JRamCloud_remove__J_3B(JNIEnv *env,
444 jobject jRamCloud,
445 jlong jTableId,
446 jbyteArray jKey)
447{
448 RamCloud* ramcloud = getRamCloud(env, jRamCloud);
449 JByteArrayReference key(env, jKey);
450 uint64_t version;
451 try {
452 ramcloud->remove(jTableId, key.pointer, key.length, NULL, &version);
453 } EXCEPTION_CATCHER(-1);
454 return static_cast<jlong>(version);
455}
456
Yuta HIGUCHI9402dab2014-01-30 19:54:31 -0800457
458// Workaround for javah generating incorrect signature for inner class
459// 00024 is an escaped signature for $ character
460#ifdef __cplusplus
461extern "C" {
462#endif
463JNIEXPORT jlong JNICALL Java_edu_stanford_ramcloud_JRamCloud_remove__J_3BLedu_stanford_ramcloud_JRamCloud_00024RejectRules_2
464 (JNIEnv *, jobject, jlong, jbyteArray, jobject);
465#ifdef __cplusplus
466}
467#endif
468
yoshi28bac132014-01-22 11:00:17 -0800469/*
470 * Class: edu_stanford_ramcloud_JRamCloud
471 * Method: remove
Yuta HIGUCHI9402dab2014-01-30 19:54:31 -0800472 * Signature: (J[BLedu/stanford/ramcloud/JRamCloud/$RejectRules;)J
yoshi28bac132014-01-22 11:00:17 -0800473 */
474JNIEXPORT jlong
Yuta HIGUCHI9402dab2014-01-30 19:54:31 -0800475JNICALL Java_edu_stanford_ramcloud_JRamCloud_remove__J_3BLedu_stanford_ramcloud_JRamCloud_00024RejectRules_2(JNIEnv *env,
yoshi28bac132014-01-22 11:00:17 -0800476 jobject jRamCloud,
477 jlong jTableId,
478 jbyteArray jKey,
479 jobject jRejectRules)
480{
481 // XXX- handle RejectRules
482 RamCloud* ramcloud = getRamCloud(env, jRamCloud);
483 JByteArrayReference key(env, jKey);
484 uint64_t version;
485 try {
486 ramcloud->remove(jTableId, key.pointer, key.length, NULL, &version);
487 } EXCEPTION_CATCHER(-1);
488 return static_cast<jlong>(version);
489}
490
491/*
492 * Class: edu_stanford_ramcloud_JRamCloud
493 * Method: write
494 * Signature: (J[B[B)J
495 */
496JNIEXPORT jlong
497JNICALL Java_edu_stanford_ramcloud_JRamCloud_write__J_3B_3B(JNIEnv *env,
498 jobject jRamCloud,
499 jlong jTableId,
500 jbyteArray jKey,
501 jbyteArray jValue)
502{
503 RamCloud* ramcloud = getRamCloud(env, jRamCloud);
504 JByteArrayReference key(env, jKey);
505 JByteArrayGetter value(env, jValue);
506 uint64_t version;
507 try {
508 ramcloud->write(jTableId,
509 key.pointer, key.length,
510 value.pointer, value.length,
511 NULL,
512 &version);
513 } EXCEPTION_CATCHER(-1);
514 return static_cast<jlong>(version);
515}
516
517/*
518 * Class: edu_stanford_ramcloud_JRamCloud
519 * Method: write
520 * Signature: (J[B[BLJRamCloud/RejectRules;)J
521 */
522JNIEXPORT jlong
523JNICALL Java_edu_stanford_ramcloud_JRamCloud_write__J_3B_3BLJRamCloud_RejectRules_2(JNIEnv *env,
524 jobject jRamCloud,
525 jlong jTableId,
526 jbyteArray jKey,
527 jbyteArray jValue,
528 jobject jRejectRules)
529{
530 // XXX- handle RejectRules
531 RamCloud* ramcloud = getRamCloud(env, jRamCloud);
532 JByteArrayReference key(env, jKey);
533 JByteArrayGetter value(env, jValue);
534 RejectRules rules;
535 jclass ruleClass = env->GetObjectClass(jRejectRules);
536 jfieldID fid = env->GetFieldID(ruleClass, "doesntExist", "Z");
537 rules.doesntExist = (uint8_t) env->GetBooleanField(jRejectRules, fid);
538
539 fid = env->GetFieldID(ruleClass, "exists", "Z");
540 rules.exists = (uint8_t) env->GetBooleanField(jRejectRules, fid);
541
542 fid = env->GetFieldID(ruleClass, "givenVersion", "J");
543 rules.givenVersion = env->GetLongField(jRejectRules, fid);
544
545 fid = env->GetFieldID(ruleClass, "versionLeGiven", "Z");
546 rules.versionLeGiven = (uint8_t) env->GetBooleanField(jRejectRules, fid);
547
548 fid = env->GetFieldID(ruleClass, "versionNeGiven", "Z");
549 rules.versionNeGiven = (uint8_t) env->GetBooleanField(jRejectRules, fid);
550
551 uint64_t version;
552 try {
553 ramcloud->write(jTableId,
554 key.pointer, key.length,
555 value.pointer, value.length,
556 &rules,
557 &version);
558 }
559 EXCEPTION_CATCHER(-1);
560 return static_cast<jlong> (version);
561}
562
563JNIEXPORT jlong
564JNICALL Java_edu_stanford_ramcloud_JRamCloud_writeRule(JNIEnv *env,
565 jobject jRamCloud,
566 jlong jTableId,
567 jbyteArray jKey,
568 jbyteArray jValue,
569 jobject jRejectRules) {
570 RamCloud* ramcloud = getRamCloud(env, jRamCloud);
571 JByteArrayReference key(env, jKey);
572 JByteArrayGetter value(env, jValue);
573 uint64_t version;
574 RejectRules rules = {};
575 const static jclass jc_RejectRules = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$RejectRules"));
576
577 const static jfieldID jf_doesntExist = env->GetFieldID(jc_RejectRules, "doesntExist", "Z");
578 check_null(jf_doesntExist, "doesentExist field id is null");
579 jboolean ruleBool;
580 ruleBool = env->GetBooleanField(jRejectRules, jf_doesntExist);
581 rules.doesntExist = ruleBool ? 1 : 0;
582
583 const static jfieldID jf_exists = env->GetFieldID(jc_RejectRules, "exists", "Z");
584 check_null(jf_exists, "exists field id is null");
585 ruleBool = env->GetBooleanField(jRejectRules, jf_exists);
586 rules.exists = ruleBool ? 1 : 0;
587
588 const static jfieldID jf_givenVersion = env->GetFieldID(jc_RejectRules, "givenVersion", "J");
589 check_null(jf_givenVersion, "givenVersion field id is null");
590 rules.givenVersion = env->GetLongField(jRejectRules, jf_givenVersion);
591
592 const static jfieldID jf_versionLeGiven = env->GetFieldID(jc_RejectRules, "versionLeGiven", "Z");
593 check_null(jf_versionLeGiven, "versionLeGiven field id is null");
594 ruleBool = env->GetBooleanField(jRejectRules, jf_versionLeGiven);
595 rules.versionLeGiven = ruleBool ? 1 : 0;
596
597 const static jfieldID jf_versionNeGiven = env->GetFieldID(jc_RejectRules, "versionNeGiven", "Z");
598 check_null(jf_versionNeGiven, "versionNeGiven field id is null");
599 ruleBool = env->GetBooleanField(jRejectRules, jf_versionNeGiven);
600 rules.versionNeGiven = ruleBool ? 1 : 0;
601 try {
602 ramcloud->write(jTableId,
603 key.pointer, key.length,
604 value.pointer, value.length,
605 &rules,
606 &version);
607 }
608 EXCEPTION_CATCHER(-1);
609 return static_cast<jlong> (version);
610}
611
612/*
613 * Class: edu_stanford_ramcloud_JRamCloud_TableEnumerator
614 * Method: init
615 * Signature: (J)V
616 */
617JNIEXPORT jlong JNICALL Java_edu_stanford_ramcloud_JRamCloud_00024TableEnumerator_init(JNIEnv *env,
618 jobject jTableEnumerator,
619 jlong jTableId)
620{
621 const static jclass cls = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$TableEnumerator"));
622 const static jfieldID fieldId = env->GetFieldID(cls, "ramCloudObjectPointer", "J");
623 RamCloud* ramcloud = reinterpret_cast<RamCloud*>(env->GetLongField(jTableEnumerator, fieldId));
624
625 return reinterpret_cast<jlong>(new TableEnumerator(*ramcloud, jTableId));
626}
627
628/*
629 * Class: edu_stanford_ramcloud_JRamCloud_TableEnumerator
630 * Method: hasNext
631 * Signature: ()Z
632 */
633JNIEXPORT jboolean JNICALL Java_edu_stanford_ramcloud_JRamCloud_00024TableEnumerator_hasNext( JNIEnv *env,
634 jobject jTableEnumerator)
635{
636 TableEnumerator* tableEnum = getTableEnumerator(env, jTableEnumerator);
637 return static_cast<jboolean>(tableEnum->hasNext());
638}
639
640/*
641 * Class: edu_stanford_ramcloud_JRamCloud_TableEnumerator
642 * Method: next
643 * Signature: ()Ledu/stanford/ramcloud/JRamCloud/Object;
644 */
645JNIEXPORT jobject JNICALL Java_edu_stanford_ramcloud_JRamCloud_00024TableEnumerator_next( JNIEnv *env,
646 jobject jTableEnumerator)
647{
648 TableEnumerator* tableEnum = getTableEnumerator(env, jTableEnumerator);
649
650 if(tableEnum->hasNext())
651 {
652 uint32_t size = 0;
653 const void* buffer = 0;
654 uint64_t version = 0;
655
656 tableEnum->next(&size, &buffer);
657 Object object(buffer, size);
658
659 jbyteArray jKey = env->NewByteArray(object.getKeyLength());
660 jbyteArray jValue = env->NewByteArray(object.getDataLength());
661
662 JByteArrayGetter key(env, jKey);
663 JByteArrayGetter value(env, jValue);
664
665 memcpy(key.pointer, object.getKey(), object.getKeyLength());
666 memcpy(value.pointer, object.getData(), object.getDataLength());
667
668 version = object.getVersion();
669
670 const static jclass cls = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$Object"));
671 check_null(cls, "FindClass failed");
672 const static jmethodID methodId = env->GetMethodID(cls,
673 "<init>",
Yoshi Muroie7693b12014-02-19 19:41:17 -0800674 "([B[BJ)V");
yoshi28bac132014-01-22 11:00:17 -0800675 check_null(methodId, "GetMethodID failed");
676 return env->NewObject(cls,
677 methodId,
yoshi28bac132014-01-22 11:00:17 -0800678 jKey,
679 jValue,
680 static_cast<jlong>(version));
681 } else
682 return NULL;
683}
684
685/*
686 * Class: edu_stanford_ramcloud_JRamCloud
Yoshi Muroie7693b12014-02-19 19:41:17 -0800687 * Method: getTableObjects
688 * Signature: (JJ)Ledu/stanford/ramcloud/JRamCloud/TableEnumeratorObject;
689 */
690JNIEXPORT jobject JNICALL Java_edu_stanford_ramcloud_JRamCloud_getTableObjects(JNIEnv *env,
691 jobject jRamCloud,
692 jlong jTableId,
693 jlong jTabletNextHash){
694
695 RamCloud* ramcloud = getRamCloud(env, jRamCloud);
696
697 Buffer state;
698 Buffer objects;
699 bool done = false;
700 uint64_t version = 0;
701
702 uint32_t nextOffset = 0;
703
704 const static jclass jc_RcObject = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$Object"));
705 check_null(jc_RcObject, "FindClass failed");
706 const static jmethodID jm_init = env->GetMethodID(jc_RcObject,
707 "<init>",
708 "([B[BJ)V");
709 check_null(jm_init, "GetMethodID failed");
710
711 const static jclass jc_RcTableObject = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$TableEnumeratorObject"));
712 check_null(jc_RcTableObject, "FindClass failed");
713 const static jmethodID jm_TableEnumeratorObject_init = env->GetMethodID(jc_RcTableObject,
714 "<init>",
715 "([Ledu/stanford/ramcloud/JRamCloud$Object;J)V");
716 check_null(jm_TableEnumeratorObject_init, "GetMethodID failed");
717
718
719 while (true) {
720 jTabletNextHash = ramcloud->enumerateTable(jTableId, jTabletNextHash, state, objects);
721 if (objects.getTotalLength() > 0) {
722 break;
723 }
724 if (objects.getTotalLength() == 0 && jTabletNextHash == 0) {
725 done = true;
726 break;
727 }
728 }
729
730 if (done) {
731 return env->NewObject(jc_RcTableObject, jm_TableEnumeratorObject_init, env->NewObjectArray(0, jc_RcObject , NULL), 0);
732 }
733
734 int numOfTable;
735 for (numOfTable = 0; nextOffset < objects.getTotalLength() ; numOfTable++) {
736 uint32_t objectSize = *objects.getOffset<uint32_t>(nextOffset);
737 nextOffset += downCast<uint32_t>(sizeof(uint32_t));
738 nextOffset += objectSize;
739 }
740
741 jobjectArray outJNIArray = env->NewObjectArray(numOfTable, jc_RcObject , NULL);
742 check_null(outJNIArray, "NewObjectArray failed");
743
744 nextOffset = 0;
745 for (int i = 0; nextOffset < objects.getTotalLength() ;i++) {
746 uint32_t objectSize = *objects.getOffset<uint32_t>(nextOffset);
747 nextOffset += downCast<uint32_t>(sizeof(uint32_t));
748
749 const void* blob = objects.getRange(nextOffset, objectSize);
750 nextOffset += objectSize;
751
752 Object object(blob, objectSize);
753
754 jbyteArray jKey = env->NewByteArray(object.getKeyLength());
755 jbyteArray jValue = env->NewByteArray(object.getDataLength());
756
757 JByteArrayGetter key(env, jKey);
758 JByteArrayGetter value(env, jValue);
759
760 memcpy(key.pointer, object.getKey(), object.getKeyLength());
761 memcpy(value.pointer, object.getData(), object.getDataLength());
762
763 version = object.getVersion();
764
765 jobject obj = env->NewObject(jc_RcObject, jm_init, jKey, jValue, static_cast<jlong>(version));
766 check_null(obj, "NewObject failed");
767
768 env->SetObjectArrayElement(outJNIArray, i, obj);
769 }
770
771 return env->NewObject(jc_RcTableObject, jm_TableEnumeratorObject_init, outJNIArray, jTabletNextHash);
772
773}
774
775/*
776 * Class: edu_stanford_ramcloud_JRamCloud
yoshi28bac132014-01-22 11:00:17 -0800777 * Method: multiWrite
778 * Signature: ([Ledu/stanford/ramcloud/JRamCloud/MultiWriteObject;)[Ledu/stanford/ramcloud/JRamCloud/MultiWriteRspObject;
779 */
Yoshi Muroie7693b12014-02-19 19:41:17 -0800780JNIEXPORT jobjectArray JNICALL Java_edu_stanford_ramcloud_JRamCloud_multiWrite(JNIEnv *env,
781 jobject jRamCloud,
782 jlongArray jTableId,
783 jobjectArray jKeyData,
784 jshortArray jKeyLength,
785 jobjectArray jValueData,
786 jshortArray jValueLength,
787 jint jrequestNum,
788 jobjectArray jRules ) {
yoshi28bac132014-01-22 11:00:17 -0800789
Yoshi Muroie7693b12014-02-19 19:41:17 -0800790 RamCloud* ramcloud = getRamCloud(env, jRamCloud);
791 Tub<MultiWriteObject> objects[jrequestNum];
792 MultiWriteObject *requests[jrequestNum];
793 RejectRules rules[jrequestNum];
794 jbyteArray jKey[jrequestNum];
795 jbyteArray jValue[jrequestNum];
796
797 jlong tableId;
798 jshort keyLength;
799 jshort valueLength;
800 jbyte* keyData[jrequestNum];
801 jbyte* valueData[jrequestNum];
802
yoshi28bac132014-01-22 11:00:17 -0800803 const static jclass jc_RejectRules = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$RejectRules"));
yoshi28bac132014-01-22 11:00:17 -0800804
805 const static jfieldID jf_doesntExist = env->GetFieldID(jc_RejectRules, "doesntExist", "Z");
806 check_null(jf_doesntExist, "doesentExist field id is null");
807 const static jfieldID jf_exists = env->GetFieldID(jc_RejectRules, "exists", "Z");
808 check_null(jf_exists, "exists field id is null");
809 const static jfieldID jf_givenVersion = env->GetFieldID(jc_RejectRules, "givenVersion", "J");
810 check_null(jf_givenVersion, "givenVersion field id is null");
811 const static jfieldID jf_versionLeGiven = env->GetFieldID(jc_RejectRules, "versionLeGiven", "Z");
812 check_null(jf_versionLeGiven, "versionLeGiven field id is null");
813 const static jfieldID jf_versionNeGiven = env->GetFieldID(jc_RejectRules, "versionNeGiven", "Z");
814 check_null(jf_versionNeGiven, "versionNeGiven field id is null");
815
Yoshi Muroie7693b12014-02-19 19:41:17 -0800816 for (int i = 0; i < jrequestNum; i++) {
817 env->GetLongArrayRegion(jTableId, i, 1, &tableId);
yoshi28bac132014-01-22 11:00:17 -0800818
Yoshi Muroie7693b12014-02-19 19:41:17 -0800819 env->GetShortArrayRegion(jKeyLength, i, 1, &keyLength);
820 jKey[i] = (jbyteArray)env->GetObjectArrayElement(jKeyData, i);
821 keyData[i] = (jbyte *) malloc(keyLength);
822 env->GetByteArrayRegion(jKey[i], 0, keyLength, keyData[i]);
823
824 env->GetShortArrayRegion(jValueLength, i, 1, &valueLength);
825 jValue[i] = (jbyteArray)env->GetObjectArrayElement(jValueData, i);
826 valueData[i] = (jbyte *) malloc(valueLength);
827 env->GetByteArrayRegion(jValue[i], 0, valueLength, valueData[i]);
828
829 jobject jRejectRules = (jbyteArray)env->GetObjectArrayElement(jRules, i);
yoshi28bac132014-01-22 11:00:17 -0800830 rules[i] = {};
831
832 if (jRejectRules != NULL) {
833 jboolean ruleBool;
834
835 ruleBool = env->GetBooleanField(jRejectRules, jf_doesntExist);
836 rules[i].doesntExist = ruleBool ? 1 : 0;
837
838 ruleBool = env->GetBooleanField(jRejectRules, jf_exists);
839 rules[i].exists = ruleBool ? 1 : 0;
840
841 rules[i].givenVersion = env->GetLongField(jRejectRules, jf_givenVersion);
842
843 ruleBool = env->GetBooleanField(jRejectRules, jf_versionLeGiven);
844 rules[i].versionLeGiven = ruleBool ? 1 : 0;
845
846 ruleBool = env->GetBooleanField(jRejectRules, jf_versionNeGiven);
847 rules[i].versionNeGiven = ruleBool ? 1 : 0;
848 }
Yoshi Muroie7693b12014-02-19 19:41:17 -0800849 objects[i].construct(tableId, keyData[i], keyLength, valueData[i], valueLength, &rules[i]);
yoshi28bac132014-01-22 11:00:17 -0800850 requests[i] = objects[i].get();
851 }
852 try {
Yoshi Muroie7693b12014-02-19 19:41:17 -0800853 ramcloud->multiWrite(requests, jrequestNum);
yoshi28bac132014-01-22 11:00:17 -0800854 } EXCEPTION_CATCHER(NULL);
855
856 const static jclass jc_RcObject = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$MultiWriteRspObject"));
857 check_null(jc_RcObject, "FindClass failed");
858 const static jmethodID jm_init = env->GetMethodID(jc_RcObject,
859 "<init>",
Yoshi Muroie7693b12014-02-19 19:41:17 -0800860 "(IJ)V");
yoshi28bac132014-01-22 11:00:17 -0800861
Yoshi Muroie7693b12014-02-19 19:41:17 -0800862 jobjectArray outJNIArray = env->NewObjectArray(jrequestNum, jc_RcObject , NULL);
yoshi28bac132014-01-22 11:00:17 -0800863 check_null(outJNIArray, "NewObjectArray failed");
864
Yoshi Muroie7693b12014-02-19 19:41:17 -0800865 for (int i = 0 ; i < jrequestNum ; i++) {
866 jobject obj = env->NewObject(jc_RcObject, jm_init, objects[i]->status, objects[i]->version);
yoshi28bac132014-01-22 11:00:17 -0800867 check_null(obj, "NewObject failed");
868 env->SetObjectArrayElement(outJNIArray, i, obj);
Yoshi Muroie7693b12014-02-19 19:41:17 -0800869 free(keyData[i]);
870 free(valueData[i]);
yoshi28bac132014-01-22 11:00:17 -0800871 objects[i].destroy();
872 }
873 return outJNIArray;
874}