diff --git a/java/jmh/pom.xml b/java/jmh/pom.xml index 3016aefa7881..0f0528e03b2a 100644 --- a/java/jmh/pom.xml +++ b/java/jmh/pom.xml @@ -38,8 +38,8 @@ - 1.7 - 1.7 + 17 + 17 UTF-8 1.22 @@ -50,7 +50,7 @@ org.rocksdb rocksdbjni - 7.9.0-SNAPSHOT + 8.7.0 diff --git a/java/jmh/src/main/java/org/rocksdb/jmh/MultiGetBenchmarks.java b/java/jmh/src/main/java/org/rocksdb/jmh/MultiGetBenchmarks.java index d374477160e3..da7bd67f6a41 100644 --- a/java/jmh/src/main/java/org/rocksdb/jmh/MultiGetBenchmarks.java +++ b/java/jmh/src/main/java/org/rocksdb/jmh/MultiGetBenchmarks.java @@ -88,6 +88,12 @@ public void setup() throws IOException, RocksDBException { cfHandles = cfHandlesList.toArray(new ColumnFamilyHandle[0]); // store initial data for retrieving via get + for (int j = 0; j < keyCount; j++) { + final byte[] paddedValue = Arrays.copyOf(ba("value" + j), valueSize); + db.put(ba("key" + j), paddedValue); + } + + // store initial data for retrieving via get - column families for (int i = 0; i < cfs; i++) { for (int j = 0; j < keyCount; j++) { final byte[] paddedValue = Arrays.copyOf(ba("value" + j), valueSize); @@ -168,10 +174,8 @@ public void allocateSliceBuffers() { valueBuffersList = new ArrayList<>(); keyBuffersList = new ArrayList<>(); for (int i = 0; i < keyCount; i++) { - valueBuffersList.add(valuesBuffer.slice()); - valuesBuffer.position(i * valueSize); - keyBuffersList.add(keysBuffer.slice()); - keysBuffer.position(i * keySize); + valueBuffersList.add(valuesBuffer.slice(i * valueSize, valueSize)); + keyBuffersList.add(keysBuffer.slice(i * keySize, keySize)); } } @@ -181,7 +185,7 @@ public void freeSliceBuffers() { } @Benchmark - public List multiGet10() throws RocksDBException { + public List multiGetList10() throws RocksDBException { final int fromKeyIdx = next(multiGetSize, keyCount); if (fromKeyIdx >= 0) { final List keys = keys(fromKeyIdx, fromKeyIdx + multiGetSize); @@ -194,6 +198,52 @@ public List multiGet10() throws RocksDBException { return new ArrayList<>(); } + @Benchmark + public List multiGetList10_intermediate() throws RocksDBException { + final int fromKeyIdx = next(multiGetSize, keyCount); + if (fromKeyIdx >= 0) { + final List keys = keys(fromKeyIdx, fromKeyIdx + multiGetSize); + final List valueResults = db.multiGetAsList_intermediate(keys); + for (final byte[] result : valueResults) { + if (result.length != valueSize) + throw new RuntimeException("Test valueSize assumption wrong"); + } + } + return new ArrayList<>(); + } + + @Benchmark + public List multiGetList10_old() throws RocksDBException { + final int fromKeyIdx = next(multiGetSize, keyCount); + if (fromKeyIdx >= 0) { + final List keys = keys(fromKeyIdx, fromKeyIdx + multiGetSize); + final List valueResults = db.multiGetAsList_old(keys); + for (final byte[] result : valueResults) { + if (result.length != valueSize) + throw new RuntimeException("Test valueSize assumption wrong"); + } + } + return new ArrayList<>(); + } + + @Benchmark + public List multiGet20() throws RocksDBException { + final int fromKeyIdx = next(multiGetSize, keyCount); + if (fromKeyIdx >= 0) { + final List keys = keys(keyBuffersList, fromKeyIdx, fromKeyIdx + multiGetSize); + final List values = valueBuffersList.subList(fromKeyIdx, fromKeyIdx + multiGetSize); + final List statusResults = + db.multiGetByteBuffers(keys, values); + for (final ByteBufferGetStatus result : statusResults) { + if (result.status.getCode() != Status.Code.Ok) + throw new RuntimeException("Test status not OK: " + result.status); + if (result.value.limit() != valueSize) + throw new RuntimeException("Test valueSize assumption wrong"); + } + } + return new ArrayList<>(); + } + public static void main(final String[] args) throws RunnerException { final org.openjdk.jmh.runner.options.Options opt = new OptionsBuilder() diff --git a/java/rocksjni/jni_get_helpers.cc b/java/rocksjni/jni_get_helpers.cc index 48d4d5eff60a..9367dcfba9f4 100644 --- a/java/rocksjni/jni_get_helpers.cc +++ b/java/rocksjni/jni_get_helpers.cc @@ -171,7 +171,7 @@ jobjectArray MultiGetValues::byteArrays( for (std::vector::size_type i = 0; i != s.size(); i++) { if (s[i].ok()) { - std::string* value = &values[i]; + TValue* value = &values[i]; const jsize jvalue_len = static_cast(value->size()); jbyteArray jentry_value = env->NewByteArray(jvalue_len); if (jentry_value == nullptr) { @@ -207,4 +207,8 @@ template jobjectArray MultiGetValues::byteArrays( JNIEnv* env, std::vector& values, std::vector& s); +template jobjectArray MultiGetValues::byteArrays( + JNIEnv* env, std::vector& values, + std::vector& s); + }; // namespace ROCKSDB_NAMESPACE diff --git a/java/rocksjni/rocksjni.cc b/java/rocksjni/rocksjni.cc index aca4fc306cac..884552efdad9 100644 --- a/java/rocksjni/rocksjni.cc +++ b/java/rocksjni/rocksjni.cc @@ -1986,7 +1986,7 @@ void multi_get_helper_direct(JNIEnv* env, jobject, ROCKSDB_NAMESPACE::DB* db, * Method: multiGet * Signature: (J[[B[I[I)[[B */ -jobjectArray Java_org_rocksdb_RocksDB_multiGet000__J_3_3B_3I_3I( +JNIEXPORT jobjectArray JNICALL Java_org_rocksdb_RocksDB_multiGetOld( JNIEnv* env, jobject jdb, jlong jdb_handle, jobjectArray jkeys, jintArray jkey_offs, jintArray jkey_lens) { return multi_get_helper( @@ -1995,13 +1995,13 @@ jobjectArray Java_org_rocksdb_RocksDB_multiGet000__J_3_3B_3I_3I( } /* - * TODO (AP) - not finished + * TODO (AP) - intermediate version * * Class: org_rocksdb_RocksDB * Method: multiGet * Signature: (J[[B[I[I)[[B */ -jobjectArray Java_org_rocksdb_RocksDB_multiGet__J_3_3B_3I_3I( +jobjectArray Java_org_rocksdb_RocksDB_multiGetIntermediate( JNIEnv* env, jobject, jlong jdb_handle, jobjectArray jkeys, jintArray jkey_offs, jintArray jkey_lens) { ROCKSDB_NAMESPACE::MultiGetKeys keys; @@ -2017,6 +2017,29 @@ jobjectArray Java_org_rocksdb_RocksDB_multiGet__J_3_3B_3I_3I( return ROCKSDB_NAMESPACE::MultiGetValues::byteArrays(env, values, statuses); } +/* + * Use the efficient/optimized variant of MultiGet() + * + * Class: org_rocksdb_RocksDB + * Method: multiGet + * Signature: (J[[B[I[I)[[B + */ +jobjectArray Java_org_rocksdb_RocksDB_multiGet__J_3_3B_3I_3I( + JNIEnv* env, jobject, jlong jdb_handle, jobjectArray jkeys, + jintArray jkey_offs, jintArray jkey_lens) { + ROCKSDB_NAMESPACE::MultiGetKeys keys; + if (!keys.fromByteArrays(env, jkeys, jkey_offs, jkey_lens)) { + return nullptr; + } + std::vector values(keys.size()); + std::vector statuses(keys.size()); + auto* db = reinterpret_cast(jdb_handle); + db->MultiGet(ROCKSDB_NAMESPACE::ReadOptions(), db->DefaultColumnFamily(), + keys.size(), keys.array(), values.data(), statuses.data(), + false /* sorted_input*/); + return ROCKSDB_NAMESPACE::MultiGetValues::byteArrays(env, values, statuses); +} + /* * Class: org_rocksdb_RocksDB * Method: multiGet diff --git a/java/src/main/java/org/rocksdb/RocksDB.java b/java/src/main/java/org/rocksdb/RocksDB.java index fb35208bc3da..1f595500f693 100644 --- a/java/src/main/java/org/rocksdb/RocksDB.java +++ b/java/src/main/java/org/rocksdb/RocksDB.java @@ -2147,6 +2147,36 @@ public List multiGetAsList(final List keys) keyLengths)); } + public List multiGetAsList_intermediate(final List keys) + throws RocksDBException { + assert(keys.size() != 0); + + final byte[][] keysArray = keys.toArray(new byte[keys.size()][]); + final int[] keyOffsets = new int[keysArray.length]; + final int[] keyLengths = new int[keysArray.length]; + for(int i = 0; i < keyLengths.length; i++) { + keyLengths[i] = keysArray[i].length; + } + + return Arrays.asList(multiGetIntermediate(nativeHandle_, keysArray, keyOffsets, + keyLengths)); + } + + public List multiGetAsList_old(final List keys) + throws RocksDBException { + assert(keys.size() != 0); + + final byte[][] keysArray = keys.toArray(new byte[keys.size()][]); + final int[] keyOffsets = new int[keysArray.length]; + final int[] keyLengths = new int[keysArray.length]; + for(int i = 0; i < keyLengths.length; i++) { + keyLengths[i] = keysArray[i].length; + } + + return Arrays.asList(multiGetOld(nativeHandle_, keysArray, keyOffsets, + keyLengths)); + } + /** * Returns a list of values for the given list of keys. List will contain * null for keys which could not be found. @@ -2359,7 +2389,7 @@ public List multiGetByteBuffers(final ReadOptions readOptio // Check if key size equals cfList size. If not a exception must be // thrown. If not a Segmentation fault happens. if (values.size() != keys.size()) { - throw new IllegalArgumentException("For each key there must be a corresponding value."); + throw new IllegalArgumentException("Mismatch " + keys.size() + " keys, but not the same as " + values.size() + " values."); } // TODO (AP) support indirect buffers @@ -4498,7 +4528,11 @@ private native byte[] get(final long handle, final long readOptHandle, final byte[] key, final int keyOffset, final int keyLength, final long cfHandle) throws RocksDBException; private native byte[][] multiGet(final long dbHandle, final byte[][] keys, - final int[] keyOffsets, final int[] keyLengths); + final int[] keyOffsets, final int[] keyLengths); + private native byte[][] multiGetIntermediate(final long dbHandle, final byte[][] keys, + final int[] keyOffsets, final int[] keyLengths); + private native byte[][] multiGetOld(final long dbHandle, final byte[][] keys, + final int[] keyOffsets, final int[] keyLengths); private native byte[][] multiGet(final long dbHandle, final byte[][] keys, final int[] keyOffsets, final int[] keyLengths, final long[] columnFamilyHandles);