diff --git a/java/src/main/java/org/rocksdb/AbstractImmutableNativeReference.java b/java/src/main/java/org/rocksdb/AbstractImmutableNativeReference.java index 173d63e9011..66f3f2ec157 100644 --- a/java/src/main/java/org/rocksdb/AbstractImmutableNativeReference.java +++ b/java/src/main/java/org/rocksdb/AbstractImmutableNativeReference.java @@ -28,7 +28,10 @@ protected AbstractImmutableNativeReference(final boolean owningHandle) { @Override public boolean isOwningHandle() { - return owningHandle_.get(); + if (!owningHandle_.get()) { + throw new RuntimeException("Object does not own its native handle."); + } + return true; } /** diff --git a/java/src/main/java/org/rocksdb/AbstractRocksIterator.java b/java/src/main/java/org/rocksdb/AbstractRocksIterator.java index b7af848f0c5..fed91988832 100644 --- a/java/src/main/java/org/rocksdb/AbstractRocksIterator.java +++ b/java/src/main/java/org/rocksdb/AbstractRocksIterator.java @@ -6,6 +6,7 @@ package org.rocksdb; import java.nio.ByteBuffer; +import java.util.function.Function; /** * Base class implementation for Rocks Iterators @@ -24,9 +25,10 @@ public abstract class AbstractRocksIterator
extends RocksObject implements RocksIteratorInterface {
final P parent_;
+ final Function Deletes underlying C++ iterator pointer. Return the key for the current entry. The underlying storage for
* the returned slice is valid only until the next modification of
diff --git a/java/src/test/java/org/rocksdb/IteratorClosedDBTest.java b/java/src/test/java/org/rocksdb/IteratorClosedDBTest.java
new file mode 100644
index 00000000000..db3d3a6fa3f
--- /dev/null
+++ b/java/src/test/java/org/rocksdb/IteratorClosedDBTest.java
@@ -0,0 +1,79 @@
+package org.rocksdb;
+
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import java.nio.file.Paths;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class IteratorClosedDBTest {
+
+ @ClassRule
+ public static final RocksNativeLibraryResource ROCKS_NATIVE_LIBRARY_RESOURCE =
+ new RocksNativeLibraryResource();
+
+ @Rule
+ public TemporaryFolder dbFolder = new TemporaryFolder();
+
+ @Test
+ public void resourceIterators() throws RocksDBException {
+ try (Options options = new Options().setCreateIfMissing(true); RocksDB db = RocksDB.open(options, dbFolder.getRoot().getAbsolutePath())) {
+
+ byte[] key = {0x1};
+ byte[] value = {0x2};
+ db.put(key, value);
+
+ try (RocksIterator it = db.newIterator()) {
+ it.seekToFirst();
+ assertThat(it.key()).isEqualTo(key);
+ assertThat(it.value()).isEqualTo(value);
+
+ it.next();
+ assertThat(it.isValid()).isFalse();
+ }
+ }
+ }
+
+ @Test
+ public void ownedIterators() throws RocksDBException {
+ try (Options options = new Options().setCreateIfMissing(true); RocksDB db = RocksDB.open(options, dbFolder.getRoot().getAbsolutePath())) {
+
+ byte[] key = {0x1};
+ byte[] value = {0x2};
+ db.put(key, value);
+
+ RocksIterator it = db.newIterator();
+ it.seekToFirst();
+ assertThat(it.key()).isEqualTo(key);
+ assertThat(it.value()).isEqualTo(value);
+
+ it.next();
+ assertThat(it.isValid()).isFalse();
+ } //iterator is still open when we close the DB, C++ assertion in DEBUG_LEVEL=1
+ }
+
+ @Test
+ public void shouldCrashJavaRocks() throws RocksDBException {
+ try (Options options = new Options().setCreateIfMissing(true)) {
+ RocksDB db = RocksDB.open(options, dbFolder.getRoot().getAbsolutePath());
+ byte[] key = {0x1};
+ byte[] value = {0x2};
+ db.put(key, value);
+
+ RocksIterator it = db.newIterator();
+ assertThat(it.isValid()).isFalse();
+ it.seekToFirst();
+ assertThat(it.isValid()).isTrue();
+
+ // Exception here (assertion failure in C++) - when built with DEBUG_LEVEL=1
+ // Outstanding iterator has a reference to the column family which is being closed
+ db.close();
+
+ assertThat(it.isValid()).isFalse();
+ it.close();
+ }
+ }
+}