Chapter 16 · Lightweight Transactions, Paxos, CAS, and Linearizable Conditional Updates
Use LWT for True Invariants and Reject It as a General Replacement for Relational Transactions
Decide where LWT is justified by a true invariant and where workflows, idempotency, or ordinary writes are the correct mechanism instead.
Learning outcomes
AtlasMart's architecture review proposes replacing a relational checkout transaction with several Cassandra LWT statements because “LWT is linearizable.” That conclusion overextends the guarantee. This lesson builds a decision framework: use CAS for a true invariant with a well-modeled Cassandra scope, and use other coordination/modeling patterns when the business operation spans independent rows, services, or partitions.
Distinguish a true compare-and-set invariant from ordinary validation, workflow, or multi-entity transaction requirements.
Explain what Cassandra LWT linearizes and what it does not guarantee across unrelated partitions/services.
Compare an LWT uniqueness-claim model with a normal-write projection/event model.
Design timeout reconciliation and compensating workflow around a high-value invariant.
Create an acceptance checklist covering correctness, contention, latency, topology, repair, observability, and rollback before adopting LWT.
The mandatory labs continue the disposable AtlasMart course
cluster: Apache Cassandra 5.0.9 in the pinned
cassandra:5.0.9 image, Java 17 inside the image,
cluster atlasmart-course, Docker network
atlasmart-cassandra, nodes
atlasmart-cass-1..3, datacenter dc1,
racks rack1..rack3, 16 virtual nodes per node,
NetworkTopologyStrategy with replication factor
(RF) 3, and regular consistency level (CL)
LOCAL_QUORUM unless an experiment says otherwise.
New tables use UnifiedCompactionStrategy (UCS),
gc_grace_seconds = 864000 unless explicitly
isolated for an exercise, and no default TTL. Authentication,
client TLS, internode TLS, and remote JMX are disabled only
inside this isolated local learning network. The optional
application examples use Apache Cassandra Java Driver
4.19.3. Verify your actual runtime with
nodetool version, cqlsh --version,
and java -version.
Run commands only against the disposable Apache Cassandra course lab or another explicitly approved non-production environment. Confirm node, keyspace, table, container, volume, path, and datacenter targets before destructive, failure-injection, cleanup, repair, restore, security, or topology operations. Capture current state and expected rollback/recovery evidence first; output and timings can differ by host, operating system, Java runtime, Docker/runtime, driver, and Cassandra configuration.
Core terms for this chapter
A lightweight transaction (LWT) is Cassandra's
conditional mutation mechanism. It uses the
Paxos consensus protocol so competing
operations on the same logical Paxos scope can agree on one
ordered outcome. Compare-and-set (CAS) means
“apply this mutation only if the current value satisfies the
condition.” A conditional mutation is CQL such
as INSERT ... IF NOT EXISTS or
UPDATE ... IF column = value.
Linearizable means successful operations appear
to occur in a single real-time-compatible order within the
guarantee's documented scope; it is stronger than ordinary
eventual consistency.
A coordinator is the Cassandra node handling one request. A replica is a node that stores the partition according to the keyspace replication strategy. A partition groups rows by partition key and maps through the partitioner to a token; the token determines natural replicas. RF is replication factor. A regular CL controls the data/learn phase of the operation. SERIAL and LOCAL_SERIAL are serial consistency levels that control the Paxos phase. A ballot is the proposal identity/order used by Paxos rounds. Contention occurs when concurrent conditional operations compete for the same Paxos state. A hot partition is a partition receiving disproportionately high request volume. A retry repeats an operation after an error or timeout; for LWT, an ambiguous outcome must be reconciled before blind retry. SSTables are immutable on-disk table files, while compaction rewrites SSTables. repair is Cassandra's anti-entropy process and is separate from Paxos agreement. Storage-Attached Indexing (SAI) and vector search can help locate rows but do not create uniqueness or cross-row transactional invariants.
1. Start from the invariant, not from the feature
A true invariant is a state condition the business cannot allow two concurrent operations to violate—for example, “this externally visible username belongs to at most one account.” That is a good CAS candidate if every contender can map to the same Cassandra key. “Update the order, charge the payment provider, decrement inventory, write shipment state, and append analytics atomically” is not one Cassandra LWT invariant; it is a cross-entity/distributed workflow that needs a different architecture.
| Business requirement | Use LWT? | Reason |
|---|---|---|
| claim unique username/email key | Often yes | all contenders can CAS one deterministic key |
| move order from PENDING to PAID only if still PENDING | Often yes if one row/partition is authoritative | conditional state transition |
| append immutable order event | usually no | idempotent normal insert is cheaper and sufficient |
| atomically mutate unrelated order + payment + inventory partitions | No general relational transaction guarantee | model workflow/saga/outbox/idempotency instead |
| prevent duplicate external payment charge | Cassandra LWT alone is insufficient | external service needs idempotency key/reconciliation too |
2. A two-model lab: invariant key vs ordinary projection
docker exec atlasmart-cass-1 nodetool versiondocker exec atlasmart-cass-1 nodetool statusdocker exec atlasmart-cass-1 java -versiondocker exec atlasmart-cass-1 cqlsh -e "SELECT cluster_name, data_center, rack, release_version FROM system.local;"docker exec atlasmart-cass-1 cqlsh -e "SELECT peer, data_center, rack, release_version FROM system.peers_v2;"# Continue only when all three nodes are UN in dc1.# If the course cluster is absent, recreate it with the same Chapter 01 conventions# and pinned cassandra:5.0.9 image before running this chapter.
CREATE KEYSPACE IF NOT EXISTS atlasmart_lwtWITH replication = {'class':'NetworkTopologyStrategy','dc1':3};CREATE TABLE IF NOT EXISTS atlasmart_lwt.inventory_guard ( sku text PRIMARY KEY, available int, reservation_owner text, revision int) WITH compaction = {'class':'UnifiedCompactionStrategy'};CREATE TABLE IF NOT EXISTS atlasmart_lwt.unique_claim ( claim_type text, claim_value text, owner_id text, created_at timestamp, PRIMARY KEY ((claim_type, claim_value))) WITH compaction = {'class':'UnifiedCompactionStrategy'};CREATE TABLE IF NOT EXISTS atlasmart_lwt.order_projection ( order_id text PRIMARY KEY, customer_id text, state text, updated_at timestamp) WITH compaction = {'class':'UnifiedCompactionStrategy'};CONSISTENCY LOCAL_QUORUM;SERIAL CONSISTENCY LOCAL_SERIAL;INSERT INTO atlasmart_lwt.inventory_guard(sku, available, reservation_owner, revision)VALUES ('sku-42', 10, 'NONE', 0);
CONSISTENCY LOCAL_QUORUM;SERIAL CONSISTENCY LOCAL_SERIAL;DELETE FROM atlasmart_lwt.unique_claim WHERE claim_type='email' AND claim_value='buyer42@example.test';INSERT INTO atlasmart_lwt.unique_claim(claim_type,claim_value,owner_id,created_at)VALUES ('email','buyer42@example.test','customer-42',toTimestamp(now()))IF NOT EXISTS;-- A competing account should lose the same deterministic claim key.INSERT INTO atlasmart_lwt.unique_claim(claim_type,claim_value,owner_id,created_at)VALUES ('email','buyer42@example.test','customer-99',toTimestamp(now()))IF NOT EXISTS;
INSERT INTO atlasmart_lwt.order_projection(order_id,customer_id,state,updated_at)VALUES ('order-9001','customer-42','PAID','2026-09-08T06:00:00Z');-- Replaying the same final projection values is an ordinary idempotent overwrite.INSERT INTO atlasmart_lwt.order_projection(order_id,customer_id,state,updated_at)VALUES ('order-9001','customer-42','PAID','2026-09-08T06:00:00Z');SELECT * FROM atlasmart_lwt.unique_claimWHERE claim_type='email' AND claim_value='buyer42@example.test';SELECT * FROM atlasmart_lwt.order_projection WHERE order_id='order-9001';
The contrast is the lesson: the email claim requires arbitration among contenders, while replaying an already-decided projection value does not. LWT everywhere would make the projection more expensive without strengthening a missing invariant.
3. What LWT does not give you
Cassandra documentation describes LWT as Paxos-backed linearizable compare-and-set. Do not translate that into “relational ACID across arbitrary rows.” The guarantee does not magically encompass independent partitions, an external payment API, a message broker, or a search/vector index. Logged batches discussed in Chapter 17 have their own atomicity/delivery semantics and are not a substitute for a relational transaction either.
Putting all business operations behind
atlasmart_lwt.global_lock can serialize
throughput, create a hotspot, and still fail to make external
side effects transactional. Model the smallest deterministic
invariant key and let workflows coordinate broader business
processes with idempotency and reconciliation.
1. CAS the one invariant that truly needs exclusivity (if any).2. Record an idempotent business command/event with a stable request ID.3. Call external services using their idempotency keys when supported.4. Materialize Cassandra query tables with ordinary idempotent writes.5. Reconcile ambiguous/time-out states from authoritative keys/events.6. Compensate or resume workflow steps; do not pretend one Cassandra CAS covered every service.
4. Failure and rollback acceptance test
Before shipping an LWT-dependent invariant, test more than the
happy [applied] case. Pause a replica and verify
the selected SERIAL/LOCAL_SERIAL plus regular CL behaves as
designed. Create concurrent contenders. Exercise a client
timeout and prove the application reconciles before retry.
Observe CAS p95/p99 and contention. Restore all nodes, run
repair if your failure drill created divergence, and verify
final equality. If switching an existing write to LWT causes
unacceptable availability or tail latency, the rollback must
preserve the business invariant through an alternate
coordination/modeling design—not simply remove IF.
docker exec atlasmart-cass-1 nodetool statusdocker exec atlasmart-cass-1 nodetool proxyhistogramsdocker exec atlasmart-cass-1 cqlsh -e "CONSISTENCY LOCAL_QUORUM; SERIAL CONSISTENCY LOCAL_SERIAL; SELECT * FROM atlasmart_lwt.unique_claim WHERE claim_type='email';"# Optional after controlled replica divergence experiments:docker exec atlasmart-cass-1 nodetool repair --full atlasmart_lwtfor n in 1 2 3; do docker exec atlasmart-cass-$n cqlsh -e "CONSISTENCY LOCAL_ONE; SELECT * FROM atlasmart_lwt.unique_claim WHERE claim_type='email' AND claim_value='buyer42@example.test';"done
5. LWT adoption checklist
| Question | Evidence required before “yes” |
|---|---|
| What exact invariant? | one sentence that identifies conflicting operations and authoritative key |
| Can all contenders route to one deterministic Paxos scope? | schema/routing proof; no index-result lock assumption |
| What serial + regular CL? | RF/DC math and failure test |
| What contention? | concurrency distribution, hot-key/cardinality model, CAS contention metrics |
| What latency budget? | representative CASRead/CASWrite p50/p95/p99, not one trace |
| What happens on timeout? | request identity + authoritative reconciliation path |
| What broader workflow exists? | idempotency/outbox/saga/compensation design for external or multi-partition steps |
| Can we roll back? | alternate invariant mechanism and migration plan |
Check your understanding
- What is the best reason to use Cassandra LWT?
- Does LWT make unrelated partitions one relational ACID transaction?
- Why might an ordinary projection write be better without LWT?
- What must an application do after an ambiguous LWT timeout?
- What is the bridge to Chapter 17?
Review the answers
1. A true concurrent invariant that can be expressed as a deterministic conditional mutation within Cassandra’s documented Paxos/CAS scope.
2. No. Do not generalize the conditional-operation guarantee to arbitrary multi-row/multi-service transactions.
3. If replaying the same state is idempotent and no concurrency invariant is being arbitrated, the regular write path avoids unnecessary Paxos cost.
4. Read/reconcile authoritative state and request identity before deciding whether another conditional attempt is appropriate.
5. Chapter 17 separates batch atomicity/delivery, counters, and idempotent retry-safe writes from LWT/Paxos so each coordination mechanism is used for its actual semantics.
Production judgment
LWT is an invariant tool, not a “strong consistency” checkbox
for every write. Before using it, define the exact invariant,
its partition/key scope, contender cardinality, expected
concurrency, RF and datacenter placement, regular and serial CL,
failure behavior, acceptable p95/p99 latency,
retry/reconciliation rules, and how a timed-out outcome will be
discovered. Measure CASRead/CASWrite
latency, timeouts, failures, unavailables, condition-not-met
counts, and contention histograms alongside ordinary request
latency, CPU, JVM garbage collection, network, disk, compaction,
repair state, and hot-key distribution.
Do not infer a universal LWT throughput number from this laptop
lab. SAI/vector indexes do not make a search result safe as a
uniqueness lock; security/tenant boundaries require
authorization and data-model controls, not
LOCAL_SERIAL. Managed Cassandra services can
constrain JMX, Paxos variants, or topology settings, so
translate the same invariant and evidence model to the service's
supported telemetry. Migration and rollback must account for
application semantics: replacing a normal write with LWT can
change latency and availability, while removing LWT can silently
weaken an invariant. Chapter 17 now compares LOGGED/UNLOGGED
batches, counters, and idempotency so LWT is not misused for
write grouping or retry safety.
Summary and next bridge
Use LWT when a real invariant needs linearizable compare-and-set and the invariant maps cleanly to Cassandra's Paxos scope. Reject it as a generic substitute for relational transactions, distributed workflow coordination, idempotency, or search uniqueness. Chapter 17 continues with batches, counters, and retry-safe write design.
Authoritative references
Use these current official sources as the version-sensitive source of truth. Re-check them when regenerating this chapter because Paxos variants, driver behavior, metrics, and operational recommendations can evolve.
- Apache Cassandra downloads — 5.0.9 and Java Driver 4.19.3
- Cassandra guarantees — LWT and linearizable consistency
- cqlsh consistency and serial consistency
- cassandra.yaml — paxos_variant
- Cassandra monitoring metrics — CASRead/CASWrite
- nodetool proxyhistograms — CAS latency distributions
- Java Driver statement attributes — regular and serial consistency
- Java Driver retries and idempotence
- Java Driver query timestamps — LWT restriction