April 14, 2017·4 min read·engineeringcassandramaterialized-viewsstorage

Cassandra 3.0.13 corrects materialized-view build recovery

A saved SSTable generation could exclude data when a materialized-view builder restarted after compaction. Cassandra 3.0.13 changes which state survives a restart.

A background job can resume from the right logical position and still read the wrong files. Cassandra 3.0.13 fixes that problem in materialized-view construction. The builder saved an SSTable generation limit across restarts. Compaction could replace the files covered by that limit, leaving the resumed builder unable to see data it still needed to process.

The 3.0.13 announcement, posted by Michael Shuler on 14 April, describes a bug-fix release for the 3.0 series. Its changelog includes CASSANDRA-13405, the view-builder correction, among several storage and upgrade fixes. This particular change explains why checkpointing physical storage metadata requires care when storage maintenance continues independently.

I am interested in Cassandra where a system needs its distributed deployment model. Materialized views add another operational commitment to that choice because the database must construct and maintain derived data. A fix to the builder's restart behavior affects whether that work includes all the intended base data.

Compaction invalidates the saved file boundary

The issue report describes a specific trigger. Adding other materialized views in the same keyspace restarts an existing view builder. If compactions run between those restarts, a saved maximum SSTable generation can filter out files the builder now needs. The report identifies generation tracking across restarts as unnecessary and distinguishes it from keeping the current build's file set stable.

That distinction concerns two kinds of state. A token records progress through the keys being built. An SSTable generation describes a physical file. Compaction changes the files without changing which logical keys should contribute to the view. A physical-file cutoff saved at an earlier point can therefore stop describing the data available when construction resumes.

The defect does not require an application to remove the base-table rows. The issue explicitly associates missing view data with the generation filter and intervening compactions. This makes the failure more difficult to interpret from the application alone. A view that lacks a row might suggest a query predicate or a write problem even though the builder skipped the file containing the key.

The corrected ViewBuilder source removes the persistent generation cutoff from file selection. Its comment explains that a stopped and restarted build might otherwise find no SSTables after compaction. The implementation begins a new build record with generation zero and retains the saved token for a resumed build.

A resumed build selects current files

Both new and resumed builds force a blocking flush of the base table before selecting SSTables. The builder then selects the canonical SSTable set and acquires references to those files. A reducing key iterator walks that selected set. This establishes the files for the current execution without reusing a generation ceiling from an earlier execution.

For each key, the code checks the saved token before doing work. Keys after the resume position are considered against the node's local token ranges. Eligible keys go through buildKey, and the builder records token progress as it proceeds. Removing the generation filter therefore does not remove the logical progress checkpoint.

Inside buildKey, the builder obtains the view's read query and checks whether it selects the key. It performs an internal base-table read for the view and generates view mutations against an empty prior state. Those mutation collections pass to StorageProxy.mutateMV. The code comment describes this as rebuilding from disk and treating what it reads as new updates.

This sequence explains why selecting the keys correctly matters even though the builder subsequently reads base-table data. A key excluded from the initial SSTable iteration never reaches that read. Correctness depends on the enumeration step as well as on the transformation that creates the view mutations.

I find the separation of progress and file selection useful here. Persisting a token answers where processing stopped. Selecting and referencing the current SSTables answers which files this execution will inspect. The repair to the implementation keeps those responsibilities distinct when compaction has changed the physical representation between executions.

Completion and restart are separate outcomes

The builder marks a view built only when its loop finishes without a stop request. If a stop occurs, it logs that the build stopped after covering a number of keys. An exception creates another builder and schedules it after five minutes. These paths make restart behavior part of ordinary construction, including recovery from a failed attempt.

The fix addresses a defect in that recovery path. Retrying a job cannot correct an inappropriate saved file filter if every retry restores the same filter. Selecting the current canonical files changes what the retry can inspect while preserving its token checkpoint. The correction concerns the inputs to resumed work, beyond the existence of a retry mechanism.

Other entries in 3.0.13 reinforce the importance of upgrade and storage-state handling. The changelog lists fixes for incomplete schema-table flushes at startup and for conversion of expired 2.X rows without regular column data. Those are separate defects, and the view-builder correction should not be treated as a general repair for every missing-data symptom.

For a deployment using materialized views, CASSANDRA-13405 supplies a concrete explanation of how view construction could omit data after a restart with intervening compaction. The corrected builder preserves token progress, flushes the base table, and references the current canonical SSTables for its next pass. Its persisted progress no longer requires the old physical file generations to remain available.