April 24, 2020·4 min read·engineeringcassandrarepairstorage

Cassandra alpha4 gives repair history an expiration policy

Cassandra 4.0-alpha4 bounds repair-history retention and adds repair diagnostics. Its preview also exposes the consistency choices behind foreground read repair.

Repair produces records about the work it performs, and those records need a retention policy of their own. Cassandra 4.0-alpha4 adds a time to live and time-window compaction to its repair-history tables. The change puts a storage limit in the schema of an operational subsystem. It also raises a practical question about how much history remains available when someone investigates an earlier repair.

The Apache release record dates alpha4 to April 24, 2020. Its tagged changelog identifies the history change as CASSANDRA-12701. Other entries expose repair-streaming metrics and add a metric for preview-repair failures. Taken together, they make this preview useful for examining both the evidence a repair produces and the lifetime of that evidence.

I find the operational detail persuasive because Cassandra is a database to adopt when its distribution model is required. Active-active operation at scale involves obligations beyond accepting writes. The records that explain maintenance work should be understandable without assuming they form a permanent archive.

Thirty days in the table definition

The system-distributed keyspace implementation defines a thirty-day default time to live for both repair_history and parent_repair_history. It configures TimeWindowCompactionStrategy with one-day windows. A generation comment explicitly identifies the addition of TTL and time-window compaction to the repair-history tables.

The two tables organise related information differently. repair_history partitions by keyspace and table name, with a time UUID identifying individual records within that partition. Its columns include the coordinator, participants, status and timestamps. Exception details occupy their own fields. This arrangement makes the history for a table accessible under a shared partition identity.

parent_repair_history uses the parent identifier as its primary key. It records the affected keyspace and tables, requested and successful ranges, timing information and options. These fields describe the overall repair request. The per-table history supplies another level of detail about the work associated with that request.

The expiration policy applies to both definitions. It therefore affects the evidence available at each level of the repair history. A record of successful ranges and a record containing an exception are both subject to the same default retention period in this implementation. The schema does not turn failures into a separate permanent archive.

This is a concrete distinction between an operational history and an audit requirement. A system that needs evidence beyond thirty days cannot infer that retention from the existence of these tables. The table definitions answer the storage question directly, and any longer-lived record needs a separately specified destination and lifetime.

Repair is also a choice made by reads

The alpha includes a broader change in how Cassandra lets a table express read-repair behaviour. Its versioned read-repair documentation explains the read_repair table option and its BLOCKING and NONE settings. This is part of the 4.0 preview, not a claim that alpha4 introduces the option for the first time.

With BLOCKING, the coordinator waits for repair writes to reach the required consistency level. The documentation connects this behaviour to monotonic quorum reads. Successive quorum reads should not return an older value after a newer one, even when a failed write placed that newer value on only a minority of replicas.

That guarantee has a specific tradeoff. Read repair repairs the data covered by the query. If an application writes multiple rows in a partition together and then reads just one of them, repairing that narrower selection can propagate only part of the earlier write. The documentation therefore distinguishes monotonic quorum reads from partition-level write atomicity.

With NONE, the coordinator still reconciles differences in the values returned for the read. It does not issue repair writes to make the replicas agree. The documented consequence is preservation of partition-level write atomicity, with no monotonic-quorum-read guarantee. Turning off repair does not mean the coordinator returns one replica response without reconciliation.

For an existing keyspace named ks, a minimal table can express the latter choice explicitly.

CREATE TABLE ks.readings (
    device int,
    sample int,
    value int,
    PRIMARY KEY (device, sample)
) WITH read_repair = 'NONE';

The example makes the partition and clustering keys visible because query granularity is central to the tradeoff. A read constrained to one sample covers less data than a write that affects several samples in the same device partition. That difference determines which data foreground read repair can propagate.

Evidence has several scopes

Read repair and scheduled repair answer different operational needs. The versioned documentation explicitly says read repair does not replace other repairs, including full repair. Its effect depends on the replicas involved in the request and the data selected by that request. A successful read therefore cannot establish that every replica holds the same complete state.

Alpha4 improves evidence around repair without changing that distinction. A preview-failure metric concerns the preview operation, while the history tables describe repair work and retain their records for a defined period. Neither observation alone establishes the consistency of data outside the operation it records.

I prefer this explicit account of scope to a general promise that repair makes a distributed database consistent. The preview provides specific controls and specific evidence. Its table schema gives repair records a thirty-day default lifetime, and its read-repair option states which consistency property the foreground read path provides.