]> git-server-git.apps.pok.os.sepia.ceph.com Git - rocksdb.git/commitdiff
Allow an offset as well as a length to be specified for byte[] operations in RocksJav...
authorAdam Retter <adam.retter@googlemail.com>
Mon, 12 Sep 2016 18:51:08 +0000 (19:51 +0100)
committerYueh-Hsuan Chiang <yhchiang@fb.com>
Mon, 12 Sep 2016 18:51:08 +0000 (11:51 -0700)
Test Plan: Execute the Java test suite

Reviewers: yhchiang

Subscribers: andrewkr, dhruba

Differential Revision: https://reviews.facebook.net/D61971

java/rocksjni/rocksjni.cc
java/src/main/java/org/rocksdb/RocksDB.java

index e77452e610ad2ac2c4c7800d08c4dec46e1d3594..4561f6801df3305c55c4f7d77492e027786d2ebe 100644 (file)
@@ -206,14 +206,18 @@ jobjectArray Java_org_rocksdb_RocksDB_listColumnFamilies(
 
 void rocksdb_put_helper(
     JNIEnv* env, rocksdb::DB* db, const rocksdb::WriteOptions& write_options,
-    rocksdb::ColumnFamilyHandle* cf_handle, jbyteArray jkey, jint jkey_len,
-    jbyteArray jentry_value, jint jentry_value_len) {
+    rocksdb::ColumnFamilyHandle* cf_handle, jbyteArray jkey, jint jkey_off,
+    jint jkey_len, jbyteArray jvalue, jint jvalue_off, jint jvalue_len) {
+
+  jbyte* key = new jbyte[jkey_len];
+  env->GetByteArrayRegion(jkey, jkey_off, jkey_len, key);
+
+  jbyte* value = new jbyte[jvalue_len];
+  env->GetByteArrayRegion(jvalue, jvalue_off, jvalue_len, value);
 
-  jbyte* key = env->GetByteArrayElements(jkey, 0);
-  jbyte* value = env->GetByteArrayElements(jentry_value, 0);
   rocksdb::Slice key_slice(reinterpret_cast<char*>(key), jkey_len);
   rocksdb::Slice value_slice(reinterpret_cast<char*>(value),
-      jentry_value_len);
+      jvalue_len);
 
   rocksdb::Status s;
   if (cf_handle != nullptr) {
@@ -223,11 +227,9 @@ void rocksdb_put_helper(
     s = db->Put(write_options, key_slice, value_slice);
   }
 
-  // trigger java unref on key and value.
-  // by passing JNI_ABORT, it will simply release the reference without
-  // copying the result back to the java byte array.
-  env->ReleaseByteArrayElements(jkey, key, JNI_ABORT);
-  env->ReleaseByteArrayElements(jentry_value, value, JNI_ABORT);
+  // cleanup
+  delete [] value;
+  delete [] key;
 
   if (s.ok()) {
     return;
@@ -238,36 +240,37 @@ void rocksdb_put_helper(
 /*
  * Class:     org_rocksdb_RocksDB
  * Method:    put
- * Signature: (J[BI[BI)V
+ * Signature: (J[BII[BII)V
  */
-void Java_org_rocksdb_RocksDB_put__J_3BI_3BI(
+void Java_org_rocksdb_RocksDB_put__J_3BII_3BII(
     JNIEnv* env, jobject jdb, jlong jdb_handle,
-    jbyteArray jkey, jint jkey_len,
-    jbyteArray jentry_value, jint jentry_value_len) {
+    jbyteArray jkey, jint jkey_off, jint jkey_len,
+    jbyteArray jvalue, jint jvalue_off, jint jvalue_len) {
   auto db = reinterpret_cast<rocksdb::DB*>(jdb_handle);
   static const rocksdb::WriteOptions default_write_options =
       rocksdb::WriteOptions();
 
   rocksdb_put_helper(env, db, default_write_options, nullptr,
-                     jkey, jkey_len,
-                     jentry_value, jentry_value_len);
+                     jkey, jkey_off, jkey_len,
+                     jvalue, jvalue_off, jvalue_len);
 }
+
 /*
  * Class:     org_rocksdb_RocksDB
  * Method:    put
- * Signature: (J[BI[BIJ)V
+ * Signature: (J[BII[BIIJ)V
  */
-void Java_org_rocksdb_RocksDB_put__J_3BI_3BIJ(
+void Java_org_rocksdb_RocksDB_put__J_3BII_3BIIJ(
     JNIEnv* env, jobject jdb, jlong jdb_handle,
-    jbyteArray jkey, jint jkey_len,
-    jbyteArray jentry_value, jint jentry_value_len, jlong jcf_handle) {
+    jbyteArray jkey, jint jkey_off, jint jkey_len,
+    jbyteArray jvalue, jint jvalue_off, jint jvalue_len, jlong jcf_handle) {
   auto db = reinterpret_cast<rocksdb::DB*>(jdb_handle);
   static const rocksdb::WriteOptions default_write_options =
       rocksdb::WriteOptions();
   auto cf_handle = reinterpret_cast<rocksdb::ColumnFamilyHandle*>(jcf_handle);
   if (cf_handle != nullptr) {
     rocksdb_put_helper(env, db, default_write_options, cf_handle,
-        jkey, jkey_len, jentry_value, jentry_value_len);
+        jkey, jkey_off, jkey_len, jvalue, jvalue_off, jvalue_len);
   } else {
     rocksdb::RocksDBExceptionJni::ThrowNew(env,
         rocksdb::Status::InvalidArgument("Invalid ColumnFamilyHandle."));
@@ -277,39 +280,39 @@ void Java_org_rocksdb_RocksDB_put__J_3BI_3BIJ(
 /*
  * Class:     org_rocksdb_RocksDB
  * Method:    put
- * Signature: (JJ[BI[BI)V
+ * Signature: (JJ[BII[BII)V
  */
-void Java_org_rocksdb_RocksDB_put__JJ_3BI_3BI(
+void Java_org_rocksdb_RocksDB_put__JJ_3BII_3BII(
     JNIEnv* env, jobject jdb,
     jlong jdb_handle, jlong jwrite_options_handle,
-    jbyteArray jkey, jint jkey_len,
-    jbyteArray jentry_value, jint jentry_value_len) {
+    jbyteArray jkey, jint jkey_off, jint jkey_len,
+    jbyteArray jvalue, jint jvalue_off, jint jvalue_len) {
   auto db = reinterpret_cast<rocksdb::DB*>(jdb_handle);
   auto write_options = reinterpret_cast<rocksdb::WriteOptions*>(
       jwrite_options_handle);
 
   rocksdb_put_helper(env, db, *write_options, nullptr,
-                     jkey, jkey_len,
-                     jentry_value, jentry_value_len);
+                     jkey, jkey_off, jkey_len,
+                     jvalue, jvalue_off, jvalue_len);
 }
 
 /*
  * Class:     org_rocksdb_RocksDB
  * Method:    put
- * Signature: (JJ[BI[BIJ)V
+ * Signature: (JJ[BII[BIIJ)V
  */
-void Java_org_rocksdb_RocksDB_put__JJ_3BI_3BIJ(
+void Java_org_rocksdb_RocksDB_put__JJ_3BII_3BIIJ(
     JNIEnv* env, jobject jdb,
     jlong jdb_handle, jlong jwrite_options_handle,
-    jbyteArray jkey, jint jkey_len,
-    jbyteArray jentry_value, jint jentry_value_len, jlong jcf_handle) {
+    jbyteArray jkey, jint jkey_off, jint jkey_len,
+    jbyteArray jvalue, jint jvalue_off, jint jvalue_len, jlong jcf_handle) {
   auto db = reinterpret_cast<rocksdb::DB*>(jdb_handle);
   auto write_options = reinterpret_cast<rocksdb::WriteOptions*>(
       jwrite_options_handle);
   auto cf_handle = reinterpret_cast<rocksdb::ColumnFamilyHandle*>(jcf_handle);
   if (cf_handle != nullptr) {
     rocksdb_put_helper(env, db, *write_options, cf_handle,
-        jkey, jkey_len, jentry_value, jentry_value_len);
+        jkey, jkey_off, jkey_len, jvalue, jvalue_off, jvalue_len);
   } else {
     rocksdb::RocksDBExceptionJni::ThrowNew(env,
         rocksdb::Status::InvalidArgument("Invalid ColumnFamilyHandle."));
@@ -363,12 +366,12 @@ void Java_org_rocksdb_RocksDB_write1(
 // rocksdb::DB::KeyMayExist
 jboolean key_may_exist_helper(JNIEnv* env, rocksdb::DB* db,
     const rocksdb::ReadOptions& read_opt,
-    rocksdb::ColumnFamilyHandle* cf_handle, jbyteArray jkey, jint jkey_len,
-    jobject jstring_buffer) {
+    rocksdb::ColumnFamilyHandle* cf_handle, jbyteArray jkey, jint jkey_off,
+    jint jkey_len, jobject jstring_buffer) {
   std::string value;
   bool value_found = false;
-  jboolean isCopy;
-  jbyte* key = env->GetByteArrayElements(jkey, &isCopy);
+  jbyte* key = new jbyte[jkey_len];
+  env->GetByteArrayRegion(jkey, jkey_off, jkey_len, key);
   rocksdb::Slice key_slice(reinterpret_cast<char*>(key), jkey_len);
   bool keyMayExist;
   if (cf_handle != nullptr) {
@@ -379,6 +382,10 @@ jboolean key_may_exist_helper(JNIEnv* env, rocksdb::DB* db,
         &value, &value_found);
   }
 
+  // cleanup
+  delete [] key;
+
+  // extract the value
   if (value_found && !value.empty()) {
     jclass clazz = env->GetObjectClass(jstring_buffer);
     jmethodID mid = env->GetMethodID(clazz, "append",
@@ -386,37 +393,36 @@ jboolean key_may_exist_helper(JNIEnv* env, rocksdb::DB* db,
     jstring new_value_str = env->NewStringUTF(value.c_str());
     env->CallObjectMethod(jstring_buffer, mid, new_value_str);
   }
-  env->ReleaseByteArrayElements(jkey, key, JNI_ABORT);
   return static_cast<jboolean>(keyMayExist);
 }
 
 /*
  * Class:     org_rocksdb_RocksDB
  * Method:    keyMayExist
- * Signature: (J[BILjava/lang/StringBuffer;)Z
+ * Signature: (J[BIILjava/lang/StringBuffer;)Z
  */
-jboolean Java_org_rocksdb_RocksDB_keyMayExist__J_3BILjava_lang_StringBuffer_2(
-    JNIEnv* env, jobject jdb, jlong jdb_handle, jbyteArray jkey, jint jkey_len,
-    jobject jstring_buffer) {
+jboolean Java_org_rocksdb_RocksDB_keyMayExist__J_3BIILjava_lang_StringBuffer_2(
+    JNIEnv* env, jobject jdb, jlong jdb_handle, jbyteArray jkey, jint jkey_off,
+    jint jkey_len, jobject jstring_buffer) {
   auto* db = reinterpret_cast<rocksdb::DB*>(jdb_handle);
   return key_may_exist_helper(env, db, rocksdb::ReadOptions(),
-      nullptr, jkey, jkey_len, jstring_buffer);
+      nullptr, jkey, jkey_off, jkey_len, jstring_buffer);
 }
 
 /*
  * Class:     org_rocksdb_RocksDB
  * Method:    keyMayExist
- * Signature: (J[BIJLjava/lang/StringBuffer;)Z
+ * Signature: (J[BIIJLjava/lang/StringBuffer;)Z
  */
-jboolean Java_org_rocksdb_RocksDB_keyMayExist__J_3BIJLjava_lang_StringBuffer_2(
-    JNIEnv* env, jobject jdb, jlong jdb_handle, jbyteArray jkey, jint jkey_len,
-    jlong jcf_handle, jobject jstring_buffer) {
+jboolean Java_org_rocksdb_RocksDB_keyMayExist__J_3BIIJLjava_lang_StringBuffer_2(
+    JNIEnv* env, jobject jdb, jlong jdb_handle, jbyteArray jkey, jint jkey_off,
+    jint jkey_len, jlong jcf_handle, jobject jstring_buffer) {
   auto* db = reinterpret_cast<rocksdb::DB*>(jdb_handle);
   auto* cf_handle = reinterpret_cast<rocksdb::ColumnFamilyHandle*>(
       jcf_handle);
   if (cf_handle != nullptr) {
     return key_may_exist_helper(env, db, rocksdb::ReadOptions(),
-        cf_handle, jkey, jkey_len, jstring_buffer);
+        cf_handle, jkey, jkey_off, jkey_len, jstring_buffer);
   } else {
     rocksdb::RocksDBExceptionJni::ThrowNew(env,
         rocksdb::Status::InvalidArgument("Invalid ColumnFamilyHandle."));
@@ -427,26 +433,27 @@ jboolean Java_org_rocksdb_RocksDB_keyMayExist__J_3BIJLjava_lang_StringBuffer_2(
 /*
  * Class:     org_rocksdb_RocksDB
  * Method:    keyMayExist
- * Signature: (JJ[BILjava/lang/StringBuffer;)Z
+ * Signature: (JJ[BIILjava/lang/StringBuffer;)Z
  */
-jboolean Java_org_rocksdb_RocksDB_keyMayExist__JJ_3BILjava_lang_StringBuffer_2(
+jboolean Java_org_rocksdb_RocksDB_keyMayExist__JJ_3BIILjava_lang_StringBuffer_2(
     JNIEnv* env, jobject jdb, jlong jdb_handle, jlong jread_options_handle,
-    jbyteArray jkey, jint jkey_len, jobject jstring_buffer) {
+    jbyteArray jkey, jint jkey_off, jint jkey_len, jobject jstring_buffer) {
   auto* db = reinterpret_cast<rocksdb::DB*>(jdb_handle);
   auto& read_options = *reinterpret_cast<rocksdb::ReadOptions*>(
       jread_options_handle);
   return key_may_exist_helper(env, db, read_options,
-      nullptr, jkey, jkey_len, jstring_buffer);
+      nullptr, jkey, jkey_off, jkey_len, jstring_buffer);
 }
 
 /*
  * Class:     org_rocksdb_RocksDB
  * Method:    keyMayExist
- * Signature: (JJ[BIJLjava/lang/StringBuffer;)Z
+ * Signature: (JJ[BIIJLjava/lang/StringBuffer;)Z
  */
-jboolean Java_org_rocksdb_RocksDB_keyMayExist__JJ_3BIJLjava_lang_StringBuffer_2(
+jboolean Java_org_rocksdb_RocksDB_keyMayExist__JJ_3BIIJLjava_lang_StringBuffer_2(
     JNIEnv* env, jobject jdb, jlong jdb_handle, jlong jread_options_handle,
-    jbyteArray jkey, jint jkey_len, jlong jcf_handle, jobject jstring_buffer) {
+    jbyteArray jkey, jint jkey_off, jint jkey_len, jlong jcf_handle,
+    jobject jstring_buffer) {
   auto* db = reinterpret_cast<rocksdb::DB*>(jdb_handle);
   auto& read_options = *reinterpret_cast<rocksdb::ReadOptions*>(
       jread_options_handle);
@@ -454,7 +461,7 @@ jboolean Java_org_rocksdb_RocksDB_keyMayExist__JJ_3BIJLjava_lang_StringBuffer_2(
       jcf_handle);
   if (cf_handle != nullptr) {
     return key_may_exist_helper(env, db, read_options, cf_handle,
-        jkey, jkey_len, jstring_buffer);
+        jkey, jkey_off, jkey_len, jstring_buffer);
   } else {
     rocksdb::RocksDBExceptionJni::ThrowNew(env,
         rocksdb::Status::InvalidArgument("Invalid ColumnFamilyHandle."));
@@ -468,9 +475,10 @@ jboolean Java_org_rocksdb_RocksDB_keyMayExist__JJ_3BIJLjava_lang_StringBuffer_2(
 jbyteArray rocksdb_get_helper(
     JNIEnv* env, rocksdb::DB* db, const rocksdb::ReadOptions& read_opt,
     rocksdb::ColumnFamilyHandle* column_family_handle, jbyteArray jkey,
-    jint jkey_len) {
-  jboolean isCopy;
-  jbyte* key = env->GetByteArrayElements(jkey, &isCopy);
+    jint jkey_off, jint jkey_len) {
+
+  jbyte* key = new jbyte[jkey_len];
+  env->GetByteArrayRegion(jkey, jkey_off, jkey_len, key);
   rocksdb::Slice key_slice(
       reinterpret_cast<char*>(key), jkey_len);
 
@@ -483,10 +491,8 @@ jbyteArray rocksdb_get_helper(
     s = db->Get(read_opt, key_slice, &value);
   }
 
-  // trigger java unref on key.
-  // by passing JNI_ABORT, it will simply release the reference without
-  // copying the result back to the java byte array.
-  env->ReleaseByteArrayElements(jkey, key, JNI_ABORT);
+  // cleanup
+  delete [] key;
 
   if (s.IsNotFound()) {
     return nullptr;
@@ -506,30 +512,30 @@ jbyteArray rocksdb_get_helper(
 /*
  * Class:     org_rocksdb_RocksDB
  * Method:    get
- * Signature: (J[BI)[B
+ * Signature: (J[BII)[B
  */
-jbyteArray Java_org_rocksdb_RocksDB_get__J_3BI(
+jbyteArray Java_org_rocksdb_RocksDB_get__J_3BII(
     JNIEnv* env, jobject jdb, jlong jdb_handle,
-    jbyteArray jkey, jint jkey_len) {
+    jbyteArray jkey, jint jkey_off, jint jkey_len) {
   return rocksdb_get_helper(env,
       reinterpret_cast<rocksdb::DB*>(jdb_handle),
       rocksdb::ReadOptions(), nullptr,
-      jkey, jkey_len);
+      jkey, jkey_off, jkey_len);
 }
 
 /*
  * Class:     org_rocksdb_RocksDB
  * Method:    get
- * Signature: (J[BIJ)[B
+ * Signature: (J[BIIJ)[B
  */
-jbyteArray Java_org_rocksdb_RocksDB_get__J_3BIJ(
+jbyteArray Java_org_rocksdb_RocksDB_get__J_3BIIJ(
     JNIEnv* env, jobject jdb, jlong jdb_handle,
-    jbyteArray jkey, jint jkey_len, jlong jcf_handle) {
+    jbyteArray jkey, jint jkey_off, jint jkey_len, jlong jcf_handle) {
   auto db_handle = reinterpret_cast<rocksdb::DB*>(jdb_handle);
   auto cf_handle = reinterpret_cast<rocksdb::ColumnFamilyHandle*>(jcf_handle);
   if (cf_handle != nullptr) {
     return rocksdb_get_helper(env, db_handle, rocksdb::ReadOptions(),
-        cf_handle, jkey, jkey_len);
+        cf_handle, jkey, jkey_off, jkey_len);
   } else {
     rocksdb::RocksDBExceptionJni::ThrowNew(env,
         rocksdb::Status::InvalidArgument("Invalid ColumnFamilyHandle."));
@@ -541,31 +547,31 @@ jbyteArray Java_org_rocksdb_RocksDB_get__J_3BIJ(
 /*
  * Class:     org_rocksdb_RocksDB
  * Method:    get
- * Signature: (JJ[BI)[B
+ * Signature: (JJ[BII)[B
  */
-jbyteArray Java_org_rocksdb_RocksDB_get__JJ_3BI(
+jbyteArray Java_org_rocksdb_RocksDB_get__JJ_3BII(
     JNIEnv* env, jobject jdb, jlong jdb_handle, jlong jropt_handle,
-    jbyteArray jkey, jint jkey_len) {
+    jbyteArray jkey, jint jkey_off, jint jkey_len) {
   return rocksdb_get_helper(env,
       reinterpret_cast<rocksdb::DB*>(jdb_handle),
       *reinterpret_cast<rocksdb::ReadOptions*>(jropt_handle), nullptr,
-      jkey, jkey_len);
+      jkey, jkey_off, jkey_len);
 }
 
 /*
  * Class:     org_rocksdb_RocksDB
  * Method:    get
- * Signature: (JJ[BIJ)[B
+ * Signature: (JJ[BIIJ)[B
  */
-jbyteArray Java_org_rocksdb_RocksDB_get__JJ_3BIJ(
+jbyteArray Java_org_rocksdb_RocksDB_get__JJ_3BIIJ(
     JNIEnv* env, jobject jdb, jlong jdb_handle, jlong jropt_handle,
-    jbyteArray jkey, jint jkey_len, jlong jcf_handle) {
+    jbyteArray jkey, jint jkey_off, jint jkey_len, jlong jcf_handle) {
   auto db_handle = reinterpret_cast<rocksdb::DB*>(jdb_handle);
   auto& ro_opt = *reinterpret_cast<rocksdb::ReadOptions*>(jropt_handle);
   auto cf_handle = reinterpret_cast<rocksdb::ColumnFamilyHandle*>(jcf_handle);
   if (cf_handle != nullptr) {
     return rocksdb_get_helper(env, db_handle, ro_opt, cf_handle,
-        jkey, jkey_len);
+        jkey, jkey_off, jkey_len);
   } else {
     rocksdb::RocksDBExceptionJni::ThrowNew(env,
         rocksdb::Status::InvalidArgument("Invalid ColumnFamilyHandle."));
@@ -577,11 +583,13 @@ jbyteArray Java_org_rocksdb_RocksDB_get__JJ_3BIJ(
 jint rocksdb_get_helper(
     JNIEnv* env, rocksdb::DB* db, const rocksdb::ReadOptions& read_options,
     rocksdb::ColumnFamilyHandle* column_family_handle, jbyteArray jkey,
-    jint jkey_len, jbyteArray jentry_value, jint jentry_value_len) {
+    jint jkey_off, jint jkey_len, jbyteArray jvalue, jint jvalue_off,
+    jint jvalue_len) {
   static const int kNotFound = -1;
   static const int kStatusError = -2;
 
-  jbyte* key = env->GetByteArrayElements(jkey, 0);
+  jbyte* key = new jbyte[jkey_len];
+  env->GetByteArrayRegion(jkey, jkey_off, jkey_len, key);
   rocksdb::Slice key_slice(
       reinterpret_cast<char*>(key), jkey_len);
 
@@ -596,10 +604,8 @@ jint rocksdb_get_helper(
     s = db->Get(read_options, key_slice, &cvalue);
   }
 
-  // trigger java unref on key.
-  // by passing JNI_ABORT, it will simply release the reference without
-  // copying the result back to the java byte array.
-  env->ReleaseByteArrayElements(jkey, key, JNI_ABORT);
+  // cleanup
+  delete [] key;
 
   if (s.IsNotFound()) {
     return kNotFound;
@@ -617,10 +623,10 @@ jint rocksdb_get_helper(
   }
 
   jint cvalue_len = static_cast<jint>(cvalue.size());
-  jint length = std::min(jentry_value_len, cvalue_len);
+  jint length = std::min(jvalue_len, cvalue_len);
 
   env->SetByteArrayRegion(
-      jentry_value, 0, length,
+      jvalue, jvalue_off, length,
       reinterpret_cast<const jbyte*>(cvalue.c_str()));
   return cvalue_len;
 }
@@ -628,6 +634,7 @@ jint rocksdb_get_helper(
 // cf multi get
 jobjectArray multi_get_helper(JNIEnv* env, jobject jdb, rocksdb::DB* db,
     const rocksdb::ReadOptions& rOpt, jobjectArray jkeys,
+    jintArray jkey_offs, jintArray jkey_lens,
     jlongArray jcolumn_family_handles) {
   std::vector<rocksdb::ColumnFamilyHandle*> cf_handles;
   if (jcolumn_family_handles != nullptr) {
@@ -642,24 +649,35 @@ jobjectArray multi_get_helper(JNIEnv* env, jobject jdb, rocksdb::DB* db,
   }
 
   std::vector<rocksdb::Slice> keys;
-  std::vector<std::tuple<jbyteArray, jbyte*, jobject>> keys_to_free;
+  std::vector<std::pair<jbyte*, jobject>> keys_to_free;
   jsize len_keys = env->GetArrayLength(jkeys);
-  if(env->EnsureLocalCapacity(len_keys) != 0) {
+  if (env->EnsureLocalCapacity(len_keys) != 0) {
     // out of memory
     return NULL;
   }
+
+  jint* jkey_off = env->GetIntArrayElements(jkey_offs, NULL);
+  jint* jkey_len = env->GetIntArrayElements(jkey_lens, NULL);
+
   for (int i = 0; i < len_keys; i++) {
-    jobject jk = env->GetObjectArrayElement(jkeys, i);
-    jbyteArray jk_ba = reinterpret_cast<jbyteArray>(jk);
-    jsize len_key = env->GetArrayLength(jk_ba);
-    jbyte* jk_val = env->GetByteArrayElements(jk_ba, NULL);
+    jobject jkey = env->GetObjectArrayElement(jkeys, i);
+
+    jbyteArray jkey_ba = reinterpret_cast<jbyteArray>(jkey);
 
-    rocksdb::Slice key_slice(reinterpret_cast<char*>(jk_val), len_key);
+    jint len_key = jkey_len[i];
+    jbyte* key = new jbyte[len_key];
+    env->GetByteArrayRegion(jkey_ba, jkey_off[i], len_key, key);
+
+    rocksdb::Slice key_slice(reinterpret_cast<char*>(key), len_key);
     keys.push_back(key_slice);
 
-    keys_to_free.push_back(std::make_tuple(jk_ba, jk_val, jk));
+    keys_to_free.push_back(std::pair<jbyte*, jobject>(key, jkey));
   }
 
+  // cleanup jkey_off and jken_len
+  env->ReleaseIntArrayElements(jkey_lens, jkey_len, JNI_ABORT);
+  env->ReleaseIntArrayElements(jkey_offs, jkey_off, JNI_ABORT);
+
   std::vector<std::string> values;
   std::vector<rocksdb::Status> s;
   if (cf_handles.size() == 0) {
@@ -669,15 +687,11 @@ jobjectArray multi_get_helper(JNIEnv* env, jobject jdb, rocksdb::DB* db,
   }
 
   // free up allocated byte arrays
-  for (std::vector<std::tuple<jbyteArray, jbyte*, jobject>>::size_type i = 0;
-      i < keys_to_free.size(); i++) {
-    jobject jk;
-    jbyteArray jk_ba;
-    jbyte* jk_val;
-    std::tie(jk_ba, jk_val, jk) = keys_to_free[i];
-    env->ReleaseByteArrayElements(jk_ba, jk_val, JNI_ABORT);
-    env->DeleteLocalRef(jk);
+  for (auto it = keys_to_free.begin(); it != keys_to_free.end(); ++it) {
+    delete [] it->first;
+    env->DeleteLocalRef(it->second);
   }
+  keys_to_free.clear();
 
   // prepare the results
   jclass jcls_ba = env->FindClass("[B");
@@ -703,80 +717,85 @@ jobjectArray multi_get_helper(JNIEnv* env, jobject jdb, rocksdb::DB* db,
 /*
  * Class:     org_rocksdb_RocksDB
  * Method:    multiGet
- * Signature: (J[[B)[[B
+ * Signature: (J[[B[I[I)[[B
  */
-jobjectArray Java_org_rocksdb_RocksDB_multiGet__J_3_3B(
-    JNIEnv* env, jobject jdb, jlong jdb_handle, jobjectArray jkeys) {
+jobjectArray Java_org_rocksdb_RocksDB_multiGet__J_3_3B_3I_3I(
+    JNIEnv* env, jobject jdb, jlong jdb_handle, jobjectArray jkeys,
+    jintArray jkey_offs, jintArray jkey_lens) {
   return multi_get_helper(env, jdb, reinterpret_cast<rocksdb::DB*>(jdb_handle),
-      rocksdb::ReadOptions(), jkeys, nullptr);
+      rocksdb::ReadOptions(), jkeys, jkey_offs, jkey_lens, nullptr);
 }
 
 /*
  * Class:     org_rocksdb_RocksDB
  * Method:    multiGet
- * Signature: (J[[B[J)[[B
+ * Signature: (J[[B[I[I[J)[[B
  */
-jobjectArray Java_org_rocksdb_RocksDB_multiGet__J_3_3B_3J(
+jobjectArray Java_org_rocksdb_RocksDB_multiGet__J_3_3B_3I_3I_3J(
     JNIEnv* env, jobject jdb, jlong jdb_handle, jobjectArray jkeys,
+    jintArray jkey_offs, jintArray jkey_lens,
     jlongArray jcolumn_family_handles) {
   return multi_get_helper(env, jdb, reinterpret_cast<rocksdb::DB*>(jdb_handle),
-      rocksdb::ReadOptions(), jkeys, jcolumn_family_handles);
+      rocksdb::ReadOptions(), jkeys, jkey_offs, jkey_lens,
+      jcolumn_family_handles);
 }
 
 /*
  * Class:     org_rocksdb_RocksDB
  * Method:    multiGet
- * Signature: (JJ[[B)[[B
+ * Signature: (JJ[[B[I[I)[[B
  */
-jobjectArray Java_org_rocksdb_RocksDB_multiGet__JJ_3_3B(
+jobjectArray Java_org_rocksdb_RocksDB_multiGet__JJ_3_3B_3I_3I(
     JNIEnv* env, jobject jdb, jlong jdb_handle, jlong jropt_handle,
-    jobjectArray jkeys) {
+    jobjectArray jkeys, jintArray jkey_offs, jintArray jkey_lens) {
   return multi_get_helper(env, jdb, reinterpret_cast<rocksdb::DB*>(jdb_handle),
-      *reinterpret_cast<rocksdb::ReadOptions*>(jropt_handle), jkeys, nullptr);
+      *reinterpret_cast<rocksdb::ReadOptions*>(jropt_handle), jkeys, jkey_offs,
+      jkey_lens, nullptr);
 }
 
 /*
  * Class:     org_rocksdb_RocksDB
  * Method:    multiGet
- * Signature: (JJ[[B[J)[[B
+ * Signature: (JJ[[B[I[I[J)[[B
  */
-jobjectArray Java_org_rocksdb_RocksDB_multiGet__JJ_3_3B_3J(
+jobjectArray Java_org_rocksdb_RocksDB_multiGet__JJ_3_3B_3I_3I_3J(
     JNIEnv* env, jobject jdb, jlong jdb_handle, jlong jropt_handle,
-    jobjectArray jkeys, jlongArray jcolumn_family_handles) {
+    jobjectArray jkeys, jintArray jkey_offs, jintArray jkey_lens,
+    jlongArray jcolumn_family_handles) {
   return multi_get_helper(env, jdb, reinterpret_cast<rocksdb::DB*>(jdb_handle),
-      *reinterpret_cast<rocksdb::ReadOptions*>(jropt_handle), jkeys,
-      jcolumn_family_handles);
+      *reinterpret_cast<rocksdb::ReadOptions*>(jropt_handle), jkeys, jkey_offs,
+      jkey_lens, jcolumn_family_handles);
 }
 
 /*
  * Class:     org_rocksdb_RocksDB
  * Method:    get
- * Signature: (J[BI[BI)I
+ * Signature: (J[BII[BII)I
  */
-jint Java_org_rocksdb_RocksDB_get__J_3BI_3BI(
+jint Java_org_rocksdb_RocksDB_get__J_3BII_3BII(
     JNIEnv* env, jobject jdb, jlong jdb_handle,
-    jbyteArray jkey, jint jkey_len,
-    jbyteArray jentry_value, jint jentry_value_len) {
+    jbyteArray jkey, jint jkey_off, jint jkey_len,
+    jbyteArray jvalue, jint jvalue_off, jint jvalue_len) {
   return rocksdb_get_helper(env,
       reinterpret_cast<rocksdb::DB*>(jdb_handle),
       rocksdb::ReadOptions(), nullptr,
-      jkey, jkey_len, jentry_value, jentry_value_len);
+      jkey, jkey_off, jkey_len, jvalue, jvalue_off, jvalue_len);
 }
 
 /*
  * Class:     org_rocksdb_RocksDB
  * Method:    get
- * Signature: (J[BI[BIJ)I
+ * Signature: (J[BII[BIIJ)I
  */
-jint Java_org_rocksdb_RocksDB_get__J_3BI_3BIJ(
+jint Java_org_rocksdb_RocksDB_get__J_3BII_3BIIJ(
     JNIEnv* env, jobject jdb, jlong jdb_handle,
-    jbyteArray jkey, jint jkey_len,
-    jbyteArray jentry_value, jint jentry_value_len, jlong jcf_handle) {
+    jbyteArray jkey, jint jkey_off, jint jkey_len,
+    jbyteArray jvalue, jint jvalue_off, jint jvalue_len, jlong jcf_handle) {
   auto db_handle = reinterpret_cast<rocksdb::DB*>(jdb_handle);
   auto cf_handle = reinterpret_cast<rocksdb::ColumnFamilyHandle*>(jcf_handle);
   if (cf_handle != nullptr) {
     return rocksdb_get_helper(env, db_handle, rocksdb::ReadOptions(), cf_handle,
-        jkey, jkey_len, jentry_value, jentry_value_len);
+        jkey, jkey_off, jkey_len, jvalue, jvalue_off, jvalue_len);
   } else {
     rocksdb::RocksDBExceptionJni::ThrowNew(env,
         rocksdb::Status::InvalidArgument("Invalid ColumnFamilyHandle."));
@@ -788,33 +807,33 @@ jint Java_org_rocksdb_RocksDB_get__J_3BI_3BIJ(
 /*
  * Class:     org_rocksdb_RocksDB
  * Method:    get
- * Signature: (JJ[BI[BI)I
+ * Signature: (JJ[BII[BII)I
  */
-jint Java_org_rocksdb_RocksDB_get__JJ_3BI_3BI(
+jint Java_org_rocksdb_RocksDB_get__JJ_3BII_3BII(
     JNIEnv* env, jobject jdb, jlong jdb_handle, jlong jropt_handle,
-    jbyteArray jkey, jint jkey_len,
-    jbyteArray jentry_value, jint jentry_value_len) {
+    jbyteArray jkey, jint jkey_off, jint jkey_len,
+    jbyteArray jvalue, jint jvalue_off, jint jvalue_len) {
   return rocksdb_get_helper(env,
       reinterpret_cast<rocksdb::DB*>(jdb_handle),
       *reinterpret_cast<rocksdb::ReadOptions*>(jropt_handle),
-      nullptr, jkey, jkey_len, jentry_value, jentry_value_len);
+      nullptr, jkey, jkey_off, jkey_len, jvalue, jvalue_off, jvalue_len);
 }
 
 /*
  * Class:     org_rocksdb_RocksDB
  * Method:    get
- * Signature: (JJ[BI[BIJ)I
+ * Signature: (JJ[BII[BIIJ)I
  */
-jint Java_org_rocksdb_RocksDB_get__JJ_3BI_3BIJ(
+jint Java_org_rocksdb_RocksDB_get__JJ_3BII_3BIIJ(
     JNIEnv* env, jobject jdb, jlong jdb_handle, jlong jropt_handle,
-    jbyteArray jkey, jint jkey_len,
-    jbyteArray jentry_value, jint jentry_value_len, jlong jcf_handle) {
+    jbyteArray jkey, jint jkey_off, jint jkey_len,
+    jbyteArray jvalue, jint jvalue_off, jint jvalue_len, jlong jcf_handle) {
   auto db_handle = reinterpret_cast<rocksdb::DB*>(jdb_handle);
   auto& ro_opt = *reinterpret_cast<rocksdb::ReadOptions*>(jropt_handle);
   auto cf_handle = reinterpret_cast<rocksdb::ColumnFamilyHandle*>(jcf_handle);
   if (cf_handle != nullptr) {
     return rocksdb_get_helper(env, db_handle, ro_opt, cf_handle, jkey,
-        jkey_len, jentry_value, jentry_value_len);
+        jkey_off, jkey_len, jvalue, jvalue_off, jvalue_len);
   } else {
     rocksdb::RocksDBExceptionJni::ThrowNew(env,
         rocksdb::Status::InvalidArgument("Invalid ColumnFamilyHandle."));
@@ -826,8 +845,10 @@ jint Java_org_rocksdb_RocksDB_get__JJ_3BI_3BIJ(
 // rocksdb::DB::Delete()
 void rocksdb_delete_helper(
     JNIEnv* env, rocksdb::DB* db, const rocksdb::WriteOptions& write_options,
-    rocksdb::ColumnFamilyHandle* cf_handle, jbyteArray jkey, jint jkey_len) {
-  jbyte* key = env->GetByteArrayElements(jkey, 0);
+    rocksdb::ColumnFamilyHandle* cf_handle, jbyteArray jkey, jint jkey_off,
+    jint jkey_len) {
+  jbyte* key = new jbyte[jkey_len];
+  env->GetByteArrayRegion(jkey, jkey_off, jkey_len, key);
   rocksdb::Slice key_slice(reinterpret_cast<char*>(key), jkey_len);
 
   rocksdb::Status s;
@@ -837,10 +858,9 @@ void rocksdb_delete_helper(
     // backwards compatibility
     s = db->Delete(write_options, key_slice);
   }
-  // trigger java unref on key and value.
-  // by passing JNI_ABORT, it will simply release the reference without
-  // copying the result back to the java byte array.
-  env->ReleaseByteArrayElements(jkey, key, JNI_ABORT);
+
+  // cleanup
+  delete [] key;
 
   if (!s.ok()) {
     rocksdb::RocksDBExceptionJni::ThrowNew(env, s);
@@ -851,33 +871,33 @@ void rocksdb_delete_helper(
 /*
  * Class:     org_rocksdb_RocksDB
  * Method:    delete
- * Signature: (J[BI)V
+ * Signature: (J[BII)V
  */
-void Java_org_rocksdb_RocksDB_delete__J_3BI(
+void Java_org_rocksdb_RocksDB_delete__J_3BII(
     JNIEnv* env, jobject jdb, jlong jdb_handle,
-    jbyteArray jkey, jint jkey_len) {
+    jbyteArray jkey, jint jkey_off, jint jkey_len) {
   auto db = reinterpret_cast<rocksdb::DB*>(jdb_handle);
   static const rocksdb::WriteOptions default_write_options =
       rocksdb::WriteOptions();
   rocksdb_delete_helper(env, db, default_write_options, nullptr,
-      jkey, jkey_len);
+      jkey, jkey_off, jkey_len);
 }
 
 /*
  * Class:     org_rocksdb_RocksDB
  * Method:    delete
- * Signature: (J[BIJ)V
+ * Signature: (J[BIIJ)V
  */
-void Java_org_rocksdb_RocksDB_delete__J_3BIJ(
+void Java_org_rocksdb_RocksDB_delete__J_3BIIJ(
     JNIEnv* env, jobject jdb, jlong jdb_handle,
-    jbyteArray jkey, jint jkey_len, jlong jcf_handle) {
+    jbyteArray jkey, jint jkey_off, jint jkey_len, jlong jcf_handle) {
   auto db = reinterpret_cast<rocksdb::DB*>(jdb_handle);
   static const rocksdb::WriteOptions default_write_options =
       rocksdb::WriteOptions();
   auto cf_handle = reinterpret_cast<rocksdb::ColumnFamilyHandle*>(jcf_handle);
   if (cf_handle != nullptr) {
     rocksdb_delete_helper(env, db, default_write_options, cf_handle,
-        jkey, jkey_len);
+        jkey, jkey_off, jkey_len);
   } else {
     rocksdb::RocksDBExceptionJni::ThrowNew(env,
         rocksdb::Status::InvalidArgument("Invalid ColumnFamilyHandle."));
@@ -887,30 +907,32 @@ void Java_org_rocksdb_RocksDB_delete__J_3BIJ(
 /*
  * Class:     org_rocksdb_RocksDB
  * Method:    delete
- * Signature: (JJ[BIJ)V
+ * Signature: (JJ[BII)V
  */
-void Java_org_rocksdb_RocksDB_delete__JJ_3BI(
+void Java_org_rocksdb_RocksDB_delete__JJ_3BII(
     JNIEnv* env, jobject jdb, jlong jdb_handle,
-    jlong jwrite_options, jbyteArray jkey, jint jkey_len) {
+    jlong jwrite_options, jbyteArray jkey, jint jkey_off, jint jkey_len) {
   auto db = reinterpret_cast<rocksdb::DB*>(jdb_handle);
   auto write_options = reinterpret_cast<rocksdb::WriteOptions*>(jwrite_options);
-  rocksdb_delete_helper(env, db, *write_options, nullptr, jkey, jkey_len);
+  rocksdb_delete_helper(env, db, *write_options, nullptr, jkey, jkey_off,
+      jkey_len);
 }
 
 /*
  * Class:     org_rocksdb_RocksDB
  * Method:    delete
- * Signature: (JJ[BIJ)V
+ * Signature: (JJ[BIIJ)V
  */
-void Java_org_rocksdb_RocksDB_delete__JJ_3BIJ(
+void Java_org_rocksdb_RocksDB_delete__JJ_3BIIJ(
     JNIEnv* env, jobject jdb, jlong jdb_handle,
-    jlong jwrite_options, jbyteArray jkey, jint jkey_len,
+    jlong jwrite_options, jbyteArray jkey, jint jkey_off, jint jkey_len,
     jlong jcf_handle) {
   auto db = reinterpret_cast<rocksdb::DB*>(jdb_handle);
   auto write_options = reinterpret_cast<rocksdb::WriteOptions*>(jwrite_options);
   auto cf_handle = reinterpret_cast<rocksdb::ColumnFamilyHandle*>(jcf_handle);
   if (cf_handle != nullptr) {
-    rocksdb_delete_helper(env, db, *write_options, cf_handle, jkey, jkey_len);
+    rocksdb_delete_helper(env, db, *write_options, cf_handle, jkey, jkey_off,
+        jkey_len);
   } else {
     rocksdb::RocksDBExceptionJni::ThrowNew(env,
         rocksdb::Status::InvalidArgument("Invalid ColumnFamilyHandle."));
@@ -1018,14 +1040,15 @@ void Java_org_rocksdb_RocksDB_singleDelete__JJ_3BIJ(
 
 void rocksdb_merge_helper(
     JNIEnv* env, rocksdb::DB* db, const rocksdb::WriteOptions& write_options,
-    rocksdb::ColumnFamilyHandle* cf_handle, jbyteArray jkey, jint jkey_len,
-    jbyteArray jentry_value, jint jentry_value_len) {
-
-  jbyte* key = env->GetByteArrayElements(jkey, 0);
-  jbyte* value = env->GetByteArrayElements(jentry_value, 0);
+    rocksdb::ColumnFamilyHandle* cf_handle, jbyteArray jkey, jint jkey_off,
+    jint jkey_len, jbyteArray jvalue, jint jvalue_off, jint jvalue_len) {
+  jbyte* key = new jbyte[jkey_len];
+  env->GetByteArrayRegion(jkey, jkey_off, jkey_len, key);
+  jbyte* value = new jbyte[jkey_len];
+  env->GetByteArrayRegion(jvalue, jvalue_off, jvalue_len, value);
   rocksdb::Slice key_slice(reinterpret_cast<char*>(key), jkey_len);
   rocksdb::Slice value_slice(reinterpret_cast<char*>(value),
-      jentry_value_len);
+      jvalue_len);
 
   rocksdb::Status s;
   if (cf_handle != nullptr) {
@@ -1034,11 +1057,9 @@ void rocksdb_merge_helper(
     s = db->Merge(write_options, key_slice, value_slice);
   }
 
-  // trigger java unref on key and value.
-  // by passing JNI_ABORT, it will simply release the reference without
-  // copying the result back to the java byte array.
-  env->ReleaseByteArrayElements(jkey, key, JNI_ABORT);
-  env->ReleaseByteArrayElements(jentry_value, value, JNI_ABORT);
+  // cleanup
+  delete [] value;
+  delete [] key;
 
   if (s.ok()) {
     return;
@@ -1049,36 +1070,36 @@ void rocksdb_merge_helper(
 /*
  * Class:     org_rocksdb_RocksDB
  * Method:    merge
- * Signature: (J[BI[BI)V
+ * Signature: (J[BII[BII)V
  */
-void Java_org_rocksdb_RocksDB_merge__J_3BI_3BI(
+void Java_org_rocksdb_RocksDB_merge__J_3BII_3BII(
     JNIEnv* env, jobject jdb, jlong jdb_handle,
-    jbyteArray jkey, jint jkey_len,
-    jbyteArray jentry_value, jint jentry_value_len) {
+    jbyteArray jkey, jint jkey_off, jint jkey_len,
+    jbyteArray jvalue, jint jvalue_off, jint jvalue_len) {
   auto db = reinterpret_cast<rocksdb::DB*>(jdb_handle);
   static const rocksdb::WriteOptions default_write_options =
       rocksdb::WriteOptions();
 
   rocksdb_merge_helper(env, db, default_write_options,
-      nullptr, jkey, jkey_len, jentry_value, jentry_value_len);
+      nullptr, jkey, jkey_off, jkey_len, jvalue, jvalue_off, jvalue_len);
 }
 
 /*
  * Class:     org_rocksdb_RocksDB
  * Method:    merge
- * Signature: (J[BI[BIJ)V
+ * Signature: (J[BII[BIIJ)V
  */
-void Java_org_rocksdb_RocksDB_merge__J_3BI_3BIJ(
+void Java_org_rocksdb_RocksDB_merge__J_3BII_3BIIJ(
     JNIEnv* env, jobject jdb, jlong jdb_handle,
-    jbyteArray jkey, jint jkey_len,
-    jbyteArray jentry_value, jint jentry_value_len, jlong jcf_handle) {
+    jbyteArray jkey, jint jkey_off, jint jkey_len,
+    jbyteArray jvalue, jint jvalue_off, jint jvalue_len, jlong jcf_handle) {
   auto db = reinterpret_cast<rocksdb::DB*>(jdb_handle);
   static const rocksdb::WriteOptions default_write_options =
       rocksdb::WriteOptions();
   auto cf_handle = reinterpret_cast<rocksdb::ColumnFamilyHandle*>(jcf_handle);
   if (cf_handle != nullptr) {
     rocksdb_merge_helper(env, db, default_write_options,
-        cf_handle, jkey, jkey_len, jentry_value, jentry_value_len);
+        cf_handle, jkey, jkey_off, jkey_len, jvalue, jvalue_off, jvalue_len);
   } else {
     rocksdb::RocksDBExceptionJni::ThrowNew(env,
         rocksdb::Status::InvalidArgument("Invalid ColumnFamilyHandle."));
@@ -1088,38 +1109,38 @@ void Java_org_rocksdb_RocksDB_merge__J_3BI_3BIJ(
 /*
  * Class:     org_rocksdb_RocksDB
  * Method:    merge
- * Signature: (JJ[BI[BI)V
+ * Signature: (JJ[BII[BII)V
  */
-void Java_org_rocksdb_RocksDB_merge__JJ_3BI_3BI(
+void Java_org_rocksdb_RocksDB_merge__JJ_3BII_3BII(
     JNIEnv* env, jobject jdb,
     jlong jdb_handle, jlong jwrite_options_handle,
-    jbyteArray jkey, jint jkey_len,
-    jbyteArray jentry_value, jint jentry_value_len) {
+    jbyteArray jkey, jint jkey_off, jint jkey_len,
+    jbyteArray jvalue, jint jvalue_off, jint jvalue_len) {
   auto db = reinterpret_cast<rocksdb::DB*>(jdb_handle);
   auto write_options = reinterpret_cast<rocksdb::WriteOptions*>(
       jwrite_options_handle);
 
   rocksdb_merge_helper(env, db, *write_options,
-      nullptr, jkey, jkey_len, jentry_value, jentry_value_len);
+      nullptr, jkey, jkey_off, jkey_len, jvalue, jvalue_off, jvalue_len);
 }
 
 /*
  * Class:     org_rocksdb_RocksDB
  * Method:    merge
- * Signature: (JJ[BI[BIJ)V
+ * Signature: (JJ[BII[BIIJ)V
  */
-void Java_org_rocksdb_RocksDB_merge__JJ_3BI_3BIJ(
+void Java_org_rocksdb_RocksDB_merge__JJ_3BII_3BIIJ(
     JNIEnv* env, jobject jdb,
     jlong jdb_handle, jlong jwrite_options_handle,
-    jbyteArray jkey, jint jkey_len,
-    jbyteArray jentry_value, jint jentry_value_len, jlong jcf_handle) {
+    jbyteArray jkey, jint jkey_off, jint jkey_len,
+    jbyteArray jvalue, jint jvalue_off, jint jvalue_len, jlong jcf_handle) {
   auto db = reinterpret_cast<rocksdb::DB*>(jdb_handle);
   auto write_options = reinterpret_cast<rocksdb::WriteOptions*>(
       jwrite_options_handle);
   auto cf_handle = reinterpret_cast<rocksdb::ColumnFamilyHandle*>(jcf_handle);
   if (cf_handle != nullptr) {
     rocksdb_merge_helper(env, db, *write_options,
-        cf_handle, jkey, jkey_len, jentry_value, jentry_value_len);
+        cf_handle, jkey, jkey_off, jkey_len, jvalue, jvalue_off, jvalue_len);
   } else {
     rocksdb::RocksDBExceptionJni::ThrowNew(env,
         rocksdb::Status::InvalidArgument("Invalid ColumnFamilyHandle."));
@@ -1696,7 +1717,7 @@ void Java_org_rocksdb_RocksDB_setOptions(JNIEnv* env, jobject jdb,
   std::unordered_map<std::string, std::string> options_map;
   const jsize len = env->GetArrayLength(jkeys);
   assert(len == env->GetArrayLength(jvalues));
-  for(int i = 0; i < len; i++) {
+  for (int i = 0; i < len; i++) {
     jobject jobj_key = env->GetObjectArrayElement(jkeys, i);
     jobject jobj_value = env->GetObjectArrayElement(jvalues, i);
     jstring jkey = reinterpret_cast<jstring>(jobj_key);
index 2781043d44f75c3a584774b72b753c23de86247f..b27c1c4fc70716ec2e853f758ac5e7ef68117c25 100644 (file)
@@ -403,7 +403,7 @@ public class RocksDB extends RocksObject {
    */
   public void put(final byte[] key, final byte[] value)
       throws RocksDBException {
-    put(nativeHandle_, key, key.length, value, value.length);
+    put(nativeHandle_, key, 0, key.length, value, 0, value.length);
   }
 
   /**
@@ -422,7 +422,7 @@ public class RocksDB extends RocksObject {
    */
   public void put(final ColumnFamilyHandle columnFamilyHandle,
       final byte[] key, final byte[] value) throws RocksDBException {
-    put(nativeHandle_, key, key.length, value, value.length,
+    put(nativeHandle_, key, 0, key.length, value, 0, value.length,
         columnFamilyHandle.nativeHandle_);
   }
 
@@ -439,7 +439,7 @@ public class RocksDB extends RocksObject {
   public void put(final WriteOptions writeOpts, final byte[] key,
       final byte[] value) throws RocksDBException {
     put(nativeHandle_, writeOpts.nativeHandle_,
-        key, key.length, value, value.length);
+        key, 0, key.length, value, 0, value.length);
   }
 
   /**
@@ -461,8 +461,8 @@ public class RocksDB extends RocksObject {
   public void put(final ColumnFamilyHandle columnFamilyHandle,
       final WriteOptions writeOpts, final byte[] key,
       final byte[] value) throws RocksDBException {
-    put(nativeHandle_, writeOpts.nativeHandle_, key, key.length, value,
-        value.length, columnFamilyHandle.nativeHandle_);
+    put(nativeHandle_, writeOpts.nativeHandle_, key, 0, key.length, value,
+        0, value.length, columnFamilyHandle.nativeHandle_);
   }
 
   /**
@@ -477,8 +477,8 @@ public class RocksDB extends RocksObject {
    *    found in block-cache.
    * @return boolean value indicating if key does not exist or might exist.
    */
-  public boolean keyMayExist(final byte[] key, final StringBuffer value){
-    return keyMayExist(nativeHandle_, key, key.length, value);
+  public boolean keyMayExist(final byte[] key, final StringBuffer value) {
+    return keyMayExist(nativeHandle_, key, 0, key.length, value);
   }
 
   /**
@@ -495,8 +495,8 @@ public class RocksDB extends RocksObject {
    * @return boolean value indicating if key does not exist or might exist.
    */
   public boolean keyMayExist(final ColumnFamilyHandle columnFamilyHandle,
-      final byte[] key, final StringBuffer value){
-    return keyMayExist(nativeHandle_, key, key.length,
+      final byte[] key, final StringBuffer value) {
+    return keyMayExist(nativeHandle_, key, 0, key.length,
         columnFamilyHandle.nativeHandle_, value);
   }
 
@@ -514,9 +514,9 @@ public class RocksDB extends RocksObject {
    * @return boolean value indicating if key does not exist or might exist.
    */
   public boolean keyMayExist(final ReadOptions readOptions,
-      final byte[] key, final StringBuffer value){
+      final byte[] key, final StringBuffer value) {
     return keyMayExist(nativeHandle_, readOptions.nativeHandle_,
-        key, key.length, value);
+        key, 0, key.length, value);
   }
 
   /**
@@ -535,9 +535,9 @@ public class RocksDB extends RocksObject {
    */
   public boolean keyMayExist(final ReadOptions readOptions,
       final ColumnFamilyHandle columnFamilyHandle, final byte[] key,
-      final StringBuffer value){
+      final StringBuffer value) {
     return keyMayExist(nativeHandle_, readOptions.nativeHandle_,
-        key, key.length, columnFamilyHandle.nativeHandle_,
+        key, 0, key.length, columnFamilyHandle.nativeHandle_,
         value);
   }
 
@@ -581,7 +581,7 @@ public class RocksDB extends RocksObject {
    */
   public void merge(final byte[] key, final byte[] value)
       throws RocksDBException {
-    merge(nativeHandle_, key, key.length, value, value.length);
+    merge(nativeHandle_, key, 0, key.length, value, 0, value.length);
   }
 
   /**
@@ -597,7 +597,7 @@ public class RocksDB extends RocksObject {
    */
   public void merge(final ColumnFamilyHandle columnFamilyHandle,
       final byte[] key, final byte[] value) throws RocksDBException {
-    merge(nativeHandle_, key, key.length, value, value.length,
+    merge(nativeHandle_, key, 0, key.length, value, 0, value.length,
         columnFamilyHandle.nativeHandle_);
   }
 
@@ -615,7 +615,7 @@ public class RocksDB extends RocksObject {
   public void merge(final WriteOptions writeOpts, final byte[] key,
       final byte[] value) throws RocksDBException {
     merge(nativeHandle_, writeOpts.nativeHandle_,
-        key, key.length, value, value.length);
+        key, 0, key.length, value, 0, value.length);
   }
 
   /**
@@ -634,7 +634,7 @@ public class RocksDB extends RocksObject {
       final WriteOptions writeOpts, final byte[] key,
       final byte[] value) throws RocksDBException {
     merge(nativeHandle_, writeOpts.nativeHandle_,
-        key, key.length, value, value.length,
+        key, 0, key.length, value, 0, value.length,
         columnFamilyHandle.nativeHandle_);
   }
 
@@ -653,7 +653,7 @@ public class RocksDB extends RocksObject {
    *    native library.
    */
   public int get(final byte[] key, final byte[] value) throws RocksDBException {
-    return get(nativeHandle_, key, key.length, value, value.length);
+    return get(nativeHandle_, key, 0, key.length, value, 0, value.length);
   }
 
   /**
@@ -675,7 +675,7 @@ public class RocksDB extends RocksObject {
    */
   public int get(final ColumnFamilyHandle columnFamilyHandle, final byte[] key,
       final byte[] value) throws RocksDBException, IllegalArgumentException {
-    return get(nativeHandle_, key, key.length, value, value.length,
+    return get(nativeHandle_, key, 0, key.length, value, 0, value.length,
         columnFamilyHandle.nativeHandle_);
   }
 
@@ -698,7 +698,7 @@ public class RocksDB extends RocksObject {
   public int get(final ReadOptions opt, final byte[] key,
       final byte[] value) throws RocksDBException {
     return get(nativeHandle_, opt.nativeHandle_,
-               key, key.length, value, value.length);
+               key, 0, key.length, value, 0, value.length);
   }
   /**
    * Get the value associated with the specified key within column family.
@@ -721,8 +721,8 @@ public class RocksDB extends RocksObject {
   public int get(final ColumnFamilyHandle columnFamilyHandle,
       final ReadOptions opt, final byte[] key, final byte[] value)
       throws RocksDBException {
-    return get(nativeHandle_, opt.nativeHandle_, key, key.length, value,
-        value.length, columnFamilyHandle.nativeHandle_);
+    return get(nativeHandle_, opt.nativeHandle_, key, 0, key.length, value,
+        0, value.length, columnFamilyHandle.nativeHandle_);
   }
 
   /**
@@ -738,7 +738,7 @@ public class RocksDB extends RocksObject {
    *    native library.
    */
   public byte[] get(final byte[] key) throws RocksDBException {
-    return get(nativeHandle_, key, key.length);
+    return get(nativeHandle_, key, 0, key.length);
   }
 
   /**
@@ -757,7 +757,7 @@ public class RocksDB extends RocksObject {
    */
   public byte[] get(final ColumnFamilyHandle columnFamilyHandle,
       final byte[] key) throws RocksDBException {
-    return get(nativeHandle_, key, key.length,
+    return get(nativeHandle_, key, 0, key.length,
         columnFamilyHandle.nativeHandle_);
   }
 
@@ -776,7 +776,7 @@ public class RocksDB extends RocksObject {
    */
   public byte[] get(final ReadOptions opt, final byte[] key)
       throws RocksDBException {
-    return get(nativeHandle_, opt.nativeHandle_, key, key.length);
+    return get(nativeHandle_, opt.nativeHandle_, key, 0, key.length);
   }
 
   /**
@@ -796,7 +796,7 @@ public class RocksDB extends RocksObject {
    */
   public byte[] get(final ColumnFamilyHandle columnFamilyHandle,
       final ReadOptions opt, final byte[] key) throws RocksDBException {
-    return get(nativeHandle_, opt.nativeHandle_, key, key.length,
+    return get(nativeHandle_, opt.nativeHandle_, key, 0, key.length,
         columnFamilyHandle.nativeHandle_);
   }
 
@@ -814,10 +814,17 @@ public class RocksDB extends RocksObject {
       throws RocksDBException {
     assert(keys.size() != 0);
 
-    final byte[][] values = multiGet(nativeHandle_,
-        keys.toArray(new byte[keys.size()][]));
+    final byte[][] keysArray = keys.toArray(new byte[keys.size()][]);
+    final int keyOffsets[] = new int[keysArray.length];
+    final int keyLengths[] = new int[keysArray.length];
+    for(int i = 0; i < keyLengths.length; i++) {
+      keyLengths[i] = keysArray[i].length;
+    }
+
+    final byte[][] values = multiGet(nativeHandle_, keysArray, keyOffsets,
+        keyLengths);
 
-    Map<byte[], byte[]> keyValueMap = new HashMap<>();
+    final Map<byte[], byte[]> keyValueMap = new HashMap<>();
     for(int i = 0; i < values.length; i++) {
       if(values[i] == null) {
         continue;
@@ -862,10 +869,18 @@ public class RocksDB extends RocksObject {
     for (int i = 0; i < columnFamilyHandleList.size(); i++) {
       cfHandles[i] = columnFamilyHandleList.get(i).nativeHandle_;
     }
-    final byte[][] values = multiGet(nativeHandle_,
-        keys.toArray(new byte[keys.size()][]), cfHandles);
 
-    Map<byte[], byte[]> keyValueMap = new HashMap<>();
+    final byte[][] keysArray = keys.toArray(new byte[keys.size()][]);
+    final int keyOffsets[] = new int[keysArray.length];
+    final int keyLengths[] = new int[keysArray.length];
+    for(int i = 0; i < keyLengths.length; i++) {
+      keyLengths[i] = keysArray[i].length;
+    }
+
+    final byte[][] values = multiGet(nativeHandle_, keysArray, keyOffsets,
+        keyLengths, cfHandles);
+
+    final Map<byte[], byte[]> keyValueMap = new HashMap<>();
     for(int i = 0; i < values.length; i++) {
       if (values[i] == null) {
         continue;
@@ -890,10 +905,17 @@ public class RocksDB extends RocksObject {
       final List<byte[]> keys) throws RocksDBException {
     assert(keys.size() != 0);
 
+    final byte[][] keysArray = keys.toArray(new byte[keys.size()][]);
+    final int keyOffsets[] = new int[keysArray.length];
+    final int keyLengths[] = new int[keysArray.length];
+    for(int i = 0; i < keyLengths.length; i++) {
+      keyLengths[i] = keysArray[i].length;
+    }
+
     final byte[][] values = multiGet(nativeHandle_, opt.nativeHandle_,
-        keys.toArray(new byte[keys.size()][]));
+        keysArray, keyOffsets, keyLengths);
 
-    Map<byte[], byte[]> keyValueMap = new HashMap<>();
+    final Map<byte[], byte[]> keyValueMap = new HashMap<>();
     for(int i = 0; i < values.length; i++) {
       if(values[i] == null) {
         continue;
@@ -938,10 +960,18 @@ public class RocksDB extends RocksObject {
     for (int i = 0; i < columnFamilyHandleList.size(); i++) {
       cfHandles[i] = columnFamilyHandleList.get(i).nativeHandle_;
     }
+
+    final byte[][] keysArray = keys.toArray(new byte[keys.size()][]);
+    final int keyOffsets[] = new int[keysArray.length];
+    final int keyLengths[] = new int[keysArray.length];
+    for(int i = 0; i < keyLengths.length; i++) {
+      keyLengths[i] = keysArray[i].length;
+    }
+
     final byte[][] values = multiGet(nativeHandle_, opt.nativeHandle_,
-        keys.toArray(new byte[keys.size()][]), cfHandles);
+        keysArray, keyOffsets, keyLengths, cfHandles);
 
-    Map<byte[], byte[]> keyValueMap = new HashMap<>();
+    final Map<byte[], byte[]> keyValueMap = new HashMap<>();
     for(int i = 0; i < values.length; i++) {
       if(values[i] == null) {
         continue;
@@ -980,7 +1010,7 @@ public class RocksDB extends RocksObject {
    *    native library.
    */
   public void delete(final byte[] key) throws RocksDBException {
-    delete(nativeHandle_, key, key.length);
+    delete(nativeHandle_, key, 0, key.length);
   }
 
   /**
@@ -1017,7 +1047,7 @@ public class RocksDB extends RocksObject {
    */
   public void delete(final ColumnFamilyHandle columnFamilyHandle,
                      final byte[] key) throws RocksDBException {
-    delete(nativeHandle_, key, key.length, columnFamilyHandle.nativeHandle_);
+    delete(nativeHandle_, key, 0, key.length, columnFamilyHandle.nativeHandle_);
   }
 
   /**
@@ -1052,7 +1082,7 @@ public class RocksDB extends RocksObject {
    */
   public void delete(final WriteOptions writeOpt, final byte[] key)
       throws RocksDBException {
-    delete(nativeHandle_, writeOpt.nativeHandle_, key, key.length);
+    delete(nativeHandle_, writeOpt.nativeHandle_, key, 0, key.length);
   }
 
   /**
@@ -1093,7 +1123,7 @@ public class RocksDB extends RocksObject {
   public void delete(final ColumnFamilyHandle columnFamilyHandle,
                      final WriteOptions writeOpt, final byte[] key)
       throws RocksDBException {
-    delete(nativeHandle_, writeOpt.nativeHandle_, key, key.length,
+    delete(nativeHandle_, writeOpt.nativeHandle_, key, 0, key.length,
         columnFamilyHandle.nativeHandle_);
   }
 
@@ -1970,91 +2000,87 @@ public class RocksDB extends RocksObject {
       final long[] columnFamilyOptions
   ) throws RocksDBException;
 
-  protected native static byte[][] listColumnFamilies(
-      long optionsHandle, String path) throws RocksDBException;
-  protected native void put(
-      long handle, byte[] key, int keyLen,
-      byte[] value, int valueLen) throws RocksDBException;
-  protected native void put(
-      long handle, byte[] key, int keyLen,
-      byte[] value, int valueLen, long cfHandle) throws RocksDBException;
-  protected native void put(
-      long handle, long writeOptHandle,
-      byte[] key, int keyLen,
-      byte[] value, int valueLen) throws RocksDBException;
-  protected native void put(
-      long handle, long writeOptHandle,
-      byte[] key, int keyLen,
-      byte[] value, int valueLen, long cfHandle) throws RocksDBException;
+  protected native static byte[][] listColumnFamilies(long optionsHandle,
+      String path) throws RocksDBException;
+  protected native void put(long handle, byte[] key, int keyOffset,
+      int keyLength, byte[] value, int valueOffset, int valueLength)
+      throws RocksDBException;
+  protected native void put(long handle, byte[] key, int keyOffset,
+      int keyLength, byte[] value, int valueOffset, int valueLength,
+      long cfHandle) throws RocksDBException;
+  protected native void put(long handle, long writeOptHandle, byte[] key,
+      int keyOffset, int keyLength, byte[] value, int valueOffset,
+      int valueLength) throws RocksDBException;
+  protected native void put(long handle, long writeOptHandle, byte[] key,
+      int keyOffset, int keyLength, byte[] value, int valueOffset,
+      int valueLength, long cfHandle) throws RocksDBException;
   protected native void write0(final long handle, long writeOptHandle,
       long wbHandle) throws RocksDBException;
   protected native void write1(final long handle, long writeOptHandle,
       long wbwiHandle) throws RocksDBException;
   protected native boolean keyMayExist(final long handle, final byte[] key,
-      final int keyLen, final StringBuffer stringBuffer);
+      final int keyOffset, final int keyLength,
+      final StringBuffer stringBuffer);
   protected native boolean keyMayExist(final long handle, final byte[] key,
-      final int keyLen, final long cfHandle, final StringBuffer stringBuffer);
-  protected native boolean keyMayExist(final long handle,
-      final long optionsHandle, final byte[] key, final int keyLen,
+      final int keyOffset, final int keyLength, final long cfHandle,
       final StringBuffer stringBuffer);
   protected native boolean keyMayExist(final long handle,
-      final long optionsHandle, final byte[] key, final int keyLen,
-      final long cfHandle, final StringBuffer stringBuffer);
-  protected native void merge(
-      long handle, byte[] key, int keyLen,
-      byte[] value, int valueLen) throws RocksDBException;
-  protected native void merge(
-      long handle, byte[] key, int keyLen,
-      byte[] value, int valueLen, long cfHandle) throws RocksDBException;
-  protected native void merge(
-      long handle, long writeOptHandle,
-      byte[] key, int keyLen,
-      byte[] value, int valueLen) throws RocksDBException;
-  protected native void merge(
-      long handle, long writeOptHandle,
-      byte[] key, int keyLen,
-      byte[] value, int valueLen, long cfHandle) throws RocksDBException;
-  protected native int get(
-      long handle, byte[] key, int keyLen,
-      byte[] value, int valueLen) throws RocksDBException;
-  protected native int get(
-      long handle, byte[] key, int keyLen,
-      byte[] value, int valueLen, long cfHandle) throws RocksDBException;
-  protected native int get(
-      long handle, long readOptHandle, byte[] key, int keyLen,
-      byte[] value, int valueLen) throws RocksDBException;
-  protected native int get(
-      long handle, long readOptHandle, byte[] key, int keyLen,
-      byte[] value, int valueLen, long cfHandle) throws RocksDBException;
-  protected native byte[][] multiGet(final long dbHandle, final byte[][] keys);
+      final long optionsHandle, final byte[] key, final int keyOffset,
+      final int keyLength, final StringBuffer stringBuffer);
+  protected native boolean keyMayExist(final long handle,
+      final long optionsHandle, final byte[] key, final int keyOffset,
+      final int keyLength, final long cfHandle,
+      final StringBuffer stringBuffer);
+  protected native void merge(long handle, byte[] key, int keyOffset,
+      int keyLength, byte[] value, int valueOffset, int valueLength)
+      throws RocksDBException;
+  protected native void merge(long handle, byte[] key, int keyOffset,
+      int keyLength, byte[] value, int valueOffset, int valueLength,
+      long cfHandle) throws RocksDBException;
+  protected native void merge(long handle, long writeOptHandle, byte[] key,
+      int keyOffset, int keyLength, byte[] value, int valueOffset,
+      int valueLength) throws RocksDBException;
+  protected native void merge(long handle, long writeOptHandle, byte[] key,
+      int keyOffset, int keyLength, byte[] value, int valueOffset,
+      int valueLength, long cfHandle) throws RocksDBException;
+  protected native int get(long handle, byte[] key, int keyOffset,
+      int keyLength, byte[] value, int valueOffset, int valueLength)
+      throws RocksDBException;
+  protected native int get(long handle, byte[] key, int keyOffset,
+      int keyLength, byte[] value, int valueOffset, int valueLength,
+      long cfHandle) throws RocksDBException;
+  protected native int get(long handle, long readOptHandle, byte[] key,
+      int keyOffset, int keyLength, byte[] value, int valueOffset,
+      int valueLength) throws RocksDBException;
+  protected native int get(long handle, long readOptHandle, byte[] key,
+      int keyOffset, int keyLength, byte[] value, int valueOffset,
+      int valueLength, long cfHandle) throws RocksDBException;
   protected native byte[][] multiGet(final long dbHandle, final byte[][] keys,
+      final int[] keyOffsets, final int[] keyLengths);
+  protected native byte[][] multiGet(final long dbHandle, final byte[][] keys,
+      final int[] keyOffsets, final int[] keyLengths,
       final long[] columnFamilyHandles);
   protected native byte[][] multiGet(final long dbHandle, final long rOptHandle,
-      final byte[][] keys);
+      final byte[][] keys, final int[] keyOffsets, final int[] keyLengths);
   protected native byte[][] multiGet(final long dbHandle, final long rOptHandle,
-      final byte[][] keys, final long[] columnFamilyHandles);
-  protected native byte[] get(
-      long handle, byte[] key, int keyLen) throws RocksDBException;
-  protected native byte[] get(
-      long handle, byte[] key, int keyLen, long cfHandle)
-      throws RocksDBException;
-  protected native byte[] get(
-      long handle, long readOptHandle,
-      byte[] key, int keyLen) throws RocksDBException;
-  protected native byte[] get(
-      long handle, long readOptHandle,
-      byte[] key, int keyLen, long cfHandle) throws RocksDBException;
-  protected native void delete(
-      long handle, byte[] key, int keyLen) throws RocksDBException;
-  protected native void delete(
-      long handle, byte[] key, int keyLen, long cfHandle)
-      throws RocksDBException;
-  protected native void delete(
-      long handle, long writeOptHandle,
-      byte[] key, int keyLen) throws RocksDBException;
-  protected native void delete(
-      long handle, long writeOptHandle,
-      byte[] key, int keyLen, long cfHandle) throws RocksDBException;
+      final byte[][] keys, final int[] keyOffsets, final int[] keyLengths,
+      final long[] columnFamilyHandles);
+  protected native byte[] get(long handle, byte[] key, int keyOffset,
+      int keyLength) throws RocksDBException;
+  protected native byte[] get(long handle, byte[] key, int keyOffset,
+      int keyLength, long cfHandle) throws RocksDBException;
+  protected native byte[] get(long handle, long readOptHandle,
+      byte[] key, int keyOffset, int keyLength) throws RocksDBException;
+  protected native byte[] get(long handle, long readOptHandle, byte[] key,
+      int keyOffset, int keyLength, long cfHandle) throws RocksDBException;
+  protected native void delete(long handle, byte[] key, int keyOffset,
+      int keyLength) throws RocksDBException;
+  protected native void delete(long handle, byte[] key, int keyOffset,
+      int keyLength, long cfHandle) throws RocksDBException;
+  protected native void delete(long handle, long writeOptHandle, byte[] key,
+      int keyOffset, int keyLength) throws RocksDBException;
+  protected native void delete(long handle, long writeOptHandle, byte[] key,
+      int keyOffset, int keyLength, long cfHandle) throws RocksDBException;
   protected native void singleDelete(
       long handle, byte[] key, int keyLen) throws RocksDBException;
   protected native void singleDelete(
@@ -2070,8 +2096,8 @@ public class RocksDB extends RocksObject {
       String property, int propertyLength) throws RocksDBException;
   protected native String getProperty0(long nativeHandle, long cfHandle,
       String property, int propertyLength) throws RocksDBException;
-  protected native long getLongProperty(long nativeHandle,
-      String property, int propertyLength) throws RocksDBException;
+  protected native long getLongProperty(long nativeHandle, String property,
+      int propertyLength) throws RocksDBException;
   protected native long getLongProperty(long nativeHandle, long cfHandle,
       String property, int propertyLength) throws RocksDBException;
   protected native long iterator(long handle);
@@ -2083,8 +2109,7 @@ public class RocksDB extends RocksObject {
       final long[] columnFamilyHandles, final long readOptHandle)
       throws RocksDBException;
   protected native long getSnapshot(long nativeHandle);
-  protected native void releaseSnapshot(
-      long nativeHandle, long snapshotHandle);
+  protected native void releaseSnapshot(long nativeHandle, long snapshotHandle);
   @Override protected final native void disposeInternal(final long handle);
   private native long getDefaultColumnFamily(long handle);
   private native long createColumnFamily(final long handle,
@@ -2094,8 +2119,8 @@ public class RocksDB extends RocksObject {
       throws RocksDBException;
   private native void flush(long handle, long flushOptHandle)
       throws RocksDBException;
-  private native void flush(long handle, long flushOptHandle,
-      long cfHandle) throws RocksDBException;
+  private native void flush(long handle, long flushOptHandle, long cfHandle)
+      throws RocksDBException;
   private native void compactRange0(long handle, boolean reduce_level,
       int target_level, int target_path_id) throws RocksDBException;
   private native void compactRange0(long handle, byte[] begin, int beginLen,
@@ -2111,8 +2136,8 @@ public class RocksDB extends RocksObject {
   private native void continueBackgroundWork(long handle) throws RocksDBException;
   private native long getLatestSequenceNumber(long handle);
   private native void disableFileDeletions(long handle) throws RocksDBException;
-  private native void enableFileDeletions(long handle,
-      boolean force) throws RocksDBException;
+  private native void enableFileDeletions(long handle, boolean force)
+      throws RocksDBException;
   private native long getUpdatesSince(long handle, long sequenceNumber)
       throws RocksDBException;
   private native void setOptions(long handle, long cfHandle, String[] keys,