-
Notifications
You must be signed in to change notification settings - Fork 40
Handle Get and Scan with conjunctions correctly in Consensus Commit #2786
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
Handle Get and Scan with conjunctions correctly in Consensus Commit #2786
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR fixes a bug in handling Get and Scan operations with conjunctions in Consensus Commit by filtering records based on before image conditions. Key changes include updating the read and scan methods to correctly throw exceptions for uncommitted records, introducing optional filtering with conjunctions, and adding logic to convert conjunctions for before image conditions.
Reviewed Changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| core/src/main/java/com/scalar/db/transaction/consensuscommit/CrudHandler.java | Updated read and scan handling with conjunctions and before image conditions |
| core/src/main/java/com/scalar/db/api/LikeExpression.java | Minor documentation and type refinements for text columns |
| core/src/main/java/com/scalar/db/api/ConditionBuilder.java | Added a buildLikeExpression utility method with corresponding documentation |
Comments suppressed due to low confidence (2)
core/src/main/java/com/scalar/db/transaction/consensuscommit/CrudHandler.java:267
- [nitpick] Consider renaming the variable 'ret' to a more descriptive name such as 'filteredResult' to enhance code readability.
Optional<TransactionResult> ret = Optional.of(result);
core/src/main/java/com/scalar/db/transaction/consensuscommit/CrudHandler.java:165
- If 'result' is empty and 'get.getConjunctions()' is not empty, the subsequent call to 'result.get()' in the throw statement will cause a NoSuchElementException. Consider handling the empty result case explicitly without calling 'result.get()'.
if (result.isPresent() || get.getConjunctions().isEmpty()) {
feeblefakie
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall, looking good.
Left one suggestion for the comment.
| * | 0 | 1 | 200 | PREPARED | 1000 | COMMITTED | | ||
| * </pre> | ||
| * | ||
| * If we scan records with the condition `column = 1000`, we will only retrieve the first record, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The description is a bit weird to me.
How about something like below?
If we scan records with the condition "column = 1000" without converting the condition (conjunction), we only get the first record, not the second one, because the condition does not match. However, the second record has not been committed yet, so we should still retrieve it, considering the possibility that the record will be rolled back.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 683337b. Thanks!
feeblefakie
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! Thank you!
|
|
||
| @Test | ||
| public void | ||
| get_WithConjunction_ForCommittedRecordWhoseBeforeImageMatchesConjunction_ShouldNotReturnRecordAfterLazyRecovery() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIUC, the final state is already COMMITTED and no lazy recovery occurs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch! Let me fix it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 6c16dcd. Thanks!
komamitsu
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! 👍
jnmt
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for finding the bug. Overall looks good to me. I just left a confirmation. PTAL!
| if (key != null) { | ||
| putIntoReadSetInSnapshot(key, result); | ||
| } else { | ||
| // Only for a Get with index, the argument `key` is null | ||
|
|
||
| if (result.isPresent()) { | ||
| // Only when we can get the record with the Get with index, we can put it into the read | ||
| // set | ||
| key = new Snapshot.Key(get, result.get()); | ||
| putIntoReadSetInSnapshot(key, result); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Confirmation. The issue we discussed before (unexpected snapshot overwrite) will be resolved in another PR, or am I missing the point?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We will address that issue in another PR. Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it. Thank you!
jnmt
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thank you!
| putIntoReadSetInSnapshot(key, result); | ||
| } | ||
| if (!get.getConjunctions().isEmpty()) { | ||
| // Check if the result matches the conjunctions |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's likely this check exists because we get records based on not only the current image but also before image using OR conditions. We would like to filter the case where the second record is committed in the example of the Javadoc comment. If my understanding is correct, it might be nice to have a comment like this for future readers to easily grasp the reasoning.
| // Check if the result matches the conjunctions | |
| // Because we also get records whose before images match the conjunctions, we need to check if | |
| // the current status of the records actually match the conjunctions. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 4ec25d6. Thanks!
| if (key != null) { | ||
| putIntoReadSetInSnapshot(key, result); | ||
| } else { | ||
| // Only for a Get with index, the argument `key` is null | ||
|
|
||
| if (result.isPresent()) { | ||
| // Only when we can get the record with the Get with index, we can put it into the read | ||
| // set | ||
| key = new Snapshot.Key(get, result.get()); | ||
| putIntoReadSetInSnapshot(key, result); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it. Thank you!
| putIntoReadSetInSnapshot(key, Optional.of(result)); | ||
| Optional<TransactionResult> ret = Optional.of(result); | ||
| if (!scan.getConjunctions().isEmpty()) { | ||
| // Check if the result matches the conjunctions |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto.
| // Check if the result matches the conjunctions | |
| // Because we also get records whose before images match the conjunctions, we need to check if | |
| // the current status of the records actually match the conjunctions. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 4ec25d6. Thanks!
…ecctly-in-consensus-commit
|
@Torch3333 I'll merge this. Please take a look when you have time! |
Description
This PR updates the code to handle
GetandScanwith conjunctions correctly in Consensus Commit.When users specify conjunctions for Get and Scan operations, the same conjunctions also need to be applied to the columns in the before images. The reason is explained in the following Javadoc—please refer to it for details:
https://github.com/scalar-labs/scalardb/pull/2786/files#diff-acc93f1366b03168017001646c7217f7dd1f3c7cbe8a41b6a9a8484dc5ef0905R482-R546
Related issues and/or PRs
N/A
Changes made
Checklist
Additional notes (optional)
N/A
Release notes
Fixed a bug where records could be missed when executing
GetorScanwith conjunctions in Consensus Commit.