diff --git a/java/org/rocksdb/RocksDB.java b/java/org/rocksdb/RocksDB.java
index 089882532..ac02860e8 100644
--- a/java/org/rocksdb/RocksDB.java
+++ b/java/org/rocksdb/RocksDB.java
@@ -1107,21 +1107,40 @@ public class RocksDB extends RocksObject {
}
/**
- * 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).
+ *
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.
+ * 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 RocksIterator newIterator() {
- return new RocksIterator(this, iterator0(nativeHandle_));
+ return new RocksIterator(this, iterator(nativeHandle_));
}
-
/**
+ * 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.
+ *
+ *
+ * @param readOptions {@link ReadOptions} instance.
+ * @return instance of iterator object.
+ */
+ public RocksIterator newIterator(ReadOptions readOptions) {
+ return new RocksIterator(this, iterator(nativeHandle_,
+ readOptions.nativeHandle_));
+ }
+
+ /**
* Return a handle to the current DB state. Iterators created with
* this handle will all observe a stable snapshot of the current DB
* state. The caller must call ReleaseSnapshot(result) when the
@@ -1153,22 +1172,45 @@ public class RocksDB extends RocksObject {
}
/**
- * 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).
+ *
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.
+ * Caller should close the iterator when it is no longer needed.
* The returned iterator should be closed before this db is closed.
+ *
*
* @param columnFamilyHandle {@link org.rocksdb.ColumnFamilyHandle}
* instance
* @return instance of iterator object.
*/
public RocksIterator newIterator(ColumnFamilyHandle columnFamilyHandle) {
- return new RocksIterator(this, iterator0(nativeHandle_,
+ return new RocksIterator(this, iteratorCF(nativeHandle_,
columnFamilyHandle.nativeHandle_));
}
+ /**
+ * 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.
+ *
+ *
+ * @param columnFamilyHandle {@link org.rocksdb.ColumnFamilyHandle}
+ * instance
+ * @param readOptions {@link ReadOptions} instance.
+ * @return instance of iterator object.
+ */
+ public RocksIterator newIterator(ColumnFamilyHandle columnFamilyHandle,
+ ReadOptions readOptions) {
+ return new RocksIterator(this, iteratorCF(nativeHandle_,
+ columnFamilyHandle.nativeHandle_, readOptions.nativeHandle_));
+ }
+
/**
* Returns iterators from a consistent database state across multiple
* column families. Iterators are heap allocated and need to be deleted
@@ -1184,10 +1226,31 @@ public class RocksDB extends RocksObject {
*/
public List newIterators(
List columnFamilyHandleList) throws RocksDBException {
+ return newIterators(columnFamilyHandleList, new ReadOptions());
+ }
+
+ /**
+ * Returns iterators from a consistent database state across multiple
+ * column families. Iterators are heap allocated and need to be deleted
+ * before the db is deleted
+ *
+ * @param columnFamilyHandleList {@link java.util.List} containing
+ * {@link org.rocksdb.ColumnFamilyHandle} instances.
+ * @param readOptions {@link ReadOptions} instance.
+ * @return {@link java.util.List} containing {@link org.rocksdb.RocksIterator}
+ * instances
+ *
+ * @throws RocksDBException thrown if error happens in underlying
+ * native library.
+ */
+ public List newIterators(
+ List columnFamilyHandleList,
+ ReadOptions readOptions) throws RocksDBException {
List iterators =
new ArrayList<>(columnFamilyHandleList.size());
- long[] iteratorRefs = iterators(nativeHandle_, columnFamilyHandleList);
+ long[] iteratorRefs = iterators(nativeHandle_, columnFamilyHandleList,
+ readOptions.nativeHandle_);
for (int i=0; i columnFamilyNames) throws RocksDBException;
+ List columnFamilyNames, long readOptHandle)
+ throws RocksDBException;
protected native long getSnapshot(long nativeHandle);
protected native void releaseSnapshot(
long nativeHandle, long snapshotHandle);
diff --git a/java/org/rocksdb/test/SnapshotTest.java b/java/org/rocksdb/test/SnapshotTest.java
index 1b45c517e..b6dd2a360 100644
--- a/java/org/rocksdb/test/SnapshotTest.java
+++ b/java/org/rocksdb/test/SnapshotTest.java
@@ -8,11 +8,7 @@ import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
-import org.rocksdb.Options;
-import org.rocksdb.ReadOptions;
-import org.rocksdb.RocksDB;
-import org.rocksdb.RocksDBException;
-import org.rocksdb.Snapshot;
+import org.rocksdb.*;
import static org.assertj.core.api.Assertions.assertThat;
@@ -94,4 +90,127 @@ public class SnapshotTest {
}
}
}
+
+ @Test
+ public void iteratorWithSnapshot() throws RocksDBException {
+ RocksDB db = null;
+ Options options = null;
+ ReadOptions readOptions = null;
+ RocksIterator iterator = null;
+ RocksIterator snapshotIterator = null;
+ try {
+
+ options = new Options();
+ options.setCreateIfMissing(true);
+
+ db = RocksDB.open(options, dbFolder.getRoot().getAbsolutePath());
+ db.put("key".getBytes(), "value".getBytes());
+ // Get new Snapshot of database
+ Snapshot snapshot = db.getSnapshot();
+ readOptions = new ReadOptions();
+ // set snapshot in ReadOptions
+ readOptions.setSnapshot(snapshot);
+ db.put("key2".getBytes(), "value2".getBytes());
+
+ // iterate over current state of db
+ iterator = db.newIterator();
+ iterator.seekToFirst();
+ assertThat(iterator.isValid()).isTrue();
+ assertThat(iterator.key()).isEqualTo("key".getBytes());
+ iterator.next();
+ assertThat(iterator.isValid()).isTrue();
+ assertThat(iterator.key()).isEqualTo("key2".getBytes());
+ iterator.next();
+ assertThat(iterator.isValid()).isFalse();
+
+ // iterate using a snapshot
+ snapshotIterator = db.newIterator(readOptions);
+ snapshotIterator.seekToFirst();
+ assertThat(snapshotIterator.isValid()).isTrue();
+ assertThat(snapshotIterator.key()).isEqualTo("key".getBytes());
+ snapshotIterator.next();
+ assertThat(snapshotIterator.isValid()).isFalse();
+
+ // release Snapshot
+ db.releaseSnapshot(snapshot);
+ } finally {
+ if (iterator != null) {
+ iterator.dispose();
+ }
+ if (snapshotIterator != null) {
+ snapshotIterator.dispose();
+ }
+ if (db != null) {
+ db.close();
+ }
+ if (options != null) {
+ options.dispose();
+ }
+ if (readOptions != null) {
+ readOptions.dispose();
+ }
+ }
+ }
+
+ @Test
+ public void iteratorWithSnapshotOnColumnFamily() throws RocksDBException {
+ RocksDB db = null;
+ Options options = null;
+ ReadOptions readOptions = null;
+ RocksIterator iterator = null;
+ RocksIterator snapshotIterator = null;
+ try {
+
+ options = new Options();
+ options.setCreateIfMissing(true);
+
+ db = RocksDB.open(options, dbFolder.getRoot().getAbsolutePath());
+ db.put("key".getBytes(), "value".getBytes());
+ // Get new Snapshot of database
+ Snapshot snapshot = db.getSnapshot();
+ readOptions = new ReadOptions();
+ // set snapshot in ReadOptions
+ readOptions.setSnapshot(snapshot);
+ db.put("key2".getBytes(), "value2".getBytes());
+
+ // iterate over current state of column family
+ iterator = db.newIterator(db.getDefaultColumnFamily());
+ iterator.seekToFirst();
+ assertThat(iterator.isValid()).isTrue();
+ assertThat(iterator.key()).isEqualTo("key".getBytes());
+ iterator.next();
+ assertThat(iterator.isValid()).isTrue();
+ assertThat(iterator.key()).isEqualTo("key2".getBytes());
+ iterator.next();
+ assertThat(iterator.isValid()).isFalse();
+
+ // iterate using a snapshot on default column family
+ snapshotIterator = db.newIterator(db.getDefaultColumnFamily(),
+ readOptions);
+ snapshotIterator.seekToFirst();
+ assertThat(snapshotIterator.isValid()).isTrue();
+ assertThat(snapshotIterator.key()).isEqualTo("key".getBytes());
+ snapshotIterator.next();
+ assertThat(snapshotIterator.isValid()).isFalse();
+
+ // release Snapshot
+ db.releaseSnapshot(snapshot);
+ } finally {
+ if (iterator != null) {
+ iterator.dispose();
+ }
+ if (snapshotIterator != null) {
+ snapshotIterator.dispose();
+ }
+ if (db != null) {
+ db.close();
+ }
+ if (options != null) {
+ options.dispose();
+ }
+ if (readOptions != null) {
+ readOptions.dispose();
+ }
+ }
+ }
}
diff --git a/java/rocksjni/rocksjni.cc b/java/rocksjni/rocksjni.cc
index dee6aaa14..1055f87fe 100644
--- a/java/rocksjni/rocksjni.cc
+++ b/java/rocksjni/rocksjni.cc
@@ -1142,40 +1142,85 @@ void Java_org_rocksdb_RocksDB_disposeInternal(
delete reinterpret_cast(jhandle);
}
+jlong rocksdb_iterator_helper(
+ rocksdb::DB* db, rocksdb::ReadOptions read_options,
+ rocksdb::ColumnFamilyHandle* cf_handle) {
+ rocksdb::Iterator* iterator = nullptr;
+ if (cf_handle != nullptr) {
+ iterator = db->NewIterator(read_options, cf_handle);
+ } else {
+ iterator = db->NewIterator(read_options);
+ }
+ return reinterpret_cast(iterator);
+}
+
/*
* Class: org_rocksdb_RocksDB
- * Method: iterator0
+ * Method: iterator
* Signature: (J)J
*/
-jlong Java_org_rocksdb_RocksDB_iterator0__J(
+jlong Java_org_rocksdb_RocksDB_iterator__J(
JNIEnv* env, jobject jdb, jlong db_handle) {
auto db = reinterpret_cast(db_handle);
- rocksdb::Iterator* iterator = db->NewIterator(rocksdb::ReadOptions());
- return reinterpret_cast(iterator);
+ return rocksdb_iterator_helper(db, rocksdb::ReadOptions(),
+ nullptr);
+}
+
+/*
+ * Class: org_rocksdb_RocksDB
+ * Method: iterator
+ * Signature: (JJ)J
+ */
+jlong Java_org_rocksdb_RocksDB_iterator__JJ(
+ JNIEnv* env, jobject jdb, jlong db_handle,
+ jlong jread_options_handle) {
+ auto db = reinterpret_cast(db_handle);
+ auto& read_options = *reinterpret_cast(
+ jread_options_handle);
+ return rocksdb_iterator_helper(db, read_options,
+ nullptr);
}
/*
* Class: org_rocksdb_RocksDB
- * Method: iterator0
+ * Method: iteratorCF
* Signature: (JJ)J
*/
-jlong Java_org_rocksdb_RocksDB_iterator0__JJ(
+jlong Java_org_rocksdb_RocksDB_iteratorCF__JJ(
JNIEnv* env, jobject jdb, jlong db_handle, jlong jcf_handle) {
auto db = reinterpret_cast(db_handle);
auto cf_handle = reinterpret_cast(jcf_handle);
- rocksdb::Iterator* iterator = db->NewIterator(rocksdb::ReadOptions(),
- cf_handle);
- return reinterpret_cast(iterator);
+ return rocksdb_iterator_helper(db, rocksdb::ReadOptions(),
+ cf_handle);
+}
+
+/*
+ * Class: org_rocksdb_RocksDB
+ * Method: iteratorCF
+ * Signature: (JJJ)J
+ */
+jlong Java_org_rocksdb_RocksDB_iteratorCF__JJJ(
+ JNIEnv* env, jobject jdb, jlong db_handle, jlong jcf_handle,
+ jlong jread_options_handle) {
+ auto db = reinterpret_cast(db_handle);
+ auto cf_handle = reinterpret_cast(jcf_handle);
+ auto& read_options = *reinterpret_cast(
+ jread_options_handle);
+ return rocksdb_iterator_helper(db, read_options,
+ cf_handle);
}
/*
* Class: org_rocksdb_RocksDB
* Method: iterators
- * Signature: (JLjava/util/List;)[J
+ * Signature: (JLjava/util/List;J)[J
*/
jlongArray Java_org_rocksdb_RocksDB_iterators(
- JNIEnv* env, jobject jdb, jlong db_handle, jobject jcfhandle_list) {
+ JNIEnv* env, jobject jdb, jlong db_handle, jobject jcfhandle_list,
+ jlong jread_options_handle) {
auto db = reinterpret_cast(db_handle);
+ auto& read_options = *reinterpret_cast(
+ jread_options_handle);
std::vector cf_handles;
std::vector iterators;
@@ -1195,7 +1240,7 @@ jlongArray Java_org_rocksdb_RocksDB_iterators(
}
}
- rocksdb::Status s = db->NewIterators(rocksdb::ReadOptions(),
+ rocksdb::Status s = db->NewIterators(read_options,
cf_handles, &iterators);
if (s.ok()) {
jlongArray jLongArray =