From 7ac3a5d4065906037ee5da6ef478d9c95b6cb25c Mon Sep 17 00:00:00 2001 From: Radek Hubner Date: Wed, 15 Dec 2021 17:45:02 -0800 Subject: [PATCH] ReadOptions - Add missing java API. (#9248) Summary: Pull Request resolved: https://github.com/facebook/rocksdb/pull/9248 Reviewed By: mrambacher Differential Revision: D33011237 Pulled By: jay-zhuang fbshipit-source-id: b6544ad40cb722e327bac60a0af711db253e36d7 --- java/rocksjni/options.cc | 135 ++++++++++ .../main/java/org/rocksdb/ReadOptions.java | 243 ++++++++++++++++++ .../java/org/rocksdb/ReadOptionsTest.java | 58 +++++ 3 files changed, 436 insertions(+) diff --git a/java/rocksjni/options.cc b/java/rocksjni/options.cc index 63fcda41f..03b631fe0 100644 --- a/java/rocksjni/options.cc +++ b/java/rocksjni/options.cc @@ -8266,6 +8266,141 @@ jlong Java_org_rocksdb_ReadOptions_iterStartSeqnum( return static_cast(opt->iter_start_seqnum); } +/* + * Class: org_rocksdb_ReadOptions + * Method: autoPrefixMode + * Signature: (J)Z + */ +jboolean Java_org_rocksdb_ReadOptions_autoPrefixMode(JNIEnv*, jobject, + jlong jhandle) { + auto* opt = reinterpret_cast(jhandle); + return static_cast(opt->auto_prefix_mode); +} + +/* + * Class: org_rocksdb_ReadOptions + * Method: setAutoPrefixMode + * Signature: (JZ)V + */ +void Java_org_rocksdb_ReadOptions_setAutoPrefixMode( + JNIEnv*, jobject, jlong jhandle, jboolean jauto_prefix_mode) { + auto* opt = reinterpret_cast(jhandle); + opt->auto_prefix_mode = static_cast(jauto_prefix_mode); +} + +/* + * Class: org_rocksdb_ReadOptions + * Method: timestamp + * Signature: (J)J + */ +jlong Java_org_rocksdb_ReadOptions_timestamp(JNIEnv*, jobject, jlong jhandle) { + auto* opt = reinterpret_cast(jhandle); + auto& timestamp_slice_handle = opt->timestamp; + return reinterpret_cast(timestamp_slice_handle); +} + +/* + * Class: org_rocksdb_ReadOptions + * Method: setTimestamp + * Signature: (JJ)V + */ +void Java_org_rocksdb_ReadOptions_setTimestamp(JNIEnv*, jobject, jlong jhandle, + jlong jtimestamp_slice_handle) { + auto* opt = reinterpret_cast(jhandle); + opt->timestamp = + reinterpret_cast(jtimestamp_slice_handle); +} + +/* + * Class: org_rocksdb_ReadOptions + * Method: iterStartTs + * Signature: (J)J + */ +jlong Java_org_rocksdb_ReadOptions_iterStartTs(JNIEnv*, jobject, + jlong jhandle) { + auto* opt = reinterpret_cast(jhandle); + auto& iter_start_ts_handle = opt->iter_start_ts; + return reinterpret_cast(iter_start_ts_handle); +} + +/* + * Class: org_rocksdb_ReadOptions + * Method: setIterStartTs + * Signature: (JJ)V + */ +void Java_org_rocksdb_ReadOptions_setIterStartTs(JNIEnv*, jobject, + jlong jhandle, + jlong jiter_start_ts_handle) { + auto* opt = reinterpret_cast(jhandle); + opt->iter_start_ts = + reinterpret_cast(jiter_start_ts_handle); +} + +/* + * Class: org_rocksdb_ReadOptions + * Method: deadline + * Signature: (J)J + */ +jlong Java_org_rocksdb_ReadOptions_deadline(JNIEnv*, jobject, jlong jhandle) { + auto* opt = reinterpret_cast(jhandle); + return static_cast(opt->deadline.count()); +} + +/* + * Class: org_rocksdb_ReadOptions + * Method: setDeadline + * Signature: (JJ)V + */ +void Java_org_rocksdb_ReadOptions_setDeadline(JNIEnv*, jobject, jlong jhandle, + jlong jdeadline) { + auto* opt = reinterpret_cast(jhandle); + opt->deadline = std::chrono::microseconds(static_cast(jdeadline)); +} + +/* + * Class: org_rocksdb_ReadOptions + * Method: ioTimeout + * Signature: (J)J + */ +jlong Java_org_rocksdb_ReadOptions_ioTimeout(JNIEnv*, jobject, jlong jhandle) { + auto* opt = reinterpret_cast(jhandle); + return static_cast(opt->io_timeout.count()); +} + +/* + * Class: org_rocksdb_ReadOptions + * Method: setIoTimeout + * Signature: (JJ)V + */ +void Java_org_rocksdb_ReadOptions_setIoTimeout(JNIEnv*, jobject, jlong jhandle, + jlong jio_timeout) { + auto* opt = reinterpret_cast(jhandle); + opt->io_timeout = + std::chrono::microseconds(static_cast(jio_timeout)); +} + +/* + * Class: org_rocksdb_ReadOptions + * Method: valueSizeSofLimit + * Signature: (J)J + */ +jlong Java_org_rocksdb_ReadOptions_valueSizeSoftLimit(JNIEnv*, jobject, + jlong jhandle) { + auto* opt = reinterpret_cast(jhandle); + return static_cast(opt->value_size_soft_limit); +} + +/* + * Class: org_rocksdb_ReadOptions + * Method: setValueSizeSofLimit + * Signature: (JJ)V + */ +void Java_org_rocksdb_ReadOptions_setValueSizeSoftLimit( + JNIEnv*, jobject, jlong jhandle, jlong jvalue_size_soft_limit) { + auto* opt = reinterpret_cast(jhandle); + opt->value_size_soft_limit = static_cast(jvalue_size_soft_limit); +} + ///////////////////////////////////////////////////////////////////// // ROCKSDB_NAMESPACE::ComparatorOptions diff --git a/java/src/main/java/org/rocksdb/ReadOptions.java b/java/src/main/java/org/rocksdb/ReadOptions.java index 8e287eb9d..8e8a4f410 100644 --- a/java/src/main/java/org/rocksdb/ReadOptions.java +++ b/java/src/main/java/org/rocksdb/ReadOptions.java @@ -37,6 +37,8 @@ public class ReadOptions extends RocksObject { super(copyReadOptions(other.nativeHandle_)); this.iterateLowerBoundSlice_ = other.iterateLowerBoundSlice_; this.iterateUpperBoundSlice_ = other.iterateUpperBoundSlice_; + this.timestampSlice_ = other.timestampSlice_; + this.iterStartTs_ = other.iterStartTs_; } /** @@ -560,6 +562,233 @@ public class ReadOptions extends RocksObject { return iterStartSeqnum(nativeHandle_); } + /** + * When true, by default use total_order_seek = true, and RocksDB can + * selectively enable prefix seek mode if won't generate a different result + * from total_order_seek, based on seek key, and iterator upper bound. + * Not supported in ROCKSDB_LITE mode, in the way that even with value true + * prefix mode is not used. + * Default: false + * + * @return true if auto prefix mode is set. + * + */ + public boolean autoPrefixMode() { + assert (isOwningHandle()); + return autoPrefixMode(nativeHandle_); + } + + /** + * When true, by default use total_order_seek = true, and RocksDB can + * selectively enable prefix seek mode if won't generate a different result + * from total_order_seek, based on seek key, and iterator upper bound. + * Not supported in ROCKSDB_LITE mode, in the way that even with value true + * prefix mode is not used. + * Default: false + * @param mode auto prefix mode + * @return the reference to the current ReadOptions. + */ + public ReadOptions setAutoPrefixMode(final boolean mode) { + assert (isOwningHandle()); + setAutoPrefixMode(nativeHandle_, mode); + return this; + } + + /** + * Timestamp of operation. Read should return the latest data visible to the + * specified timestamp. All timestamps of the same database must be of the + * same length and format. The user is responsible for providing a customized + * compare function via Comparator to order >key, timestamp> tuples. + * For iterator, iter_start_ts is the lower bound (older) and timestamp + * serves as the upper bound. Versions of the same record that fall in + * the timestamp range will be returned. If iter_start_ts is nullptr, + * only the most recent version visible to timestamp is returned. + * The user-specified timestamp feature is still under active development, + * and the API is subject to change. + * + * Default: null + * @see #iterStartTs() + * @return Reference to timestamp or null if there is no timestamp defined. + */ + public Slice timestamp() { + assert (isOwningHandle()); + final long timestampSliceHandle = timestamp(nativeHandle_); + if (timestampSliceHandle != 0) { + return new Slice(timestampSliceHandle); + } else { + return null; + } + } + + /** + * Timestamp of operation. Read should return the latest data visible to the + * specified timestamp. All timestamps of the same database must be of the + * same length and format. The user is responsible for providing a customized + * compare function via Comparator to order {@code } tuples. + * For iterator, {@code iter_start_ts} is the lower bound (older) and timestamp + * serves as the upper bound. Versions of the same record that fall in + * the timestamp range will be returned. If iter_start_ts is nullptr, + * only the most recent version visible to timestamp is returned. + * The user-specified timestamp feature is still under active development, + * and the API is subject to change. + * + * Default: null + * @see #setIterStartTs(AbstractSlice) + * @param timestamp Slice representing the timestamp + * @return the reference to the current ReadOptions. + */ + public ReadOptions setTimestamp(final AbstractSlice timestamp) { + assert (isOwningHandle()); + setTimestamp(nativeHandle_, timestamp == null ? 0 : timestamp.getNativeHandle()); + timestampSlice_ = timestamp; + return this; + } + + /** + * Timestamp of operation. Read should return the latest data visible to the + * specified timestamp. All timestamps of the same database must be of the + * same length and format. The user is responsible for providing a customized + * compare function via Comparator to order {@code } tuples. + * For iterator, {@code iter_start_ts} is the lower bound (older) and timestamp + * serves as the upper bound. Versions of the same record that fall in + * the timestamp range will be returned. If iter_start_ts is nullptr, + * only the most recent version visible to timestamp is returned. + * The user-specified timestamp feature is still under active development, + * and the API is subject to change. + * + * Default: null + * @return Reference to lower bound timestamp or null if there is no lower bound timestamp + * defined. + */ + public Slice iterStartTs() { + assert (isOwningHandle()); + final long iterStartTsHandle = iterStartTs(nativeHandle_); + if (iterStartTsHandle != 0) { + return new Slice(iterStartTsHandle); + } else { + return null; + } + } + + /** + * Timestamp of operation. Read should return the latest data visible to the + * specified timestamp. All timestamps of the same database must be of the + * same length and format. The user is responsible for providing a customized + * compare function via Comparator to order {@code } tuples. + * For iterator, {@code iter_start_ts} is the lower bound (older) and timestamp + * serves as the upper bound. Versions of the same record that fall in + * the timestamp range will be returned. If iter_start_ts is nullptr, + * only the most recent version visible to timestamp is returned. + * The user-specified timestamp feature is still under active development, + * and the API is subject to change. + * + * Default: null + * + * @param iterStartTs Reference to lower bound timestamp or null if there is no lower bound + * timestamp defined + * @return the reference to the current ReadOptions. + */ + public ReadOptions setIterStartTs(final AbstractSlice iterStartTs) { + assert (isOwningHandle()); + setIterStartTs(nativeHandle_, iterStartTs == null ? 0 : iterStartTs.getNativeHandle()); + iterStartTs_ = iterStartTs; + return this; + } + + /** + * Deadline for completing an API call (Get/MultiGet/Seek/Next for now) + * in microseconds. + * It should be set to microseconds since epoch, i.e, {@code gettimeofday} or + * equivalent plus allowed duration in microseconds. The best way is to use + * {@code env->NowMicros() + some timeout}. + * This is best efforts. The call may exceed the deadline if there is IO + * involved and the file system doesn't support deadlines, or due to + * checking for deadline periodically rather than for every key if + * processing a batch + * + * @return deadline time in microseconds + */ + public long deadline() { + assert (isOwningHandle()); + return deadline(nativeHandle_); + } + + /** + * Deadline for completing an API call (Get/MultiGet/Seek/Next for now) + * in microseconds. + * It should be set to microseconds since epoch, i.e, {@code gettimeofday} or + * equivalent plus allowed duration in microseconds. The best way is to use + * {@code env->NowMicros() + some timeout}. + * This is best efforts. The call may exceed the deadline if there is IO + * involved and the file system doesn't support deadlines, or due to + * checking for deadline periodically rather than for every key if + * processing a batch + * + * @param deadlineTime deadline time in microseconds. + * @return the reference to the current ReadOptions. + */ + public ReadOptions setDeadline(final long deadlineTime) { + assert (isOwningHandle()); + setDeadline(nativeHandle_, deadlineTime); + return this; + } + + /** + * A timeout in microseconds to be passed to the underlying FileSystem for + * reads. As opposed to deadline, this determines the timeout for each + * individual file read request. If a MultiGet/Get/Seek/Next etc call + * results in multiple reads, each read can last up to io_timeout us. + * @return ioTimeout time in microseconds + */ + public long ioTimeout() { + assert (isOwningHandle()); + return ioTimeout(nativeHandle_); + } + + /** + * A timeout in microseconds to be passed to the underlying FileSystem for + * reads. As opposed to deadline, this determines the timeout for each + * individual file read request. If a MultiGet/Get/Seek/Next etc call + * results in multiple reads, each read can last up to io_timeout us. + * + * @param ioTimeout time in microseconds. + * @return the reference to the current ReadOptions. + */ + public ReadOptions setIoTimeout(final long ioTimeout) { + assert (isOwningHandle()); + setIoTimeout(nativeHandle_, ioTimeout); + return this; + } + + /** + * It limits the maximum cumulative value size of the keys in batch while + * reading through MultiGet. Once the cumulative value size exceeds this + * soft limit then all the remaining keys are returned with status Aborted. + * + * Default: {@code std::numeric_limits::max()} + * @return actual valueSizeSofLimit + */ + public long valueSizeSoftLimit() { + assert (isOwningHandle()); + return valueSizeSoftLimit(nativeHandle_); + } + + /** + * It limits the maximum cumulative value size of the keys in batch while + * reading through MultiGet. Once the cumulative value size exceeds this + * soft limit then all the remaining keys are returned with status Aborted. + * + * Default: {@code std::numeric_limits::max()} + * + * @param valueSizeSofLimit + * @return the reference to the current ReadOptions + */ + public ReadOptions setValueSizeSoftLimit(final long valueSizeSofLimit) { + assert (isOwningHandle()); + setValueSizeSoftLimit(nativeHandle_, valueSizeSofLimit); + return this; + } + // instance variables // NOTE: If you add new member variables, please update the copy constructor above! // @@ -570,6 +799,8 @@ public class ReadOptions extends RocksObject { // it's possibly (likely) to be an owning handle. private AbstractSlice iterateLowerBoundSlice_; private AbstractSlice iterateUpperBoundSlice_; + private AbstractSlice timestampSlice_; + private AbstractSlice iterStartTs_; private native static long newReadOptions(); private native static long newReadOptions(final boolean verifyChecksums, @@ -617,4 +848,16 @@ public class ReadOptions extends RocksObject { final long tableFilterHandle); private native void setIterStartSeqnum(final long handle, final long seqNum); private native long iterStartSeqnum(final long handle); + private native boolean autoPrefixMode(final long handle); + private native void setAutoPrefixMode(final long handle, final boolean autoPrefixMode); + private native long timestamp(final long handle); + private native void setTimestamp(final long handle, final long timestampSliceHandle); + private native long iterStartTs(final long handle); + private native void setIterStartTs(final long handle, final long iterStartTsHandle); + private native long deadline(final long handle); + private native void setDeadline(final long handle, final long deadlineTime); + private native long ioTimeout(final long handle); + private native void setIoTimeout(final long handle, final long ioTimeout); + private native long valueSizeSoftLimit(final long handle); + private native void setValueSizeSoftLimit(final long handle, final long softLimit); } diff --git a/java/src/test/java/org/rocksdb/ReadOptionsTest.java b/java/src/test/java/org/rocksdb/ReadOptionsTest.java index 689c48cb0..9565b5c3e 100644 --- a/java/src/test/java/org/rocksdb/ReadOptionsTest.java +++ b/java/src/test/java/org/rocksdb/ReadOptionsTest.java @@ -39,11 +39,15 @@ public class ReadOptionsTest { opt.setFillCache(false); opt.setIterateUpperBound(buildRandomSlice()); opt.setIterateLowerBound(buildRandomSlice()); + opt.setTimestamp(buildRandomSlice()); + opt.setIterStartTs(buildRandomSlice()); try (final ReadOptions other = new ReadOptions(opt)) { assertThat(opt.verifyChecksums()).isEqualTo(other.verifyChecksums()); assertThat(opt.fillCache()).isEqualTo(other.fillCache()); assertThat(Arrays.equals(opt.iterateUpperBound().data(), other.iterateUpperBound().data())).isTrue(); assertThat(Arrays.equals(opt.iterateLowerBound().data(), other.iterateLowerBound().data())).isTrue(); + assertThat(Arrays.equals(opt.timestamp().data(), other.timestamp().data())).isTrue(); + assertThat(Arrays.equals(opt.iterStartTs().data(), other.iterStartTs().data())).isTrue(); } } } @@ -207,6 +211,60 @@ public class ReadOptionsTest { } } + @Test + public void autoPrefixMode() { + try (final ReadOptions opt = new ReadOptions()) { + opt.setAutoPrefixMode(true); + assertThat(opt.autoPrefixMode()).isTrue(); + } + } + + @Test + public void timestamp() { + try (final ReadOptions opt = new ReadOptions()) { + Slice timestamp = buildRandomSlice(); + opt.setTimestamp(timestamp); + assertThat(Arrays.equals(timestamp.data(), opt.timestamp().data())).isTrue(); + opt.setTimestamp(null); + assertThat(opt.timestamp()).isNull(); + } + } + + @Test + public void iterStartTs() { + try (final ReadOptions opt = new ReadOptions()) { + Slice itertStartTsSlice = buildRandomSlice(); + opt.setIterStartTs(itertStartTsSlice); + assertThat(Arrays.equals(itertStartTsSlice.data(), opt.iterStartTs().data())).isTrue(); + opt.setIterStartTs(null); + assertThat(opt.iterStartTs()).isNull(); + } + } + + @Test + public void deadline() { + try (final ReadOptions opt = new ReadOptions()) { + opt.setDeadline(1999l); + assertThat(opt.deadline()).isEqualTo(1999l); + } + } + + @Test + public void ioTimeout() { + try (final ReadOptions opt = new ReadOptions()) { + opt.setIoTimeout(34555l); + assertThat(opt.ioTimeout()).isEqualTo(34555l); + } + } + + @Test + public void valueSizeSoftLimit() { + try (final ReadOptions opt = new ReadOptions()) { + opt.setValueSizeSoftLimit(12134324l); + assertThat(opt.valueSizeSoftLimit()).isEqualTo(12134324l); + } + } + @Test public void failSetVerifyChecksumUninitialized() { try (final ReadOptions readOptions =