-
Notifications
You must be signed in to change notification settings - Fork 44
Collation 3/4: follow the collation in Consensus Commit layer #3844
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -4,6 +4,7 @@ | |||||||||||||||||||||
|
|
||||||||||||||||||||||
| import com.google.common.annotations.VisibleForTesting; | ||||||||||||||||||||||
| import com.scalar.db.api.ConditionalExpression; | ||||||||||||||||||||||
| import com.scalar.db.api.ConditionalExpression.Operator; | ||||||||||||||||||||||
| import com.scalar.db.api.Delete; | ||||||||||||||||||||||
| import com.scalar.db.api.DeleteIf; | ||||||||||||||||||||||
| import com.scalar.db.api.DeleteIfExists; | ||||||||||||||||||||||
|
|
@@ -26,6 +27,7 @@ | |||||||||||||||||||||
| import com.scalar.db.common.VirtualTableInfoManager; | ||||||||||||||||||||||
| import com.scalar.db.common.checker.ConditionChecker; | ||||||||||||||||||||||
| import com.scalar.db.exception.storage.ExecutionException; | ||||||||||||||||||||||
| import com.scalar.db.io.Collation; | ||||||||||||||||||||||
| import com.scalar.db.util.ScalarDbUtils; | ||||||||||||||||||||||
| import javax.annotation.concurrent.ThreadSafe; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
|
|
@@ -36,16 +38,35 @@ public class ConsensusCommitOperationChecker { | |||||||||||||||||||||
| private final VirtualTableInfoManager virtualTableInfoManager; | ||||||||||||||||||||||
| private final StorageInfoProvider storageInfoProvider; | ||||||||||||||||||||||
| private final boolean isIncludeMetadataEnabled; | ||||||||||||||||||||||
| private final Collation collation; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| public ConsensusCommitOperationChecker( | ||||||||||||||||||||||
| TransactionTableMetadataManager transactionTableMetadataManager, | ||||||||||||||||||||||
| VirtualTableInfoManager virtualTableInfoManager, | ||||||||||||||||||||||
| StorageInfoProvider storageInfoProvider, | ||||||||||||||||||||||
| boolean isIncludeMetadataEnabled) { | ||||||||||||||||||||||
| boolean isIncludeMetadataEnabled, | ||||||||||||||||||||||
| Collation collation) { | ||||||||||||||||||||||
| this.transactionTableMetadataManager = transactionTableMetadataManager; | ||||||||||||||||||||||
| this.virtualTableInfoManager = virtualTableInfoManager; | ||||||||||||||||||||||
| this.storageInfoProvider = storageInfoProvider; | ||||||||||||||||||||||
| this.isIncludeMetadataEnabled = isIncludeMetadataEnabled; | ||||||||||||||||||||||
| this.collation = collation; | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| private void throwIfLikeConditionUnderIcuCollation(Selection selection) { | ||||||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: The other private helpers in this class, including |
||||||||||||||||||||||
| if (collation != Collation.ICU) { | ||||||||||||||||||||||
| return; | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| for (Selection.Conjunction conjunction : selection.getConjunctions()) { | ||||||||||||||||||||||
| for (ConditionalExpression condition : conjunction.getConditions()) { | ||||||||||||||||||||||
| Operator operator = condition.getOperator(); | ||||||||||||||||||||||
| if (operator == Operator.LIKE || operator == Operator.NOT_LIKE) { | ||||||||||||||||||||||
| throw new IllegalArgumentException( | ||||||||||||||||||||||
| CoreError.COLLATION_ICU_LIKE_CONDITION_NOT_SUPPORTED.buildMessage( | ||||||||||||||||||||||
| operator, selection.forFullTableName().get(), condition.getColumn().getName())); | ||||||||||||||||||||||
|
Comment on lines
+63
to
+66
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Question: Could you explain why |
||||||||||||||||||||||
| } | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| /** | ||||||||||||||||||||||
|
|
@@ -58,6 +79,7 @@ public ConsensusCommitOperationChecker( | |||||||||||||||||||||
| */ | ||||||||||||||||||||||
| public void check(Get get, TransactionContext context) throws ExecutionException { | ||||||||||||||||||||||
| throwIfOperationForVirtualTableButNotConsistentVirtualTableReadStorage(get); | ||||||||||||||||||||||
| throwIfLikeConditionUnderIcuCollation(get); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| TransactionTableMetadata metadata = | ||||||||||||||||||||||
| getTransactionTableMetadata(transactionTableMetadataManager, get); | ||||||||||||||||||||||
|
|
@@ -115,6 +137,7 @@ public void check(Get get, TransactionContext context) throws ExecutionException | |||||||||||||||||||||
| */ | ||||||||||||||||||||||
| public void check(Scan scan, TransactionContext context) throws ExecutionException { | ||||||||||||||||||||||
| throwIfOperationForVirtualTableButNotConsistentVirtualTableReadStorage(scan); | ||||||||||||||||||||||
| throwIfLikeConditionUnderIcuCollation(scan); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| TransactionTableMetadata metadata = | ||||||||||||||||||||||
| getTransactionTableMetadata(transactionTableMetadataManager, scan); | ||||||||||||||||||||||
|
|
@@ -201,6 +224,7 @@ public void check(Scan scan, TransactionContext context) throws ExecutionExcepti | |||||||||||||||||||||
| */ | ||||||||||||||||||||||
| public void check(Mutation mutation) throws ExecutionException { | ||||||||||||||||||||||
| throwIfOperationForVirtualTableButNotConsistentVirtualTableReadStorage(mutation); | ||||||||||||||||||||||
| throwIfKeyedMutationAtomicityUnitUnderIcuCollation(mutation); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| if (mutation instanceof Put) { | ||||||||||||||||||||||
| check((Put) mutation); | ||||||||||||||||||||||
|
|
@@ -274,6 +298,28 @@ ConditionChecker createConditionChecker(TableMetadata tableMetadata) { | |||||||||||||||||||||
| return new ConditionChecker(tableMetadata); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| private void throwIfKeyedMutationAtomicityUnitUnderIcuCollation(Mutation mutation) | ||||||||||||||||||||||
| throws ExecutionException { | ||||||||||||||||||||||
| if (collation != Collation.ICU) { | ||||||||||||||||||||||
| return; | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| assert mutation.forNamespace().isPresent(); | ||||||||||||||||||||||
| StorageInfo storageInfo = storageInfoProvider.getStorageInfo(mutation.forNamespace().get()); | ||||||||||||||||||||||
| StorageInfo.MutationAtomicityUnit unit = storageInfo.getMutationAtomicityUnit(); | ||||||||||||||||||||||
| if (unit == StorageInfo.MutationAtomicityUnit.RECORD | ||||||||||||||||||||||
| || unit == StorageInfo.MutationAtomicityUnit.PARTITION) { | ||||||||||||||||||||||
| // No storage with a record or partition atomicity supports ICU collation | ||||||||||||||||||||||
| // If we support such storage in the future, we need to make the MutationsGrouper collation | ||||||||||||||||||||||
| // aware | ||||||||||||||||||||||
|
Comment on lines
+311
to
+313
|
||||||||||||||||||||||
| throw new UnsupportedOperationException( | ||||||||||||||||||||||
|
Comment on lines
+311
to
+314
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This branch is effectively dead code: every storage whose mutation atomicity unit is
Suggested change
|
||||||||||||||||||||||
| "The ICU collation is not supported for a storage that applies mutations atomically only " | ||||||||||||||||||||||
| + "within a record or a partition. Storage: " | ||||||||||||||||||||||
| + storageInfo.getStorageName() | ||||||||||||||||||||||
| + "; Mutation atomicity unit: " | ||||||||||||||||||||||
| + unit); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| private void throwIfOperationForVirtualTableButNotConsistentVirtualTableReadStorage( | ||||||||||||||||||||||
| Operation operation) throws ExecutionException { | ||||||||||||||||||||||
| assert operation.forNamespace().isPresent(); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
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
LIKE/NOT_LIKErejection added here doesn't take effect in Consensus Commit.ConsensusCommitOperationCheckercallsConditionChecker.check()forPutandDeletebut discards the result:scalardb/core/src/main/java/com/scalar/db/transaction/consensuscommit/ConsensusCommitOperationChecker.java
Line 262 in cf6b7be
scalardb/core/src/main/java/com/scalar/db/transaction/consensuscommit/ConsensusCommitOperationChecker.java
Line 281 in cf6b7be
Since
ConditionCheckerhas no side effects, these calls currently do nothing. ALIKEcondition that bypasses the builder check (e.g., viaConditionBuilder.putIf(List)ordeleteIf(List)) passes the checker and, when the target record exists, hitsdefault: throw new AssertionError()inMutationConditionsValidator.shouldMutate(). Other conditions that the storage-sideOperationCheckerrejects, such as a nonexistent column or a type mismatch, aren't rejected up front in Consensus Commit either.This bug isn't introduced by this PR. The result has been discarded since the call was added in #899, and the same code is on
3and3.16through3.19. Could you fix it in a separate PR againstmaster? The fix should be backported to all the supported release branches, which is easier as a standalone change than as part of this collation stack.Some notes for that PR:
IllegalArgumentExceptionwhencheck()returnsfalse, asOperationChecker.checkCondition()does withCoreError.OPERATION_CHECK_ERROR_CONDITION, would align Consensus Commit with the storage API and JDBC transactions.isEqualToText(null)) are currently accepted and evaluated in memory; they would start to be rejected.ConsensusCommitOperationCheckerTestuses an unstubbedConditionCheckermock, which returnsfalse, so the existing tests that assert no exception would needcheck()stubbed to returntrue.