From 4f5a6872541ec1aaf04e1b6f34ce2b774fa2e83e Mon Sep 17 00:00:00 2001 From: fyrz Date: Thu, 9 Oct 2014 23:16:41 +0200 Subject: [PATCH] 32-Bit RocksJava resolution for jlong overflows Summary: This pull request solves the jlong overflow problem on 32-Bit machines as described in https://github.com/facebook/rocksdb/issues/278: 1. There is a new org.rocksdb.test.PlatformRandomHelper to assist in getting random values. For 32 Bit the getLong method is overriden by xpromaches code above. For 64 Bit it behaves as is. 2. The detection should be cross-platform (Windows is supported though it is not ported completely yet). 3. Every JNI method which sets jlong values must check if the value fits into size_t. If it overflows size_t a InvalidArgument Status object will be returned. If its ok a OK Status will be returned. 4. Setters which have this check will throw a RocksDBException if its no OK Status. Additionally some other parts of code were corrected using the wrong type casts. Test Plan: make rocksdbjava make jtest Differential Revision: https://reviews.facebook.net/D24531 --- java/RocksDBSample.java | 85 +++++++++--------- .../rocksdb/HashLinkedListMemTableConfig.java | 6 +- .../rocksdb/HashSkipListMemTableConfig.java | 6 +- java/org/rocksdb/MemTableConfig.java | 3 +- java/org/rocksdb/Options.java | 56 ++++++++---- java/org/rocksdb/benchmark/DbBenchmark.java | 2 +- java/org/rocksdb/test/OptionsTest.java | 87 +++++++++++++------ .../rocksdb/test/PlatformRandomHelper.java | 54 ++++++++++++ .../rocksdb/test/StatisticsCollectorTest.java | 4 +- java/rocksjni/memtablejni.cc | 31 +++++-- java/rocksjni/options.cc | 81 ++++++++++++----- java/rocksjni/portal.h | 12 ++- java/rocksjni/ratelimiterjni.cc | 4 +- java/rocksjni/restorejni.cc | 9 +- java/rocksjni/rocksjni.cc | 19 ++-- java/rocksjni/write_batch.cc | 2 +- 16 files changed, 322 insertions(+), 139 deletions(-) create mode 100644 java/org/rocksdb/test/PlatformRandomHelper.java diff --git a/java/RocksDBSample.java b/java/RocksDBSample.java index c9a30476a..9eff06037 100644 --- a/java/RocksDBSample.java +++ b/java/RocksDBSample.java @@ -35,13 +35,18 @@ public class RocksDBSample { assert(db == null); } - options.setCreateIfMissing(true) - .createStatistics() - .setWriteBufferSize(8 * SizeUnit.KB) - .setMaxWriteBufferNumber(3) - .setMaxBackgroundCompactions(10) - .setCompressionType(CompressionType.SNAPPY_COMPRESSION) - .setCompactionStyle(CompactionStyle.UNIVERSAL); + try { + options.setCreateIfMissing(true) + .createStatistics() + .setWriteBufferSize(8 * SizeUnit.KB) + .setMaxWriteBufferNumber(3) + .setMaxBackgroundCompactions(10) + .setCompressionType(CompressionType.SNAPPY_COMPRESSION) + .setCompactionStyle(CompactionStyle.UNIVERSAL); + } catch (RocksDBException e) { + assert(false); + } + Statistics stats = options.statisticsPtr(); assert(options.createIfMissing() == true); @@ -50,36 +55,38 @@ public class RocksDBSample { assert(options.maxBackgroundCompactions() == 10); assert(options.compressionType() == CompressionType.SNAPPY_COMPRESSION); assert(options.compactionStyle() == CompactionStyle.UNIVERSAL); - - assert(options.memTableFactoryName().equals("SkipListFactory")); - options.setMemTableConfig( - new HashSkipListMemTableConfig() - .setHeight(4) - .setBranchingFactor(4) - .setBucketCount(2000000)); - assert(options.memTableFactoryName().equals("HashSkipListRepFactory")); - - options.setMemTableConfig( - new HashLinkedListMemTableConfig() - .setBucketCount(100000)); - assert(options.memTableFactoryName().equals("HashLinkedListRepFactory")); - - options.setMemTableConfig( - new VectorMemTableConfig().setReservedSize(10000)); - assert(options.memTableFactoryName().equals("VectorRepFactory")); - - options.setMemTableConfig(new SkipListMemTableConfig()); - assert(options.memTableFactoryName().equals("SkipListFactory")); - - options.setTableFormatConfig(new PlainTableConfig()); - // Plain-Table requires mmap read - options.setAllowMmapReads(true); - assert(options.tableFactoryName().equals("PlainTable")); - - options.setRateLimiterConfig(new GenericRateLimiterConfig(10000000, - 10000, 10)); - options.setRateLimiterConfig(new GenericRateLimiterConfig(10000000)); - + try { + assert(options.memTableFactoryName().equals("SkipListFactory")); + options.setMemTableConfig( + new HashSkipListMemTableConfig() + .setHeight(4) + .setBranchingFactor(4) + .setBucketCount(2000000)); + assert(options.memTableFactoryName().equals("HashSkipListRepFactory")); + + options.setMemTableConfig( + new HashLinkedListMemTableConfig() + .setBucketCount(100000)); + assert(options.memTableFactoryName().equals("HashLinkedListRepFactory")); + + options.setMemTableConfig( + new VectorMemTableConfig().setReservedSize(10000)); + assert(options.memTableFactoryName().equals("VectorRepFactory")); + + options.setMemTableConfig(new SkipListMemTableConfig()); + assert(options.memTableFactoryName().equals("SkipListFactory")); + + options.setTableFormatConfig(new PlainTableConfig()); + // Plain-Table requires mmap read + options.setAllowMmapReads(true); + assert(options.tableFactoryName().equals("PlainTable")); + + options.setRateLimiterConfig(new GenericRateLimiterConfig(10000000, + 10000, 10)); + options.setRateLimiterConfig(new GenericRateLimiterConfig(10000000)); + } catch (RocksDBException e) { + assert(false); + } Filter bloomFilter = new BloomFilter(10); BlockBasedTableConfig table_options = new BlockBasedTableConfig(); table_options.setBlockCacheSize(64 * SizeUnit.KB) @@ -91,7 +98,7 @@ public class RocksDBSample { .setHashIndexAllowCollision(false) .setBlockCacheCompressedSize(64 * SizeUnit.KB) .setBlockCacheCompressedNumShardBits(10); - + assert(table_options.blockCacheSize() == 64 * SizeUnit.KB); assert(table_options.cacheNumShardBits() == 6); assert(table_options.blockSizeDeviation() == 5); @@ -100,7 +107,7 @@ public class RocksDBSample { assert(table_options.hashIndexAllowCollision() == false); assert(table_options.blockCacheCompressedSize() == 64 * SizeUnit.KB); assert(table_options.blockCacheCompressedNumShardBits() == 10); - + options.setTableFormatConfig(table_options); assert(options.tableFactoryName().equals("BlockBasedTable")); diff --git a/java/org/rocksdb/HashLinkedListMemTableConfig.java b/java/org/rocksdb/HashLinkedListMemTableConfig.java index 24fcd8b52..381a16f49 100644 --- a/java/org/rocksdb/HashLinkedListMemTableConfig.java +++ b/java/org/rocksdb/HashLinkedListMemTableConfig.java @@ -42,11 +42,13 @@ public class HashLinkedListMemTableConfig extends MemTableConfig { return bucketCount_; } - @Override protected long newMemTableFactoryHandle() { + @Override protected long newMemTableFactoryHandle() + throws RocksDBException { return newMemTableFactoryHandle(bucketCount_); } - private native long newMemTableFactoryHandle(long bucketCount); + private native long newMemTableFactoryHandle(long bucketCount) + throws RocksDBException; private long bucketCount_; } diff --git a/java/org/rocksdb/HashSkipListMemTableConfig.java b/java/org/rocksdb/HashSkipListMemTableConfig.java index 74fb0dba2..100f16c82 100644 --- a/java/org/rocksdb/HashSkipListMemTableConfig.java +++ b/java/org/rocksdb/HashSkipListMemTableConfig.java @@ -83,13 +83,15 @@ public class HashSkipListMemTableConfig extends MemTableConfig { return branchingFactor_; } - @Override protected long newMemTableFactoryHandle() { + @Override protected long newMemTableFactoryHandle() + throws RocksDBException { return newMemTableFactoryHandle( bucketCount_, height_, branchingFactor_); } private native long newMemTableFactoryHandle( - long bucketCount, int height, int branchingFactor); + long bucketCount, int height, int branchingFactor) + throws RocksDBException; private long bucketCount_; private int branchingFactor_; diff --git a/java/org/rocksdb/MemTableConfig.java b/java/org/rocksdb/MemTableConfig.java index a69b1008f..deb74f185 100644 --- a/java/org/rocksdb/MemTableConfig.java +++ b/java/org/rocksdb/MemTableConfig.java @@ -23,5 +23,6 @@ public abstract class MemTableConfig { * * @see Options#setMemTableConfig(MemTableConfig) */ - abstract protected long newMemTableFactoryHandle(); + abstract protected long newMemTableFactoryHandle() + throws RocksDBException; } diff --git a/java/org/rocksdb/Options.java b/java/org/rocksdb/Options.java index b0989363b..1ad8f9489 100644 --- a/java/org/rocksdb/Options.java +++ b/java/org/rocksdb/Options.java @@ -118,8 +118,10 @@ public class Options extends RocksObject { * @param writeBufferSize the size of write buffer. * @return the instance of the current Options. * @see org.rocksdb.RocksDB#open(Options, String) + * @throws RocksDBException */ - public Options setWriteBufferSize(long writeBufferSize) { + public Options setWriteBufferSize(long writeBufferSize) + throws RocksDBException { assert(isInitialized()); setWriteBufferSize(nativeHandle_, writeBufferSize); return this; @@ -561,13 +563,16 @@ public class Options extends RocksObject { * * @param maxLogFileSize the maximum size of a info log file. * @return the reference to the current option. + * @throws RocksDBException */ - public Options setMaxLogFileSize(long maxLogFileSize) { + public Options setMaxLogFileSize(long maxLogFileSize) + throws RocksDBException { assert(isInitialized()); setMaxLogFileSize(nativeHandle_, maxLogFileSize); return this; } - private native void setMaxLogFileSize(long handle, long maxLogFileSize); + private native void setMaxLogFileSize(long handle, long maxLogFileSize) + throws RocksDBException; /** * Returns the time interval for the info log file to roll (in seconds). @@ -591,14 +596,16 @@ public class Options extends RocksObject { * * @param logFileTimeToRoll the time interval in seconds. * @return the reference to the current option. + * @throws RocksDBException */ - public Options setLogFileTimeToRoll(long logFileTimeToRoll) { + public Options setLogFileTimeToRoll(long logFileTimeToRoll) + throws RocksDBException{ assert(isInitialized()); setLogFileTimeToRoll(nativeHandle_, logFileTimeToRoll); return this; } private native void setLogFileTimeToRoll( - long handle, long logFileTimeToRoll); + long handle, long logFileTimeToRoll) throws RocksDBException; /** * Returns the maximum number of info log files to be kept. @@ -618,13 +625,16 @@ public class Options extends RocksObject { * * @param keepLogFileNum the maximum number of info log files to be kept. * @return the reference to the current option. + * @throws RocksDBException */ - public Options setKeepLogFileNum(long keepLogFileNum) { + public Options setKeepLogFileNum(long keepLogFileNum) + throws RocksDBException{ assert(isInitialized()); setKeepLogFileNum(nativeHandle_, keepLogFileNum); return this; } - private native void setKeepLogFileNum(long handle, long keepLogFileNum); + private native void setKeepLogFileNum(long handle, long keepLogFileNum) + throws RocksDBException; /** * Manifest file is rolled over on reaching this limit. @@ -844,14 +854,16 @@ public class Options extends RocksObject { * * @param size the size in byte * @return the reference to the current option. + * @throws RocksDBException */ - public Options setManifestPreallocationSize(long size) { + public Options setManifestPreallocationSize(long size) + throws RocksDBException { assert(isInitialized()); setManifestPreallocationSize(nativeHandle_, size); return this; } private native void setManifestPreallocationSize( - long handle, long size); + long handle, long size) throws RocksDBException; /** * Data being read from file storage may be buffered in the OS @@ -1110,8 +1122,10 @@ public class Options extends RocksObject { * * @param config the mem-table config. * @return the instance of the current Options. + * @throws RocksDBException */ - public Options setMemTableConfig(MemTableConfig config) { + public Options setMemTableConfig(MemTableConfig config) + throws RocksDBException { setMemTableFactory(nativeHandle_, config.newMemTableFactoryHandle()); return this; } @@ -1123,6 +1137,7 @@ public class Options extends RocksObject { * * @param config rate limiter config. * @return the instance of the current Options. + * @throws RocksDBException */ public Options setRateLimiterConfig(RateLimiterConfig config) { setRateLimiter(nativeHandle_, config.newRateLimiterHandle()); @@ -1768,13 +1783,15 @@ public class Options extends RocksObject { * * @param arenaBlockSize the size of an arena block * @return the reference to the current option. + * @throws RocksDBException */ - public Options setArenaBlockSize(long arenaBlockSize) { + public Options setArenaBlockSize(long arenaBlockSize) + throws RocksDBException { setArenaBlockSize(nativeHandle_, arenaBlockSize); return this; } private native void setArenaBlockSize( - long handle, long arenaBlockSize); + long handle, long arenaBlockSize) throws RocksDBException; /** * Disable automatic compactions. Manual compactions can still @@ -1977,13 +1994,15 @@ public class Options extends RocksObject { * @param inplaceUpdateNumLocks the number of locks used for * inplace updates. * @return the reference to the current option. + * @throws RocksDBException */ - public Options setInplaceUpdateNumLocks(long inplaceUpdateNumLocks) { + public Options setInplaceUpdateNumLocks(long inplaceUpdateNumLocks) + throws RocksDBException { setInplaceUpdateNumLocks(nativeHandle_, inplaceUpdateNumLocks); return this; } private native void setInplaceUpdateNumLocks( - long handle, long inplaceUpdateNumLocks); + long handle, long inplaceUpdateNumLocks) throws RocksDBException; /** * Returns the number of bits used in the prefix bloom filter. @@ -2108,13 +2127,15 @@ public class Options extends RocksObject { * * @param maxSuccessiveMerges the maximum number of successive merges. * @return the reference to the current option. + * @throws RocksDBException */ - public Options setMaxSuccessiveMerges(long maxSuccessiveMerges) { + public Options setMaxSuccessiveMerges(long maxSuccessiveMerges) + throws RocksDBException { setMaxSuccessiveMerges(nativeHandle_, maxSuccessiveMerges); return this; } private native void setMaxSuccessiveMerges( - long handle, long maxSuccessiveMerges); + long handle, long maxSuccessiveMerges) throws RocksDBException; /** * The minimum number of write buffers that will be merged together @@ -2204,7 +2225,8 @@ public class Options extends RocksObject { private native void disposeInternal(long handle); private native void setCreateIfMissing(long handle, boolean flag); private native boolean createIfMissing(long handle); - private native void setWriteBufferSize(long handle, long writeBufferSize); + private native void setWriteBufferSize(long handle, long writeBufferSize) + throws RocksDBException; private native long writeBufferSize(long handle); private native void setMaxWriteBufferNumber( long handle, int maxWriteBufferNumber); diff --git a/java/org/rocksdb/benchmark/DbBenchmark.java b/java/org/rocksdb/benchmark/DbBenchmark.java index 612fdaf28..d3d9f8c58 100644 --- a/java/org/rocksdb/benchmark/DbBenchmark.java +++ b/java/org/rocksdb/benchmark/DbBenchmark.java @@ -489,7 +489,7 @@ public class DbBenchmark { options.setDisableWAL((Boolean)flags_.get(Flag.disable_wal)); } - private void prepareOptions(Options options) { + private void prepareOptions(Options options) throws RocksDBException { if (!useExisting_) { options.setCreateIfMissing(true); } else { diff --git a/java/org/rocksdb/test/OptionsTest.java b/java/org/rocksdb/test/OptionsTest.java index d3abb48cd..9f14b40d9 100644 --- a/java/org/rocksdb/test/OptionsTest.java +++ b/java/org/rocksdb/test/OptionsTest.java @@ -7,15 +7,19 @@ package org.rocksdb.test; import java.util.Random; import org.rocksdb.RocksDB; +import org.rocksdb.RocksDBException; import org.rocksdb.Options; +import org.rocksdb.test.PlatformRandomHelper; public class OptionsTest { + static { RocksDB.loadLibrary(); } public static void main(String[] args) { Options opt = new Options(); - Random rand = new Random(); + Random rand = PlatformRandomHelper. + getPlatformSpecificRandomFactory(); { // CreateIfMissing test boolean boolValue = rand.nextBoolean(); opt.setCreateIfMissing(boolValue); @@ -83,21 +87,34 @@ public class OptionsTest { } { // MaxLogFileSize test - long longValue = rand.nextLong(); - opt.setMaxLogFileSize(longValue); - assert(opt.maxLogFileSize() == longValue); + try { + long longValue = rand.nextLong(); + opt.setMaxLogFileSize(longValue); + assert(opt.maxLogFileSize() == longValue); + } catch (RocksDBException e) { + System.out.println(e.getMessage()); + assert(false); + } } { // LogFileTimeToRoll test - long longValue = rand.nextLong(); - opt.setLogFileTimeToRoll(longValue); - assert(opt.logFileTimeToRoll() == longValue); + try { + long longValue = rand.nextLong(); + opt.setLogFileTimeToRoll(longValue); + assert(opt.logFileTimeToRoll() == longValue); + } catch (RocksDBException e) { + assert(false); + } } { // KeepLogFileNum test - long longValue = rand.nextLong(); - opt.setKeepLogFileNum(longValue); - assert(opt.keepLogFileNum() == longValue); + try { + long longValue = rand.nextLong(); + opt.setKeepLogFileNum(longValue); + assert(opt.keepLogFileNum() == longValue); + } catch (RocksDBException e) { + assert(false); + } } { // MaxManifestFileSize test @@ -125,9 +142,13 @@ public class OptionsTest { } { // ManifestPreallocationSize test - long longValue = rand.nextLong(); - opt.setManifestPreallocationSize(longValue); - assert(opt.manifestPreallocationSize() == longValue); + try { + long longValue = rand.nextLong(); + opt.setManifestPreallocationSize(longValue); + assert(opt.manifestPreallocationSize() == longValue); + } catch (RocksDBException e) { + assert(false); + } } { // AllowOsBuffer test @@ -185,9 +206,13 @@ public class OptionsTest { } { // WriteBufferSize test - long longValue = rand.nextLong(); - opt.setWriteBufferSize(longValue); - assert(opt.writeBufferSize() == longValue); + try { + long longValue = rand.nextLong(); + opt.setWriteBufferSize(longValue); + assert(opt.writeBufferSize() == longValue); + } catch (RocksDBException e) { + assert(false); + } } { // MaxWriteBufferNumber test @@ -293,9 +318,13 @@ public class OptionsTest { } { // ArenaBlockSize test - long longValue = rand.nextLong(); - opt.setArenaBlockSize(longValue); - assert(opt.arenaBlockSize() == longValue); + try { + long longValue = rand.nextLong(); + opt.setArenaBlockSize(longValue); + assert(opt.arenaBlockSize() == longValue); + } catch (RocksDBException e) { + assert(false); + } } { // DisableAutoCompactions test @@ -335,9 +364,13 @@ public class OptionsTest { } { // InplaceUpdateNumLocks test - long longValue = rand.nextLong(); - opt.setInplaceUpdateNumLocks(longValue); - assert(opt.inplaceUpdateNumLocks() == longValue); + try { + long longValue = rand.nextLong(); + opt.setInplaceUpdateNumLocks(longValue); + assert(opt.inplaceUpdateNumLocks() == longValue); + } catch (RocksDBException e) { + assert(false); + } } { // MemtablePrefixBloomBits test @@ -359,9 +392,13 @@ public class OptionsTest { } { // MaxSuccessiveMerges test - long longValue = rand.nextLong(); - opt.setMaxSuccessiveMerges(longValue); - assert(opt.maxSuccessiveMerges() == longValue); + try { + long longValue = rand.nextLong(); + opt.setMaxSuccessiveMerges(longValue); + assert(opt.maxSuccessiveMerges() == longValue); + } catch (RocksDBException e){ + assert(false); + } } { // MinPartialMergeOperands test diff --git a/java/org/rocksdb/test/PlatformRandomHelper.java b/java/org/rocksdb/test/PlatformRandomHelper.java new file mode 100644 index 000000000..b0ef8d8a6 --- /dev/null +++ b/java/org/rocksdb/test/PlatformRandomHelper.java @@ -0,0 +1,54 @@ +// 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.test; + +import java.util.Random; + +/** + * Helper class to get the appropriate Random class instance dependent + * on the current platform architecture (32bit vs 64bit) + */ +public class PlatformRandomHelper { + /** + * Determine if OS is 32-Bit/64-Bit + */ + public static boolean isOs64Bit(){ + boolean is64Bit = false; + if (System.getProperty("os.name").contains("Windows")) { + is64Bit = (System.getenv("ProgramFiles(x86)") != null); + } else { + is64Bit = (System.getProperty("os.arch").indexOf("64") != -1); + } + return is64Bit; + } + + /** + * Factory to get a platform specific Random instance + */ + public static Random getPlatformSpecificRandomFactory(){ + if (isOs64Bit()) { + return new Random(); + } + return new Random32Bit(); + } + + /** + * Random32Bit is a class which overrides {@code nextLong} to + * provide random numbers which fit in size_t. This workaround + * is necessary because there is no unsigned_int < Java 8 + */ + private static class Random32Bit extends Random { + @Override + public long nextLong(){ + return this.nextInt(Integer.MAX_VALUE); + } + } + + /** + * Utility class constructor + */ + private PlatformRandomHelper() { } +} diff --git a/java/org/rocksdb/test/StatisticsCollectorTest.java b/java/org/rocksdb/test/StatisticsCollectorTest.java index e497d14df..edbf693e4 100644 --- a/java/org/rocksdb/test/StatisticsCollectorTest.java +++ b/java/org/rocksdb/test/StatisticsCollectorTest.java @@ -14,7 +14,7 @@ public class StatisticsCollectorTest { RocksDB.loadLibrary(); } - public static void main(String[] args) + public static void main(String[] args) throws InterruptedException, RocksDBException { Options opt = new Options().createStatistics().setCreateIfMissing(true); Statistics stats = opt.statisticsPtr(); @@ -23,7 +23,7 @@ public class StatisticsCollectorTest { StatsCallbackMock callback = new StatsCallbackMock(); StatsCollectorInput statsInput = new StatsCollectorInput(stats, callback); - + StatisticsCollector statsCollector = new StatisticsCollector( Collections.singletonList(statsInput), 100); statsCollector.start(); diff --git a/java/rocksjni/memtablejni.cc b/java/rocksjni/memtablejni.cc index 9b0dc252c..4be03d491 100644 --- a/java/rocksjni/memtablejni.cc +++ b/java/rocksjni/memtablejni.cc @@ -20,10 +20,15 @@ jlong Java_org_rocksdb_HashSkipListMemTableConfig_newMemTableFactoryHandle( JNIEnv* env, jobject jobj, jlong jbucket_count, jint jheight, jint jbranching_factor) { - return reinterpret_cast(rocksdb::NewHashSkipListRepFactory( - rocksdb::jlong_to_size_t(jbucket_count), - static_cast(jheight), - static_cast(jbranching_factor))); + rocksdb::Status s = rocksdb::check_if_jlong_fits_size_t(jbucket_count); + if (s.ok()) { + return reinterpret_cast(rocksdb::NewHashSkipListRepFactory( + static_cast(jbucket_count), + static_cast(jheight), + static_cast(jbranching_factor))); + } + rocksdb::RocksDBExceptionJni::ThrowNew(env, s); + return 0; } /* @@ -33,8 +38,13 @@ jlong Java_org_rocksdb_HashSkipListMemTableConfig_newMemTableFactoryHandle( */ jlong Java_org_rocksdb_HashLinkedListMemTableConfig_newMemTableFactoryHandle( JNIEnv* env, jobject jobj, jlong jbucket_count) { - return reinterpret_cast(rocksdb::NewHashLinkListRepFactory( - rocksdb::jlong_to_size_t(jbucket_count))); + rocksdb::Status s = rocksdb::check_if_jlong_fits_size_t(jbucket_count); + if (s.ok()) { + return reinterpret_cast(rocksdb::NewHashLinkListRepFactory( + static_cast(jbucket_count))); + } + rocksdb::RocksDBExceptionJni::ThrowNew(env, s); + return 0; } /* @@ -44,8 +54,13 @@ jlong Java_org_rocksdb_HashLinkedListMemTableConfig_newMemTableFactoryHandle( */ jlong Java_org_rocksdb_VectorMemTableConfig_newMemTableFactoryHandle( JNIEnv* env, jobject jobj, jlong jreserved_size) { - return reinterpret_cast(new rocksdb::VectorRepFactory( - rocksdb::jlong_to_size_t(jreserved_size))); + rocksdb::Status s = rocksdb::check_if_jlong_fits_size_t(jreserved_size); + if (s.ok()) { + return reinterpret_cast(new rocksdb::VectorRepFactory( + static_cast(jreserved_size))); + } + rocksdb::RocksDBExceptionJni::ThrowNew(env, s); + return 0; } /* diff --git a/java/rocksjni/options.cc b/java/rocksjni/options.cc index a8be5af8b..8d3cb37e0 100644 --- a/java/rocksjni/options.cc +++ b/java/rocksjni/options.cc @@ -71,7 +71,7 @@ jboolean Java_org_rocksdb_Options_createIfMissing( */ void Java_org_rocksdb_Options_setBuiltinComparator( JNIEnv* env, jobject jobj, jlong jhandle, jint builtinComparator) { - switch (builtinComparator){ + switch (builtinComparator) { case 1: reinterpret_cast(jhandle)->comparator = rocksdb::ReverseBytewiseComparator(); @@ -90,11 +90,15 @@ void Java_org_rocksdb_Options_setBuiltinComparator( */ void Java_org_rocksdb_Options_setWriteBufferSize( JNIEnv* env, jobject jobj, jlong jhandle, jlong jwrite_buffer_size) { - reinterpret_cast(jhandle)->write_buffer_size = - rocksdb::jlong_to_size_t(jwrite_buffer_size); + rocksdb::Status s = rocksdb::check_if_jlong_fits_size_t(jwrite_buffer_size); + if (s.ok()) { + reinterpret_cast(jhandle)->write_buffer_size = + jwrite_buffer_size; + } else { + rocksdb::RocksDBExceptionJni::ThrowNew(env, s); + } } - /* * Class: org_rocksdb_Options * Method: writeBufferSize @@ -382,8 +386,13 @@ jlong Java_org_rocksdb_Options_maxLogFileSize( */ void Java_org_rocksdb_Options_setMaxLogFileSize( JNIEnv* env, jobject jobj, jlong jhandle, jlong max_log_file_size) { - reinterpret_cast(jhandle)->max_log_file_size = - rocksdb::jlong_to_size_t(max_log_file_size); + rocksdb::Status s = rocksdb::check_if_jlong_fits_size_t(max_log_file_size); + if (s.ok()) { + reinterpret_cast(jhandle)->max_log_file_size = + max_log_file_size; + } else { + rocksdb::RocksDBExceptionJni::ThrowNew(env, s); + } } /* @@ -403,8 +412,14 @@ jlong Java_org_rocksdb_Options_logFileTimeToRoll( */ void Java_org_rocksdb_Options_setLogFileTimeToRoll( JNIEnv* env, jobject jobj, jlong jhandle, jlong log_file_time_to_roll) { - reinterpret_cast(jhandle)->log_file_time_to_roll = - rocksdb::jlong_to_size_t(log_file_time_to_roll); + rocksdb::Status s = rocksdb::check_if_jlong_fits_size_t( + log_file_time_to_roll); + if (s.ok()) { + reinterpret_cast(jhandle)->log_file_time_to_roll = + log_file_time_to_roll; + } else { + rocksdb::RocksDBExceptionJni::ThrowNew(env, s); + } } /* @@ -424,8 +439,13 @@ jlong Java_org_rocksdb_Options_keepLogFileNum( */ void Java_org_rocksdb_Options_setKeepLogFileNum( JNIEnv* env, jobject jobj, jlong jhandle, jlong keep_log_file_num) { - reinterpret_cast(jhandle)->keep_log_file_num = - rocksdb::jlong_to_size_t(keep_log_file_num); + rocksdb::Status s = rocksdb::check_if_jlong_fits_size_t(keep_log_file_num); + if (s.ok()) { + reinterpret_cast(jhandle)->keep_log_file_num = + keep_log_file_num; + } else { + rocksdb::RocksDBExceptionJni::ThrowNew(env, s); + } } /* @@ -542,7 +562,7 @@ void Java_org_rocksdb_Options_useFixedLengthPrefixExtractor( JNIEnv* env, jobject jobj, jlong jhandle, jint jprefix_length) { reinterpret_cast(jhandle)->prefix_extractor.reset( rocksdb::NewFixedPrefixTransform( - rocksdb::jlong_to_size_t(jprefix_length))); + static_cast(jprefix_length))); } /* @@ -605,8 +625,13 @@ jlong Java_org_rocksdb_Options_manifestPreallocationSize( */ void Java_org_rocksdb_Options_setManifestPreallocationSize( JNIEnv* env, jobject jobj, jlong jhandle, jlong preallocation_size) { - reinterpret_cast(jhandle)->manifest_preallocation_size = - rocksdb::jlong_to_size_t(preallocation_size); + rocksdb::Status s = rocksdb::check_if_jlong_fits_size_t(preallocation_size); + if (s.ok()) { + reinterpret_cast(jhandle)->manifest_preallocation_size = + preallocation_size; + } else { + rocksdb::RocksDBExceptionJni::ThrowNew(env, s); + } } /* @@ -1256,8 +1281,13 @@ jlong Java_org_rocksdb_Options_arenaBlockSize( */ void Java_org_rocksdb_Options_setArenaBlockSize( JNIEnv* env, jobject jobj, jlong jhandle, jlong jarena_block_size) { - reinterpret_cast(jhandle)->arena_block_size = - rocksdb::jlong_to_size_t(jarena_block_size); + rocksdb::Status s = rocksdb::check_if_jlong_fits_size_t(jarena_block_size); + if (s.ok()) { + reinterpret_cast(jhandle)->arena_block_size = + jarena_block_size; + } else { + rocksdb::RocksDBExceptionJni::ThrowNew(env, s); + } } /* @@ -1420,9 +1450,14 @@ jlong Java_org_rocksdb_Options_inplaceUpdateNumLocks( void Java_org_rocksdb_Options_setInplaceUpdateNumLocks( JNIEnv* env, jobject jobj, jlong jhandle, jlong jinplace_update_num_locks) { - reinterpret_cast( - jhandle)->inplace_update_num_locks = - rocksdb::jlong_to_size_t(jinplace_update_num_locks); + rocksdb::Status s = rocksdb::check_if_jlong_fits_size_t( + jinplace_update_num_locks); + if (s.ok()) { + reinterpret_cast(jhandle)->inplace_update_num_locks = + jinplace_update_num_locks; + } else { + rocksdb::RocksDBExceptionJni::ThrowNew(env, s); + } } /* @@ -1512,8 +1547,14 @@ jlong Java_org_rocksdb_Options_maxSuccessiveMerges( void Java_org_rocksdb_Options_setMaxSuccessiveMerges( JNIEnv* env, jobject jobj, jlong jhandle, jlong jmax_successive_merges) { - reinterpret_cast(jhandle)->max_successive_merges = - rocksdb::jlong_to_size_t(jmax_successive_merges); + rocksdb::Status s = rocksdb::check_if_jlong_fits_size_t( + jmax_successive_merges); + if (s.ok()) { + reinterpret_cast(jhandle)->max_successive_merges = + jmax_successive_merges; + } else { + rocksdb::RocksDBExceptionJni::ThrowNew(env, s); + } } /* diff --git a/java/rocksjni/portal.h b/java/rocksjni/portal.h index 4c7a8b9b9..374d20b0b 100644 --- a/java/rocksjni/portal.h +++ b/java/rocksjni/portal.h @@ -14,14 +14,18 @@ #include #include "rocksdb/db.h" #include "rocksdb/filter_policy.h" +#include "rocksdb/status.h" #include "rocksdb/utilities/backupable_db.h" namespace rocksdb { -inline size_t jlong_to_size_t(const jlong& jvalue) { - return static_cast(jvalue) <= - static_cast(std::numeric_limits::max()) ? - static_cast(jvalue) : std::numeric_limits::max(); +// detect if jlong overflows size_t +inline Status check_if_jlong_fits_size_t(const jlong& jvalue) { + Status s = Status::OK(); + if (static_cast(jvalue) > std::numeric_limits::max()) { + s = Status::InvalidArgument(Slice("jlong overflows 32 bit value.")); + } + return s; } // The portal class for org.rocksdb.RocksDB diff --git a/java/rocksjni/ratelimiterjni.cc b/java/rocksjni/ratelimiterjni.cc index 5413978a0..ab6160e0d 100644 --- a/java/rocksjni/ratelimiterjni.cc +++ b/java/rocksjni/ratelimiterjni.cc @@ -18,7 +18,7 @@ jlong Java_org_rocksdb_GenericRateLimiterConfig_newRateLimiterHandle( JNIEnv* env, jobject jobj, jlong jrate_bytes_per_second, jlong jrefill_period_micros, jint jfairness) { return reinterpret_cast(rocksdb::NewGenericRateLimiter( - rocksdb::jlong_to_size_t(jrate_bytes_per_second), - rocksdb::jlong_to_size_t(jrefill_period_micros), + static_cast(jrate_bytes_per_second), + static_cast(jrefill_period_micros), static_cast(jfairness))); } diff --git a/java/rocksjni/restorejni.cc b/java/rocksjni/restorejni.cc index 942e707e6..bd1734010 100644 --- a/java/rocksjni/restorejni.cc +++ b/java/rocksjni/restorejni.cc @@ -10,7 +10,6 @@ #include #include #include -#include #include #include "include/org_rocksdb_RestoreOptions.h" @@ -72,7 +71,7 @@ void Java_org_rocksdb_RestoreBackupableDB_restoreDBFromBackup0(JNIEnv* env, env->ReleaseStringUTFChars(jdb_dir, cdb_dir); env->ReleaseStringUTFChars(jwal_dir, cwal_dir); - if(!s.ok()) { + if (!s.ok()) { rocksdb::RocksDBExceptionJni::ThrowNew(env, s); } } @@ -97,7 +96,7 @@ void Java_org_rocksdb_RestoreBackupableDB_restoreDBFromLatestBackup0( env->ReleaseStringUTFChars(jdb_dir, cdb_dir); env->ReleaseStringUTFChars(jwal_dir, cwal_dir); - if(!s.ok()) { + if (!s.ok()) { rocksdb::RocksDBExceptionJni::ThrowNew(env, s); } } @@ -112,7 +111,7 @@ void Java_org_rocksdb_RestoreBackupableDB_purgeOldBackups0(JNIEnv* env, auto rdb = reinterpret_cast(jhandle); rocksdb::Status s = rdb->PurgeOldBackups(jnum_backups_to_keep); - if(!s.ok()) { + if (!s.ok()) { rocksdb::RocksDBExceptionJni::ThrowNew(env, s); } } @@ -127,7 +126,7 @@ void Java_org_rocksdb_RestoreBackupableDB_deleteBackup0(JNIEnv* env, auto rdb = reinterpret_cast(jhandle); rocksdb::Status s = rdb->DeleteBackup(jbackup_id); - if(!s.ok()) { + if (!s.ok()) { rocksdb::RocksDBExceptionJni::ThrowNew(env, s); } } diff --git a/java/rocksjni/rocksjni.cc b/java/rocksjni/rocksjni.cc index f1b9cc758..bb3f1a845 100644 --- a/java/rocksjni/rocksjni.cc +++ b/java/rocksjni/rocksjni.cc @@ -246,7 +246,7 @@ jobject multi_get_helper(JNIEnv* env, jobject jdb, rocksdb::DB* db, jkey_list, rocksdb::ListJni::getIteratorMethod(env)); // iterate over keys and convert java byte array to slice - while(env->CallBooleanMethod( + while (env->CallBooleanMethod( iteratorObj, rocksdb::ListJni::getHasNextMethod(env)) == JNI_TRUE) { jbyteArray jkey = (jbyteArray) env->CallObjectMethod( iteratorObj, rocksdb::ListJni::getNextMethod(env)); @@ -272,23 +272,22 @@ jobject multi_get_helper(JNIEnv* env, jobject jdb, rocksdb::DB* db, jobject jvalue_list = env->NewObject(jclazz, mid, jkeys_count); // insert in java list - for(std::vector::size_type i = 0; i != s.size(); i++) { - if(s[i].ok()) { + for (std::vector::size_type i = 0; i != s.size(); i++) { + if (s[i].ok()) { jbyteArray jvalue = env->NewByteArray(values[i].size()); env->SetByteArrayRegion( jvalue, 0, values[i].size(), reinterpret_cast(values[i].c_str())); env->CallBooleanMethod( jvalue_list, rocksdb::ListJni::getListAddMethodId(env), jvalue); - } - else { + } else { env->CallBooleanMethod( jvalue_list, rocksdb::ListJni::getListAddMethodId(env), nullptr); } } // free up allocated byte arrays - for(std::vector::size_type i = 0; i != keys_to_free.size(); i++) { + for (std::vector::size_type i = 0; i != keys_to_free.size(); i++) { delete[] keys_to_free[i]; } keys_to_free.clear(); @@ -435,17 +434,17 @@ jstring Java_org_rocksdb_RocksDB_getProperty0( JNIEnv* env, jobject jdb, jlong db_handle, jstring jproperty, jint jproperty_len) { auto db = reinterpret_cast(db_handle); - + const char* property = env->GetStringUTFChars(jproperty, 0); rocksdb::Slice property_slice(property, jproperty_len); - + std::string property_value; bool retCode = db->GetProperty(property_slice, &property_value); env->ReleaseStringUTFChars(jproperty, property); - + if (!retCode) { rocksdb::RocksDBExceptionJni::ThrowNew(env, rocksdb::Status::NotFound()); } - + return env->NewStringUTF(property_value.data()); } diff --git a/java/rocksjni/write_batch.cc b/java/rocksjni/write_batch.cc index 46e7a6fa0..a51cfce12 100644 --- a/java/rocksjni/write_batch.cc +++ b/java/rocksjni/write_batch.cc @@ -30,7 +30,7 @@ void Java_org_rocksdb_WriteBatch_newWriteBatch( JNIEnv* env, jobject jobj, jint jreserved_bytes) { rocksdb::WriteBatch* wb = new rocksdb::WriteBatch( - rocksdb::jlong_to_size_t(jreserved_bytes)); + static_cast(jreserved_bytes)); rocksdb::WriteBatchJni::setHandle(env, jobj, wb); }