April 22, 2025·6 min read·engineeringcassandraaccordtransactionsconsensus

Accord reaches Cassandra trunk with transaction recovery as a core concern

The Accord merge brings multi-key transaction machinery into Cassandra development. Its integration separates coordination, replica execution and recovery while tracking changes in topology.

Coordinating a transaction across several keys requires more than agreeing that each individual write is valid. The system needs a shared execution order and a way to finish when the original coordinator stops making progress. On 22 April, the Cassandra project announced that Accord transactions had merged into trunk.

The announcement describes strict serializability across multiple tables and keys using commodity clocks. This is a development milestone, not an announcement that an existing stable Cassandra release has gained those capabilities. The integration can now develop in the project's main branch.

Cassandra's distributed availability model is what attracts me to it. Multi-key transactions are interesting because they can remove application coordination that otherwise complicates using that model. The engineering work lies in preserving transaction ordering through failures and changing replica ownership, rather than simply adding a transaction delimiter to CQL.

The proposal addresses a data-modeling constraint

CEP-15 motivates general transactions with the difficulty of coordinating state across partitions. Putting related state into one partition constrains scale, while building a distributed state machine above the database makes applications more complex.

Its goals include strict-serializable transactions over arbitrary keys and a one-wide-area-round-trip normal path. Those are protocol goals, not a universal latency measurement for every application. Contention and recovery still require explicit protocol handling.

The proposal also treats integration as modular. Accord is a library with interfaces that Cassandra implements. That allows the protocol and the database-specific execution machinery to have identifiable responsibilities, even though a working transaction depends on both.

Coordination and local execution hold different state

The integration guide available at the merge divides the code into coordinator and replica-local responsibilities. The coordinator drives a client's request through the transaction state machine. Replica-local code records state and responds to protocol messages.

A parsed request becomes a transaction statement containing the reads, updates, assignments and conditions intended for atomic execution. Cassandra translates those into Accord operations and forms a transaction. Executing it produces a result for the client.

That translation is one reason a consensus protocol alone is insufficient. Cassandra supplies messaging and serialization, integrates CQL, controls concurrent execution and provides durable storage. The protocol's agreement must ultimately become database operations with recoverable state.

The guide distinguishes a local command from a complete transaction. A command records the portion relevant to a particular shard. A coordinator manages the whole transaction across those local states. Confusing them would make a local completion appear stronger than it is.

Agreement establishes an execution position

The coordinator allocates a globally unique transaction identifier and begins coordination. Initial PreAccept and Accept rounds establish when the transaction should execute. Messages carry the transaction definition together with routing information.

Replicas process those messages through an Accord verb handler. They check the transaction's epoch before sending work to the appropriate local command stores. A message for a future epoch waits until the node recognizes that epoch as active.

The epoch check connects transaction agreement to cluster configuration. A node must interpret the request using the relevant mapping of key ranges to replicas. Accepting work under an unknown future configuration would leave that interpretation unresolved.

Each transaction also has a home key identifying the shard responsible for making sure it finishes. The guide describes choosing a coordinator-owned key when possible, or another key otherwise. This responsibility gives recovery somewhere to establish progress even when the initial coordination is incomplete.

That role is different from making one node the permanent global leader for all transactions. The integration describes a coordinator for a transaction and local stores for its participants. Their responsibilities exist at different scopes.

Local serialization needs durable command state

A command store is a single-threaded internal shard of transaction metadata. It sequences local command execution and provides an exclusive safe-command-store view while an operation runs. That view can update command state without concurrent operations observing partial local changes.

Before execution, the command store gathers a preload context. It identifies state that must be in memory, including transaction dependencies and key-related command information. Execution cannot assume that all relevant metadata remains resident indefinitely.

The Cassandra-side task machinery handles loading and persistence callbacks. Command states can shrink to a binary representation or leave memory entirely. A task may therefore need to load dependencies before it becomes ready to execute.

This makes metadata management part of transaction performance. The protocol requires dependency information, and the implementation must make that information available without retaining every full command object in memory forever. Scheduling and cache loading contribute to the actual work behind a transaction.

The guide describes separate executor states for waiting to load, loading and running. A limit on concurrent loads can queue additional loading work. That is an internal resource constraint, distinct from whether the transaction protocol has already established an order.

Dependencies constrain execution after agreement

Agreement about an execution timestamp does not mean a replica can immediately apply every operation. Commands can depend on earlier conflicting work. The implementation tracks those prerequisites in a waiting collection and uses notifications when they become ready.

The guide describes command-store listeners as the normal progress path. As coordinators advance transactions, local state changes notify waiting work. This permits execution to proceed when its actual dependencies have completed.

A local task therefore needs both its required data and the correct dependency state. Loading a command from disk does not eliminate ordering constraints. Conversely, satisfying an ordering condition does not guarantee the necessary local metadata is already in memory.

My interest is in this separation of responsibilities. It makes the cost of stronger transactions inspectable. The database has to retain and schedule the ordering information that an application might otherwise try to approximate through its own workflow.

Recovery distinguishes missing information from stalled coordination

The progress log addresses transactions that stop advancing. One path fetches needed information from peers. Another can invoke recovery when coordination itself has stalled. These are different diagnoses and need different actions.

A replica ready to execute may be missing an apply message or dependency information. Fetching data can resolve that local gap without starting transaction agreement again. The guide associates this work with waiting-state tracking.

A transaction whose coordinator has stopped making progress needs a recovery decision. Home-state tracking can trigger that process. The distinction prevents every local delay from being treated as a failed coordinator.

Recovery also explains why transaction metadata survives beyond the immediate request. Another participant may need enough information to continue a transaction after the original client-facing operation has lost its coordinator. Discarding that information too early would undermine the recovery path.

Metadata cleanup depends on distributed evidence

The guide's redundant-before tracking records transactions applied or invalidated across shards. It supports journal compaction and removal of command metadata once the required durability conditions hold. Cleanup is therefore a protocol decision, not merely an age threshold on cached objects.

Sync points provide another part of that lifecycle. They establish boundaries in transaction history used during bootstrap and metadata collection. The durability scheduler coordinates them so nodes can eventually discard older detailed state while retaining the information needed for ordering.

This is a significant operational consequence of multi-key transactions. Correctness needs historical information, but an indefinitely growing history is not a workable storage policy. The implementation must obtain evidence that makes particular records unnecessary.

The same concern appears during topology changes. Epoch readiness includes distinct metadata, coordination, data and read states. Knowing the new topology locally is not enough to claim that a node can already serve every transactional read safely.

The merge includes a verification model

The integration guide emphasizes deterministic burn testing with a strict-serializability checker. The simulation controls time and message passing and introduces concurrency and faults. Built-in assertions check protocol invariants during development.

That testing model fits the failure conditions the implementation has to handle. Healthy execution alone cannot establish what happens when messages arrive under a later epoch or a coordinator fails between protocol stages. A deterministic simulation can preserve the execution needed to investigate such a case.

The guide also warns against disabling invariant checks when they fire. Those checks describe assumptions the implementation depends on. A passing workload after removing an assertion would not establish that the transaction history satisfies the intended guarantee.

For users following trunk, April's milestone makes this machinery part of Cassandra's main development line. The available integration explains how requests reach Accord, how replicas preserve local state and how progress continues after coordination stalls. Stable-release availability and the final user-facing transaction contract remain separate release work.