Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JNI support for ReadOptions::iterate_lower_bound #4444

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions java/rocksjni/options.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6525,6 +6525,31 @@ jlong Java_org_rocksdb_ReadOptions_iterateUpperBound(JNIEnv* /*env*/,
return reinterpret_cast<jlong>(upper_bound_slice_handle);
}

/*
* Class: org_rocksdb_ReadOptions
* Method: setIterateLowerBound
* Signature: (JJ)I
*/
void Java_org_rocksdb_ReadOptions_setIterateLowerBound(
JNIEnv* /*env*/, jobject /*jobj*/, jlong jhandle,
jlong jlower_bound_slice_handle) {
reinterpret_cast<rocksdb::ReadOptions*>(jhandle)->iterate_lower_bound =
reinterpret_cast<rocksdb::Slice*>(jlower_bound_slice_handle);
}

/*
* Class: org_rocksdb_ReadOptions
* Method: iterateLowerBound
* Signature: (J)J
*/
jlong Java_org_rocksdb_ReadOptions_iterateLowerBound(JNIEnv* /*env*/,
jobject /*jobj*/,
jlong jhandle) {
auto& lower_bound_slice_handle =
reinterpret_cast<rocksdb::ReadOptions*>(jhandle)->iterate_lower_bound;
return reinterpret_cast<jlong>(lower_bound_slice_handle);
}

/////////////////////////////////////////////////////////////////////
// rocksdb::ComparatorOptions

Expand Down
58 changes: 56 additions & 2 deletions java/src/main/java/org/rocksdb/ReadOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public ReadOptions() {
public ReadOptions(ReadOptions other) {
super(copyReadOptions(other.nativeHandle_));
iterateUpperBoundSlice_ = other.iterateUpperBoundSlice_;
iterateLowerBoundSlice_ = other.iterateLowerBoundSlice_;
}

/**
Expand Down Expand Up @@ -423,15 +424,65 @@ public Slice iterateUpperBound() {
return null;
}

/**
* Defines the smallest key at which the backward iterator can return an
* entry. Once the bound is passed, Valid() will be false.
* `iterate_lower_bound` is inclusive ie the bound value is a valid entry.
*
* If prefix_extractor is not null, the Seek target and `iterate_lower_bound`
* need to have the same prefix. This is because ordering is not guaranteed
* outside of prefix domain.
*
* Default: nullptr
*
* @param iterateLowerBound Slice representing the lower bound
* @return the reference to the current ReadOptions.
*/
public ReadOptions setIterateLowerBound(final Slice iterateLowerBound) {
assert(isOwningHandle());
if (iterateLowerBound != null) {
// Hold onto a reference so it doesn't get garbaged collected out from under us.
iterateLowerBoundSlice_ = iterateLowerBound;
setIterateLowerBound(nativeHandle_, iterateLowerBoundSlice_.getNativeHandle());
}
return this;
}

/**
* Defines the smallest key at which the backward iterator can return an
* entry. Once the bound is passed, Valid() will be false.
* `iterate_lower_bound` is inclusive ie the bound value is a valid entry.
*
* If prefix_extractor is not null, the Seek target and `iterate_lower_bound`
* need to have the same prefix. This is because ordering is not guaranteed
* outside of prefix domain.
*
* Default: nullptr
*
* @return Slice representing current iterate_lower_bound setting, or null if
* one does not exist.
*/
public Slice iterateLowerBound() {
assert(isOwningHandle());
long lowerBoundSliceHandle = iterateLowerBound(nativeHandle_);
if (lowerBoundSliceHandle != 0) {
// Disown the new slice - it's owned by the C++ side of the JNI boundary
// from the perspective of this method.
return new Slice(lowerBoundSliceHandle, false);
}
return null;
}

// instance variables
// NOTE: If you add new member variables, please update the copy constructor above!
//
// Hold a reference to any iterate upper bound that was set on this object
// until we're destroyed or it's overwritten. That way the caller can freely
// Hold a reference to any iterate upper/lower bound that was set on this object
// until we're destroyed or it's overwritten. That way the caller can freely
// leave scope without us losing the Java Slice object, which during close()
// would also reap its associated rocksdb::Slice native object since it's
// possibly (likely) to be an owning handle.
protected Slice iterateUpperBoundSlice_;
protected Slice iterateLowerBoundSlice_;

private native static long newReadOptions();
private native static long copyReadOptions(long handle);
Expand Down Expand Up @@ -465,6 +516,9 @@ private native void setIgnoreRangeDeletions(final long handle,
private native void setIterateUpperBound(final long handle,
final long upperBoundSliceHandle);
private native long iterateUpperBound(final long handle);
private native void setIterateLowerBound(final long handle,
final long upperBoundSliceHandle);
private native long iterateLowerBound(final long handle);

@Override protected final native void disposeInternal(final long handle);

Expand Down
34 changes: 34 additions & 0 deletions java/src/test/java/org/rocksdb/ReadOptionsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -144,16 +144,34 @@ public void iterateUpperBoundNull() {
}
}

@Test
public void iterateLowerBound() {
try (final ReadOptions opt = new ReadOptions()) {
Slice lowerBound = buildRandomSlice();
opt.setIterateLowerBound(lowerBound);
assertThat(Arrays.equals(lowerBound.data(), opt.iterateLowerBound().data())).isTrue();
}
}

@Test
public void iterateLowerBoundNull() {
try (final ReadOptions opt = new ReadOptions()) {
assertThat(opt.iterateLowerBound()).isNull();
}
}

@Test
public void copyConstructor() {
moozzyk marked this conversation as resolved.
Show resolved Hide resolved
try (final ReadOptions opt = new ReadOptions()) {
opt.setVerifyChecksums(false);
opt.setFillCache(false);
opt.setIterateUpperBound(buildRandomSlice());
opt.setIterateLowerBound(buildRandomSlice());
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();
}
}

Expand Down Expand Up @@ -237,6 +255,22 @@ public void failIterateUpperBoundUninitialized() {
}
}

@Test
public void failSetIterateLowerBoundUninitialized() {
try (final ReadOptions readOptions =
setupUninitializedReadOptions(exception)) {
readOptions.setIterateLowerBound(null);
}
}

@Test
public void failIterateLowerBoundUninitialized() {
try (final ReadOptions readOptions =
setupUninitializedReadOptions(exception)) {
readOptions.iterateLowerBound();
}
}

private ReadOptions setupUninitializedReadOptions(
ExpectedException exception) {
final ReadOptions readOptions = new ReadOptions();
Expand Down