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.

Intermediate → Advanced110–150 minutesInvariant decision + acceptance labApache Cassandra 5.0.9 · Java 17 · cqlsh/nodetool · Java Driver 4.19.3 optional · RF=3 dc1 · UCSLast reviewed: September 2026

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.

01

Distinguish a true compare-and-set invariant from ordinary validation, workflow, or multi-entity transaction requirements.

02

Explain what Cassandra LWT linearizes and what it does not guarantee across unrelated partitions/services.

03

Compare an LWT uniqueness-claim model with a normal-write projection/event model.

04

Design timeout reconciliation and compensating workflow around a high-value invariant.

05

Create an acceptance checklist covering correctness, contention, latency, topology, repair, observability, and rollback before adopting LWT.

Chapter 16 lab baseline

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.

Execution and safety note

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

bash · verify the disposable AtlasMart cluster
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.
CQL · create the Chapter 16 invariant fixtures
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);
CQL · use LWT only on the uniqueness claim
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;
CQL · ordinary idempotent projection does not need Paxos
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.

Wrong design: one global CAS row as a distributed lock manager.

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.

text · workflow boundary for a checkout-like process
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.

bash · chapter acceptance evidence
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

  1. What is the best reason to use Cassandra LWT?
  2. Does LWT make unrelated partitions one relational ACID transaction?
  3. Why might an ordinary projection write be better without LWT?
  4. What must an application do after an ambiguous LWT timeout?
  5. 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.

Keep knowledge open

Help the academy stay free and grow.

If these tutorials save you time, a small donation supports new lessons, technical review, diagrams, examples, and long-term maintenance.

ETHEthereum / ERC-20 only
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0

Send only Ethereum or ERC-20 compatible assets to this address.