Merge pull request #124 from ankgup87/master

[Java] Add iterator JNI bindings
This commit is contained in:
Igor Canadi 2014-04-21 09:59:39 -07:00
commit 11e8525422
9 changed files with 391 additions and 6 deletions

View File

@ -1,4 +1,4 @@
NATIVE_JAVA_CLASSES = org.rocksdb.RocksDB org.rocksdb.Options org.rocksdb.WriteBatch org.rocksdb.WriteBatchInternal org.rocksdb.WriteBatchTest org.rocksdb.WriteOptions org.rocksdb.BackupableDB org.rocksdb.BackupableDBOptions org.rocksdb.Statistics
NATIVE_JAVA_CLASSES = org.rocksdb.RocksDB org.rocksdb.Options org.rocksdb.WriteBatch org.rocksdb.WriteBatchInternal org.rocksdb.WriteBatchTest org.rocksdb.WriteOptions org.rocksdb.BackupableDB org.rocksdb.BackupableDBOptions org.rocksdb.Statistics org.rocksdb.Iterator
NATIVE_INCLUDE = ./include
ROCKSDB_JAR = rocksdbjni.jar

View File

@ -3,8 +3,7 @@
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
import java.util.*;
import java.lang.*;
import java.util.Arrays;
import org.rocksdb.*;
import org.rocksdb.util.SizeUnit;
import java.io.IOException;
@ -142,6 +141,41 @@ public class RocksDBSample {
System.out.println("Failed in call to geHistogramData()");
assert(false); //Should never reach here.
}
Iterator iterator = db.newIterator();
boolean seekToFirstPassed = false;
for (iterator.seekToFirst(); iterator.isValid(); iterator.next()) {
iterator.status();
assert(iterator.key() != null);
assert(iterator.value() != null);
seekToFirstPassed = true;
}
if(seekToFirstPassed) {
System.out.println("iterator seekToFirst tests passed.");
}
boolean seekToLastPassed = false;
for (iterator.seekToLast(); iterator.isValid(); iterator.prev()) {
iterator.status();
assert(iterator.key() != null);
assert(iterator.value() != null);
seekToLastPassed = true;
}
if(seekToLastPassed) {
System.out.println("iterator seekToLastPassed tests passed.");
}
iterator.seekToFirst();
iterator.seek(iterator.key());
assert(iterator.key() != null);
assert(iterator.value() != null);
System.out.println("iterator seek test passed.");
iterator.close();
System.out.println("iterator tests passed.");
} catch (RocksDBException e) {
System.err.println(e);
}

View File

@ -0,0 +1,146 @@
// Copyright (c) 2014, Facebook, Inc. All rights reserved.
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
package org.rocksdb;
/**
* An iterator yields a sequence of key/value pairs from a source.
* The following class defines the interface. Multiple implementations
* are provided by this library. In particular, iterators are provided
* to access the contents of a Table or a DB.
*
* Multiple threads can invoke const methods on an Iterator without
* external synchronization, but if any of the threads may call a
* non-const method, all threads accessing the same Iterator must use
* external synchronization.
*/
public class Iterator {
private long nativeHandle_;
public Iterator(long nativeHandle) {
nativeHandle_ = nativeHandle;
}
/**
* An iterator is either positioned at a key/value pair, or
* not valid. This method returns true iff the iterator is valid.
* @return true if iterator is valid.
*/
public boolean isValid() {
assert(isInitialized());
return isValid0(nativeHandle_);
}
/**
* Position at the first key in the source. The iterator is Valid()
* after this call iff the source is not empty.
*/
public void seekToFirst() {
assert(isInitialized());
seekToFirst0(nativeHandle_);
}
/**
* Position at the last key in the source. The iterator is
* Valid() after this call iff the source is not empty.
*/
public void seekToLast() {
assert(isInitialized());
seekToLast0(nativeHandle_);
}
/**
* Moves to the next entry in the source. After this call, Valid() is
* true iff the iterator was not positioned at the last entry in the source.
* REQUIRES: Valid()
*/
public void next() {
assert(isInitialized());
next0(nativeHandle_);
}
/**
* Moves to the previous entry in the source. After this call, Valid() is
* true iff the iterator was not positioned at the first entry in source.
* REQUIRES: Valid()
*/
public void prev() {
assert(isInitialized());
prev0(nativeHandle_);
}
/**
* Return the key for the current entry. The underlying storage for
* the returned slice is valid only until the next modification of
* the iterator.
* REQUIRES: Valid()
* @return key for the current entry.
*/
public byte[] key() {
assert(isInitialized());
return key0(nativeHandle_);
}
/**
* Return the value for the current entry. The underlying storage for
* the returned slice is valid only until the next modification of
* the iterator.
* REQUIRES: !AtEnd() && !AtStart()
* @return value for the current entry.
*/
public byte[] value() {
assert(isInitialized());
return value0(nativeHandle_);
}
/**
* Position at the first key in the source that at or past target
* The iterator is Valid() after this call iff the source contains
* an entry that comes at or past target.
*/
public void seek(byte[] target) {
assert(isInitialized());
seek0(nativeHandle_, target, target.length);
}
/**
* If an error has occurred, return it. Else return an ok status.
* If non-blocking IO is requested and this operation cannot be
* satisfied without doing some IO, then this returns Status::Incomplete().
*
*/
public void status() throws RocksDBException {
assert(isInitialized());
status0(nativeHandle_);
}
/**
* Deletes underlying C++ iterator pointer.
*/
public synchronized void close() {
if(nativeHandle_ != 0) {
close0(nativeHandle_);
}
}
@Override protected void finalize() {
close();
}
private boolean isInitialized() {
return (nativeHandle_ != 0);
}
private native boolean isValid0(long handle);
private native void close0(long handle);
private native void seekToFirst0(long handle);
private native void seekToLast0(long handle);
private native void next0(long handle);
private native void prev0(long handle);
private native byte[] key0(long handle);
private native byte[] value0(long handle);
private native void seek0(long handle, byte[] target, int targetLen);
private native void status0(long handle);
}

View File

@ -508,7 +508,7 @@ public class Options {
return maxBackgroundCompactions(nativeHandle_);
}
/**
/**
* Creates statistics object which collects metrics about database operations.
Statistics objects should not be shared between DB instances as
it does not use any locks to prevent concurrent updates.

View File

@ -5,7 +5,6 @@
package org.rocksdb;
import java.util.*;
import java.io.Closeable;
import java.io.IOException;
@ -137,6 +136,20 @@ public class RocksDB {
remove(nativeHandle_, writeOpt.nativeHandle_, key, key.length);
}
/**
* Return a heap-allocated iterator over the contents of the database.
* The result of newIterator() is initially invalid (caller must
* call one of the Seek methods on the iterator before using it).
*
* Caller should close the iterator when it is no longer needed.
* The returned iterator should be closed before this db is closed.
*
* @return instance of iterator object.
*/
public Iterator newIterator() {
return new Iterator(iterator0(nativeHandle_));
}
@Override protected void finalize() {
close();
}
@ -170,6 +183,7 @@ public class RocksDB {
protected native void remove(
long handle, long writeOptHandle,
byte[] key, int keyLen) throws RocksDBException;
protected native long iterator0(long optHandle);
protected native void close0();
protected long nativeHandle_;

147
java/rocksjni/iterator.cc Normal file
View File

@ -0,0 +1,147 @@
// Copyright (c) 2014, Facebook, Inc. All rights reserved.
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
// This file implements the "bridge" between Java and C++ and enables
// calling c++ rocksdb::Iterator methods from Java side.
#include <stdio.h>
#include <stdlib.h>
#include <jni.h>
#include "include/org_rocksdb_Iterator.h"
#include "rocksjni/portal.h"
#include "rocksdb/iterator.h"
/*
* Class: org_rocksdb_Iterator
* Method: isValid0
* Signature: (J)Z
*/
jboolean Java_org_rocksdb_Iterator_isValid0(
JNIEnv* env, jobject jobj, jlong handle) {
return reinterpret_cast<rocksdb::Iterator*>(handle)->Valid();
}
/*
* Class: org_rocksdb_Iterator
* Method: close0
* Signature: (J)V
*/
void Java_org_rocksdb_Iterator_seekToFirst0(
JNIEnv* env, jobject jobj, jlong handle) {
reinterpret_cast<rocksdb::Iterator*>(handle)->SeekToFirst();
}
/*
* Class: org_rocksdb_Iterator
* Method: seekToFirst0
* Signature: (J)V
*/
void Java_org_rocksdb_Iterator_seekToLast0(
JNIEnv* env, jobject jobj, jlong handle) {
reinterpret_cast<rocksdb::Iterator*>(handle)->SeekToLast();
}
/*
* Class: org_rocksdb_Iterator
* Method: seekToLast0
* Signature: (J)V
*/
void Java_org_rocksdb_Iterator_next0(
JNIEnv* env, jobject jobj, jlong handle) {
reinterpret_cast<rocksdb::Iterator*>(handle)->Next();
}
/*
* Class: org_rocksdb_Iterator
* Method: next0
* Signature: (J)V
*/
void Java_org_rocksdb_Iterator_prev0(
JNIEnv* env, jobject jobj, jlong handle) {
reinterpret_cast<rocksdb::Iterator*>(handle)->Prev();
}
/*
* Class: org_rocksdb_Iterator
* Method: prev0
* Signature: (J)V
*/
jbyteArray Java_org_rocksdb_Iterator_key0(
JNIEnv* env, jobject jobj, jlong handle) {
auto it = reinterpret_cast<rocksdb::Iterator*>(handle);
rocksdb::Slice key_slice = it->key();
jbyteArray jkey = env->NewByteArray(key_slice.size());
env->SetByteArrayRegion(
jkey, 0, key_slice.size(),
reinterpret_cast<const jbyte*>(key_slice.data()));
return jkey;
}
/*
* Class: org_rocksdb_Iterator
* Method: key0
* Signature: (J)[B
*/
jbyteArray Java_org_rocksdb_Iterator_value0(
JNIEnv* env, jobject jobj, jlong handle) {
auto it = reinterpret_cast<rocksdb::Iterator*>(handle);
rocksdb::Slice value_slice = it->value();
jbyteArray jvalue = env->NewByteArray(value_slice.size());
env->SetByteArrayRegion(
jvalue, 0, value_slice.size(),
reinterpret_cast<const jbyte*>(value_slice.data()));
return jvalue;
}
/*
* Class: org_rocksdb_Iterator
* Method: value0
* Signature: (J)[B
*/
void Java_org_rocksdb_Iterator_seek0(
JNIEnv* env, jobject jobj, jlong handle,
jbyteArray jtarget, jint jtarget_len) {
auto it = reinterpret_cast<rocksdb::Iterator*>(handle);
jbyte* target = env->GetByteArrayElements(jtarget, 0);
rocksdb::Slice target_slice(
reinterpret_cast<char*>(target), jtarget_len);
it->Seek(target_slice);
env->ReleaseByteArrayElements(jtarget, target, JNI_ABORT);
}
/*
* Class: org_rocksdb_Iterator
* Method: seek0
* Signature: (J[BI)V
*/
void Java_org_rocksdb_Iterator_status0(
JNIEnv* env, jobject jobj, jlong handle) {
auto it = reinterpret_cast<rocksdb::Iterator*>(handle);
rocksdb::Status s = it->status();
if (s.ok()) {
return;
}
rocksdb::RocksDBExceptionJni::ThrowNew(env, s);
}
/*
* Class: org_rocksdb_Iterator
* Method: status0
* Signature: (J)V
*/
void Java_org_rocksdb_Iterator_close0(
JNIEnv* env, jobject jobj, jlong handle) {
auto it = reinterpret_cast<rocksdb::Iterator*>(handle);
delete it;
rocksdb::IteratorJni::setHandle(env, jobj, nullptr);
}

View File

@ -213,5 +213,38 @@ class BackupableDBOptionsJni {
reinterpret_cast<jlong>(op));
}
};
class IteratorJni {
public:
// Get the java class id of org.rocksdb.Iteartor.
static jclass getJClass(JNIEnv* env) {
static jclass jclazz = env->FindClass("org/rocksdb/Iterator");
assert(jclazz != nullptr);
return jclazz;
}
// Get the field id of the member variable of org.rocksdb.Iterator
// that stores the pointer to rocksdb::Iterator.
static jfieldID getHandleFieldID(JNIEnv* env) {
static jfieldID fid = env->GetFieldID(
getJClass(env), "nativeHandle_", "J");
assert(fid != nullptr);
return fid;
}
// Get the pointer to rocksdb::Iterator.
static rocksdb::Iterator* getHandle(JNIEnv* env, jobject jobj) {
return reinterpret_cast<rocksdb::Iterator*>(
env->GetLongField(jobj, getHandleFieldID(env)));
}
// Pass the rocksdb::Iterator pointer to the java side.
static void setHandle(
JNIEnv* env, jobject jobj, rocksdb::Iterator* op) {
env->SetLongField(
jobj, getHandleFieldID(env),
reinterpret_cast<jlong>(op));
}
};
} // namespace rocksdb
#endif // JAVA_ROCKSJNI_PORTAL_H_

View File

@ -296,3 +296,15 @@ void Java_org_rocksdb_RocksDB_close0(
rocksdb::RocksDBJni::setHandle(env, java_db, nullptr);
}
/*
* Class: org_rocksdb_RocksDB
* Method: iterator0
* Signature: (J)J
*/
jlong Java_org_rocksdb_RocksDB_iterator0(
JNIEnv* env, jobject jdb, jlong db_handle) {
auto db = reinterpret_cast<rocksdb::DB*>(db_handle);
rocksdb::Iterator* iterator = db->NewIterator(rocksdb::ReadOptions());
return reinterpret_cast<jlong>(iterator);
}

View File

@ -13,7 +13,6 @@
#include "include/org_rocksdb_Statistics.h"
#include "rocksjni/portal.h"
#include "rocksdb/statistics.h"
#include <iostream>
/*
* Class: org_rocksdb_Statistics