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

Java API for Merge Operator v2 #12122

Open
wants to merge 8 commits into
base: main
Choose a base branch
from

Conversation

rhubner
Copy link
Contributor

@rhubner rhubner commented Dec 6, 2023

This is the first implementation of the merge operator API, where merge operators can be implemented in Java without any C++ code. It prefers simplicity and community feedback is appreciated.

Copy link
Contributor

@alanpaxton alanpaxton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few small things to tidy up. Looks good apart from those.

db.merge(KEY, "value2".getBytes());
db.merge(KEY, "value3".getBytes());
byte[] valueFromDb = db.get(KEY);
assertThat(valueFromDb).containsExactly("value2".getBytes(StandardCharsets.UTF_8));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you throw a RuntimeException instead of expecting a value in the code that doesn't get reached ? it's confusing otherwise.

}

/**
* All parameters of this method are valid only during the call. If you want to keep this, you
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"This is the callback method which supplies the values to be merged for the provided key. The parameters are only valid until the method returns, and must be deep copied if you wish to retain them.

The method should return the result of merging the supplied values with the implemented merge algorithm."

Please also comment the individual parameters.

db.merge(KEY, "value2".getBytes());
db.merge(KEY, "value3".getBytes());
byte[] valueFromDb = db.get(KEY);
assertThat(valueFromDb).containsExactly("value2".getBytes(StandardCharsets.UTF_8));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you throw a RuntimeException instead of expecting a value in the code that doesn't get reached ? it's confusing otherwise.

}

@Override
public long nativeHandler() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is already a getNativeHandle() method on RocksCallbackObject and RocksObject. Shouldn't this be getNativeHandle() too ? You may need to fix inheritance a bit ?

package org.rocksdb;

public interface MergeOperator {
long nativeHandler();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above, getNativeHandle()

}

@Override
final public long nativeHandler() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getNativeHandle() ?

char* operator_name = reinterpret_cast<char*>(_operator_name);

auto* jni_merge_operator =
new std::shared_ptr<ROCKSDB_NAMESPACE::MergeOperator>(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this can be std::make_shared(...), which is preferred..

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so. We need to create a new std:pointer which won't be discarded after this method finishes.

if (j_merge_class == nullptr) {
return; // Exception
}
j_merge_class = static_cast<jclass>(env->NewGlobalRef(j_merge_class));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The JNI manual says NewGlobalRef() can return nullptr WITHOUT an exception, e.g. if the system is out of memory. So we should throw a Java exception here. Can you also check the other JNI methods you call, to confirm that they always set an exception on nullptr, and if they don't we should set one in each case.

Then fix the comments to say "XYZException has been thrown", or whatever is appropriate.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I check existing code and we don't throw exceptions when we can't create global references.

@rhubner rhubner force-pushed the eb/merge-operator-v2 branch 3 times, most recently from 80ea516 to b6dc8f8 Compare December 19, 2023 07:42
@rhubner rhubner force-pushed the eb/merge-operator-v2 branch 3 times, most recently from 82606aa to 2b4c318 Compare February 7, 2024 12:26
@rhubner rhubner marked this pull request as ready for review February 7, 2024 13:28
@adamretter adamretter changed the title Java API for merge operator Java API for Merge Operator v2 Feb 7, 2024
This is the first implementation of the merge operator API,
where merge operators can be implemented in Java without any C++ code.
It prefers simplicity and community feedback is appreciated.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants