Optimization of multiRead

Change-Id: If50403d13a4ec238a30d0676e42701c8d333a2db
diff --git a/src/main/cpp/edu_stanford_ramcloud_JRamCloud.cc b/src/main/cpp/edu_stanford_ramcloud_JRamCloud.cc
index f8d6db6..fe61007 100644
--- a/src/main/cpp/edu_stanford_ramcloud_JRamCloud.cc
+++ b/src/main/cpp/edu_stanford_ramcloud_JRamCloud.cc
@@ -375,38 +375,39 @@
 JNIEXPORT jobjectArray
 JNICALL Java_edu_stanford_ramcloud_JRamCloud_multiRead(JNIEnv *env,   
                                                         jobject jRamCloud,
-                                                        jobjectArray jmultiReadArray){
+							jlongArray jTableId,
+							jobjectArray jKeyData,
+							jshortArray jKeyDataSize,
+							jint jrequestNum){
 
     RamCloud* ramcloud = getRamCloud(env, jRamCloud);
-    const jint requestNum = env->GetArrayLength(jmultiReadArray);
-    MultiReadObject objects[requestNum];
-    Tub<Buffer> values[requestNum];
-    jbyteArray jKey[requestNum];
-    MultiReadObject* requests[requestNum];
+    MultiReadObject objects[jrequestNum];
+    Tub<Buffer> values[jrequestNum];
+    jbyteArray jKey[jrequestNum];
+    MultiReadObject* requests[jrequestNum];
 
-    const static jclass jc_multiReadObject = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$multiReadObject"));
-    const static jfieldID jf_tableId = env->GetFieldID(jc_multiReadObject, "tableId", "J");
-    const static jfieldID jf_key = env->GetFieldID(jc_multiReadObject, "key", "[B");
+    jlong TableId;
+    jshort KeyDataSize;
+    jbyte* data[jrequestNum];
 
-    for (int i = 0 ; i < requestNum ; i++){
-        jobject obj = env->GetObjectArrayElement(jmultiReadArray, i);
-        check_null(obj, "GetObjectArrayElement failed");
-        jlong jTableId = env->GetLongField(obj, jf_tableId);
+    for (int i = 0 ; i < jrequestNum ; i++){
+        jKey[i] = (jbyteArray)env->GetObjectArrayElement(jKeyData, i); 
 
-        jKey[i] = (jbyteArray)env->GetObjectField(obj, jf_key);
+        env->GetShortArrayRegion(jKeyDataSize, i, 1, &KeyDataSize);
 
-        jbyte* data = env->GetByteArrayElements(jKey[i], NULL);
-        check_null(data, "GetByteArrayElements failed");
+        data[i] = (jbyte *) malloc(KeyDataSize);
+        env->GetByteArrayRegion(jKey[i], 0, KeyDataSize, data[i]);
 
-        objects[i].tableId = jTableId;
-        objects[i].key = data;
-        objects[i].keyLength = env->GetArrayLength(jKey[i]);
+        env->GetLongArrayRegion(jTableId, i, 1, &TableId);
+        objects[i].tableId = TableId;
+        objects[i].key = data[i];
+	objects[i].keyLength = KeyDataSize;
         objects[i].value = &values[i];
         requests[i] = &objects[i];
     }
 
     try {
-        ramcloud->multiRead(requests, requestNum);
+        ramcloud->multiRead(requests, jrequestNum);
     } EXCEPTION_CATCHER(NULL);
     
     const static jclass jc_RcObject = (jclass)env->NewGlobalRef(env->FindClass(PACKAGE_PATH "JRamCloud$Object"));
@@ -415,10 +416,10 @@
                                         "<init>",
                                         "(L" PACKAGE_PATH "JRamCloud;[B[BJ)V");
 
-    jobjectArray outJNIArray = env->NewObjectArray(requestNum, jc_RcObject , NULL);
+    jobjectArray outJNIArray = env->NewObjectArray(jrequestNum, jc_RcObject , NULL);
     check_null(outJNIArray, "NewObjectArray failed");
     
-    for (int i = 0 ; i < requestNum ; i++) {
+    for (int i = 0 ; i < jrequestNum ; i++) {
 	if (objects[i].status == 0) {
 	    jbyteArray jValue = env->NewByteArray(values[i].get()->getTotalLength());
 	    check_null(jValue, "NewByteArray failed");
@@ -428,8 +429,7 @@
 	    check_null(obj, "NewObject failed");
 	    env->SetObjectArrayElement(outJNIArray, i, obj);
 	}
-	// keys are read only so no need to copy back to Java side: JNI_ABORT
-	env->ReleaseByteArrayElements(jKey[i], (jbyte *) objects[i].key, JNI_ABORT);
+	free(data[i]);
     }
     return outJNIArray;
 }
diff --git a/src/main/java/com/tinkerpop/blueprints/impls/ramcloud/RamCloudGraph.java b/src/main/java/com/tinkerpop/blueprints/impls/ramcloud/RamCloudGraph.java
index 9871aaa..26f1418 100644
--- a/src/main/java/com/tinkerpop/blueprints/impls/ramcloud/RamCloudGraph.java
+++ b/src/main/java/com/tinkerpop/blueprints/impls/ramcloud/RamCloudGraph.java
@@ -433,17 +433,21 @@
 
 	    final int mreadMax = 400;
 	    final int size = Math.min(mreadMax, vertexList.size());
-	    JRamCloud.multiReadObject vertPropTableMread[] = new JRamCloud.multiReadObject[size];
+
+            long tableId[] = new long[size];
+            byte[] keyData[] = new byte[size][];
+            short keySize[] = new short[size];
 
 	    int vertexNum = 0;
 	    for (Object vert : vertexList) {
-		byte[] rckey =
+                tableId[vertexNum] = vertPropTableId;
+		keyData[vertexNum] =
 			ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN).putLong((Long) vert).array();
-		vertPropTableMread[vertexNum] = new JRamCloud.multiReadObject(vertPropTableId, rckey);
+		keySize[vertexNum] = (short) keyData[vertexNum].length;
 		if (vertexNum >= (mreadMax - 1)) {
 		    pm.multiread_start("RamCloudGraph getVertices()");
 		    JRamCloud.Object outvertPropTable[] =
-			    vertTable.multiRead(vertPropTableMread);
+			    vertTable.multiRead(tableId, keyData, keySize, vertexNum);
 		    pm.multiread_end("RamCloudGraph getVertices()");
 		    for (int i = 0; i < outvertPropTable.length; i++) {
 			if (outvertPropTable[i] != null) {
@@ -457,14 +461,12 @@
 	    }
 
 	    if (vertexNum != 0) {
-		JRamCloud.multiReadObject mread_leftover[] = Arrays.copyOf(vertPropTableMread, vertexNum);
-
 		long startTime2 = 0;
 		if (measureRcTimeProp == 1) {
 		    startTime2 = System.nanoTime();
 		}
 		pm.multiread_start("RamCloudGraph getVertices()");
-		JRamCloud.Object outvertPropTable[] = vertTable.multiRead(mread_leftover);
+		JRamCloud.Object outvertPropTable[] = vertTable.multiRead(tableId, keyData, keySize, vertexNum);
 		pm.multiread_end("RamCloudGraph getVertices()");
 		if (measureRcTimeProp == 1) {
 		    long endTime2 = System.nanoTime();
diff --git a/src/main/java/edu/stanford/ramcloud/JRamCloud.java b/src/main/java/edu/stanford/ramcloud/JRamCloud.java
index fef2b12..dfb4b6a 100644
--- a/src/main/java/edu/stanford/ramcloud/JRamCloud.java
+++ b/src/main/java/edu/stanford/ramcloud/JRamCloud.java
@@ -14,6 +14,9 @@
  */
 
 package edu.stanford.ramcloud;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.lang.Integer;
 
 /*
  * This class provides Java bindings for RAMCloud. Right now it is a rather
@@ -285,7 +288,7 @@
     public native long getTableId(String name);
     public native Object read(long tableId, byte[] key);
     public native Object read(long tableId, byte[] key, RejectRules rules);
-    public native Object[] multiRead(multiReadObject[] mread);
+    public native Object[] multiRead(long[] tableId, byte[] keydata[], short[] keyDataSize, int requestNum);
     public native long remove(long tableId, byte[] key);
     public native long remove(long tableId, byte[] key, RejectRules rules);
     public native long write(long tableId, byte[] key, byte[] value);
@@ -388,16 +391,22 @@
         ramcloud.write(tableId6, "object3-1", "value:3-1");
         ramcloud.write(tableId6, "object3-2", "value:3-2");
 
-        multiReadObject mread[] = new multiReadObject[2];
-        //for (int k = 0; k < 2000; k++) {
-        mread[0] = new multiReadObject(tableId4, "object1-1".getBytes());
-        mread[1] = new multiReadObject(tableId5, "object2-1".getBytes());
-        JRamCloud.Object out[] = ramcloud.multiRead(mread);
+	long tableIdList[] = new long[2];
+        byte[] keydata[] = new byte[2][];
+        short keydataSize[] = new short[2];
+        tableIdList[0] = tableId4;
+        keydata[0] = "object1-1".getBytes();
+        keydataSize[0] = (short) keydata[0].length;
+        tableIdList[1] = tableId5;
+        keydata[1] = "object2-1".getBytes();
+	keydataSize[1] = (short) keydata[1].length;
+
+        JRamCloud.Object out[] = ramcloud.multiRead(tableIdList, keydata, keydataSize, 2);
         for (int i = 0 ; i < 2 ; i++){
             System.out.println("multi read object: key = [" + out[i].getKey() + "], value = ["
                     + out[i].getValue() + "]");
-        //}
         }
+
         MultiWriteObject mwrite[] = new MultiWriteObject[2];
         for (int i = 0; i < 1000; i++) {
             String key1 = "key1" + new Integer(i).toString();
@@ -415,13 +424,19 @@
         for (int i = 0; i < 1000; i++) {
             String key1 = "key1" + new Integer(i).toString();
             String key2 = "key2" + new Integer(i).toString();
-            mread[0] = new multiReadObject(tableId4, key1.getBytes());
-            mread[1] = new multiReadObject(tableId5, key2.getBytes());
-            out = ramcloud.multiRead(mread);
+            tableIdList[0] = tableId4;
+            keydata[0] = key1.getBytes();
+            keydataSize[0] = (short) keydata[0].length;
+            tableIdList[1] = tableId5;
+            keydata[1] = key2.getBytes();
+            keydataSize[1] = (short) keydata[1].length;
+
+            out = ramcloud.multiRead(tableIdList, keydata, keydataSize, 2);
             for (int j = 0; j < 2; j++) {
                 System.out.println("multi read object: key = [" + out[j].getKey() + "], value = [" + out[j].getValue() + "]");
             }
         }
+
         ramcloud.dropTable("table4");
         ramcloud.dropTable("table5");
         ramcloud.dropTable("table6");
diff --git a/src/main/java/net/onrc/onos/datastore/RCObject.java b/src/main/java/net/onrc/onos/datastore/RCObject.java
index a4bbf1c..a990978 100644
--- a/src/main/java/net/onrc/onos/datastore/RCObject.java
+++ b/src/main/java/net/onrc/onos/datastore/RCObject.java
@@ -304,17 +304,21 @@
 	JRamCloud rcClient = RCClient.getClient();
 
 	final int reqs = req.size();
-	JRamCloud.multiReadObject mrObjs[] = new JRamCloud.multiReadObject[reqs];
+
+        long tableId[] = new long[reqs];
+        byte[] key[] = new byte[reqs][];
+        short keySize[] = new short[reqs];
 
 	// setup multi-read operation
 	for (int i = 0; i < reqs; ++i) {
 	    RCObject obj = req.get(i);
-	    mrObjs[i] = new JRamCloud.multiReadObject(obj.getTableId(),
-		    obj.getKey());
+            tableId[i] = obj.getTableId();
+            key[i] = obj.getKey();
+            keySize[i] = (short) key[i].length;
 	}
 
 	// execute
-	JRamCloud.Object results[] = rcClient.multiRead(mrObjs);
+	JRamCloud.Object results[] = rcClient.multiRead(tableId, key, keySize, reqs);
 	assert (results.length <= req.size());
 
 	// reflect changes to RCObject