Skip to content

Fixes for fully-expired SSTable index notification in compaction - #5027

Open
frankgh wants to merge 1 commit into
apache:trunkfrom
frankgh:CASSANDRA-21577
Open

Fixes for fully-expired SSTable index notification in compaction#5027
frankgh wants to merge 1 commit into
apache:trunkfrom
frankgh:CASSANDRA-21577

Conversation

@frankgh

@frankgh frankgh commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

The 2i notification path added to CompactionTask (CASSANDRA-20829) had three issues, all reachable on upgrade for existing clusters:

  • A read error or a throwing custom indexer aborted the whole compaction. Expired SSTables were never obsoleted and every retry hit the same failure.
  • The static row was never passed to removeRow, so static-column indexes missed expired-data notifications.
  • NoOpIndex, PaxosUncommittedIndex and RouteJournalIndex inherited the default (true) and did no useful work on this path, forcing needless full scans of expired SSTables on system.paxos / accord tables. Opt them out matching SAI/SASI.

patch by Francisco Guerrero; reviewed by TBD for CASSANDRA-21577

The 2i notification path added to CompactionTask (CASSANDRA-20829) had
three issues, all reachable on upgrade for existing clusters:

- A read error or a throwing custom indexer aborted the whole compaction.
  Expired SSTables were never obsoleted and every retry hit the same
  failure.

- The static row was never passed to removeRow, so static-column indexes
  missed expired-data notifications.

- NoOpIndex, PaxosUncommittedIndex and RouteJournalIndex inherited the
  default (true) and did no useful work on this path, forcing needless
  full scans of expired SSTables on system.paxos / accord tables. Opt
  them out matching SAI/SASI.

patch by Francisco Guerrero; reviewed by TBD for CASSANDRA-21577
@smiklosovic
smiklosovic requested a lite review from Copilot August 17, 2026 09:30

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

This PR fixes issues in the compaction-time “fully expired SSTable” secondary-index notification path to ensure expired SSTables are reliably dropped, static rows are notified, and certain system/accord-related indexes opt out to avoid unnecessary work.

Changes:

  • Make index notifications best-effort during fully-expired SSTable handling so compaction can still drop expired SSTables even if reads/indexers fail.
  • Include static rows when notifying indexers about fully-expired SSTables.
  • Opt out specific indexes (NoOpIndex, PaxosUncommittedIndex, RouteJournalIndex) from fully-expired SSTable row notifications; add regression tests.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
test/unit/org/apache/cassandra/index/CustomIndexTest.java Adds regression tests for indexer-failure resilience and static-row notifications during fully-expired SSTable compaction.
src/java/org/apache/cassandra/service/paxos/uncommitted/PaxosUncommittedIndex.java Disables fully-expired SSTable row notification for PaxosUncommittedIndex to avoid unnecessary scans.
src/java/org/apache/cassandra/index/accord/RouteJournalIndex.java Disables fully-expired SSTable row notification for RouteJournalIndex to avoid unnecessary scans.
src/java/org/apache/cassandra/index/accord/NoOpIndex.java Disables fully-expired SSTable row notification for NoOpIndex to avoid unnecessary scans.
src/java/org/apache/cassandra/db/compaction/CompactionTask.java Makes notification best-effort, ensures static rows are notified, and guarantees finish() is called even on failures.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines 654 to +680
for (Index.Indexer indexer : indexers)
indexer.begin();

while (partition.hasNext())
try
{
Unfiltered unfiltered = partition.next();
if (unfiltered instanceof Row)
Row staticRow = partition.staticRow();
if (!staticRow.isEmpty())
{
for (Index.Indexer indexer : indexers)
indexer.removeRow((Row) unfiltered);
indexer.removeRow(staticRow);
}
}

for (Index.Indexer indexer : indexers)
indexer.finish();
while (partition.hasNext())
{
Unfiltered unfiltered = partition.next();
if (unfiltered instanceof Row)
{
for (Index.Indexer indexer : indexers)
indexer.removeRow((Row) unfiltered);
}
}
}
finally
{
for (Index.Indexer indexer : indexers)
indexer.finish();
}
Comment on lines +768 to +769
// Let the rows (and SSTable) fully expire.
Uninterruptibles.sleepUninterruptibly(60, TimeUnit.SECONDS);
Comment on lines +794 to +802
// Static-only writes: each partition gets a static row and no clustering rows, so removeRow would never be
// invoked for these partitions unless the static row is handled explicitly.
execute("INSERT INTO %s (pk, s) VALUES (?, ?) USING TTL 20", 0, 100);
execute("INSERT INTO %s (pk, s) VALUES (?, ?) USING TTL 20", 1, 200);

flush();
Assert.assertFalse(cfs.getLiveSSTables().isEmpty());

Uninterruptibles.sleepUninterruptibly(60, TimeUnit.SECONDS);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants