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

maedhroz pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/cassandra.git


The following commit(s) were added to refs/heads/trunk by this push:
     new 55db3181fb Make legacy index rebuilds safe on Gossip -> TCM upgrades
55db3181fb is described below

commit 55db3181fb940c4adaa41a37f2ebea4d94f22e4e
Author: Marcus Eriksson <[email protected]>
AuthorDate: Thu Aug 28 10:43:33 2025 +0200

    Make legacy index rebuilds safe on Gossip -> TCM upgrades
    
    patch by Caleb Rackliffe; reviewed by Marcus Eriksson for CASSANDRA-20887
    
    Co-authored-by: Caleb Rackliffe <[email protected]>
    Co-authored-by: Marcus Eriksson <[email protected]>
---
 CHANGES.txt                                        |  1 +
 .../org/apache/cassandra/db/ColumnFamilyStore.java | 43 ++++++++++++++----
 src/java/org/apache/cassandra/db/Keyspace.java     | 10 ++---
 .../cassandra/index/internal/CassandraIndex.java   |  3 +-
 .../apache/cassandra/schema/DistributedSchema.java | 30 +++++++++++--
 .../upgrade/ClusterMetadata2iUpgradeTest.java      | 51 ++++++++++++++++++++++
 .../index/internal/CustomCassandraIndex.java       |  3 +-
 7 files changed, 123 insertions(+), 18 deletions(-)

diff --git a/CHANGES.txt b/CHANGES.txt
index c09abf651d..febc9d5da0 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
 5.1
+ * Make legacy index rebuilds safe on Gossip -> TCM upgrades (CASSANDRA-20887)
  * Minor improvements and hardening for IndexHints (CASSANDRA-20888)
  * Stop repair scheduler if two major versions are detected (CASSANDRA-20048)
  * Optimize audit logic for batch operations especially when audit is not 
enabled for DML (CASSANDRA-20885)
diff --git a/src/java/org/apache/cassandra/db/ColumnFamilyStore.java 
b/src/java/org/apache/cassandra/db/ColumnFamilyStore.java
index 5b39dd42da..0d6cd2eb9b 100644
--- a/src/java/org/apache/cassandra/db/ColumnFamilyStore.java
+++ b/src/java/org/apache/cassandra/db/ColumnFamilyStore.java
@@ -477,6 +477,19 @@ public class ColumnFamilyStore implements 
ColumnFamilyStoreMBean, Memtable.Owner
                              Directories directories,
                              boolean loadSSTables,
                              boolean registerBookeeping)
+    {
+        this(keyspace, columnFamilyName, sstableIdGenerator, initMetadata, 
directories, loadSSTables, registerBookeeping, true);
+    }
+
+    @VisibleForTesting
+    public ColumnFamilyStore(Keyspace keyspace,
+                             String columnFamilyName,
+                             Supplier<? extends SSTableId> sstableIdGenerator,
+                             TableMetadata initMetadata,
+                             Directories directories,
+                             boolean loadSSTables,
+                             boolean registerBookeeping,
+                             boolean addIndexes)
     {
         assert directories != null;
         assert initMetadata != null : "null metadata for " + keyspace + ':' + 
columnFamilyName;
@@ -528,9 +541,11 @@ public class ColumnFamilyStore implements 
ColumnFamilyStoreMBean, Memtable.Owner
 
         // create the private ColumnFamilyStores for the secondary column 
indexes
         indexManager = new SecondaryIndexManager(this);
-        for (IndexMetadata info : initMetadata.indexes)
+
+        if (addIndexes)
         {
-            indexManager.addIndex(info, true);
+            for (IndexMetadata info : initMetadata.indexes)
+                indexManager.addIndex(info, true);
         }
 
         // See CASSANDRA-16228. We need to ensure that metrics are exposed 
after the CFS is initialized,
@@ -744,18 +759,29 @@ public class ColumnFamilyStore implements 
ColumnFamilyStoreMBean, Memtable.Owner
     }
 
 
-    public static ColumnFamilyStore createColumnFamilyStore(Keyspace keyspace, 
TableMetadata metadata, boolean loadSSTables)
+    public static ColumnFamilyStore createColumnFamilyStore(Keyspace keyspace, 
TableMetadata metadata, boolean loadSSTables, boolean addIndexes)
     {
-        return createColumnFamilyStore(keyspace, metadata.name, metadata, 
loadSSTables);
+        return createColumnFamilyStore(keyspace, metadata.name, metadata, 
loadSSTables, addIndexes);
     }
 
     public static ColumnFamilyStore createColumnFamilyStore(Keyspace keyspace,
                                                             String 
columnFamily,
                                                             TableMetadata 
metadata,
-                                                            boolean 
loadSSTables)
+                                                            boolean 
loadSSTables,
+                                                            boolean addIndexes)
     {
         Directories directories = new Directories(metadata);
-        return createColumnFamilyStore(keyspace, columnFamily, metadata, 
directories, loadSSTables, true);
+        return createColumnFamilyStore(keyspace, columnFamily, metadata, 
directories, loadSSTables, true, addIndexes);
+    }
+
+    public static ColumnFamilyStore createColumnFamilyStore(Keyspace keyspace,
+                                                            String 
columnFamily,
+                                                            TableMetadata 
metadata,
+                                                            Directories 
directories,
+                                                            boolean 
loadSSTables,
+                                                            boolean 
registerBookkeeping)
+    {
+        return createColumnFamilyStore(keyspace, columnFamily, metadata, 
directories, loadSSTables, registerBookkeeping, true);
     }
 
     /** This is only directly used by offline tools */
@@ -764,11 +790,12 @@ public class ColumnFamilyStore implements 
ColumnFamilyStoreMBean, Memtable.Owner
                                                                          
TableMetadata metadata,
                                                                          
Directories directories,
                                                                          
boolean loadSSTables,
-                                                                         
boolean registerBookkeeping)
+                                                                         
boolean registerBookkeeping,
+                                                                         
boolean addIndexes)
     {
         return new ColumnFamilyStore(keyspace, columnFamily,
                                      
directories.getUIDGenerator(SSTableIdFactory.instance.defaultBuilder()),
-                                     metadata, directories, loadSSTables, 
registerBookkeeping);
+                                     metadata, directories, loadSSTables, 
registerBookkeeping, addIndexes);
     }
 
     /**
diff --git a/src/java/org/apache/cassandra/db/Keyspace.java 
b/src/java/org/apache/cassandra/db/Keyspace.java
index f31662660b..cbf6039e42 100644
--- a/src/java/org/apache/cassandra/db/Keyspace.java
+++ b/src/java/org/apache/cassandra/db/Keyspace.java
@@ -255,10 +255,10 @@ public class Keyspace
 
     private Keyspace(String keyspaceName, SchemaProvider schema, boolean 
loadSSTables)
     {
-        this(schema,  schema.getKeyspaceMetadata(keyspaceName), loadSSTables);
+        this(schema,  schema.getKeyspaceMetadata(keyspaceName), loadSSTables, 
true);
     }
 
-    public Keyspace(SchemaProvider schema, KeyspaceMetadata metadata, boolean 
loadSSTables)
+    public Keyspace(SchemaProvider schema, KeyspaceMetadata metadata, boolean 
loadSSTables, boolean addIndexes)
     {
         this.schema = schema;
         this.name = metadata.name;
@@ -275,7 +275,7 @@ public class Keyspace
         for (TableMetadata cfm : metadata.tablesAndViews())
         {
             logger.trace("Initializing {}.{}", getName(), cfm.name);
-            initCf(cfm, loadSSTables);
+            initCf(cfm, loadSSTables, addIndexes);
         }
 
         this.viewManager.reload(metadata);
@@ -367,7 +367,7 @@ public class Keyspace
     /**
      * adds a cf to internal structures, ends up creating disk files).
      */
-    public void initCf(TableMetadata metadata, boolean loadSSTables)
+    public void initCf(TableMetadata metadata, boolean loadSSTables, boolean 
addIndexes)
     {
         ColumnFamilyStore cfs = columnFamilyStores.get(metadata.id);
 
@@ -377,7 +377,7 @@ public class Keyspace
             // We don't worry about races here; startup is safe, and adding 
multiple idential CFs
             // simultaneously is a "don't do that" scenario.
             ColumnFamilyStore oldCfs = 
columnFamilyStores.putIfAbsent(metadata.id,
-                                                                      
ColumnFamilyStore.createColumnFamilyStore(this, metadata, loadSSTables));
+                                                                      
ColumnFamilyStore.createColumnFamilyStore(this, metadata, loadSSTables, 
addIndexes));
             // CFS mbean instantiation will error out before we hit this, but 
in case that changes...
             if (oldCfs != null)
                 throw new IllegalStateException("added multiple mappings for 
cf id " + metadata.id);
diff --git a/src/java/org/apache/cassandra/index/internal/CassandraIndex.java 
b/src/java/org/apache/cassandra/index/internal/CassandraIndex.java
index b07e446bf2..53100ad499 100644
--- a/src/java/org/apache/cassandra/index/internal/CassandraIndex.java
+++ b/src/java/org/apache/cassandra/index/internal/CassandraIndex.java
@@ -235,7 +235,8 @@ public abstract class CassandraIndex implements Index
         indexCfs = ColumnFamilyStore.createColumnFamilyStore(baseCfs.keyspace,
                                                              tm.name,
                                                              tm,
-                                                             
baseCfs.getTracker().loadsstables);
+                                                             
baseCfs.getTracker().loadsstables,
+                                                             true);
         indexedColumn = target.left;
     }
 
diff --git a/src/java/org/apache/cassandra/schema/DistributedSchema.java 
b/src/java/org/apache/cassandra/schema/DistributedSchema.java
index 0eceb9b169..77fec54eda 100644
--- a/src/java/org/apache/cassandra/schema/DistributedSchema.java
+++ b/src/java/org/apache/cassandra/schema/DistributedSchema.java
@@ -23,6 +23,7 @@ import com.google.common.collect.ImmutableMap;
 import org.apache.cassandra.auth.AuthKeyspace;
 import org.apache.cassandra.config.DatabaseDescriptor;
 import org.apache.cassandra.cql3.functions.UserFunction;
+import org.apache.cassandra.db.ColumnFamilyStore;
 import org.apache.cassandra.db.Keyspace;
 import org.apache.cassandra.db.Mutation;
 import org.apache.cassandra.db.marshal.UserType;
@@ -226,7 +227,7 @@ public class DistributedSchema implements 
MetadataValue<DistributedSchema>
         schemaChangeNotifier.notifyPreChanges(new 
SchemaTransformation.SchemaTransformationResult(prev, this, ksDiff));
 
         ksDiff.dropped.forEach(metadata -> dropKeyspace(metadata, true));
-        ksDiff.created.forEach(metadata -> 
keyspaceInstances.put(metadata.name, new Keyspace(Schema.instance, metadata, 
loadSSTables)));
+        ksDiff.created.forEach(metadata -> 
keyspaceInstances.put(metadata.name, new Keyspace(Schema.instance, metadata, 
loadSSTables, DatabaseDescriptor.isClientOrToolInitialized())));
         ksDiff.altered.forEach(delta -> {
             boolean initialized = Keyspace.isInitialized();
 
@@ -281,6 +282,22 @@ public class DistributedSchema implements 
MetadataValue<DistributedSchema>
             }
         });
         ksDiff.created.forEach(schemaChangeNotifier::notifyKeyspaceCreated);
+
+        ksDiff.created.forEach(ks -> {
+            if (ks.tables.size() == 0)
+                return;
+
+            boolean initialized = Keyspace.isInitialized();
+            Keyspace keyspace = initialized ? keyspaceInstances.get(ks.name) : 
null;
+
+            if (keyspace != null)
+            {
+                for (ColumnFamilyStore cfs : keyspace.getColumnFamilyStores())
+                    for (IndexMetadata info : cfs.metadata().indexes)
+                        cfs.indexManager.addIndex(info, true);
+            }
+        });
+
         ksDiff.altered.forEach(delta -> {
             boolean initialized = Keyspace.isInitialized();
             Keyspace keyspace = initialized ? 
keyspaceInstances.get(delta.before.name) : null;
@@ -296,6 +313,13 @@ public class DistributedSchema implements 
MetadataValue<DistributedSchema>
 
                 // add tables and views
                 delta.tables.created.forEach(t -> 
SchemaDiagnostics.tableCreated(Schema.instance, t));
+
+                delta.tables.created.forEach(t -> {
+                    ColumnFamilyStore cfs = 
keyspace.getColumnFamilyStore(t.name);
+                    for (IndexMetadata info : cfs.metadata().indexes)
+                        cfs.indexManager.addIndex(info, true);
+                });
+
                 delta.views.created.forEach(v -> 
SchemaDiagnostics.tableCreated(Schema.instance, v.metadata));
 
                 // update tables and views
@@ -369,13 +393,13 @@ public class DistributedSchema implements 
MetadataValue<DistributedSchema>
     private void createTable(Keyspace keyspace, TableMetadata table, boolean 
loadSSTables)
     {
         SchemaDiagnostics.tableCreating(Schema.instance, table);
-        keyspace.initCf(table, loadSSTables);
+        keyspace.initCf(table, loadSSTables, 
DatabaseDescriptor.isClientOrToolInitialized());
     }
 
     private void createView(Keyspace keyspace, ViewMetadata view)
     {
         SchemaDiagnostics.tableCreating(Schema.instance, view.metadata);
-        keyspace.initCf(view.metadata, true);
+        keyspace.initCf(view.metadata, true, 
DatabaseDescriptor.isClientOrToolInitialized());
     }
 
     private void alterTable(Keyspace keyspace, TableMetadata updated)
diff --git 
a/test/distributed/org/apache/cassandra/distributed/upgrade/ClusterMetadata2iUpgradeTest.java
 
b/test/distributed/org/apache/cassandra/distributed/upgrade/ClusterMetadata2iUpgradeTest.java
new file mode 100644
index 0000000000..1259104284
--- /dev/null
+++ 
b/test/distributed/org/apache/cassandra/distributed/upgrade/ClusterMetadata2iUpgradeTest.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.distributed.upgrade;
+
+import org.junit.Test;
+
+import org.apache.cassandra.distributed.api.ConsistencyLevel;
+import org.apache.cassandra.distributed.api.Feature;
+import org.apache.cassandra.distributed.test.TestBaseImpl;
+
+import static org.apache.cassandra.distributed.upgrade.UpgradeTestBase.v50;
+
+public class ClusterMetadata2iUpgradeTest extends TestBaseImpl
+{
+    @Test
+    public void upgradeIndexIsNotBuiltTest() throws Throwable
+    {
+        new UpgradeTestBase.TestCase()
+        .nodes(1)
+        .nodesToUpgrade(1)
+        .withConfig((cfg) -> cfg.with(Feature.GOSSIP))
+        .upgradesToCurrentFrom(v50)
+        .setup((cluster) -> {
+            cluster.schemaChange("CREATE TABLE " + KEYSPACE + ".tbl (pk int, 
ck int, v int, PRIMARY KEY (pk, ck))");
+            cluster.schemaChange(withKeyspace("create index iii on %s.tbl 
(ck)"));
+            cluster.schemaChange(withKeyspace("create index iii2 on %s.tbl 
(v)"));
+            for (int i = 0; i < 1000; i++)
+                cluster.coordinator(1).execute(withKeyspace("insert into 
%s.tbl (pk, ck, v) values (?, ?, ?)"), ConsistencyLevel.ALL, i, i, i);
+            cluster.forEach(i -> i.flush(KEYSPACE));
+            cluster.forEach(i -> i.executeInternal("truncate 
system.\"IndexInfo\""));
+        })
+        .runAfterClusterUpgrade((cluster) -> {
+        }).run();
+    }
+}
diff --git 
a/test/unit/org/apache/cassandra/index/internal/CustomCassandraIndex.java 
b/test/unit/org/apache/cassandra/index/internal/CustomCassandraIndex.java
index de9ac3a54d..2a06a715bb 100644
--- a/test/unit/org/apache/cassandra/index/internal/CustomCassandraIndex.java
+++ b/test/unit/org/apache/cassandra/index/internal/CustomCassandraIndex.java
@@ -183,7 +183,8 @@ public class CustomCassandraIndex implements Index
         indexCfs = ColumnFamilyStore.createColumnFamilyStore(baseCfs.keyspace,
                                                              cfm.name,
                                                              cfm.ref.get(),
-                                                             
baseCfs.getTracker().loadsstables);
+                                                             
baseCfs.getTracker().loadsstables,
+                                                             false);
         indexedColumn = target.left;
     }
 


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

Reply via email to