-
Notifications
You must be signed in to change notification settings - Fork 3.8k
CASSANDRA-21127: Added user facing docs for accord #4572
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
base: trunk
Are you sure you want to change the base?
Conversation
|
I used AI to help write these docs, and had it create test cases for each example to make sure it actually works. While doing this it found a lot of nice UX or issues; below is the state that it created Accord Future Syntax and Semantic FeaturesThis document tracks CQL transaction syntax and semantic features that are documented or desired but not yet implemented in the current version of Cassandra. These features may be added in future releases. Arithmetic Expressions with Row ReferencesIssue: Row Reference Arithmetic in UPDATE SET ClausesStatus: Not implemented Description: Example of Unsupported Syntax: BEGIN TRANSACTION
LET user_data = (SELECT balance FROM users WHERE id = ?);
UPDATE users SET balance = user_data.balance - 50 WHERE id = ?;
COMMIT TRANSACTIONError Message: Current Workaround: BEGIN TRANSACTION
LET user_data = (SELECT balance FROM users WHERE id = ?);
IF user_data.balance > 50 THEN
UPDATE users SET balance = balance - 50 WHERE id = ?;
END IF
COMMIT TRANSACTIONImpact:
Comparing Two Row ReferencesIssue: Comparison Between Two LET VariablesStatus: Not implemented Description: Example of Unsupported Syntax: BEGIN TRANSACTION
LET account = (SELECT balance FROM accounts WHERE id = ?);
LET limit = (SELECT max_balance FROM limits WHERE type = 'standard');
IF account.balance < limit.max_balance THEN
UPDATE accounts SET balance = balance + 10 WHERE id = ?;
END IF
COMMIT TRANSACTIONCurrent Workaround: -- Application code:
-- double maxBalance = 1000.00; // Retrieved from limits table
BEGIN TRANSACTION
LET account = (SELECT balance FROM accounts WHERE id = ?);
IF account.balance < ? THEN -- Pass maxBalance
UPDATE accounts SET balance = balance + 10 WHERE id = ?;
END IF
COMMIT TRANSACTIONImpact:
Range Updates and DeletesIssue: Updates or Deletes without Full Primary KeyStatus: Not implemented Description: Example of Unsupported Syntax: BEGIN TRANSACTION
-- Attempting to update all sessions for a user
UPDATE user_sessions
SET status = 'invalidated'
WHERE user_id = ?; -- Missing session_id (clustering key)
COMMIT TRANSACTIONCurrent Workaround: -- Step 1: Query active sessions (outside transaction or in previous step)
-- SELECT session_id FROM user_sessions WHERE user_id = ?;
-- Step 2: Transaction with specific updates
BEGIN TRANSACTION
UPDATE users SET status = 'deactivated' WHERE id = ?;
-- Update known sessions individually
UPDATE user_sessions SET status = 'invalidated' WHERE user_id = ? AND session_id = ?;
UPDATE user_sessions SET status = 'invalidated' WHERE user_id = ? AND session_id = ?;
COMMIT TRANSACTIONImpact:
Arithmetic Expressions with Row References in SELECTIssue: Row Reference Arithmetic in SELECT Return ValuesStatus: Not implemented Description: Example of Unsupported Syntax: BEGIN TRANSACTION
LET user_data = (SELECT balance FROM users WHERE id = ?);
UPDATE users SET balance = balance - 50 WHERE id = ?;
SELECT user_data.balance, user_data.balance - 50;
COMMIT TRANSACTIONError Message: Current Workaround: BEGIN TRANSACTION
LET user_data = (SELECT balance FROM users WHERE id = ?);
UPDATE users SET balance = balance - 50 WHERE id = ?;
SELECT user_data.balance;
COMMIT TRANSACTIONImpact:
SELECT with Row Data References PositioningIssue: SELECT with Row References Must Precede ModificationsStatus: Grammar limitation Description: Example of Unsupported Syntax: BEGIN TRANSACTION
LET user_data = (SELECT balance FROM users WHERE id = ?);
UPDATE users SET balance = balance - 50 WHERE id = ?;
SELECT user_data.balance; -- Error: SELECT with row references after UPDATE
COMMIT TRANSACTIONError Message: Current Workaround: -- Option 1: SELECT before UPDATE
BEGIN TRANSACTION
LET user_data = (SELECT balance FROM users WHERE id = ?);
SELECT user_data.balance; -- SELECT before UPDATE
UPDATE users SET balance = balance - 50 WHERE id = ?;
COMMIT TRANSACTION
-- Option 2: Query after transaction commits
BEGIN TRANSACTION
UPDATE users SET balance = balance - 50 WHERE id = ?;
COMMIT TRANSACTION
-- Then query outside transaction:
SELECT balance FROM users WHERE id = ?;Grammar Structure: The grammar does NOT allow SELECT statements after modification statements, even if they are full SELECT statements with FROM clauses. The SELECT position is fixed in the grammar structure. Impact:
Computed LET AssignmentsIssue: LET Assignments with Computed ValuesStatus: Not implemented Description: Example of Unsupported Syntax: BEGIN TRANSACTION
LET user_data = (SELECT balance FROM users WHERE id = ?);
LET new_balance = user_data.balance - 50; -- Error: computed assignment
LET discount_rate = CASE user_data.tier
WHEN 'gold' THEN 0.10
ELSE 0.0 END; -- Error: CASE expression
UPDATE users SET balance = new_balance WHERE id = ?;
COMMIT TRANSACTIONCurrent Workaround: BEGIN TRANSACTION
LET user_data = (SELECT balance, tier FROM users WHERE id = ?);
-- Compute in the UPDATE statement instead
IF user_data.balance >= 50 THEN
UPDATE users SET balance = balance - 50 WHERE id = ?;
END IF
COMMIT TRANSACTIONImpact:
SELECT After Modification StatementsIssue: SELECT Must Precede All ModificationsStatus: Grammar restriction Description: Example of Unsupported Syntax: BEGIN TRANSACTION
LET user_data = (SELECT balance FROM users WHERE id = ?);
UPDATE users SET balance = balance - 50 WHERE id = ?;
-- Error: SELECT after UPDATE not allowed
SELECT user_data.balance, 'Update successful' as message;
COMMIT TRANSACTIONCurrent Workaround: -- Option 1: SELECT before modifications
BEGIN TRANSACTION
LET user_data = (SELECT balance FROM users WHERE id = ?);
SELECT user_data.balance; -- Before UPDATE
UPDATE users SET balance = balance - 50 WHERE id = ?;
COMMIT TRANSACTION
-- Option 2: Query after transaction
BEGIN TRANSACTION
UPDATE users SET balance = balance - 50 WHERE id = ?;
COMMIT TRANSACTION
-- Then query outside:
SELECT balance FROM users WHERE id = ?;Impact:
IN and OR Operators in IF ConditionsIssue: IN and OR Not Supported in Transaction ConditionsStatus: Not implemented Description: Example of Unsupported Syntax (IN): BEGIN TRANSACTION
LET order = (SELECT status FROM orders WHERE order_id = ?);
IF order.status IN ('PENDING', 'PAID') THEN
UPDATE orders SET status = 'CANCELLED' WHERE order_id = ?;
END IF
COMMIT TRANSACTIONError Message: Example of Unsupported Syntax (OR): BEGIN TRANSACTION
LET order = (SELECT status FROM orders WHERE order_id = ?);
IF order.status = 'PENDING' OR order.status = 'PAID' THEN
UPDATE orders SET status = 'CANCELLED' WHERE order_id = ?;
END IF
COMMIT TRANSACTIONError Message: Current Workaround: -- Schema uses integer status codes: 10=PENDING, 20=PAID, 30=SHIPPED, etc.
BEGIN TRANSACTION
LET order = (SELECT status_code FROM orders WHERE order_id = ?);
-- Use range comparison instead of IN/OR
-- status_code <= 20 means PENDING or PAID
IF order.status_code <= 20 THEN
UPDATE orders SET status_code = 99 WHERE order_id = ?; -- 99=CANCELLED
END IF
COMMIT TRANSACTIONImpact:
Grammar Reference: txnConditions returns [List<ConditionStatement.Raw> conditions]
: txnColumnCondition[conditions] ( K_AND txnColumnCondition[conditions] )*
;Code Reference: // TODO: Support for IN, CONTAINS, CONTAINS KEYSummary of LimitationsRow Reference Arithmetic LimitationsWhat Works:
What Doesn't Work:
Parser Status: Future EnhancementsThese features may be added in future Cassandra versions:
Testing NotesAll examples in the Cassandra documentation (doc/modules/cassandra/pages/developing/cql/transactions*.adoc) should only show syntax that currently works. Examples using unsupported syntax have been removed and documented here for future reference. Test classes validating documentation examples:
|
|
Tried the format in a build and looks good. Love the load of examples. We could use more of these. This is really nice coverage of the existing syntax. The only thing I could find that needs more clarity is handling NULL values. Calling that out as a specific difference between how LWT handles NULL vs Accord. |
2f245ec to
0422b68
Compare
|
|
||
| === BATCH vs Transactions | ||
|
|
||
| While BATCH statements provide atomicity for multiple operations, they have limitations compared to Accord transactions. Understanding the differences helps you choose the right approach for your use case. |
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.
BATCH statements do not provide atomicity. LWT batches do, and single partition batches do.
|
|
||
| == Pattern: Synchronous Unique Constraints | ||
|
|
||
| Cassandra's primary key enforces uniqueness, but what if you need uniqueness on a non-primary-key column like `email` or `username`? This pattern uses sidecar index tables to enforce multiple unique constraints atomically. |
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.
is sidecar a useful word to use here?
|
|
||
| Accord ensures data integrity through: | ||
|
|
||
| * **Snapshot Isolation**: Each transaction sees a consistent snapshot of data |
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 provide stronger guarantees than "snapshot isolation". Transactions are strict serializable; snapshot isolation is typically an implementation of read committed isolation.
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.
thanks for the call out. I was thinking to express it as something simpler for users, but if you know what these terms mean it can cause more confusion than anything; ill update.
|
|
||
| ==== Migration from LWT | ||
|
|
||
| If your LWT code uses `IF column = null`, you must update it when migrating to Accord: |
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.
Maybe clarify that this doesn't affect automatically upgraded LWT syntax?
I wonder if we should make a semantic distinction between "Accord" and "transaction syntax". That is, we have Paxos vs Accord, and LWT vs Transaction syntax. Since Accord can execute both LWT and transaction syntax, and maintains all of the semantics of Paxos LWTs.
|
|
||
| **High latency investigation:** | ||
|
|
||
| . Check transaction complexity (LET count < 5, partitions < 3) |
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.
are these empirically determined out of interest?
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.
empirically determined
nope; pulled out of my b***.
We don't have guardrails in place yet, if we did i would use those here. I am more trying to express the more queries you do, the larger the cost.
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.
i checked with Alex, we do have benchmarks that can test multiple partitions, but they are not run atm so don't have clear data to see how multi partition and single partition compare.
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.
ok, doesn't seem unreasonable but might be worth clarifying in case we don't visit this again soon that these are not empirically determined (maybe a footnote or something?)
No description provided.