blob: 41d87a541d1f291572d7303c3430fcd4c9ccf263 [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
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -080028// Java RejectRules flags bit index
29const static int DoesntExist = 1;
30const static int Exists = 1 << 1;
31const static int VersionLeGiven = 1 << 2;
32const static int VersionNeGiven = 1 << 3;
33
yoshi28bac132014-01-22 11:00:17 -080034#define check_null(var, msg) \
35 if (var == NULL) { \
36 throw Exception(HERE, "JRamCloud: NULL returned: " msg "\n"); \
37 }
38
39/**
40 * This class provides a simple means of extracting C-style strings
41 * from a jstring and cleans up when the destructor is called. This
42 * avoids having to manually do the annoying GetStringUTFChars /
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -080043 * ReleaseStringUTFChars dance.
yoshi28bac132014-01-22 11:00:17 -080044 */
45class JStringGetter {
46 public:
47 JStringGetter(JNIEnv* env, jstring jString)
48 : env(env)
49 , jString(jString)
50 , string(env->GetStringUTFChars(jString, 0))
51 {
52 check_null(string, "GetStringUTFChars failed");
53 }
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -080054
yoshi28bac132014-01-22 11:00:17 -080055 ~JStringGetter()
56 {
57 if (string != NULL)
58 env->ReleaseStringUTFChars(jString, string);
59 }
60
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -080061 private:
yoshi28bac132014-01-22 11:00:17 -080062 JNIEnv* env;
63 jstring jString;
64
65 public:
66 const char* const string;
67};
68
69/**
70 * This class provides a simple means of accessing jbyteArrays as
71 * C-style void* buffers and cleans up when the destructor is called.
72 * This avoids having to manually do the annoying GetByteArrayElements /
73 * ReleaseByteArrayElements dance.
74 */
75class JByteArrayGetter {
76 public:
77 JByteArrayGetter(JNIEnv* env, jbyteArray jByteArray)
78 : env(env)
79 , jByteArray(jByteArray)
80 , pointer(static_cast<void*>(env->GetByteArrayElements(jByteArray, 0)))
81 , length(env->GetArrayLength(jByteArray))
82 {
83 check_null(pointer, "GetByteArrayElements failed");
84 }
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -080085
yoshi28bac132014-01-22 11:00:17 -080086 ~JByteArrayGetter()
87 {
88 if (pointer != NULL) {
89 env->ReleaseByteArrayElements(jByteArray,
90 reinterpret_cast<jbyte*>(pointer),
91 0);
92 }
93 }
94
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -080095 private:
yoshi28bac132014-01-22 11:00:17 -080096 JNIEnv* env;
97 jbyteArray jByteArray;
98
99 public:
100 void* const pointer;
101 const jsize length;
102};
103
104class JByteArrayReference {
105 public:
106 JByteArrayReference(JNIEnv* env, jbyteArray jByteArray)
107 : env(env)
108 , jByteArray(jByteArray)
109 , pointer(static_cast<const void*>(env->GetByteArrayElements(jByteArray, 0)))
110 , length(env->GetArrayLength(jByteArray))
111 {
112 check_null(pointer, "GetByteArrayElements failed");
113 }
114
115 ~JByteArrayReference()
116 {
117 if (pointer != NULL) {
118 env->ReleaseByteArrayElements(jByteArray,
119 (jbyte*)pointer,
120 JNI_ABORT);
121 }
122 }
123
124 private:
125 JNIEnv* env;
126 jbyteArray jByteArray;
127
128 public:
129 const void* const pointer;
130 const jsize length;
131};
132
133static RamCloud*
134getRamCloud(JNIEnv* env, jobject jRamCloud)
135{
136 const static jclass cls = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud"));
137 const static jfieldID fieldId = env->GetFieldID(cls, "ramcloudObjectPointer", "J");
138 return reinterpret_cast<RamCloud*>(env->GetLongField(jRamCloud, fieldId));
139}
140
141static TableEnumerator*
142getTableEnumerator(JNIEnv* env, jobject jTableEnumerator)
143{
144 const static jclass cls = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$TableEnumerator"));
145 const static jfieldID fieldId = env->GetFieldID(cls, "tableEnumeratorObjectPointer", "J");
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800146 return reinterpret_cast<TableEnumerator*>(env->GetLongField(jTableEnumerator, fieldId));
yoshi28bac132014-01-22 11:00:17 -0800147}
148
149static void
150createException(JNIEnv* env, jobject jRamCloud, const char* name)
151{
152 // Need to specify the full class name, including the package. To make it
153 // slightly more complicated, our exceptions are nested under the JRamCloud
154 // class.
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800155 string fullName(PACKAGE_PATH "JRamCloud$");
yoshi28bac132014-01-22 11:00:17 -0800156 fullName += name;
157
yoshi28bac132014-01-22 11:00:17 -0800158 jclass cls = env->FindClass(fullName.c_str());
159 check_null(cls, "FindClass failed");
160
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800161 env->ThrowNew(cls, "");
162}
yoshi28bac132014-01-22 11:00:17 -0800163
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800164static void
165setRejectRules(JNIEnv* env, jobject jRejectRules, RejectRules& rules)
166{
167 const static jclass jc_RejectRules = (jclass) env->NewGlobalRef(
168 env->FindClass(PACKAGE_PATH "JRamCloud$RejectRules"));
169 static const jfieldID jf_flags = env->GetFieldID(jc_RejectRules, "flags", "I");
170 check_null(jf_flags, "flags field ID is null");
171 static const jfieldID jf_givenVersion = env->GetFieldID(jc_RejectRules,
172 "givenVersion", "J");
173 check_null(jf_givenVersion, "givenVersion field ID is null");
yoshi28bac132014-01-22 11:00:17 -0800174
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800175 const jint rejectFlag = env->GetIntField(jRejectRules, jf_flags);
176 rules.doesntExist = (rejectFlag & DoesntExist) != 0;
177 rules.exists = (rejectFlag & Exists) != 0;
178 rules.versionLeGiven = (rejectFlag & VersionLeGiven) != 0;
179 rules.versionNeGiven = (rejectFlag & VersionNeGiven) != 0;
180 if (rules.versionLeGiven || rules.versionNeGiven) {
181 rules.givenVersion = env->GetLongField(jRejectRules, jf_givenVersion);
182 }
yoshi28bac132014-01-22 11:00:17 -0800183}
184
185/**
186 * This macro is used to catch C++ exceptions and convert them into Java
187 * exceptions. Be sure to wrap the individual RamCloud:: calls in try blocks,
188 * rather than the entire methods, since doing so with functions that return
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800189 * non-void is a bad idea with undefined(?) behaviour.
yoshi28bac132014-01-22 11:00:17 -0800190 *
191 * _returnValue is the value that should be returned from the JNI function
192 * when an exception is caught and generated in Java. As far as I can tell,
193 * the exception fires immediately upon returning from the JNI method. I
194 * don't think anything else would make sense, but the JNI docs kind of
195 * suck.
196 */
197#define EXCEPTION_CATCHER(_returnValue) \
198 catch (TableDoesntExistException& e) { \
199 createException(env, jRamCloud, "TableDoesntExistException"); \
200 return _returnValue; \
201 } catch (ObjectDoesntExistException& e) { \
202 createException(env, jRamCloud, "ObjectDoesntExistException"); \
203 return _returnValue; \
204 } catch (ObjectExistsException& e) { \
205 createException(env, jRamCloud, "ObjectExistsException"); \
206 return _returnValue; \
207 } catch (WrongVersionException& e) { \
208 createException(env, jRamCloud, "WrongVersionException"); \
209 return _returnValue; \
210 } catch (RejectRulesException& e) { \
211 createException(env, jRamCloud, "RejectRulesException"); \
212 return _returnValue; \
213 } catch (InvalidObjectException& e) { \
214 createException(env, jRamCloud, "InvalidObjectException"); \
215 return _returnValue; \
216 }
217
218/*
219 * Class: edu_stanford_ramcloud_JRamCloud
220 * Method: connect
221 * Signature: (Ljava/lang/String;)J
222 */
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800223JNIEXPORT jlong
yoshi28bac132014-01-22 11:00:17 -0800224JNICALL Java_edu_stanford_ramcloud_JRamCloud_connect(JNIEnv *env,
225 jclass jRamCloud,
226 jstring coordinatorLocator)
227{
228 JStringGetter locator(env, coordinatorLocator);
229 RamCloud* ramcloud = NULL;
230 try {
231 ramcloud = new RamCloud(locator.string);
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800232 } EXCEPTION_CATCHER(reinterpret_cast<jlong>(NULL));
yoshi28bac132014-01-22 11:00:17 -0800233 return reinterpret_cast<jlong>(ramcloud);
234}
235
236/*
237 * Class: edu_stanford_ramcloud_JRamCloud
238 * Method: disconnect
239 * Signature: (J)V
240 */
241JNIEXPORT void
242JNICALL Java_edu_stanford_ramcloud_JRamCloud_disconnect(JNIEnv *env,
243 jclass jRamCloud,
244 jlong ramcloudObjectPointer)
245{
246 delete reinterpret_cast<RamCloud*>(ramcloudObjectPointer);
247}
248
249/*
250 * Class: edu_stanford_ramcloud_JRamCloud
251 * Method: createTable
252 * Signature: (Ljava/lang/String;)I
253 */
254JNIEXPORT jlong
255JNICALL Java_edu_stanford_ramcloud_JRamCloud_createTable__Ljava_lang_String_2(JNIEnv *env,
256 jobject jRamCloud,
257 jstring jTableName)
258{
259 return Java_edu_stanford_ramcloud_JRamCloud_createTable__Ljava_lang_String_2I(env,
260 jRamCloud,
261 jTableName,
262 1);
263}
264
265/*
266 * Class: edu_stanford_ramcloud_JRamCloud
267 * Method: createTable
268 * Signature: (Ljava/lang/String;I)I
269 */
270JNIEXPORT jlong
271JNICALL Java_edu_stanford_ramcloud_JRamCloud_createTable__Ljava_lang_String_2I(JNIEnv *env,
272 jobject jRamCloud,
273 jstring jTableName,
274 jint jServerSpan)
275{
276 RamCloud* ramcloud = getRamCloud(env, jRamCloud);
277 JStringGetter tableName(env, jTableName);
278 uint64_t tableId;
279 try {
280 tableId = ramcloud->createTable(tableName.string, jServerSpan);
281 } EXCEPTION_CATCHER(-1);
282 return static_cast<jlong>(tableId);
283}
284
285/*
286 * Class: edu_stanford_ramcloud_JRamCloud
287 * Method: dropTable
288 * Signature: (Ljava/lang/String;)I
289 */
290JNIEXPORT void
291JNICALL Java_edu_stanford_ramcloud_JRamCloud_dropTable(JNIEnv *env,
292 jobject jRamCloud,
293 jstring jTableName)
294{
295 RamCloud* ramcloud = getRamCloud(env, jRamCloud);
296 JStringGetter tableName(env, jTableName);
297 try {
298 ramcloud->dropTable(tableName.string);
299 } EXCEPTION_CATCHER();
300}
301
302/*
303 * Class: edu_stanford_ramcloud_JRamCloud
304 * Method: getTableId
305 * Signature: (Ljava/lang/String;)J
306 */
307JNIEXPORT jlong
308JNICALL Java_edu_stanford_ramcloud_JRamCloud_getTableId(JNIEnv *env,
309 jobject jRamCloud,
310 jstring jTableName)
311{
312 RamCloud* ramcloud = getRamCloud(env, jRamCloud);
313 JStringGetter tableName(env, jTableName);
314 uint64_t tableId;
315 try {
316 tableId = ramcloud->getTableId(tableName.string);
317 } EXCEPTION_CATCHER(-1);
318 return tableId;
319}
320
321/*
322 * Class: edu_stanford_ramcloud_JRamCloud
323 * Method: read
324 * Signature: (J[B)LJRamCloud/Object;
325 */
326JNIEXPORT jobject
327JNICALL Java_edu_stanford_ramcloud_JRamCloud_read__J_3B(JNIEnv *env,
328 jobject jRamCloud,
329 jlong jTableId,
330 jbyteArray jKey)
331{
332 RamCloud* ramcloud = getRamCloud(env, jRamCloud);
333 JByteArrayReference key(env, jKey);
334
335 Buffer buffer;
336 uint64_t version;
337 try {
338 ramcloud->read(jTableId, key.pointer, key.length, &buffer, NULL, &version);
339 } EXCEPTION_CATCHER(NULL);
340
341 jbyteArray jValue = env->NewByteArray(buffer.getTotalLength());
342 check_null(jValue, "NewByteArray failed");
343 JByteArrayGetter value(env, jValue);
344 buffer.copy(0, buffer.getTotalLength(), value.pointer);
345
346 // Note that using 'javap -s' on the class file will print out the method
347 // signatures (the third argument to GetMethodID).
348 const static jclass cls = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$Object"));
349 check_null(cls, "FindClass failed");
350
351 const static jmethodID methodId = env->GetMethodID(cls,
352 "<init>",
Yoshi Muroie7693b12014-02-19 19:41:17 -0800353 "([B[BJ)V");
yoshi28bac132014-01-22 11:00:17 -0800354 check_null(methodId, "GetMethodID failed");
355
356 return env->NewObject(cls,
357 methodId,
yoshi28bac132014-01-22 11:00:17 -0800358 jKey,
359 jValue,
360 static_cast<jlong>(version));
361}
362
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800363// Workaround for javah generating incorrect signature for inner class
364// 00024 is an escaped signature for $ character
365#ifdef __cplusplus
366extern "C" {
367#endif
368JNIEXPORT jobject JNICALL Java_edu_stanford_ramcloud_JRamCloud_read__J_3BLedu_stanford_ramcloud_JRamCloud_00024RejectRules_2
369 (JNIEnv *, jobject, jlong, jbyteArray, jobject);
370#ifdef __cplusplus
371}
372#endif
373
yoshi28bac132014-01-22 11:00:17 -0800374/*
375 * Class: edu_stanford_ramcloud_JRamCloud
376 * Method: read
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800377 * Signature: (J[BLedu/stanford/ramcloud/JRamCloud/RejectRules;)Ledu/stanford/ramcloud/JRamCloud/Object;
yoshi28bac132014-01-22 11:00:17 -0800378 */
379JNIEXPORT jobject
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800380JNICALL Java_edu_stanford_ramcloud_JRamCloud_read__J_3BLedu_stanford_ramcloud_JRamCloud_00024RejectRules_2(JNIEnv *env,
yoshi28bac132014-01-22 11:00:17 -0800381 jobject jRamCloud,
382 jlong jTableId,
383 jbyteArray jKey,
384 jobject jRejectRules)
385{
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800386 RamCloud* ramcloud = getRamCloud(env, jRamCloud);
387 JByteArrayReference key(env, jKey);
388
389 Buffer buffer;
390 uint64_t version;
391 RejectRules rules = {};
392 setRejectRules(env, jRejectRules, rules);
393
394 try {
395 ramcloud->read(jTableId, key.pointer, key.length, &buffer, &rules, &version);
396 } EXCEPTION_CATCHER(NULL);
397
398 jbyteArray jValue = env->NewByteArray(buffer.getTotalLength());
399 check_null(jValue, "NewByteArray failed");
400 JByteArrayGetter value(env, jValue);
401 buffer.copy(0, buffer.getTotalLength(), value.pointer);
402
403 // Note that using 'javap -s' on the class file will print out the method
404 // signatures (the third argument to GetMethodID).
405 const static jclass cls = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$Object"));
406 check_null(cls, "FindClass failed");
407
408 const static jmethodID methodId = env->GetMethodID(cls,
409 "<init>",
410 "([B[BJ)V");
411 check_null(methodId, "GetMethodID failed");
412
413 return env->NewObject(cls,
414 methodId,
415 jKey,
416 jValue,
417 static_cast<jlong>(version));
yoshi28bac132014-01-22 11:00:17 -0800418}
419
420/*
421 * Class: edu_stanford_ramcloud_JRamCloud
422 * Method: multiRead
423 * Signature: ([Ledu/stanford/ramcloud/JRamCloud$multiReadObject;I)[Ledu/stanford/ramcloud/JRamCloud$Object;
424 */
425JNIEXPORT jobjectArray
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800426JNICALL Java_edu_stanford_ramcloud_JRamCloud_multiRead(JNIEnv *env,
yoshi28bac132014-01-22 11:00:17 -0800427 jobject jRamCloud,
Yoshi Muroi2c170602014-02-15 08:31:28 -0800428 jlongArray jTableId,
429 jobjectArray jKeyData,
Yoshi Muroie7693b12014-02-19 19:41:17 -0800430 jshortArray jKeyLength,
Yoshi Muroi2c170602014-02-15 08:31:28 -0800431 jint jrequestNum){
yoshi28bac132014-01-22 11:00:17 -0800432
433 RamCloud* ramcloud = getRamCloud(env, jRamCloud);
Yoshi Muroi2c170602014-02-15 08:31:28 -0800434 MultiReadObject objects[jrequestNum];
435 Tub<Buffer> values[jrequestNum];
436 jbyteArray jKey[jrequestNum];
437 MultiReadObject* requests[jrequestNum];
yoshi28bac132014-01-22 11:00:17 -0800438
Yoshi Muroie7693b12014-02-19 19:41:17 -0800439 jlong tableId;
440 jshort keyLength;
441 jbyte* keyData[jrequestNum];
yoshi28bac132014-01-22 11:00:17 -0800442
Yoshi Muroi2c170602014-02-15 08:31:28 -0800443 for (int i = 0 ; i < jrequestNum ; i++){
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800444 jKey[i] = (jbyteArray)env->GetObjectArrayElement(jKeyData, i);
yoshi28bac132014-01-22 11:00:17 -0800445
Yoshi Muroie7693b12014-02-19 19:41:17 -0800446 env->GetShortArrayRegion(jKeyLength, i, 1, &keyLength);
yoshi28bac132014-01-22 11:00:17 -0800447
Yoshi Muroie7693b12014-02-19 19:41:17 -0800448 keyData[i] = (jbyte *) malloc(keyLength);
449 env->GetByteArrayRegion(jKey[i], 0, keyLength, keyData[i]);
yoshi28bac132014-01-22 11:00:17 -0800450
Yoshi Muroie7693b12014-02-19 19:41:17 -0800451 env->GetLongArrayRegion(jTableId, i, 1, &tableId);
452 objects[i].tableId = tableId;
453 objects[i].key = keyData[i];
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800454 objects[i].keyLength = keyLength;
yoshi28bac132014-01-22 11:00:17 -0800455 objects[i].value = &values[i];
456 requests[i] = &objects[i];
457 }
458
459 try {
Yoshi Muroi2c170602014-02-15 08:31:28 -0800460 ramcloud->multiRead(requests, jrequestNum);
yoshi28bac132014-01-22 11:00:17 -0800461 } EXCEPTION_CATCHER(NULL);
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800462
yoshi28bac132014-01-22 11:00:17 -0800463 const static jclass jc_RcObject = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$Object"));
464 check_null(jc_RcObject, "FindClass failed");
465 const static jmethodID jm_init = env->GetMethodID(jc_RcObject,
466 "<init>",
Yoshi Muroie7693b12014-02-19 19:41:17 -0800467 "([B[BJ)V");
yoshi28bac132014-01-22 11:00:17 -0800468
Yoshi Muroi2c170602014-02-15 08:31:28 -0800469 jobjectArray outJNIArray = env->NewObjectArray(jrequestNum, jc_RcObject , NULL);
yoshi28bac132014-01-22 11:00:17 -0800470 check_null(outJNIArray, "NewObjectArray failed");
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800471
Yoshi Muroi2c170602014-02-15 08:31:28 -0800472 for (int i = 0 ; i < jrequestNum ; i++) {
yoshi28bac132014-01-22 11:00:17 -0800473 if (objects[i].status == 0) {
474 jbyteArray jValue = env->NewByteArray(values[i].get()->getTotalLength());
475 check_null(jValue, "NewByteArray failed");
476 JByteArrayGetter value(env, jValue);
477 values[i].get()->copy(0, values[i].get()->getTotalLength(), value.pointer);
Yoshi Muroie7693b12014-02-19 19:41:17 -0800478 jobject obj = env->NewObject(jc_RcObject, jm_init, jKey[i], jValue);
yoshi28bac132014-01-22 11:00:17 -0800479 check_null(obj, "NewObject failed");
480 env->SetObjectArrayElement(outJNIArray, i, obj);
481 }
Yoshi Muroie7693b12014-02-19 19:41:17 -0800482 free(keyData[i]);
yoshi28bac132014-01-22 11:00:17 -0800483 }
484 return outJNIArray;
485}
486
487
488/*
489 * Class: edu_stanford_ramcloud_JRamCloud
490 * Method: remove
491 * Signature: (J[B)J
492 */
493JNIEXPORT jlong
494JNICALL Java_edu_stanford_ramcloud_JRamCloud_remove__J_3B(JNIEnv *env,
495 jobject jRamCloud,
496 jlong jTableId,
497 jbyteArray jKey)
498{
499 RamCloud* ramcloud = getRamCloud(env, jRamCloud);
500 JByteArrayReference key(env, jKey);
501 uint64_t version;
502 try {
503 ramcloud->remove(jTableId, key.pointer, key.length, NULL, &version);
504 } EXCEPTION_CATCHER(-1);
505 return static_cast<jlong>(version);
506}
507
Yuta HIGUCHI9402dab2014-01-30 19:54:31 -0800508
509// Workaround for javah generating incorrect signature for inner class
510// 00024 is an escaped signature for $ character
511#ifdef __cplusplus
512extern "C" {
513#endif
514JNIEXPORT jlong JNICALL Java_edu_stanford_ramcloud_JRamCloud_remove__J_3BLedu_stanford_ramcloud_JRamCloud_00024RejectRules_2
515 (JNIEnv *, jobject, jlong, jbyteArray, jobject);
516#ifdef __cplusplus
517}
518#endif
519
yoshi28bac132014-01-22 11:00:17 -0800520/*
521 * Class: edu_stanford_ramcloud_JRamCloud
522 * Method: remove
Yuta HIGUCHI9402dab2014-01-30 19:54:31 -0800523 * Signature: (J[BLedu/stanford/ramcloud/JRamCloud/$RejectRules;)J
yoshi28bac132014-01-22 11:00:17 -0800524 */
525JNIEXPORT jlong
Yuta HIGUCHI9402dab2014-01-30 19:54:31 -0800526JNICALL Java_edu_stanford_ramcloud_JRamCloud_remove__J_3BLedu_stanford_ramcloud_JRamCloud_00024RejectRules_2(JNIEnv *env,
yoshi28bac132014-01-22 11:00:17 -0800527 jobject jRamCloud,
528 jlong jTableId,
529 jbyteArray jKey,
530 jobject jRejectRules)
531{
yoshi28bac132014-01-22 11:00:17 -0800532 RamCloud* ramcloud = getRamCloud(env, jRamCloud);
533 JByteArrayReference key(env, jKey);
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800534 RejectRules rules = {};
535 setRejectRules(env, jRejectRules, rules);
yoshi28bac132014-01-22 11:00:17 -0800536 uint64_t version;
537 try {
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800538 ramcloud->remove(jTableId, key.pointer, key.length, &rules, &version);
yoshi28bac132014-01-22 11:00:17 -0800539 } EXCEPTION_CATCHER(-1);
540 return static_cast<jlong>(version);
541}
542
543/*
544 * Class: edu_stanford_ramcloud_JRamCloud
545 * Method: write
546 * Signature: (J[B[B)J
547 */
548JNIEXPORT jlong
549JNICALL Java_edu_stanford_ramcloud_JRamCloud_write__J_3B_3B(JNIEnv *env,
550 jobject jRamCloud,
551 jlong jTableId,
552 jbyteArray jKey,
553 jbyteArray jValue)
554{
555 RamCloud* ramcloud = getRamCloud(env, jRamCloud);
556 JByteArrayReference key(env, jKey);
557 JByteArrayGetter value(env, jValue);
558 uint64_t version;
559 try {
560 ramcloud->write(jTableId,
561 key.pointer, key.length,
562 value.pointer, value.length,
563 NULL,
564 &version);
565 } EXCEPTION_CATCHER(-1);
566 return static_cast<jlong>(version);
567}
568
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800569// Workaround for javah generating incorrect signature for inner class
570// 00024 is an escaped signature for $ character
571#ifdef __cplusplus
572extern "C" {
573#endif
574JNIEXPORT jlong JNICALL Java_edu_stanford_ramcloud_JRamCloud_write__J_3B_3BLedu_stanford_ramcloud_JRamCloud_00024RejectRules_2
575 (JNIEnv *, jobject, jlong, jbyteArray, jbyteArray, jobject);
576#ifdef __cplusplus
577}
578#endif
579
yoshi28bac132014-01-22 11:00:17 -0800580/*
581 * Class: edu_stanford_ramcloud_JRamCloud
582 * Method: write
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800583 * Signature: (J[B[BLedu/stanford/ramcloud/JRamCloud/RejectRules;)J
yoshi28bac132014-01-22 11:00:17 -0800584 */
585JNIEXPORT jlong
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800586JNICALL Java_edu_stanford_ramcloud_JRamCloud_write__J_3B_3BLedu_stanford_ramcloud_JRamCloud_00024RejectRules_2(JNIEnv *env,
yoshi28bac132014-01-22 11:00:17 -0800587 jobject jRamCloud,
588 jlong jTableId,
589 jbyteArray jKey,
590 jbyteArray jValue,
591 jobject jRejectRules)
592{
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800593 return Java_edu_stanford_ramcloud_JRamCloud_writeRule(env, jRamCloud, jTableId, jKey, jValue, jRejectRules);
yoshi28bac132014-01-22 11:00:17 -0800594}
595
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800596/*
597 * Class: edu_stanford_ramcloud_JRamCloud
598 * Method: writeRule
599 * Signature: (J[B[BLedu/stanford/ramcloud/JRamCloud/RejectRules;)J
600 */
yoshi28bac132014-01-22 11:00:17 -0800601JNIEXPORT jlong
602JNICALL Java_edu_stanford_ramcloud_JRamCloud_writeRule(JNIEnv *env,
603 jobject jRamCloud,
604 jlong jTableId,
605 jbyteArray jKey,
606 jbyteArray jValue,
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800607 jobject jRejectRules)
608{
yoshi28bac132014-01-22 11:00:17 -0800609 RamCloud* ramcloud = getRamCloud(env, jRamCloud);
610 JByteArrayReference key(env, jKey);
611 JByteArrayGetter value(env, jValue);
yoshi28bac132014-01-22 11:00:17 -0800612 RejectRules rules = {};
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800613 setRejectRules(env, jRejectRules, rules);
614 uint64_t version;
yoshi28bac132014-01-22 11:00:17 -0800615 try {
616 ramcloud->write(jTableId,
617 key.pointer, key.length,
618 value.pointer, value.length,
619 &rules,
620 &version);
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800621 } EXCEPTION_CATCHER(-1);
yoshi28bac132014-01-22 11:00:17 -0800622 return static_cast<jlong> (version);
623}
624
625/*
626 * Class: edu_stanford_ramcloud_JRamCloud_TableEnumerator
627 * Method: init
628 * Signature: (J)V
629 */
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800630JNIEXPORT jlong JNICALL Java_edu_stanford_ramcloud_JRamCloud_00024TableEnumerator_init(JNIEnv *env,
631 jobject jTableEnumerator,
yoshi28bac132014-01-22 11:00:17 -0800632 jlong jTableId)
633{
634 const static jclass cls = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$TableEnumerator"));
635 const static jfieldID fieldId = env->GetFieldID(cls, "ramCloudObjectPointer", "J");
636 RamCloud* ramcloud = reinterpret_cast<RamCloud*>(env->GetLongField(jTableEnumerator, fieldId));
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800637
yoshi28bac132014-01-22 11:00:17 -0800638 return reinterpret_cast<jlong>(new TableEnumerator(*ramcloud, jTableId));
639}
640
641/*
642 * Class: edu_stanford_ramcloud_JRamCloud_TableEnumerator
643 * Method: hasNext
644 * Signature: ()Z
645 */
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800646JNIEXPORT jboolean JNICALL Java_edu_stanford_ramcloud_JRamCloud_00024TableEnumerator_hasNext( JNIEnv *env,
yoshi28bac132014-01-22 11:00:17 -0800647 jobject jTableEnumerator)
648{
649 TableEnumerator* tableEnum = getTableEnumerator(env, jTableEnumerator);
650 return static_cast<jboolean>(tableEnum->hasNext());
651}
652
653/*
654 * Class: edu_stanford_ramcloud_JRamCloud_TableEnumerator
655 * Method: next
656 * Signature: ()Ledu/stanford/ramcloud/JRamCloud/Object;
657 */
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800658JNIEXPORT jobject JNICALL Java_edu_stanford_ramcloud_JRamCloud_00024TableEnumerator_next( JNIEnv *env,
yoshi28bac132014-01-22 11:00:17 -0800659 jobject jTableEnumerator)
660{
661 TableEnumerator* tableEnum = getTableEnumerator(env, jTableEnumerator);
662
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800663 if (tableEnum->hasNext()) {
yoshi28bac132014-01-22 11:00:17 -0800664 uint32_t size = 0;
665 const void* buffer = 0;
666 uint64_t version = 0;
667
668 tableEnum->next(&size, &buffer);
669 Object object(buffer, size);
670
671 jbyteArray jKey = env->NewByteArray(object.getKeyLength());
672 jbyteArray jValue = env->NewByteArray(object.getDataLength());
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800673
yoshi28bac132014-01-22 11:00:17 -0800674 JByteArrayGetter key(env, jKey);
675 JByteArrayGetter value(env, jValue);
676
677 memcpy(key.pointer, object.getKey(), object.getKeyLength());
678 memcpy(value.pointer, object.getData(), object.getDataLength());
679
680 version = object.getVersion();
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800681
yoshi28bac132014-01-22 11:00:17 -0800682 const static jclass cls = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$Object"));
683 check_null(cls, "FindClass failed");
684 const static jmethodID methodId = env->GetMethodID(cls,
685 "<init>",
Yoshi Muroie7693b12014-02-19 19:41:17 -0800686 "([B[BJ)V");
yoshi28bac132014-01-22 11:00:17 -0800687 check_null(methodId, "GetMethodID failed");
688 return env->NewObject(cls,
689 methodId,
yoshi28bac132014-01-22 11:00:17 -0800690 jKey,
691 jValue,
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800692 static_cast<jlong>(version));
693 } else {
yoshi28bac132014-01-22 11:00:17 -0800694 return NULL;
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800695 }
yoshi28bac132014-01-22 11:00:17 -0800696}
697
698/*
699 * Class: edu_stanford_ramcloud_JRamCloud
Yoshi Muroie7693b12014-02-19 19:41:17 -0800700 * Method: getTableObjects
701 * Signature: (JJ)Ledu/stanford/ramcloud/JRamCloud/TableEnumeratorObject;
702 */
703JNIEXPORT jobject JNICALL Java_edu_stanford_ramcloud_JRamCloud_getTableObjects(JNIEnv *env,
704 jobject jRamCloud,
705 jlong jTableId,
706 jlong jTabletNextHash){
707
708 RamCloud* ramcloud = getRamCloud(env, jRamCloud);
709
Yoshi Muroie7693b12014-02-19 19:41:17 -0800710 const static jclass jc_RcObject = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$Object"));
711 check_null(jc_RcObject, "FindClass failed");
712 const static jmethodID jm_init = env->GetMethodID(jc_RcObject,
713 "<init>",
714 "([B[BJ)V");
715 check_null(jm_init, "GetMethodID failed");
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800716
Yoshi Muroie7693b12014-02-19 19:41:17 -0800717 const static jclass jc_RcTableObject = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$TableEnumeratorObject"));
718 check_null(jc_RcTableObject, "FindClass failed");
719 const static jmethodID jm_TableEnumeratorObject_init = env->GetMethodID(jc_RcTableObject,
720 "<init>",
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800721 "([L" PACKAGE_PATH "JRamCloud$Object;J)V");
Yoshi Muroie7693b12014-02-19 19:41:17 -0800722 check_null(jm_TableEnumeratorObject_init, "GetMethodID failed");
723
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800724
725 Buffer state;
726 Buffer objects;
727 bool done = false;
728
Yoshi Muroie7693b12014-02-19 19:41:17 -0800729 while (true) {
730 jTabletNextHash = ramcloud->enumerateTable(jTableId, jTabletNextHash, state, objects);
731 if (objects.getTotalLength() > 0) {
732 break;
733 }
734 if (objects.getTotalLength() == 0 && jTabletNextHash == 0) {
735 done = true;
736 break;
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800737 }
Yoshi Muroie7693b12014-02-19 19:41:17 -0800738 }
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800739
Yoshi Muroie7693b12014-02-19 19:41:17 -0800740 if (done) {
741 return env->NewObject(jc_RcTableObject, jm_TableEnumeratorObject_init, env->NewObjectArray(0, jc_RcObject , NULL), 0);
742 }
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800743
744 int numOfObjects = 0;
745 uint32_t nextOffset = 0;
746 for (numOfObjects = 0; nextOffset < objects.getTotalLength() ; numOfObjects++) {
Yoshi Muroie7693b12014-02-19 19:41:17 -0800747 uint32_t objectSize = *objects.getOffset<uint32_t>(nextOffset);
748 nextOffset += downCast<uint32_t>(sizeof(uint32_t));
749 nextOffset += objectSize;
750 }
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800751
752 jobjectArray outJNIArray = env->NewObjectArray(numOfObjects, jc_RcObject , NULL);
Yoshi Muroie7693b12014-02-19 19:41:17 -0800753 check_null(outJNIArray, "NewObjectArray failed");
754
755 nextOffset = 0;
756 for (int i = 0; nextOffset < objects.getTotalLength() ;i++) {
757 uint32_t objectSize = *objects.getOffset<uint32_t>(nextOffset);
758 nextOffset += downCast<uint32_t>(sizeof(uint32_t));
759
760 const void* blob = objects.getRange(nextOffset, objectSize);
761 nextOffset += objectSize;
762
763 Object object(blob, objectSize);
764
765 jbyteArray jKey = env->NewByteArray(object.getKeyLength());
766 jbyteArray jValue = env->NewByteArray(object.getDataLength());
767
768 JByteArrayGetter key(env, jKey);
769 JByteArrayGetter value(env, jValue);
770
771 memcpy(key.pointer, object.getKey(), object.getKeyLength());
772 memcpy(value.pointer, object.getData(), object.getDataLength());
773
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800774 uint64_t version = object.getVersion();
Yoshi Muroie7693b12014-02-19 19:41:17 -0800775
776 jobject obj = env->NewObject(jc_RcObject, jm_init, jKey, jValue, static_cast<jlong>(version));
777 check_null(obj, "NewObject failed");
778
779 env->SetObjectArrayElement(outJNIArray, i, obj);
780 }
781
782 return env->NewObject(jc_RcTableObject, jm_TableEnumeratorObject_init, outJNIArray, jTabletNextHash);
Yoshi Muroie7693b12014-02-19 19:41:17 -0800783}
784
785/*
786 * Class: edu_stanford_ramcloud_JRamCloud
yoshi28bac132014-01-22 11:00:17 -0800787 * Method: multiWrite
788 * Signature: ([Ledu/stanford/ramcloud/JRamCloud/MultiWriteObject;)[Ledu/stanford/ramcloud/JRamCloud/MultiWriteRspObject;
789 */
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800790JNIEXPORT jobjectArray JNICALL Java_edu_stanford_ramcloud_JRamCloud_multiWrite(JNIEnv *env,
Yoshi Muroie7693b12014-02-19 19:41:17 -0800791 jobject jRamCloud,
792 jlongArray jTableId,
793 jobjectArray jKeyData,
794 jshortArray jKeyLength,
795 jobjectArray jValueData,
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800796 jintArray jValueLength,
Yoshi Muroie7693b12014-02-19 19:41:17 -0800797 jint jrequestNum,
798 jobjectArray jRules ) {
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800799
Yoshi Muroie7693b12014-02-19 19:41:17 -0800800 RamCloud* ramcloud = getRamCloud(env, jRamCloud);
801 Tub<MultiWriteObject> objects[jrequestNum];
802 MultiWriteObject *requests[jrequestNum];
803 RejectRules rules[jrequestNum];
804 jbyteArray jKey[jrequestNum];
805 jbyteArray jValue[jrequestNum];
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800806
Yoshi Muroie7693b12014-02-19 19:41:17 -0800807 jlong tableId;
808 jshort keyLength;
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800809 jint valueLength;
Yoshi Muroie7693b12014-02-19 19:41:17 -0800810 jbyte* keyData[jrequestNum];
811 jbyte* valueData[jrequestNum];
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800812
yoshi28bac132014-01-22 11:00:17 -0800813 const static jclass jc_RejectRules = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$RejectRules"));
yoshi28bac132014-01-22 11:00:17 -0800814
yoshi28bac132014-01-22 11:00:17 -0800815 const static jfieldID jf_givenVersion = env->GetFieldID(jc_RejectRules, "givenVersion", "J");
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800816 check_null(jf_givenVersion, "givenVersion field ID is null");
817
818 const static jfieldID jf_flags = env->GetFieldID(jc_RejectRules, "flags", "I");
819 check_null(jf_flags, "flags field ID is null");
yoshi28bac132014-01-22 11:00:17 -0800820
Yoshi Muroie7693b12014-02-19 19:41:17 -0800821 for (int i = 0; i < jrequestNum; i++) {
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800822 env->GetLongArrayRegion(jTableId, i, 1, &tableId);
yoshi28bac132014-01-22 11:00:17 -0800823
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800824 env->GetShortArrayRegion(jKeyLength, i, 1, &keyLength);
825 jKey[i] = (jbyteArray)env->GetObjectArrayElement(jKeyData, i);
826 keyData[i] = (jbyte *) malloc(keyLength);
827 env->GetByteArrayRegion(jKey[i], 0, keyLength, keyData[i]);
828
829 env->GetIntArrayRegion(jValueLength, i, 1, &valueLength);
Yoshi Muroie7693b12014-02-19 19:41:17 -0800830 jValue[i] = (jbyteArray)env->GetObjectArrayElement(jValueData, i);
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800831 valueData[i] = (jbyte *) malloc(valueLength);
832 env->GetByteArrayRegion(jValue[i], 0, valueLength, valueData[i]);
833
834 jobject jRejectRules = (jbyteArray)env->GetObjectArrayElement(jRules, i);
yoshi28bac132014-01-22 11:00:17 -0800835 rules[i] = {};
836
837 if (jRejectRules != NULL) {
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800838 const jint flags = env->GetIntField(jRejectRules, jf_flags);
yoshi28bac132014-01-22 11:00:17 -0800839
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800840 rules[i].doesntExist = (flags & DoesntExist) != 0;
yoshi28bac132014-01-22 11:00:17 -0800841
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800842 rules[i].exists = (flags & Exists) != 0;
yoshi28bac132014-01-22 11:00:17 -0800843
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800844 rules[i].versionLeGiven = (flags & VersionLeGiven) != 0;
yoshi28bac132014-01-22 11:00:17 -0800845
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800846 rules[i].versionNeGiven = (flags & VersionNeGiven) != 0;
yoshi28bac132014-01-22 11:00:17 -0800847
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800848 if (rules[i].versionLeGiven || rules[i].versionNeGiven) {
849 rules[i].givenVersion = env->GetLongField(jRejectRules, jf_givenVersion);
850 }
yoshi28bac132014-01-22 11:00:17 -0800851 }
Yoshi Muroie7693b12014-02-19 19:41:17 -0800852 objects[i].construct(tableId, keyData[i], keyLength, valueData[i], valueLength, &rules[i]);
yoshi28bac132014-01-22 11:00:17 -0800853 requests[i] = objects[i].get();
854 }
855 try {
Yoshi Muroie7693b12014-02-19 19:41:17 -0800856 ramcloud->multiWrite(requests, jrequestNum);
yoshi28bac132014-01-22 11:00:17 -0800857 } EXCEPTION_CATCHER(NULL);
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800858
yoshi28bac132014-01-22 11:00:17 -0800859 const static jclass jc_RcObject = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$MultiWriteRspObject"));
860 check_null(jc_RcObject, "FindClass failed");
861 const static jmethodID jm_init = env->GetMethodID(jc_RcObject,
862 "<init>",
Yoshi Muroie7693b12014-02-19 19:41:17 -0800863 "(IJ)V");
yoshi28bac132014-01-22 11:00:17 -0800864
Yoshi Muroie7693b12014-02-19 19:41:17 -0800865 jobjectArray outJNIArray = env->NewObjectArray(jrequestNum, jc_RcObject , NULL);
yoshi28bac132014-01-22 11:00:17 -0800866 check_null(outJNIArray, "NewObjectArray failed");
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800867
Yoshi Muroie7693b12014-02-19 19:41:17 -0800868 for (int i = 0 ; i < jrequestNum ; i++) {
869 jobject obj = env->NewObject(jc_RcObject, jm_init, objects[i]->status, objects[i]->version);
yoshi28bac132014-01-22 11:00:17 -0800870 check_null(obj, "NewObject failed");
871 env->SetObjectArrayElement(outJNIArray, i, obj);
Yuta HIGUCHI1d6a22a2014-02-21 19:17:42 -0800872 free(keyData[i]);
873 free(valueData[i]);
yoshi28bac132014-01-22 11:00:17 -0800874 objects[i].destroy();
875 }
876 return outJNIArray;
877}