From 93e0715fad881f9abfc0b0430a6ee136fd4c965c Mon Sep 17 00:00:00 2001 From: Alan Paxton Date: Wed, 24 May 2023 11:04:46 -0700 Subject: [PATCH] Implement missing compactrangeoptions from Java API (#10880) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: Add the following missing options to `src/main/java/org/rocksdb/CompactRangeOptions.java` and in `java/rocksjni/options.cc` in RocksJava. For the descriptions and API see the C++ file `include/rocksdb/options.h`, specifically the struct `CompactRangeOptions` * full_history_ts_low * canceled We changed the handle to return an object (of class `Java_org_rocksdb_CompactRangeOptions`) containing a `ROCKSDB_NAMESPACE::CompactRangeOptions` at (almost certainly) 0-offset, rather than a raw `ROCKSDB_NAMESPACE::CompactRangeOptions`. The `Java_org_rocksdb_CompactRangeOptions` contains as supplementary fields objects (std::string, std::atomic) which are passed as pointers to the `ROCKSDB_NAMESPACE::CompactRangeOptions` and which must therefore live for as long as the `ROCKSDB_NAMESPACE::CompactRangeOptions`. By placing them in a `Java_org_rocksdb_CompactRangeOptions` we achieve this. Because the field offset of the `ROCKSDB_NAMESPACE::CompactRangeOptions` member is (very probably) 0, casting the handle to ROCKSDB_NAMESPACE::CompactRangeOptions works (i.e. old methods didn’t have to be changed), but really that’s a minefield and the correct answer is to cast to the correct type (Java_org_rocksdb_CompactRangeOptions) and then use the ROCKSDB_NAMESPACE::CompactRangeOptions field in that. So the get/set methods for existing parameters have this change. Testing ------- We added unit tests for getting and setting the newly implemented fields to `CompactRangeOptionsTest` Pull Request resolved: https://github.com/facebook/rocksdb/pull/10880 Reviewed By: ajkr Differential Revision: D41482476 Pulled By: anand1976 fbshipit-source-id: c70795e790436fb3544655920adf6fca62ed34e2 --- java/rocksjni/compact_range_options.cc | 178 +++++++++++++++--- java/rocksjni/portal.h | 23 +++ .../java/org/rocksdb/CompactRangeOptions.java | 59 ++++++ .../org/rocksdb/CompactRangeOptionsTest.java | 36 ++++ 4 files changed, 265 insertions(+), 31 deletions(-) diff --git a/java/rocksjni/compact_range_options.cc b/java/rocksjni/compact_range_options.cc index 77fbb8890..d07263ab6 100644 --- a/java/rocksjni/compact_range_options.cc +++ b/java/rocksjni/compact_range_options.cc @@ -12,6 +12,56 @@ #include "rocksdb/options.h" #include "rocksjni/cplusplus_to_java_convert.h" #include "rocksjni/portal.h" +#include "util/coding.h" + +/** + * @brief Class containing compact range options for Java API + * + * An object of this class is returned as the native handle for + * ROCKSDB_NAMESPACE::CompactRangeOptions It contains objects for various + * parameters which are passed by reference/pointer in CompactRangeOptions. We + * maintain the lifetime of these parameters (`full_history_ts_low`, `canceled`) + * by including their values in this class. + */ +class Java_org_rocksdb_CompactRangeOptions { + public: + ROCKSDB_NAMESPACE::CompactRangeOptions compactRangeOptions; + + private: + std::string full_history_ts_low; + std::atomic canceled; + + public: + void set_full_history_ts_low(uint64_t start, uint64_t range) { + full_history_ts_low = ""; + ROCKSDB_NAMESPACE::PutFixed64(&full_history_ts_low, start); + ROCKSDB_NAMESPACE::PutFixed64(&full_history_ts_low, range); + compactRangeOptions.full_history_ts_low = + new ROCKSDB_NAMESPACE::Slice(full_history_ts_low); + } + + bool read_full_history_ts_low(uint64_t* start, uint64_t* range) { + if (compactRangeOptions.full_history_ts_low == nullptr) return false; + ROCKSDB_NAMESPACE::Slice read_slice( + compactRangeOptions.full_history_ts_low->ToStringView()); + if (!ROCKSDB_NAMESPACE::GetFixed64(&read_slice, start)) return false; + return ROCKSDB_NAMESPACE::GetFixed64(&read_slice, range); + } + + void set_canceled(bool value) { + if (compactRangeOptions.canceled == nullptr) { + canceled.store(value, std::memory_order_seq_cst); + compactRangeOptions.canceled = &canceled; + } else { + compactRangeOptions.canceled->store(value, std::memory_order_seq_cst); + } + } + + bool get_canceled() { + return compactRangeOptions.canceled && + compactRangeOptions.canceled->load(std::memory_order_seq_cst); + } +}; /* * Class: org_rocksdb_CompactRangeOptions @@ -20,8 +70,8 @@ */ jlong Java_org_rocksdb_CompactRangeOptions_newCompactRangeOptions( JNIEnv* /*env*/, jclass /*jclazz*/) { - auto* options = new ROCKSDB_NAMESPACE::CompactRangeOptions(); - return GET_CPLUSPLUS_POINTER(options); + auto* options = new Java_org_rocksdb_CompactRangeOptions(); + return GET_CPLUSPLUS_POINTER(&options->compactRangeOptions); } /* @@ -32,8 +82,9 @@ jlong Java_org_rocksdb_CompactRangeOptions_newCompactRangeOptions( jboolean Java_org_rocksdb_CompactRangeOptions_exclusiveManualCompaction( JNIEnv* /*env*/, jobject /*jobj*/, jlong jhandle) { auto* options = - reinterpret_cast(jhandle); - return static_cast(options->exclusive_manual_compaction); + reinterpret_cast(jhandle); + return static_cast( + options->compactRangeOptions.exclusive_manual_compaction); } /* @@ -45,8 +96,8 @@ void Java_org_rocksdb_CompactRangeOptions_setExclusiveManualCompaction( JNIEnv* /*env*/, jobject /*jobj*/, jlong jhandle, jboolean exclusive_manual_compaction) { auto* options = - reinterpret_cast(jhandle); - options->exclusive_manual_compaction = + reinterpret_cast(jhandle); + options->compactRangeOptions.exclusive_manual_compaction = static_cast(exclusive_manual_compaction); } @@ -58,9 +109,10 @@ void Java_org_rocksdb_CompactRangeOptions_setExclusiveManualCompaction( jint Java_org_rocksdb_CompactRangeOptions_bottommostLevelCompaction( JNIEnv* /*env*/, jobject /*jobj*/, jlong jhandle) { auto* options = - reinterpret_cast(jhandle); + reinterpret_cast(jhandle); return ROCKSDB_NAMESPACE::BottommostLevelCompactionJni:: - toJavaBottommostLevelCompaction(options->bottommost_level_compaction); + toJavaBottommostLevelCompaction( + options->compactRangeOptions.bottommost_level_compaction); } /* @@ -72,8 +124,8 @@ void Java_org_rocksdb_CompactRangeOptions_setBottommostLevelCompaction( JNIEnv* /*env*/, jobject /*jobj*/, jlong jhandle, jint bottommost_level_compaction) { auto* options = - reinterpret_cast(jhandle); - options->bottommost_level_compaction = + reinterpret_cast(jhandle); + options->compactRangeOptions.bottommost_level_compaction = ROCKSDB_NAMESPACE::BottommostLevelCompactionJni:: toCppBottommostLevelCompaction(bottommost_level_compaction); } @@ -87,8 +139,8 @@ jboolean Java_org_rocksdb_CompactRangeOptions_changeLevel(JNIEnv* /*env*/, jobject /*jobj*/, jlong jhandle) { auto* options = - reinterpret_cast(jhandle); - return static_cast(options->change_level); + reinterpret_cast(jhandle); + return static_cast(options->compactRangeOptions.change_level); } /* @@ -99,8 +151,8 @@ jboolean Java_org_rocksdb_CompactRangeOptions_changeLevel(JNIEnv* /*env*/, void Java_org_rocksdb_CompactRangeOptions_setChangeLevel( JNIEnv* /*env*/, jobject /*jobj*/, jlong jhandle, jboolean change_level) { auto* options = - reinterpret_cast(jhandle); - options->change_level = static_cast(change_level); + reinterpret_cast(jhandle); + options->compactRangeOptions.change_level = static_cast(change_level); } /* @@ -112,8 +164,8 @@ jint Java_org_rocksdb_CompactRangeOptions_targetLevel(JNIEnv* /*env*/, jobject /*jobj*/, jlong jhandle) { auto* options = - reinterpret_cast(jhandle); - return static_cast(options->target_level); + reinterpret_cast(jhandle); + return static_cast(options->compactRangeOptions.target_level); } /* @@ -126,8 +178,8 @@ void Java_org_rocksdb_CompactRangeOptions_setTargetLevel(JNIEnv* /*env*/, jlong jhandle, jint target_level) { auto* options = - reinterpret_cast(jhandle); - options->target_level = static_cast(target_level); + reinterpret_cast(jhandle); + options->compactRangeOptions.target_level = static_cast(target_level); } /* @@ -139,8 +191,8 @@ jint Java_org_rocksdb_CompactRangeOptions_targetPathId(JNIEnv* /*env*/, jobject /*jobj*/, jlong jhandle) { auto* options = - reinterpret_cast(jhandle); - return static_cast(options->target_path_id); + reinterpret_cast(jhandle); + return static_cast(options->compactRangeOptions.target_path_id); } /* @@ -153,8 +205,9 @@ void Java_org_rocksdb_CompactRangeOptions_setTargetPathId(JNIEnv* /*env*/, jlong jhandle, jint target_path_id) { auto* options = - reinterpret_cast(jhandle); - options->target_path_id = static_cast(target_path_id); + reinterpret_cast(jhandle); + options->compactRangeOptions.target_path_id = + static_cast(target_path_id); } /* @@ -166,8 +219,8 @@ jboolean Java_org_rocksdb_CompactRangeOptions_allowWriteStall(JNIEnv* /*env*/, jobject /*jobj*/, jlong jhandle) { auto* options = - reinterpret_cast(jhandle); - return static_cast(options->allow_write_stall); + reinterpret_cast(jhandle); + return static_cast(options->compactRangeOptions.allow_write_stall); } /* @@ -179,8 +232,9 @@ void Java_org_rocksdb_CompactRangeOptions_setAllowWriteStall( JNIEnv* /*env*/, jobject /*jobj*/, jlong jhandle, jboolean allow_write_stall) { auto* options = - reinterpret_cast(jhandle); - options->allow_write_stall = static_cast(allow_write_stall); + reinterpret_cast(jhandle); + options->compactRangeOptions.allow_write_stall = + static_cast(allow_write_stall); } /* @@ -192,8 +246,8 @@ jint Java_org_rocksdb_CompactRangeOptions_maxSubcompactions(JNIEnv* /*env*/, jobject /*jobj*/, jlong jhandle) { auto* options = - reinterpret_cast(jhandle); - return static_cast(options->max_subcompactions); + reinterpret_cast(jhandle); + return static_cast(options->compactRangeOptions.max_subcompactions); } /* @@ -204,8 +258,70 @@ jint Java_org_rocksdb_CompactRangeOptions_maxSubcompactions(JNIEnv* /*env*/, void Java_org_rocksdb_CompactRangeOptions_setMaxSubcompactions( JNIEnv* /*env*/, jobject /*jobj*/, jlong jhandle, jint max_subcompactions) { auto* options = - reinterpret_cast(jhandle); - options->max_subcompactions = static_cast(max_subcompactions); + reinterpret_cast(jhandle); + options->compactRangeOptions.max_subcompactions = + static_cast(max_subcompactions); +} + +/* + * Class: org_rocksdb_CompactRangeOptions + * Method: setFullHistoryTSLow + * Signature: (JJJ)V + */ +void Java_org_rocksdb_CompactRangeOptions_setFullHistoryTSLow(JNIEnv*, jobject, + jlong jhandle, + jlong start, + jlong range) { + auto* options = + reinterpret_cast(jhandle); + options->set_full_history_ts_low(start, range); +} + +/* + * Class: org_rocksdb_CompactRangeOptions + * Method: fullHistoryTSLow + * Signature: (J)Lorg/rocksdb/CompactRangeOptions/Timestamp; + */ +jobject Java_org_rocksdb_CompactRangeOptions_fullHistoryTSLow(JNIEnv* env, + jobject, + jlong jhandle) { + auto* options = + reinterpret_cast(jhandle); + uint64_t start; + uint64_t range; + jobject result = nullptr; + if (options->read_full_history_ts_low(&start, &range)) { + result = + ROCKSDB_NAMESPACE::CompactRangeOptionsTimestampJni::fromCppTimestamp( + env, start, range); + } + + return result; +} + +/* + * Class: org_rocksdb_CompactRangeOptions + * Method: setCanceled + * Signature: (JZ)V + */ +void Java_org_rocksdb_CompactRangeOptions_setCanceled(JNIEnv*, jobject, + jlong jhandle, + jboolean jcanceled) { + auto* options = + reinterpret_cast(jhandle); + options->set_canceled(jcanceled); +} + +/* + * Class: org_rocksdb_CompactRangeOptions + * Method: canceled + * Signature: (J)Z + */ +jboolean Java_org_rocksdb_CompactRangeOptions_canceled(JNIEnv*, jobject, + jlong jhandle) { + auto* options = + reinterpret_cast(jhandle); + return options->get_canceled(); } /* @@ -217,6 +333,6 @@ void Java_org_rocksdb_CompactRangeOptions_disposeInternal(JNIEnv* /*env*/, jobject /*jobj*/, jlong jhandle) { auto* options = - reinterpret_cast(jhandle); + reinterpret_cast(jhandle); delete options; } diff --git a/java/rocksjni/portal.h b/java/rocksjni/portal.h index aa0cc6131..f75e002b8 100644 --- a/java/rocksjni/portal.h +++ b/java/rocksjni/portal.h @@ -8702,5 +8702,28 @@ class FileOperationInfoJni : public JavaClass { "(Ljava/lang/String;JJJJLorg/rocksdb/Status;)V"); } }; + +class CompactRangeOptionsTimestampJni : public JavaClass { + public: + static jobject fromCppTimestamp(JNIEnv* env, const uint64_t start, + const uint64_t range) { + jclass jclazz = getJClass(env); + assert(jclazz != nullptr); + static jmethodID ctor = getConstructorMethodId(env, jclazz); + assert(ctor != nullptr); + return env->NewObject(jclazz, ctor, static_cast(start), + static_cast(range)); + } + + static jclass getJClass(JNIEnv* env) { + return JavaClass::getJClass(env, + "org/rocksdb/CompactRangeOptions$Timestamp"); + } + + static jmethodID getConstructorMethodId(JNIEnv* env, jclass clazz) { + return env->GetMethodID(clazz, "", "(JJ)V"); + } +}; + } // namespace ROCKSDB_NAMESPACE #endif // JAVA_ROCKSJNI_PORTAL_H_ diff --git a/java/src/main/java/org/rocksdb/CompactRangeOptions.java b/java/src/main/java/org/rocksdb/CompactRangeOptions.java index 62559b34f..616a77572 100644 --- a/java/src/main/java/org/rocksdb/CompactRangeOptions.java +++ b/java/src/main/java/org/rocksdb/CompactRangeOptions.java @@ -5,6 +5,8 @@ package org.rocksdb; +import java.util.Objects; + /** * CompactRangeOptions is used by CompactRange() call. In the documentation of the methods "the compaction" refers to * any compaction that is using this CompactRangeOptions. @@ -69,6 +71,36 @@ public class CompactRangeOptions extends RocksObject { } } + public static class Timestamp { + public final long start; + public final long range; + + public Timestamp(final long start, final long duration) { + this.start = start; + this.range = duration; + } + + public Timestamp() { + this.start = 0; + this.range = 0; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + Timestamp timestamp = (Timestamp) o; + return start == timestamp.start && range == timestamp.range; + } + + @Override + public int hashCode() { + return Objects.hash(start, range); + } + } + /** * Construct CompactRangeOptions. */ @@ -218,6 +250,24 @@ public class CompactRangeOptions extends RocksObject { return this; } + public CompactRangeOptions setFullHistoryTSLow(final Timestamp tsLow) { + setFullHistoryTSLow(nativeHandle_, tsLow.start, tsLow.range); + return this; + } + + public Timestamp fullHistoryTSLow() { + return fullHistoryTSLow(nativeHandle_); + } + + public CompactRangeOptions setCanceled(final boolean canceled) { + setCanceled(nativeHandle_, canceled); + return this; + } + + public boolean canceled() { + return canceled(nativeHandle_); + } + private static native long newCompactRangeOptions(); @Override protected final native void disposeInternal(final long handle); @@ -242,4 +292,13 @@ public class CompactRangeOptions extends RocksObject { private native void setMaxSubcompactions(final long handle, final int maxSubcompactions); private native int maxSubcompactions(final long handle); + + private native void setFullHistoryTSLow( + final long handle, final long timestampStart, final long timestampRange); + + private native Timestamp fullHistoryTSLow(final long handle); + + private native void setCanceled(final long handle, final boolean canceled); + + private native boolean canceled(final long handle); } diff --git a/java/src/test/java/org/rocksdb/CompactRangeOptionsTest.java b/java/src/test/java/org/rocksdb/CompactRangeOptionsTest.java index 4440d0a71..549b74beb 100644 --- a/java/src/test/java/org/rocksdb/CompactRangeOptionsTest.java +++ b/java/src/test/java/org/rocksdb/CompactRangeOptionsTest.java @@ -99,4 +99,40 @@ public class CompactRangeOptionsTest { assertThat(opt.maxSubcompactions()).isEqualTo(value); } } + + @Test + public void fullHistoryTSLow() { + CompactRangeOptions opt = new CompactRangeOptions(); + CompactRangeOptions.Timestamp timestamp = new CompactRangeOptions.Timestamp(18, 1); + opt.setFullHistoryTSLow(timestamp); + + for (int times = 1; times <= 2; times++) { + // worried slightly about destructive reads, so read it twice + CompactRangeOptions.Timestamp timestampResult = opt.fullHistoryTSLow(); + assertThat(timestamp.start).isEqualTo(timestampResult.start); + assertThat(timestamp.range).isEqualTo(timestampResult.range); + assertThat(timestamp).isEqualTo(timestampResult); + } + } + + @Test + public void fullHistoryTSLowDefault() { + CompactRangeOptions opt = new CompactRangeOptions(); + CompactRangeOptions.Timestamp timestampResult = opt.fullHistoryTSLow(); + assertThat(timestampResult).isNull(); + } + + @Test + public void canceled() { + CompactRangeOptions opt = new CompactRangeOptions(); + assertThat(opt.canceled()).isEqualTo(false); + opt.setCanceled(true); + assertThat(opt.canceled()).isEqualTo(true); + opt.setCanceled(false); + assertThat(opt.canceled()).isEqualTo(false); + opt.setCanceled(true); + assertThat(opt.canceled()).isEqualTo(true); + opt.setCanceled(true); + assertThat(opt.canceled()).isEqualTo(true); + } }