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

asf-gitbox-commits pushed a commit to branch cassandra-5.0
in repository https://gitbox.apache.org/repos/asf/cassandra.git


The following commit(s) were added to refs/heads/cassandra-5.0 by this push:
     new f000bddd36 Avoid rebuilding per-SSTable SAI components unless missing 
or corrupted
f000bddd36 is described below

commit f000bddd36e4cdf0d294b16ca9642f77964b24db
Author: Caleb Rackliffe <[email protected]>
AuthorDate: Tue Aug 11 16:42:18 2026 -0500

    Avoid rebuilding per-SSTable SAI components unless missing or corrupted
    
    patch by Sunil Ramchandra Pawar; reviewed by Caleb Rackliffe and David 
Capwell for CASSANDRA-21515
---
 CHANGES.txt                                        |  1 +
 .../index/sai/StorageAttachedIndexBuilder.java     |  2 -
 .../index/sai/cql/StorageAttachedIndexDDLTest.java | 66 ++++++++++++++++++++++
 .../index/sai/functional/SnapshotTest.java         |  3 +-
 4 files changed, 69 insertions(+), 3 deletions(-)

diff --git a/CHANGES.txt b/CHANGES.txt
index edc51e1203..35a6124889 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
 5.0.10
+ * Avoid rebuilding per-SSTable SAI components unless missing or corrupted 
(CASSANDRA-21515)
  * Propagate trickle_fsync settings to compressed SSTable writers 
(CASSANDRA-21487)
  * Allow DatabaseDescriptor.setCompressedReadAheadBufferSizeInKb(0) to disable 
read-ahead buffer (CASSANDRA-21522)
  * Return CorruptSSTableException if chunk metadata and file size are out of 
sync (CASSANDRA-21519)
diff --git 
a/src/java/org/apache/cassandra/index/sai/StorageAttachedIndexBuilder.java 
b/src/java/org/apache/cassandra/index/sai/StorageAttachedIndexBuilder.java
index fe856059f8..dd94272700 100644
--- a/src/java/org/apache/cassandra/index/sai/StorageAttachedIndexBuilder.java
+++ b/src/java/org/apache/cassandra/index/sai/StorageAttachedIndexBuilder.java
@@ -262,9 +262,7 @@ public class StorageAttachedIndexBuilder extends 
SecondaryIndexBuilder
     {
         IndexDescriptor indexDescriptor = IndexDescriptor.create(sstable);
 
-        // if per-table files are incomplete, full rebuild is requested, or 
checksum fails
         if (!indexDescriptor.isPerSSTableIndexBuildComplete()
-            || isFullRebuild
             || 
!indexDescriptor.validatePerSSTableComponents(IndexValidation.CHECKSUM, true, 
false))
         {
             CountDownLatch latch = CountDownLatch.newCountDownLatch(1);
diff --git 
a/test/unit/org/apache/cassandra/index/sai/cql/StorageAttachedIndexDDLTest.java 
b/test/unit/org/apache/cassandra/index/sai/cql/StorageAttachedIndexDDLTest.java
index d21331c1ab..90bc1c1a71 100644
--- 
a/test/unit/org/apache/cassandra/index/sai/cql/StorageAttachedIndexDDLTest.java
+++ 
b/test/unit/org/apache/cassandra/index/sai/cql/StorageAttachedIndexDDLTest.java
@@ -60,6 +60,7 @@ import 
org.apache.cassandra.exceptions.InvalidRequestException;
 import org.apache.cassandra.index.Index;
 import org.apache.cassandra.index.SecondaryIndexManager;
 import org.apache.cassandra.index.sai.SAITester;
+import org.apache.cassandra.index.sai.SSTableContext;
 import org.apache.cassandra.index.sai.StorageAttachedIndex;
 import org.apache.cassandra.index.sai.StorageAttachedIndexBuilder;
 import org.apache.cassandra.index.sai.analyzer.NonTokenizingOptions;
@@ -1003,6 +1004,71 @@ public class StorageAttachedIndexDDLTest extends 
SAITester
         assertEquals(rowCount, rows.all().size());
     }
 
+    @Test
+    public void rebuildingOneIndexNotRewriteSharedPerSSTableComponents() 
throws Throwable
+    {
+        Injections.Counter sharedContextBuilds = 
Injections.newCounter("SharedPerSSTableContextBuilds")
+                                                           
.add(InvokePointBuilder.newInvokePoint().onClass(SSTableContext.class).onMethod("create"))
+                                                           .build();
+
+        Injections.inject(sharedContextBuilds);
+
+        createTable(CREATE_TABLE_TEMPLATE);
+        String v1Index = createIndex(String.format(CREATE_INDEX_TEMPLATE, 
"v1"));
+        createIndex(String.format(CREATE_INDEX_TEMPLATE, "v2"));
+
+        execute("INSERT INTO %s (id1, v1, v2) VALUES ('0', 0, '100')");
+        execute("INSERT INTO %s (id1, v1, v2) VALUES ('1', 1, '101')");
+        flush();
+
+        assertEquals(1, sharedContextBuilds.get());
+
+        assertEquals(1, execute("SELECT id1 FROM %s WHERE v1 = 0").size());
+        assertEquals(1, execute("SELECT id1 FROM %s WHERE v2 = '101'").size());
+
+        sharedContextBuilds.reset();
+
+        rebuildIndexes(v1Index);
+
+        // CASSANDRA-21515: rebuilding one index must NOT rewrite the shared 
per-SSTable components.
+        assertEquals("Rebuilding of a single SAI index must not rebuild the 
shared per-SSTable components",
+                     0, sharedContextBuilds.get());
+
+        assertEquals(1, execute("SELECT id1 FROM %s WHERE v2 = '101'").size());
+        assertEquals(1, execute("SELECT id1 FROM %s WHERE v1 = 0").size());
+    }
+
+    @Test
+    public void rebuildRegeneratesCorruptSharedPerSSTableComponents() throws 
Throwable
+    {
+        Injections.Counter sharedContextBuilds = 
Injections.newCounter("SharedPerSSTableContextBuilds")
+                                                           
.add(InvokePointBuilder.newInvokePoint().onClass(SSTableContext.class).onMethod("create"))
+                                                           .build();
+        Injections.inject(sharedContextBuilds);
+
+        createTable(CREATE_TABLE_TEMPLATE);
+        String v1Index = createIndex(String.format(CREATE_INDEX_TEMPLATE, 
"v1"));
+        String v2Index = createIndex(String.format(CREATE_INDEX_TEMPLATE, 
"v2"));
+
+        execute("INSERT INTO %s (id1, v1, v2) VALUES ('0', 0, '100')");
+        execute("INSERT INTO %s (id1, v1, v2) VALUES ('1', 1, '101')");
+        flush();
+
+        assertEquals(1, sharedContextBuilds.get());
+
+        corruptIndexComponent(IndexComponent.ROW_TO_PARTITION, 
CorruptionType.EMPTY_FILE);
+        sharedContextBuilds.reset();
+        assertEquals(0, sharedContextBuilds.get());
+
+        rebuildIndexes(v1Index, v2Index);
+
+        assertEquals("corrupt shared per-SSTable components must be 
regenerated on rebuild",
+                     1, sharedContextBuilds.get());
+
+        assertEquals(1, execute("SELECT id1 FROM %s WHERE v1 = 0").size());
+        assertEquals(1, execute("SELECT id1 FROM %s WHERE v2 = '101'").size());
+    }
+
     @Test
     public void verifyCleanupFailedPerIndexFiles() throws Throwable
     {
diff --git 
a/test/unit/org/apache/cassandra/index/sai/functional/SnapshotTest.java 
b/test/unit/org/apache/cassandra/index/sai/functional/SnapshotTest.java
index fd38bc6006..83365cf987 100644
--- a/test/unit/org/apache/cassandra/index/sai/functional/SnapshotTest.java
+++ b/test/unit/org/apache/cassandra/index/sai/functional/SnapshotTest.java
@@ -106,7 +106,8 @@ public class SnapshotTest extends SAITester
         verifyIndexFiles(indexTermType, indexIdentifier, 2);
         assertNotEquals(snapshotLastModified, indexFilesLastModified());
         assertNumRows(2, "SELECT * FROM %%s WHERE v1 >= 0");
-        assertValidationCount(2, 2); // compaction should not validate
+        // CASSANDRA-21515: a single-index rebuild no longer rewrites the 
shared per-SSTable components
+        assertValidationCount(4, 2);
 
         // index components are included after rebuild
         verifyIndexComponentsIncludedInSSTable();


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to