This is an automated email from the ASF dual-hosted git repository.

maedhroz pushed a commit to branch cep-45-mutation-tracking
in repository https://gitbox.apache.org/repos/asf/cassandra.git

commit 4bbb14c179da9770a20e84b815d3820d4a5340c0
Author: Abe Ratnofsky <a...@aber.io>
AuthorDate: Fri Sep 5 15:56:00 2025 -0400

    Fix loss of isRepaired StatsMetadata on compaction race
    
    Found via MultiNodeTableWalkWithMutationTrackingTest after ~hundreds of
    seeds.
    
    java.lang.IllegalArgumentException: Cannot compact repaired and unrepaired 
sstables
        at 
com.google.common.base.Preconditions.checkArgument(Preconditions.java:143)
        at 
org.apache.cassandra.db.compaction.AbstractCompactionTask.validateSSTables(AbstractCompactionTask.java:84)
        at 
org.apache.cassandra.db.compaction.AbstractCompactionTask.<init>(AbstractCompactionTask.java:60)
        at 
org.apache.cassandra.db.compaction.CompactionTask.<init>(CompactionTask.java:79)
        at 
org.apache.cassandra.db.compaction.CompactionTask.<init>(CompactionTask.java:74)
        at 
org.apache.cassandra.db.compaction.LeveledCompactionTask.<init>(LeveledCompactionTask.java:39)
        at 
org.apache.cassandra.db.compaction.LeveledCompactionStrategy.getMaximalTasks(LeveledCompactionStrategy.java:192)
        at 
org.apache.cassandra.db.compaction.CompactionStrategyHolder.getMaximalTasks(CompactionStrategyHolder.java:121)
    
    patch by Abe Ratnofsky; reviewed by Caleb Rackliffe for CASSANDRA-20830
---
 .../cassandra/io/sstable/format/SSTableWriter.java   | 20 +++++++++++++++++++-
 1 file changed, 19 insertions(+), 1 deletion(-)

diff --git a/src/java/org/apache/cassandra/io/sstable/format/SSTableWriter.java 
b/src/java/org/apache/cassandra/io/sstable/format/SSTableWriter.java
index d1a2df907c..0190282fc7 100644
--- a/src/java/org/apache/cassandra/io/sstable/format/SSTableWriter.java
+++ b/src/java/org/apache/cassandra/io/sstable/format/SSTableWriter.java
@@ -401,13 +401,31 @@ public abstract class SSTableWriter extends SSTable 
implements Transactional
         protected void doPrepare()
         {
             transactionals.get().forEach(Transactional::prepareToCommit);
-            new StatsComponent(finalizeMetadata()).save(descriptor);
+            Map<MetadataType, MetadataComponent> metadata = finalizeMetadata();
+            new StatsComponent(metadata).save(descriptor);
 
             // save the table of components
             TOCComponent.updateTOC(descriptor, components);
 
             if (openResult)
+            {
                 finalReader = openFinal(SSTableReader.OpenReason.NORMAL);
+
+                /*
+                When we open above, we re-finalize metadata and may be durably 
reconciled, but this is after
+                StatsComponent is saved, so the next reload from disk loses 
the reconciliation update. We need to save
+                again to ensure the descriptor file matches what's in memory.
+
+                Could move this to the post-flush compaction, but then we 
couldn't flush directly into the repaired set.
+                Or see if we can open before the first save, so we never have 
to write stats to disk twice.
+                */
+                StatsMetadata stale = ((StatsMetadata) 
metadata.get(MetadataType.STATS));
+                if (finalReader.getSSTableMetadata().repairedAt != 
stale.repairedAt)
+                {
+                    metadata.put(MetadataType.STATS, 
finalReader.getSSTableMetadata());
+                    new StatsComponent(metadata).save(descriptor);
+                }
+            }
         }
 
         protected Throwable doCommit(Throwable accumulate)


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@cassandra.apache.org
For additional commands, e-mail: commits-h...@cassandra.apache.org

Reply via email to