diff --git a/java/RocksDBSample.java b/java/RocksDBSample.java index 2d9e3a920..5d11b1aa9 100644 --- a/java/RocksDBSample.java +++ b/java/RocksDBSample.java @@ -218,7 +218,7 @@ public class RocksDBSample { System.out.println("iterator seek test passed."); - iterator.close(); + iterator.dispose(); System.out.println("iterator tests passed."); iterator = db.newIterator(); @@ -226,7 +226,7 @@ public class RocksDBSample { for (iterator.seekToLast(); iterator.isValid(); iterator.prev()) { keys.add(iterator.key()); } - iterator.close(); + iterator.dispose(); Map values = db.multiGet(keys); assert(values.size() == keys.size()); @@ -248,5 +248,6 @@ public class RocksDBSample { // be sure to dispose c++ pointers options.dispose(); readOptions.dispose(); + filter.dispose(); } } diff --git a/java/org/rocksdb/BackupableDB.java b/java/org/rocksdb/BackupableDB.java index 100680ebd..91607d4df 100644 --- a/java/org/rocksdb/BackupableDB.java +++ b/java/org/rocksdb/BackupableDB.java @@ -55,8 +55,8 @@ public class BackupableDB extends RocksDB { * should be transparent to Java developers. */ @Override public synchronized void close() { - if (isOpened()) { - super.close0(); + if (isInitialized()) { + super.close(); } } @@ -73,10 +73,6 @@ public class BackupableDB extends RocksDB { close(); } - private boolean isOpened() { - return nativeHandle_ != 0; - } - protected native void open(long rocksDBHandle, long backupDBOptionsHandle); protected native void createNewBackup(long handle, boolean flag); diff --git a/java/org/rocksdb/BackupableDBOptions.java b/java/org/rocksdb/BackupableDBOptions.java index 209c2bc47..2c64b60a3 100644 --- a/java/org/rocksdb/BackupableDBOptions.java +++ b/java/org/rocksdb/BackupableDBOptions.java @@ -12,8 +12,9 @@ package org.rocksdb; * Note that dispose() must be called before an Options instance * become out-of-scope to release the allocated memory in c++. */ -public class BackupableDBOptions { +public class BackupableDBOptions extends RocksObject { public BackupableDBOptions(String path) { + super(); newBackupableDBOptions(path); } @@ -31,22 +32,13 @@ public class BackupableDBOptions { * Release the memory allocated for the current instance * in the c++ side. */ - public synchronized void dispose() { + @Override public synchronized void dispose() { if (isInitialized()) { dispose(nativeHandle_); } } - @Override protected void finalize() { - dispose(); - } - - boolean isInitialized() { - return nativeHandle_ != 0; - } - private native void newBackupableDBOptions(String path); private native String backupDir(long handle); private native void dispose(long handle); - long nativeHandle_; } diff --git a/java/org/rocksdb/Filter.java b/java/org/rocksdb/Filter.java index d16dedc69..3a01ad4ee 100644 --- a/java/org/rocksdb/Filter.java +++ b/java/org/rocksdb/Filter.java @@ -12,27 +12,21 @@ package org.rocksdb; * number of disk seeks form a handful to a single disk seek per * DB::Get() call. */ -public abstract class Filter { - protected long nativeHandle_ = 0; - +public abstract class Filter extends RocksObject { protected abstract void createNewFilter(); /** * Deletes underlying C++ filter pointer. + * + * Note that this function should be called only after all + * RocksDB instances referencing the filter are closed. + * Otherwise an undefined behavior will occur. */ - protected synchronized void dispose() { - if(nativeHandle_ != 0) { + @Override public synchronized void dispose() { + if (isInitialized()) { dispose0(nativeHandle_); } } - @Override protected void finalize() { - dispose(); - } - - protected boolean isInitialized() { - return (nativeHandle_ != 0); - } - private native void dispose0(long handle); } diff --git a/java/org/rocksdb/Iterator.java b/java/org/rocksdb/Iterator.java index c34deab35..3c745a4d4 100644 --- a/java/org/rocksdb/Iterator.java +++ b/java/org/rocksdb/Iterator.java @@ -16,10 +16,9 @@ package org.rocksdb; * non-const method, all threads accessing the same Iterator must use * external synchronization. */ -public class Iterator { - private long nativeHandle_; - +public class Iterator extends RocksObject { public Iterator(long nativeHandle) { + super(); nativeHandle_ = nativeHandle; } @@ -119,22 +118,15 @@ public class Iterator { /** * Deletes underlying C++ iterator pointer. */ - public synchronized void close() { - if(nativeHandle_ != 0) { - close0(nativeHandle_); + @Override public synchronized void dispose() { + if(isInitialized()) { + dispose(nativeHandle_); + nativeHandle_ = 0; } } - @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 dispose(long handle); private native void seekToFirst0(long handle); private native void seekToLast0(long handle); private native void next0(long handle); diff --git a/java/org/rocksdb/Options.java b/java/org/rocksdb/Options.java index cfb3c4a3f..02d3e200a 100644 --- a/java/org/rocksdb/Options.java +++ b/java/org/rocksdb/Options.java @@ -12,7 +12,7 @@ package org.rocksdb; * Note that dispose() must be called before an Options instance * become out-of-scope to release the allocated memory in c++. */ -public class Options { +public class Options extends RocksObject { static final long DEFAULT_CACHE_SIZE = 8 << 20; /** * Construct options for opening a RocksDB. @@ -21,7 +21,7 @@ public class Options { * an rocksdb::Options in the c++ side. */ public Options() { - nativeHandle_ = 0; + super(); cacheSize_ = DEFAULT_CACHE_SIZE; newOptions(); } @@ -2311,20 +2311,12 @@ public class Options { * Release the memory allocated for the current instance * in the c++ side. */ - public synchronized void dispose() { + @Override public synchronized void dispose() { if (isInitialized()) { dispose0(); } } - @Override protected void finalize() { - dispose(); - } - - private boolean isInitialized() { - return (nativeHandle_ != 0); - } - static final int DEFAULT_PLAIN_TABLE_BLOOM_BITS_PER_KEY = 10; static final double DEFAULT_PLAIN_TABLE_HASH_TABLE_RATIO = 0.75; static final int DEFAULT_PLAIN_TABLE_INDEX_SPARSENESS = 16; @@ -2358,7 +2350,6 @@ public class Options { private native void useFixedLengthPrefixExtractor( long handle, int prefixLength); - long nativeHandle_; long cacheSize_; Filter filter_; } diff --git a/java/org/rocksdb/ReadOptions.java b/java/org/rocksdb/ReadOptions.java index ffd741a20..23250fc6f 100644 --- a/java/org/rocksdb/ReadOptions.java +++ b/java/org/rocksdb/ReadOptions.java @@ -11,9 +11,9 @@ package org.rocksdb; * Note that dispose() must be called before an Options instance * become out-of-scope to release the allocated memory in c++. */ -public class ReadOptions { +public class ReadOptions extends RocksObject { public ReadOptions() { - nativeHandle_ = 0; + super(); newReadOptions(); } private native void newReadOptions(); @@ -24,7 +24,7 @@ public class ReadOptions { * * Calling other methods after dispose() leads to undefined behavior. */ - public synchronized void dispose() { + @Override public synchronized void dispose() { if (isInitialized()) { dispose(nativeHandle_); } @@ -127,10 +127,4 @@ public class ReadOptions { } private native void setTailing( long handle, boolean tailing); - - protected long nativeHandle_; - - private boolean isInitialized() { - return nativeHandle_ != 0; - } } diff --git a/java/org/rocksdb/RocksDB.java b/java/org/rocksdb/RocksDB.java index 4d2c89d4b..e92acea27 100644 --- a/java/org/rocksdb/RocksDB.java +++ b/java/org/rocksdb/RocksDB.java @@ -18,7 +18,7 @@ import org.rocksdb.util.Environment; * All methods of this class could potentially throw RocksDBException, which * indicates sth wrong at the rocksdb library side and the call failed. */ -public class RocksDB { +public class RocksDB extends RocksObject { public static final int NOT_FOUND = -1; private static final String[] compressionLibs_ = { "snappy", "zlib", "bzip2", "lz4", "lz4hc"}; @@ -114,12 +114,21 @@ public class RocksDB { return db; } - public synchronized void close() { - if (nativeHandle_ != 0) { - close0(); + @Override public synchronized void dispose() { + if (isInitialized()) { + dispose(nativeHandle_); + nativeHandle_ = 0; } } + /** + * Close the RocksDB instance. + * This function is equivalent to dispose(). + */ + public void close() { + dispose(); + } + /** * Set the database entry for "key" to "value". * @@ -314,7 +323,7 @@ public class RocksDB { * Private constructor. */ protected RocksDB() { - nativeHandle_ = 0; + super(); } /** @@ -361,8 +370,7 @@ public class RocksDB { long handle, long writeOptHandle, byte[] key, int keyLen) throws RocksDBException; protected native long iterator0(long optHandle); - protected native void close0(); + protected native void dispose(long handle); - protected long nativeHandle_; protected Filter filter_; } diff --git a/java/org/rocksdb/RocksObject.java b/java/org/rocksdb/RocksObject.java new file mode 100644 index 000000000..6e36cbaea --- /dev/null +++ b/java/org/rocksdb/RocksObject.java @@ -0,0 +1,35 @@ +// 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; + +/** + * RocksObject is the base-class of all RocksDB related class that has + * a pointer to some c++ rocksdb object. Although RocksObject + * will release its c++ resource on its finalize() once it has been + * garbage-collected, it is suggested to call dispose() manually to + * release its c++ resource once an instance of RocksObject is no + * longer used. + */ +public abstract class RocksObject { + protected RocksObject() { + nativeHandle_ = 0; + } + + /** + * Release the c++ object pointed by the native handle. + */ + public abstract void dispose(); + + protected boolean isInitialized() { + return (nativeHandle_ != 0); + } + + @Override protected void finalize() { + dispose(); + } + + protected long nativeHandle_; +} diff --git a/java/org/rocksdb/WriteBatch.java b/java/org/rocksdb/WriteBatch.java index 451d82409..1ddbd449d 100644 --- a/java/org/rocksdb/WriteBatch.java +++ b/java/org/rocksdb/WriteBatch.java @@ -24,9 +24,9 @@ import java.util.*; * non-const method, all threads accessing the same WriteBatch must use * external synchronization. */ -public class WriteBatch { +public class WriteBatch extends RocksObject { public WriteBatch() { - nativeHandle_ = 0; + super(); newWriteBatch(0); } @@ -86,16 +86,12 @@ public class WriteBatch { /** * Delete the c++ side pointer. */ - public synchronized void dispose() { - if (nativeHandle_ != 0) { + @Override public synchronized void dispose() { + if (isInitialized()) { dispose0(); } } - @Override protected void finalize() { - dispose(); - } - private native void newWriteBatch(int reserved_bytes); private native void put(byte[] key, int keyLen, byte[] value, int valueLen); @@ -104,8 +100,6 @@ public class WriteBatch { private native void remove(byte[] key, int keyLen); private native void putLogData(byte[] blob, int blobLen); private native void dispose0(); - - long nativeHandle_; } /** diff --git a/java/org/rocksdb/WriteOptions.java b/java/org/rocksdb/WriteOptions.java index aa7a73164..f4a1d6a0f 100644 --- a/java/org/rocksdb/WriteOptions.java +++ b/java/org/rocksdb/WriteOptions.java @@ -11,14 +11,14 @@ package org.rocksdb; * Note that developers should call WriteOptions.dispose() to release the * c++ side memory before a WriteOptions instance runs out of scope. */ -public class WriteOptions { +public class WriteOptions extends RocksObject { public WriteOptions() { - nativeHandle_ = 0; + super(); newWriteOptions(); } - public synchronized void dispose() { - if (nativeHandle_ != 0) { + @Override public synchronized void dispose() { + if (isInitialized()) { dispose0(nativeHandle_); } } @@ -91,16 +91,10 @@ public class WriteOptions { return disableWAL(nativeHandle_); } - @Override protected void finalize() { - dispose(); - } - private native void newWriteOptions(); private native void setSync(long handle, boolean flag); private native boolean sync(long handle); private native void setDisableWAL(long handle, boolean flag); private native boolean disableWAL(long handle); private native void dispose0(long handle); - - protected long nativeHandle_; } diff --git a/java/rocksjni/iterator.cc b/java/rocksjni/iterator.cc index f23ca1d87..a7ea97d66 100644 --- a/java/rocksjni/iterator.cc +++ b/java/rocksjni/iterator.cc @@ -26,7 +26,7 @@ jboolean Java_org_rocksdb_Iterator_isValid0( /* * Class: org_rocksdb_Iterator - * Method: close0 + * Method: seekToFirst0 * Signature: (J)V */ void Java_org_rocksdb_Iterator_seekToFirst0( @@ -135,13 +135,11 @@ void Java_org_rocksdb_Iterator_status0( /* * Class: org_rocksdb_Iterator - * Method: status0 + * Method: dispose * Signature: (J)V */ -void Java_org_rocksdb_Iterator_close0( +void Java_org_rocksdb_Iterator_dispose( JNIEnv* env, jobject jobj, jlong handle) { auto it = reinterpret_cast(handle); delete it; - - rocksdb::IteratorJni::setHandle(env, jobj, nullptr); } diff --git a/java/rocksjni/rocksjni.cc b/java/rocksjni/rocksjni.cc index 94c41392d..4595f3f35 100644 --- a/java/rocksjni/rocksjni.cc +++ b/java/rocksjni/rocksjni.cc @@ -415,16 +415,14 @@ void Java_org_rocksdb_RocksDB_remove__JJ_3BI( /* * Class: org_rocksdb_RocksDB - * Method: close0 - * Signature: ()V + * Method: dispose + * Signature: (J)V */ -void Java_org_rocksdb_RocksDB_close0( - JNIEnv* env, jobject java_db) { - rocksdb::DB* db = rocksdb::RocksDBJni::getHandle(env, java_db); +void Java_org_rocksdb_RocksDB_dispose( + JNIEnv* env, jobject java_db, jlong jhandle) { + auto db = reinterpret_cast(jhandle); assert(db != nullptr); delete db; - - rocksdb::RocksDBJni::setHandle(env, java_db, nullptr); } /*