Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Replacing byte[] and ByteBuffer compareTo methods with JDK builtins#199

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Conversation

danielcranford
Copy link
Contributor

Resolves#198

@danielcranford
Copy link
ContributorAuthor

Ahh, missed the factArrays.compare(byte[], byte[]) was added in JDK 9. ByteByffer.compareTo() still works.ByteBuffer.wrap(byte[]).compareTo(ByteBuffer.wrap(byte[]) works as an alternative to Arrays.compare though adds allocation cost to the compare

@benalexaubenalexauforce-pushed themaster branch 2 times, most recently from0a78414 toa1162e1CompareDecember 10, 2022 01:29
Copy link

@cgilliardcgilliard left a comment

Choose a reason for hiding this comment

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

Test cases cover these changes.

@benalexau
Copy link
Member

This is a more complicated proposal than it first appears.

The PR modifies two implementations of theBufferProxy.compare(T, T) method. This method provides comparator functionality shouldnull be passed in as the comparator toDbi.iterate(Txn, KeyRange, Comparator). A comparator is needed for theCursorIterator to facilitate its iteration logic.CursorIterator is a relatively uncommonly used API and there is no equivalent in the LMDB native library.

LMDB native code does not call the provided comparator. While a user is free to provide their own Java-side comparator when creating aDbi, most do not given this would impose a significant overhead. The majority of users carefully configure theDbi with the correct flags for their key type and let native code on the LMDB side handle ordering. The JavaDocs forCursorIterable make reference to this:

If iterating over keys stored with {@link DbiFlags#MDB_INTEGERKEY} you must provide a Java comparator when constructing the {@link Dbi} or this class. It is more efficient to use a comparator only with this class, as this avoids LMDB calling back into Java code to perform the integer key comparison.

Where we run into issues is when using anMDB_INTEGERKEY with aCursorIterator. This is because what we need is a Java comparator that will treat buffers containing integer keys in the same manner as LMDB would.ByteBuffer.compareTo(..) delegates toByte.compare(byte, byte) and Java bytes are signed. So we end up with a different order.

There are a few options available, such as better clarifying the requirements in the JavaDocs ofBufferProxy.compare(T, T), requiring the user to instantiate theCursorIterator with an integer-aware comparator, or automatically doing the latter if theDbi is using an integer key. However I am wondering how much of an issue this presently is given the limited occasions these comparators are called and the existing code already handles integers.

@benalexau
Copy link
Member

After thinking about this some more I believe the better approach is to store a mandatoryComparator in theDbi at construction time. If the user does not provide aComparator - which they very rarely would - theBufferProxy can select an optimal implementation based on theDbi flags. So if there are integer keys it would use an approach like the existing code, otherwise it can fall back to a built-in Java method.

Storing aComparator in theDbi is the most natural approach given all keys in theDbi must align with thatComparator for theCursorIterator to function correctly and there is no reason to provide a differentComparator for a particular invocation ofDbi.iterate(Txn, KeyRange, Comparator). Removing theComparator parameter from the iterate method would remove this overloaded variant and potential API usage confusion.

It would be natural to only accept a singleComparator in aDbi and use a boolean flag to denote whether it should be invoked from the LMDB native library side. The majority of the time this would be false for efficiency reasons, with theComparator only used forCursorIterator instances if the user requests one.

The only downside I can presently see to this is it would represent a breaking change by removing the aforementioned method and some minor variations to theEnv.openDbi(...) methods. Nevertheless it would allow more efficientComparators and a more concise and clearerDbi API. It's worth doing this but I will need to defer it until 0.9.0 to comply with semantic versioning expectations.

I'll leave this PR open as a reminder to address this when preparing 0.9.0.

benalexau added a commit that referenced this pull requestFeb 4, 2023
benalexau added a commit that referenced this pull requestFeb 4, 2023
benalexau added a commit that referenced this pull requestFeb 4, 2023
@benalexau
Copy link
Member

Following the release of 0.8.3 I switched the target development version to 0.9.0 and implemented my prior comment. The main changes are:

  • A defaultComparator is provided by eachBufferProxy (just as it always has been)
  • A singleComparator must be associated with eachDbi when that database is opened
  • There is no longer support for a differentComparator when creating aCursorIterator
  • Clearer JavaDocs about how theComparator is used
  • ByteBufferProxy detects ifDbiFlags includesMDB_INTEGERKEY and uses the same custom logic as it always has (otherwise it uses theByteBuffer.compare(..) method)
  • Various internals have been cleaned up (egTxn no longer exposes theBufferProxy etc)

I decided against making otherBufferProxy implementations (egByteArrayProxy) similarly differentiate between the existing customComparators and any inbuilt alternatives. In the case of Netty, we are already delegating to itscompareTo method. In the case ofbyte[]s, the previously-mentioned absence ofArrays.compare(byte[], byte[]) in Java 8, plus the allocation costs of delegating through toByteBuffers, would likely exceed any performance gain. If it is ultimately required it is easy enough to implement without further API changes, and/or for end users to provide their ownBufferProxy implementation.

Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers

@cgilliardcgilliardcgilliard approved these changes

Assignees
No one assigned
Labels
None yet
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

ByteBufferProxy and ByteArrayProxy are using hand rolled compareTo implementations
3 participants
@danielcranford@benalexau@cgilliard

[8]ページ先頭

©2009-2025 Movatter.jp