Merge pull request #131 from ankgup87/master
[Java] Add multiget JNI bindings
This commit is contained in:
commit
2e11e47c7c
@ -4,6 +4,9 @@
|
|||||||
// of patent rights can be found in the PATENTS file in the same directory.
|
// of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.ArrayList;
|
||||||
import org.rocksdb.*;
|
import org.rocksdb.*;
|
||||||
import org.rocksdb.util.SizeUnit;
|
import org.rocksdb.util.SizeUnit;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -217,6 +220,25 @@ public class RocksDBSample {
|
|||||||
|
|
||||||
iterator.close();
|
iterator.close();
|
||||||
System.out.println("iterator tests passed.");
|
System.out.println("iterator tests passed.");
|
||||||
|
|
||||||
|
iterator = db.newIterator();
|
||||||
|
List<byte[]> keys = new ArrayList<byte[]>();
|
||||||
|
for (iterator.seekToLast(); iterator.isValid(); iterator.prev()) {
|
||||||
|
keys.add(iterator.key());
|
||||||
|
}
|
||||||
|
iterator.close();
|
||||||
|
|
||||||
|
Map<byte[], byte[]> values = db.multiGet(keys);
|
||||||
|
assert(values.size() == keys.size());
|
||||||
|
for(byte[] value1 : values.values()) {
|
||||||
|
assert(value1 != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
values = db.multiGet(new ReadOptions(), keys);
|
||||||
|
assert(values.size() == keys.size());
|
||||||
|
for(byte[] value1 : values.values()) {
|
||||||
|
assert(value1 != null);
|
||||||
|
}
|
||||||
} catch (RocksDBException e) {
|
} catch (RocksDBException e) {
|
||||||
System.err.println(e);
|
System.err.println(e);
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,9 @@
|
|||||||
|
|
||||||
package org.rocksdb;
|
package org.rocksdb;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
@ -147,6 +150,7 @@ public class RocksDB {
|
|||||||
* returned if the specified key is not found.
|
* returned if the specified key is not found.
|
||||||
*
|
*
|
||||||
* @param key the key retrieve the value.
|
* @param key the key retrieve the value.
|
||||||
|
* @param opt Read options.
|
||||||
* @return a byte array storing the value associated with the input key if
|
* @return a byte array storing the value associated with the input key if
|
||||||
* any. null if it does not find the specified key.
|
* any. null if it does not find the specified key.
|
||||||
*
|
*
|
||||||
@ -156,6 +160,64 @@ public class RocksDB {
|
|||||||
return get(nativeHandle_, opt.nativeHandle_, key, key.length);
|
return get(nativeHandle_, opt.nativeHandle_, key, key.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a map of keys for which values were found in DB.
|
||||||
|
*
|
||||||
|
* @param keys List of keys for which values need to be retrieved.
|
||||||
|
* @return Map where key of map is the key passed by user and value for map
|
||||||
|
* entry is the corresponding value in DB.
|
||||||
|
*
|
||||||
|
* @see RocksDBException
|
||||||
|
*/
|
||||||
|
public Map<byte[], byte[]> multiGet(List<byte[]> keys)
|
||||||
|
throws RocksDBException {
|
||||||
|
assert(keys.size() != 0);
|
||||||
|
|
||||||
|
List<byte[]> values = multiGet(
|
||||||
|
nativeHandle_, keys, keys.size());
|
||||||
|
|
||||||
|
Map<byte[], byte[]> keyValueMap = new HashMap<byte[], byte[]>();
|
||||||
|
for(int i = 0; i < values.size(); i++) {
|
||||||
|
if(values.get(i) == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
keyValueMap.put(keys.get(i), values.get(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
return keyValueMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a map of keys for which values were found in DB.
|
||||||
|
*
|
||||||
|
* @param List of keys for which values need to be retrieved.
|
||||||
|
* @param opt Read options.
|
||||||
|
* @return Map where key of map is the key passed by user and value for map
|
||||||
|
* entry is the corresponding value in DB.
|
||||||
|
*
|
||||||
|
* @see RocksDBException
|
||||||
|
*/
|
||||||
|
public Map<byte[], byte[]> multiGet(ReadOptions opt, List<byte[]> keys)
|
||||||
|
throws RocksDBException {
|
||||||
|
assert(keys.size() != 0);
|
||||||
|
|
||||||
|
List<byte[]> values = multiGet(
|
||||||
|
nativeHandle_, opt.nativeHandle_, keys, keys.size());
|
||||||
|
|
||||||
|
Map<byte[], byte[]> keyValueMap = new HashMap<byte[], byte[]>();
|
||||||
|
for(int i = 0; i < values.size(); i++) {
|
||||||
|
if(values.get(i) == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
keyValueMap.put(keys.get(i), values.get(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
return keyValueMap;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove the database entry (if any) for "key". Returns OK on
|
* Remove the database entry (if any) for "key". Returns OK on
|
||||||
* success, and a non-OK status on error. It is not an error if "key"
|
* success, and a non-OK status on error. It is not an error if "key"
|
||||||
@ -229,6 +291,10 @@ public class RocksDB {
|
|||||||
protected native int get(
|
protected native int get(
|
||||||
long handle, long readOptHandle, byte[] key, int keyLen,
|
long handle, long readOptHandle, byte[] key, int keyLen,
|
||||||
byte[] value, int valueLen) throws RocksDBException;
|
byte[] value, int valueLen) throws RocksDBException;
|
||||||
|
protected native List<byte[]> multiGet(
|
||||||
|
long dbHandle, List<byte[]> keys, int keysCount);
|
||||||
|
protected native List<byte[]> multiGet(
|
||||||
|
long dbHandle, long rOptHandle, List<byte[]> keys, int keysCount);
|
||||||
protected native byte[] get(
|
protected native byte[] get(
|
||||||
long handle, byte[] key, int keyLen) throws RocksDBException;
|
long handle, byte[] key, int keyLen) throws RocksDBException;
|
||||||
protected native byte[] get(
|
protected native byte[] get(
|
||||||
|
@ -315,5 +315,69 @@ class FilterJni {
|
|||||||
reinterpret_cast<jlong>(op));
|
reinterpret_cast<jlong>(op));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ListJni {
|
||||||
|
public:
|
||||||
|
// Get the java class id of java.util.List.
|
||||||
|
static jclass getListClass(JNIEnv* env) {
|
||||||
|
static jclass jclazz = env->FindClass("java/util/List");
|
||||||
|
assert(jclazz != nullptr);
|
||||||
|
return jclazz;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the java class id of java.util.ArrayList.
|
||||||
|
static jclass getArrayListClass(JNIEnv* env) {
|
||||||
|
static jclass jclazz = env->FindClass("java/util/ArrayList");
|
||||||
|
assert(jclazz != nullptr);
|
||||||
|
return jclazz;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the java class id of java.util.Iterator.
|
||||||
|
static jclass getIteratorClass(JNIEnv* env) {
|
||||||
|
static jclass jclazz = env->FindClass("java/util/Iterator");
|
||||||
|
assert(jclazz != nullptr);
|
||||||
|
return jclazz;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the java method id of java.util.List.iterator().
|
||||||
|
static jmethodID getIteratorMethod(JNIEnv* env) {
|
||||||
|
static jmethodID mid = env->GetMethodID(
|
||||||
|
getListClass(env), "iterator", "()Ljava/util/Iterator;");
|
||||||
|
assert(mid != nullptr);
|
||||||
|
return mid;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the java method id of java.util.Iterator.hasNext().
|
||||||
|
static jmethodID getHasNextMethod(JNIEnv* env) {
|
||||||
|
static jmethodID mid = env->GetMethodID(
|
||||||
|
getIteratorClass(env), "hasNext", "()Z");
|
||||||
|
assert(mid != nullptr);
|
||||||
|
return mid;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the java method id of java.util.Iterator.next().
|
||||||
|
static jmethodID getNextMethod(JNIEnv* env) {
|
||||||
|
static jmethodID mid = env->GetMethodID(
|
||||||
|
getIteratorClass(env), "next", "()Ljava/lang/Object;");
|
||||||
|
assert(mid != nullptr);
|
||||||
|
return mid;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the java method id of arrayList constructor.
|
||||||
|
static jmethodID getArrayListConstructorMethodId(JNIEnv* env, jclass jclazz) {
|
||||||
|
static jmethodID mid = env->GetMethodID(
|
||||||
|
jclazz, "<init>", "(I)V");
|
||||||
|
assert(mid != nullptr);
|
||||||
|
return mid;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the java method id of java.util.List.add().
|
||||||
|
static jmethodID getListAddMethodId(JNIEnv* env) {
|
||||||
|
static jmethodID mid = env->GetMethodID(
|
||||||
|
getListClass(env), "add", "(Ljava/lang/Object;)Z");
|
||||||
|
assert(mid != nullptr);
|
||||||
|
return mid;
|
||||||
|
}
|
||||||
|
};
|
||||||
} // namespace rocksdb
|
} // namespace rocksdb
|
||||||
#endif // JAVA_ROCKSJNI_PORTAL_H_
|
#endif // JAVA_ROCKSJNI_PORTAL_H_
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "include/org_rocksdb_RocksDB.h"
|
#include "include/org_rocksdb_RocksDB.h"
|
||||||
#include "rocksjni/portal.h"
|
#include "rocksjni/portal.h"
|
||||||
@ -244,6 +245,91 @@ jint rocksdb_get_helper(
|
|||||||
return cvalue_len;
|
return cvalue_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jobject multi_get_helper(JNIEnv* env, jobject jdb, rocksdb::DB* db,
|
||||||
|
const rocksdb::ReadOptions& rOpt, jobject jkey_list, jint jkeys_count) {
|
||||||
|
std::vector<rocksdb::Slice> keys;
|
||||||
|
std::vector<jbyte*> keys_to_free;
|
||||||
|
|
||||||
|
// get iterator
|
||||||
|
jobject iteratorObj = env->CallObjectMethod(
|
||||||
|
jkey_list, rocksdb::ListJni::getIteratorMethod(env));
|
||||||
|
|
||||||
|
// iterate over keys and convert java byte array to slice
|
||||||
|
while(env->CallBooleanMethod(
|
||||||
|
iteratorObj, rocksdb::ListJni::getHasNextMethod(env)) == JNI_TRUE) {
|
||||||
|
jbyteArray jkey = (jbyteArray) env->CallObjectMethod(
|
||||||
|
iteratorObj, rocksdb::ListJni::getNextMethod(env));
|
||||||
|
jint key_length = env->GetArrayLength(jkey);
|
||||||
|
|
||||||
|
jbyte* key = new jbyte[key_length];
|
||||||
|
env->GetByteArrayRegion(jkey, 0, key_length, key);
|
||||||
|
// store allocated jbyte to free it after multiGet call
|
||||||
|
keys_to_free.push_back(key);
|
||||||
|
|
||||||
|
rocksdb::Slice key_slice(
|
||||||
|
reinterpret_cast<char*>(key), key_length);
|
||||||
|
keys.push_back(key_slice);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> values;
|
||||||
|
std::vector<rocksdb::Status> s = db->MultiGet(rOpt, keys, &values);
|
||||||
|
|
||||||
|
// Don't reuse class pointer
|
||||||
|
jclass jclazz = env->FindClass("java/util/ArrayList");
|
||||||
|
jmethodID mid = rocksdb::ListJni::getArrayListConstructorMethodId(
|
||||||
|
env, jclazz);
|
||||||
|
jobject jvalue_list = env->NewObject(jclazz, mid, jkeys_count);
|
||||||
|
|
||||||
|
// insert in java list
|
||||||
|
for(std::vector<rocksdb::Status>::size_type i = 0; i != s.size(); i++) {
|
||||||
|
if(s[i].ok()) {
|
||||||
|
jbyteArray jvalue = env->NewByteArray(values[i].size());
|
||||||
|
env->SetByteArrayRegion(
|
||||||
|
jvalue, 0, values[i].size(),
|
||||||
|
reinterpret_cast<const jbyte*>(values[i].c_str()));
|
||||||
|
env->CallBooleanMethod(
|
||||||
|
jvalue_list, rocksdb::ListJni::getListAddMethodId(env), jvalue);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
env->CallBooleanMethod(
|
||||||
|
jvalue_list, rocksdb::ListJni::getListAddMethodId(env), nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// free up allocated byte arrays
|
||||||
|
for(std::vector<jbyte*>::size_type i = 0; i != keys_to_free.size(); i++) {
|
||||||
|
delete[] keys_to_free[i];
|
||||||
|
}
|
||||||
|
keys_to_free.clear();
|
||||||
|
|
||||||
|
return jvalue_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_rocksdb_RocksDB
|
||||||
|
* Method: multiGet
|
||||||
|
* Signature: (JLjava/util/List;I)Ljava/util/List;
|
||||||
|
*/
|
||||||
|
jobject Java_org_rocksdb_RocksDB_multiGet__JLjava_util_List_2I(
|
||||||
|
JNIEnv* env, jobject jdb, jlong jdb_handle,
|
||||||
|
jobject jkey_list, jint jkeys_count) {
|
||||||
|
return multi_get_helper(env, jdb, reinterpret_cast<rocksdb::DB*>(jdb_handle),
|
||||||
|
rocksdb::ReadOptions(), jkey_list, jkeys_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_rocksdb_RocksDB
|
||||||
|
* Method: multiGet
|
||||||
|
* Signature: (JJLjava/util/List;I)Ljava/util/List;
|
||||||
|
*/
|
||||||
|
jobject Java_org_rocksdb_RocksDB_multiGet__JJLjava_util_List_2I(
|
||||||
|
JNIEnv* env, jobject jdb, jlong jdb_handle,
|
||||||
|
jlong jropt_handle, jobject jkey_list, jint jkeys_count) {
|
||||||
|
return multi_get_helper(env, jdb, reinterpret_cast<rocksdb::DB*>(jdb_handle),
|
||||||
|
*reinterpret_cast<rocksdb::ReadOptions*>(jropt_handle), jkey_list,
|
||||||
|
jkeys_count);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Class: org_rocksdb_RocksDB
|
* Class: org_rocksdb_RocksDB
|
||||||
* Method: get
|
* Method: get
|
||||||
|
Loading…
Reference in New Issue
Block a user