blob: fef2b12c68facd2e0d44395e3f78abe6116412a3 [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
16package edu.stanford.ramcloud;
17
18/*
19 * This class provides Java bindings for RAMCloud. Right now it is a rather
20 * simple subset of what RamCloud.h defines.
21 *
22 * Running ``javah'' on this file will generate a C header file with the
23 * appropriate JNI function definitions. The glue interfacing to the C++
24 * RAMCloud library can be found in JRamCloud.cc.
25 *
26 * For JNI information, the IBM tutorials and Android developer docs are much
27 * better than Sun's at giving an overall intro:
28 * http://www.ibm.com/developerworks/java/tutorials/j-jni/section4.html
29 * http://developer.android.com/training/articles/perf-jni.html
30 */
31public class JRamCloud {
32 static {
33 System.loadLibrary("edu_stanford_ramcloud_JRamCloud");
34 }
35
36 /// Pointer to the underlying C++ RAMCloud object associated with this
37 /// object.
38 private long ramcloudObjectPointer = 0;
39
40 /**
41 * See src/RejectRules.h.
42 */
43 public class RejectRules {
44 private long givenVersion;
45 private boolean doesntExist;
46 private boolean exists;
47 private boolean versionLeGiven;
48 private boolean versionNeGiven;
49
50 public RejectRules() {
51 this.givenVersion = -1;
52 this.exists = this.doesntExist = this.versionLeGiven = this.versionNeGiven = false;
53 }
54
55 public void setLeVersion(long version) {
56 setVersion(version);
57 this.versionLeGiven = true;
58 }
59
60 public void setExists() {
61 this.exists = true;
62 }
63
64 public void setDoesntExists() {
65 this.doesntExist = true;
66 }
67
68 public void setNeVersion(long version) {
69 setVersion(version);
70 this.versionNeGiven = true;
71 }
72
73 private void setVersion(long version) {
74 this.givenVersion = version;
75 }
76 }
77
78 public static class multiReadObject {
79 long tableId;
80 byte[] key;
81
82 public multiReadObject(long _tableId, byte[] _key){
83 tableId = _tableId;
84 key = _key;
85 }
86 }
87
88 public static class MultiWriteObject {
89 long tableId;
90 byte[] key;
91 byte[] value;
92 RejectRules rules;
93
94 public MultiWriteObject(long tableId, byte[] key, byte[] value, RejectRules rules) {
95 this.tableId = tableId;
96 this.key = key;
97 this.value = value;
98 this.rules = rules;
99 }
100 }
101
102 public class MultiWriteRspObject {
103 private int status;
104 private long version;
105
106 public MultiWriteRspObject(int status, long version) {
107 this.status = status;
108 this.version = version;
109 }
110 public int getStatus() {
111 return status;
112 }
113
114 public long getVersion() {
115 return version;
116 }
117 }
118
119 /**
120 * This class is returned by Read operations. It encapsulates the entire
121 * object, including the key, value, and version.
122 *
123 * It mostly exists because Java doesn't support primitive out parameters
124 * or multiple return values, and we don't know the object's size ahead of
125 * time, so passing in a fixed-length array would be problematic.
126 */
127 public class Object {
128 Object(byte[] _key, byte[] _value, long _version)
129 {
130 key = _key;
131 value = _value;
132 version = _version;
133 }
134
135 public String
136 getKey()
137 {
138 return new String(key);
139 }
140
141 public String
142 getValue()
143 {
144 return new String(value);
145 }
146
147 final public byte[] key;
148 final public byte[] value;
149 final public long version;
150 }
151
152 public class TableEnumerator {
153 private long tableEnumeratorObjectPointer = 0;
154 private long ramCloudObjectPointer = 0;
155
156 public TableEnumerator(long tableId)
157 {
158 ramCloudObjectPointer = ramcloudObjectPointer;
159 tableEnumeratorObjectPointer = init(tableId);
160 }
161
162 private native long init(long tableId);
163 public native boolean hasNext();
164 public native Object next();
165 }
166
167 /**
168 * Connect to the RAMCloud cluster specified by the given coordinator's
169 * service locator string. This causes the JNI code to instantiate the
170 * underlying RamCloud C++ object.
171 */
172 public
173 JRamCloud(String coordinatorLocator)
174 {
175 ramcloudObjectPointer = connect(coordinatorLocator);
176 }
177
178 /**
179 * Disconnect from the RAMCloud cluster. This causes the JNI code to
180 * destroy the underlying RamCloud C++ object.
181 */
182 public void
183 disconnect()
184 {
185 if (ramcloudObjectPointer != 0) {
186 disconnect(ramcloudObjectPointer);
187 ramcloudObjectPointer = 0;
188 }
189 }
190
191 /**
192 * This method is called by the garbage collector before destroying the
193 * object. The user really should have called disconnect, but in case
194 * they did not, be sure to clean up after them.
195 */
196 public void
197 finalize()
198 {
199 System.err.println("warning: JRamCloud::disconnect() was not called " +
200 "prior to the finalizer. You should disconnect " +
201 "your JRamCloud object when you're done with it.");
202 disconnect();
203 }
204
205 /**
206 * Convenience read() wrapper that take a String key argument.
207 */
208 public Object
209 read(long tableId, String key)
210 {
211 return read(tableId, key.getBytes());
212 }
213
214 /**
215 * Convenience read() wrapper that take a String key argument.
216 */
217 public Object
218 read(long tableId, String key, RejectRules rules)
219 {
220 return read(tableId, key.getBytes(), rules);
221 }
222
223 /**
224 * Convenience remove() wrapper that take a String key argument.
225 */
226 public long
227 remove(long tableId, String key)
228 {
229 return remove(tableId, key.getBytes());
230 }
231
232 /**
233 * Convenience remove() wrapper that take a String key argument.
234 */
235 public long
236 remove(long tableId, String key, RejectRules rules)
237 {
238 return remove(tableId, key.getBytes(), rules);
239 }
240
241 /**
242 * Convenience write() wrapper that take String key and value arguments.
243 */
244 public long
245 write(long tableId, String key, String value)
246 {
247 return write(tableId, key.getBytes(), value.getBytes());
248 }
249
250 /**
251 * Convenience write() wrapper that take String key and value arguments.
252 */
253 public long
254 write(long tableId, String key, String value, RejectRules rules)
255 {
256 return write(tableId, key.getBytes(), value.getBytes(), rules);
257 }
258
259 /**
260 * Convenience write() wrapper that takes a String key and a byte[] value
261 * argument.
262 */
263 public long
264 write(long tableId, String key, byte[] value)
265 {
266 return write(tableId, key.getBytes(), value);
267 }
268
269 /**
270 * Convenience write() wrapper that takes a String key and a byte[] value
271 * argument.
272 */
273 public long
274 write(long tableId, String key, byte[] value, RejectRules rules)
275 {
276 return write(tableId, key.getBytes(), value, rules);
277 }
278
279 private static native long connect(String coordinatorLocator);
280 private static native void disconnect(long ramcloudObjectPointer);
281
282 public native long createTable(String name);
283 public native long createTable(String name, int serverSpan);
284 public native void dropTable(String name);
285 public native long getTableId(String name);
286 public native Object read(long tableId, byte[] key);
287 public native Object read(long tableId, byte[] key, RejectRules rules);
288 public native Object[] multiRead(multiReadObject[] mread);
289 public native long remove(long tableId, byte[] key);
290 public native long remove(long tableId, byte[] key, RejectRules rules);
291 public native long write(long tableId, byte[] key, byte[] value);
292 public native long write(long tableId, byte[] key, byte[] value, RejectRules rules);
293 public native long writeRule(long tableId, byte[] key, byte[] value, RejectRules rules);
294 public native MultiWriteRspObject[] multiWrite(MultiWriteObject[] mwrite);
295
296 /*
297 * The following exceptions may be thrown by the JNI functions:
298 */
299
300 public class TableDoesntExistException extends Exception {
301 public TableDoesntExistException(String message)
302 {
303 super(message);
304 }
305 }
306
307 public class ObjectDoesntExistException extends Exception {
308 public ObjectDoesntExistException(String message)
309 {
310 super(message);
311 }
312 }
313
314 public class ObjectExistsException extends Exception {
315 public ObjectExistsException(String message)
316 {
317 super(message);
318 }
319 }
320
321 public class WrongVersionException extends Exception {
322 public WrongVersionException(String message)
323 {
324 super(message);
325 }
326 }
327
328 public class InvalidObjectException extends Exception {
329 public InvalidObjectException(String message) {
330 super(message);
331 }
332 }
333
334 public class RejectRulesException extends Exception {
335 public RejectRulesException(String message) {
336 super(message);
337 }
338 }
339
340 /**
341 * A simple end-to-end test of the java bindings.
342 */
343 public static void
344 main(String argv[])
345 {
346 JRamCloud ramcloud = new JRamCloud(argv[0]);
347 long tableId = ramcloud.createTable("hi");
348 System.out.println("created table, id = " + tableId);
349 long tableId2 = ramcloud.getTableId("hi");
350 System.out.println("getTableId says tableId = " + tableId2);
351
352 System.out.println("wrote obj version = " +
353 ramcloud.write(tableId, "thisIsTheKey", "thisIsTheValue"));
354
355 JRamCloud.Object o = ramcloud.read(tableId, "thisIsTheKey");
356 System.out.println("read object: key = [" + o.getKey() + "], value = ["
357 + o.getValue() + "], version = " + o.version);
358
359 ramcloud.remove(tableId, "thisIsTheKey");
360
361 try {
362 ramcloud.read(tableId, "thisIsTheKey");
363 System.out.println("Error: shouldn't have read successfully!");
364 } catch (Exception e) {
365 // OK
366 }
367
368 ramcloud.write(tableId, "thisIsTheKey", "thisIsTheValue");
369
370 long before = System.nanoTime();
371 for (int i = 0; i < 1000; i++) {
372 JRamCloud.Object unused = ramcloud.read(tableId, "thisIsTheKey");
373 }
374 long after = System.nanoTime();
375 System.out.println("Avg read latency: " +
376 ((double)(after - before) / 1000 / 1000) + " usec");
377
378 // multiRead test
379 long tableId4 = ramcloud.createTable("table4");
380 System.out.println("table4 id " + tableId4);
381 ramcloud.write(tableId4, "object1-1", "value:1-1");
382 ramcloud.write(tableId4, "object1-2", "value:1-2");
383 ramcloud.write(tableId4, "object1-3", "value:1-3");
384 long tableId5 = ramcloud.createTable("table5");
385 System.out.println("table5 id " + tableId5);
386 ramcloud.write(tableId5, "object2-1", "value:2-1");
387 long tableId6 = ramcloud.createTable("table6");
388 ramcloud.write(tableId6, "object3-1", "value:3-1");
389 ramcloud.write(tableId6, "object3-2", "value:3-2");
390
391 multiReadObject mread[] = new multiReadObject[2];
392 //for (int k = 0; k < 2000; k++) {
393 mread[0] = new multiReadObject(tableId4, "object1-1".getBytes());
394 mread[1] = new multiReadObject(tableId5, "object2-1".getBytes());
395 JRamCloud.Object out[] = ramcloud.multiRead(mread);
396 for (int i = 0 ; i < 2 ; i++){
397 System.out.println("multi read object: key = [" + out[i].getKey() + "], value = ["
398 + out[i].getValue() + "]");
399 //}
400 }
401 MultiWriteObject mwrite[] = new MultiWriteObject[2];
402 for (int i = 0; i < 1000; i++) {
403 String key1 = "key1" + new Integer(i).toString();
404 String key2 = "key2" + new Integer(i).toString();
405
406 mwrite[0] = new MultiWriteObject(tableId4, key1.getBytes(), "v0-value".getBytes(), null);
407 mwrite[1] = new MultiWriteObject(tableId5, key2.getBytes(), "v1".getBytes(), null);
408 MultiWriteRspObject[] rsp = ramcloud.multiWrite(mwrite);
409 if (rsp != null) {
410 for (int j = 0; j < rsp.length; j++) {
411 System.out.println("multi write rsp(" + j + ") status:version " + rsp[j].getStatus() + ":" + rsp[j].getVersion());
412 }
413 }
414 }
415 for (int i = 0; i < 1000; i++) {
416 String key1 = "key1" + new Integer(i).toString();
417 String key2 = "key2" + new Integer(i).toString();
418 mread[0] = new multiReadObject(tableId4, key1.getBytes());
419 mread[1] = new multiReadObject(tableId5, key2.getBytes());
420 out = ramcloud.multiRead(mread);
421 for (int j = 0; j < 2; j++) {
422 System.out.println("multi read object: key = [" + out[j].getKey() + "], value = [" + out[j].getValue() + "]");
423 }
424 }
425 ramcloud.dropTable("table4");
426 ramcloud.dropTable("table5");
427 ramcloud.dropTable("table6");
428 ramcloud.disconnect();
429 }
430}