diff --git a/java/Makefile b/java/Makefile index 5311af14f5..1a199e1dfc 100644 --- a/java/Makefile +++ b/java/Makefile @@ -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 org.rocksdb.Iterator org.rocksdb.VectorMemTableConfig org.rocksdb.SkipListMemTableConfig org.rocksdb.HashLinkedListMemTableConfig org.rocksdb.HashSkipListMemTableConfig org.rocksdb.PlainTableConfig org.rocksdb.ReadOptions +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 org.rocksdb.VectorMemTableConfig org.rocksdb.SkipListMemTableConfig org.rocksdb.HashLinkedListMemTableConfig org.rocksdb.HashSkipListMemTableConfig org.rocksdb.PlainTableConfig org.rocksdb.ReadOptions org.rocksdb.Filter org.rocksdb.BloomFilter NATIVE_INCLUDE = ./include ROCKSDB_JAR = rocksdbjni.jar diff --git a/java/RocksDBSample.java b/java/RocksDBSample.java index 940b4bd408..7e59747229 100644 --- a/java/RocksDBSample.java +++ b/java/RocksDBSample.java @@ -32,13 +32,15 @@ public class RocksDBSample { assert(db == null); } + Filter filter = new BloomFilter(10); options.setCreateIfMissing(true) .createStatistics() .setWriteBufferSize(8 * SizeUnit.KB) .setMaxWriteBufferNumber(3) .setDisableSeekCompaction(true) .setBlockSize(64 * SizeUnit.KB) - .setMaxBackgroundCompactions(10); + .setMaxBackgroundCompactions(10) + .setFilter(filter); Statistics stats = options.statisticsPtr(); assert(options.createIfMissing() == true); @@ -224,5 +226,6 @@ public class RocksDBSample { // be sure to dispose c++ pointers options.dispose(); readOptions.dispose(); + filter.dispose(); } } diff --git a/java/org/rocksdb/BloomFilter.java b/java/org/rocksdb/BloomFilter.java new file mode 100644 index 0000000000..9c4913a8c6 --- /dev/null +++ b/java/org/rocksdb/BloomFilter.java @@ -0,0 +1,37 @@ +// 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; + +/** + * This class creates a new filter policy that uses a bloom filter + * with approximately the specified number of bits per key. + * A good value for bitsPerKey is 10, which yields a filter + * with ~ 1% false positive rate. + * + * Default value of bits per key is 10. + */ +public class BloomFilter extends Filter { + private static final int DEFAULT_BITS_PER_KEY = 10; + private final int bitsPerKey_; + + public BloomFilter() { + this(DEFAULT_BITS_PER_KEY); + } + + public BloomFilter(int bitsPerKey) { + super(); + bitsPerKey_ = bitsPerKey; + + createNewFilter(); + } + + @Override + protected void createNewFilter() { + createNewFilter0(bitsPerKey_); + } + + private native void createNewFilter0(int bitsKeyKey); +} diff --git a/java/org/rocksdb/Filter.java b/java/org/rocksdb/Filter.java new file mode 100644 index 0000000000..0de392ac6e --- /dev/null +++ b/java/org/rocksdb/Filter.java @@ -0,0 +1,38 @@ +// 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; + +/** + * Filters are stored in rocksdb and are consulted automatically + * by rocksdb to decide whether or not to read some + * information from disk. In many cases, a filter can cut down the + * number of disk seeks form a handful to a single disk seek per + * DB::Get() call. + */ +public abstract class Filter { + protected long nativeHandle_ = 0; + + protected abstract void createNewFilter(); + + /** + * Deletes underlying C++ filter pointer. + */ + public synchronized void dispose() { + if(nativeHandle_ != 0) { + 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/Options.java b/java/org/rocksdb/Options.java index 287ef29fa5..ff289b7768 100644 --- a/java/org/rocksdb/Options.java +++ b/java/org/rocksdb/Options.java @@ -144,6 +144,18 @@ public class Options { return blockSize(nativeHandle_); } + /** + * Use the specified filter policy to reduce disk reads. + * @param Filter policy java instance. + * @return the instance of the current Options. + * @see RocksDB.open() + */ + public Options setFilter(Filter filter) { + assert(isInitialized()); + setFilter0(nativeHandle_, filter); + return this; + } + /* * Disable compaction triggered by seek. * With bloomfilter and fast storage, a miss on one level @@ -1238,6 +1250,8 @@ public class Options { private native void useFixedLengthPrefixExtractor( long handle, int prefixLength); + private native void setFilter0(long optHandle, Filter fp); + long nativeHandle_; long cacheSize_; } diff --git a/java/org/rocksdb/ReadOptions.java b/java/org/rocksdb/ReadOptions.java index c9ab547cc5..aead12ec86 100644 --- a/java/org/rocksdb/ReadOptions.java +++ b/java/org/rocksdb/ReadOptions.java @@ -162,4 +162,3 @@ public class ReadOptions { return nativeHandle_ != 0; } } - diff --git a/java/rocksjni/filter.cc b/java/rocksjni/filter.cc new file mode 100644 index 0000000000..7ef959814e --- /dev/null +++ b/java/rocksjni/filter.cc @@ -0,0 +1,41 @@ +// 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++ for +// rocksdb::FilterPolicy. + +#include +#include +#include +#include + +#include "include/org_rocksdb_Filter.h" +#include "include/org_rocksdb_BloomFilter.h" +#include "rocksjni/portal.h" +#include "rocksdb/filter_policy.h" + +/* + * Class: org_rocksdb_BloomFilter + * Method: createNewFilter0 + * Signature: (I)V + */ +void Java_org_rocksdb_BloomFilter_createNewFilter0( + JNIEnv* env, jobject jobj, jint bits_per_key) { + const rocksdb::FilterPolicy* fp = rocksdb::NewBloomFilterPolicy(bits_per_key); + rocksdb::FilterJni::setHandle(env, jobj, fp); +} + +/* + * Class: org_rocksdb_Filter + * Method: dispose0 + * Signature: (J)V + */ +void Java_org_rocksdb_Filter_dispose0( + JNIEnv* env, jobject jobj, jlong handle) { + auto fp = reinterpret_cast(handle); + delete fp; + + rocksdb::FilterJni::setHandle(env, jobj, nullptr); +} diff --git a/java/rocksjni/options.cc b/java/rocksjni/options.cc index 99b6b605e8..d9aef3d741 100644 --- a/java/rocksjni/options.cc +++ b/java/rocksjni/options.cc @@ -21,6 +21,7 @@ #include "rocksdb/memtablerep.h" #include "rocksdb/table.h" #include "rocksdb/slice_transform.h" +#include "rocksdb/filter_policy.h" /* * Class: org_rocksdb_Options @@ -119,6 +120,17 @@ jlong Java_org_rocksdb_Options_statisticsPtr( return reinterpret_cast(st); } +/* + * Class: org_rocksdb_Options + * Method: setFilter0 + * Signature: (JJ)V + */ +void Java_org_rocksdb_Options_setFilter0( + JNIEnv* env, jobject jobj, jlong jopt_handle, jobject jfp) { + reinterpret_cast(jopt_handle)->filter_policy = + rocksdb::FilterJni::getHandle(env, jfp); +} + /* * Class: org_rocksdb_Options * Method: maxWriteBufferNumber diff --git a/java/rocksjni/portal.h b/java/rocksjni/portal.h index 0b485e2e36..4c44443297 100644 --- a/java/rocksjni/portal.h +++ b/java/rocksjni/portal.h @@ -12,6 +12,7 @@ #include #include "rocksdb/db.h" +#include "rocksdb/filter_policy.h" #include "utilities/backupable_db.h" namespace rocksdb { @@ -281,5 +282,38 @@ class IteratorJni { reinterpret_cast(op)); } }; + +class FilterJni { + public: + // Get the java class id of org.rocksdb.FilterPolicy. + static jclass getJClass(JNIEnv* env) { + static jclass jclazz = env->FindClass("org/rocksdb/Filter"); + assert(jclazz != nullptr); + return jclazz; + } + + // Get the field id of the member variable of org.rocksdb.Filter + // that stores the pointer to rocksdb::FilterPolicy. + static jfieldID getHandleFieldID(JNIEnv* env) { + static jfieldID fid = env->GetFieldID( + getJClass(env), "nativeHandle_", "J"); + assert(fid != nullptr); + return fid; + } + + // Get the pointer to rocksdb::FilterPolicy. + static rocksdb::FilterPolicy* getHandle(JNIEnv* env, jobject jobj) { + return reinterpret_cast( + env->GetLongField(jobj, getHandleFieldID(env))); + } + + // Pass the rocksdb::FilterPolicy pointer to the java side. + static void setHandle( + JNIEnv* env, jobject jobj, const rocksdb::FilterPolicy* op) { + env->SetLongField( + jobj, getHandleFieldID(env), + reinterpret_cast(op)); + } +}; } // namespace rocksdb #endif // JAVA_ROCKSJNI_PORTAL_H_