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

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


The following commit(s) were added to refs/heads/cep-45-mutation-tracking by 
this push:
     new 950f930a8a CEP-45: Fixes and improvements to mutation tracking 
migration
950f930a8a is described below

commit 950f930a8a952db5a16acc27aacdcc6268b21c46
Author: Aleksey Yeshchenko <[email protected]>
AuthorDate: Thu Aug 27 14:56:38 2026 +0100

    CEP-45: Fixes and improvements to mutation tracking migration
    
    patch by Aleksey Yeschenko; reviewed by Blake Eggleston for
    CASSANDSA-21653
---
 CHANGES.txt                                        |  1 +
 .../db/virtual/MutationTrackingTables.java         | 95 +++++++++++++++++++++-
 .../org/apache/cassandra/repair/RepairJob.java     |  2 +-
 .../migration/KeyspaceMigrationInfo.java           | 14 +++-
 .../MutationTrackingMigrationRepairResult.java     | 16 +++-
 .../migration/MutationTrackingMigrationState.java  |  4 +-
 .../migration/MutationTrackingRepairHandler.java   | 27 ++++--
 .../AdvanceMutationTrackingMigration.java          | 24 ++++--
 .../migration/KeyspaceMigrationInfoTest.java       |  6 +-
 .../AdvanceMutationTrackingMigrationTest.java      | 15 +---
 10 files changed, 167 insertions(+), 37 deletions(-)

diff --git a/CHANGES.txt b/CHANGES.txt
index 0738fb414d..c79abe7f88 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
 cep-45-mutation-tracking
+ * CEP-45: Fixes and improvements to mutation tracking migration
  * Add support for counters to mutation tracking (CASSANDRA-20959)
  * CEP-45: Query forwarding (CASSANDRA-20309)
  * Fix mutation tracking startup (CASSANDRA-20540)
diff --git 
a/src/java/org/apache/cassandra/db/virtual/MutationTrackingTables.java 
b/src/java/org/apache/cassandra/db/virtual/MutationTrackingTables.java
index 406693d23e..e0498028ee 100644
--- a/src/java/org/apache/cassandra/db/virtual/MutationTrackingTables.java
+++ b/src/java/org/apache/cassandra/db/virtual/MutationTrackingTables.java
@@ -22,15 +22,21 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.stream.Collectors;
 
 import org.apache.cassandra.config.DatabaseDescriptor;
 import org.apache.cassandra.db.DecoratedKey;
 import org.apache.cassandra.db.Mutation;
 import org.apache.cassandra.db.marshal.BooleanType;
 import org.apache.cassandra.db.marshal.Int32Type;
+import org.apache.cassandra.db.marshal.ListType;
 import org.apache.cassandra.db.marshal.LongType;
 import org.apache.cassandra.db.marshal.UTF8Type;
+import org.apache.cassandra.db.marshal.UUIDType;
 import org.apache.cassandra.dht.LocalPartitioner;
+import org.apache.cassandra.dht.NormalizedRanges;
+import org.apache.cassandra.dht.Range;
+import org.apache.cassandra.dht.Token;
 import org.apache.cassandra.journal.ActiveSegment;
 import org.apache.cassandra.journal.Segment;
 import org.apache.cassandra.replication.CoordinatorLog;
@@ -39,12 +45,16 @@ import org.apache.cassandra.replication.MutationJournal;
 import org.apache.cassandra.replication.MutationTrackingService;
 import org.apache.cassandra.replication.Shard;
 import org.apache.cassandra.replication.ShortMutationId;
+import org.apache.cassandra.schema.TableId;
 import org.apache.cassandra.schema.TableMetadata;
+import 
org.apache.cassandra.service.replication.migration.KeyspaceMigrationInfo;
+import org.apache.cassandra.tcm.ClusterMetadata;
 
 public class MutationTrackingTables
 {
     public static final String MUTATION_JOURNAL = "mutation_journal";
     public static final String MUTATION_TRACKING_SHARDS = 
"mutation_tracking_shards";
+    public static final String MUTATION_TRACKING_MIGRATION_STATE = 
"mutation_tracking_migration_state";
 
     private MutationTrackingTables() {}
 
@@ -53,7 +63,9 @@ public class MutationTrackingTables
         if (!DatabaseDescriptor.getMutationTrackingEnabled())
             return Collections.emptyList();
 
-        return List.of(new MutationJournalTable(keyspace), new 
MutationTrackingShardsTable(keyspace));
+        return List.of(new MutationJournalTable(keyspace),
+                       new MutationTrackingShardsTable(keyspace),
+                       new MutationTrackingMigrationStateTable(keyspace));
     }
 
     public static final class MutationJournalTable extends AbstractVirtualTable
@@ -183,4 +195,85 @@ public class MutationTrackingTables
             return result;
         }
     }
+
+    /**
+     * Mutation tracking migration progress (held in {@link ClusterMetadata}).
+     */
+    public static class MutationTrackingMigrationStateTable extends 
AbstractVirtualTable
+    {
+        private static final String KEYSPACE_NAME = "keyspace_name";
+        private static final String TABLE_NAME = "table_name";
+        private static final String TABLE_ID = "table_id";
+        private static final String STARTED_AT_EPOCH = "started_at_epoch";
+        private static final String PENDING_RANGES = "pending_ranges";
+        private static final String MIGRATED_RANGES = "migrated_ranges";
+
+        private static final ListType<String> STRING_LIST_TYPE = 
ListType.getInstance(UTF8Type.instance, false);
+
+        MutationTrackingMigrationStateTable(String keyspace)
+        {
+            super(TableMetadata.builder(keyspace, 
MUTATION_TRACKING_MIGRATION_STATE)
+                               .comment("ranges still to be repaired for 
in-progress mutation tracking migrations")
+                               .kind(TableMetadata.Kind.VIRTUAL)
+                               .partitioner(new 
LocalPartitioner(UTF8Type.instance))
+                               .addPartitionKeyColumn(KEYSPACE_NAME, 
UTF8Type.instance)
+                               .addClusteringColumn(TABLE_NAME, 
UTF8Type.instance)
+                               .addRegularColumn(TABLE_ID, UUIDType.instance)
+                               .addRegularColumn(STARTED_AT_EPOCH, 
LongType.instance)
+                               .addRegularColumn(PENDING_RANGES, 
STRING_LIST_TYPE)
+                               .addRegularColumn(MIGRATED_RANGES, 
STRING_LIST_TYPE)
+                               .build());
+        }
+
+        @Override
+        public DataSet data()
+        {
+            SimpleDataSet result = new SimpleDataSet(metadata());
+            ClusterMetadata metadata = ClusterMetadata.current();
+
+            for (KeyspaceMigrationInfo info : 
metadata.mutationTrackingMigrationState.keyspaceInfo.values())
+                addTableRows(metadata, info, result);
+
+            return result;
+        }
+
+        @Override
+        public DataSet data(DecoratedKey key)
+        {
+            String keyspaceName = UTF8Type.instance.compose(key.getKey());
+            SimpleDataSet result = new SimpleDataSet(metadata());
+            ClusterMetadata metadata = ClusterMetadata.current();
+
+            KeyspaceMigrationInfo info = 
metadata.mutationTrackingMigrationState.getKeyspaceInfo(keyspaceName);
+            if (info != null)
+                addTableRows(metadata, info, result);
+
+            return result;
+        }
+
+        private static void addTableRows(ClusterMetadata metadata, 
KeyspaceMigrationInfo info, SimpleDataSet result)
+        {
+            NormalizedRanges<Token> fullRing = 
KeyspaceMigrationInfo.fullRing();
+            for (Map.Entry<TableId, NormalizedRanges<Token>> entry : 
info.pendingRangesPerTable.entrySet())
+            {
+                TableId tid = entry.getKey();
+                NormalizedRanges<Token> pendingRanges = entry.getValue();
+
+                TableMetadata tm = metadata.schema.getTableMetadata(tid);
+                if (tm == null)
+                    continue;
+
+                result.row(info.keyspace, tm.name)
+                      .column(TABLE_ID, tid.asUUID())
+                      .column(STARTED_AT_EPOCH, info.startedAtEpoch.getEpoch())
+                      .column(PENDING_RANGES, rangesToStrings(pendingRanges))
+                      .column(MIGRATED_RANGES, 
rangesToStrings(fullRing.subtract(pendingRanges)));
+            }
+        }
+
+        private static List<String> rangesToStrings(NormalizedRanges<Token> 
ranges)
+        {
+            return 
ranges.stream().map(Range::toString).collect(Collectors.toList());
+        }
+    }
 }
diff --git a/src/java/org/apache/cassandra/repair/RepairJob.java 
b/src/java/org/apache/cassandra/repair/RepairJob.java
index db7079efc1..35f764c489 100644
--- a/src/java/org/apache/cassandra/repair/RepairJob.java
+++ b/src/java/org/apache/cassandra/repair/RepairJob.java
@@ -295,7 +295,7 @@ public class RepairJob extends AsyncFuture<RepairResult> 
implements Runnable
                 cfs.metric.repairsCompleted.inc();
                 logger.info("Completing repair with excludedDeadNodes {}", 
session.excludedDeadNodes);
                 ConsensusMigrationRepairResult cmrs = 
ConsensusMigrationRepairResult.fromRepair(repairStartingEpoch, 
getUnchecked(accordRepair), session.repairData, doPaxosRepair, doAccordRepair, 
session.excludedDeadNodes, session.isIncremental);
-                MutationTrackingMigrationRepairResult mtmrs = 
MutationTrackingMigrationRepairResult.fromRepair(repairStartingEpoch, 
session.excludedDeadNodes, session.previewKind.isPreview());
+                MutationTrackingMigrationRepairResult mtmrs = 
MutationTrackingMigrationRepairResult.fromRepair(repairStartingEpoch, 
session.repairData, session.allReplicas, session.pullRepair, 
session.excludedDeadNodes, session.previewKind.isPreview());
                 trySuccess(new RepairResult(desc, stats, cmrs, mtmrs));
             }
 
diff --git 
a/src/java/org/apache/cassandra/service/replication/migration/KeyspaceMigrationInfo.java
 
b/src/java/org/apache/cassandra/service/replication/migration/KeyspaceMigrationInfo.java
index 65b08d0d78..a2021226cb 100644
--- 
a/src/java/org/apache/cassandra/service/replication/migration/KeyspaceMigrationInfo.java
+++ 
b/src/java/org/apache/cassandra/service/replication/migration/KeyspaceMigrationInfo.java
@@ -174,18 +174,24 @@ public class KeyspaceMigrationInfo
                                                             @Nonnull TableId 
tableId,
                                                             @Nonnull 
Collection<Range<Token>> repairedRanges)
     {
-        if (repairStartedEpoch.isBefore(startedAtEpoch))
-            return this;
+        // TODO (expected): do something about this? nuke or serialize the 
correct epoch alongised the transformation?
+        //      this was dead code; repairStartedEpoch as passed was always 
next transformation's epoch,
+        //      and it was always > startedAtEpoch, guarding against nothing;
+        //      there is an epoch eligibility check in 
MutationTrackingRepairHandler in onSuccess(), but it is
+        //      insufficient in face of potential race conditions (AY)
+        // if (repairStartedEpoch.isBefore(startedAtEpoch))
+        //    return this;
 
         NormalizedRanges<Token> currentPendingForTable = 
pendingRangesPerTable.get(tableId);
         if (currentPendingForTable == null)
-        {
             return this;
-        }
 
         NormalizedRanges<Token> normalizedRepaired = 
NormalizedRanges.normalizedRanges(repairedRanges);
         NormalizedRanges<Token> remainingForTable = 
currentPendingForTable.subtract(normalizedRepaired);
 
+        if (remainingForTable.equals(currentPendingForTable))
+            return this;
+
         ImmutableMap.Builder<TableId, NormalizedRanges<Token>> builder = 
ImmutableMap.builder();
         for (Map.Entry<TableId, NormalizedRanges<Token>> entry : 
pendingRangesPerTable.entrySet())
         {
diff --git 
a/src/java/org/apache/cassandra/service/replication/migration/MutationTrackingMigrationRepairResult.java
 
b/src/java/org/apache/cassandra/service/replication/migration/MutationTrackingMigrationRepairResult.java
index e0ec934382..fb5009f4fb 100644
--- 
a/src/java/org/apache/cassandra/service/replication/migration/MutationTrackingMigrationRepairResult.java
+++ 
b/src/java/org/apache/cassandra/service/replication/migration/MutationTrackingMigrationRepairResult.java
@@ -33,6 +33,12 @@ public class MutationTrackingMigrationRepairResult
         new MutationTrackingMigrationRepairResult(Epoch.EMPTY, false, "dead 
nodes were excluded from the repair");
     private static final MutationTrackingMigrationRepairResult PREVIEW =
         new MutationTrackingMigrationRepairResult(Epoch.EMPTY, false, "the 
repair was a preview");
+    private static final MutationTrackingMigrationRepairResult NO_DATA_REPAIR =
+        new MutationTrackingMigrationRepairResult(Epoch.EMPTY, false, "the 
repair did not repair data (paxos-only or accord-only repair)");
+    private static final MutationTrackingMigrationRepairResult 
NOT_ALL_REPLICAS =
+        new MutationTrackingMigrationRepairResult(Epoch.EMPTY, false, "the 
repair did not include all replicas (-local, -dc, or -hosts repair)");
+    private static final MutationTrackingMigrationRepairResult PULL_REPAIR =
+        new MutationTrackingMigrationRepairResult(Epoch.EMPTY, false, "the 
repair only streamed data one way (-pull repair)");
 
     public final Epoch minEpoch;
     public final boolean eligible;
@@ -48,10 +54,18 @@ public class MutationTrackingMigrationRepairResult
         this.ineligibleReason = ineligibleReason;
     }
 
-    public static MutationTrackingMigrationRepairResult fromRepair(Epoch 
minEpoch, boolean deadNodesExcluded, boolean isPreview)
+    public static MutationTrackingMigrationRepairResult fromRepair(Epoch 
minEpoch,
+                                                                   boolean 
dataRepaired,
+                                                                   boolean 
allReplicas,
+                                                                   boolean 
pullRepair,
+                                                                   boolean 
deadNodesExcluded,
+                                                                   boolean 
isPreview)
     {
         if (deadNodesExcluded) return DEAD_NODES_EXCLUDED;
         if (isPreview) return PREVIEW;
+        if (!dataRepaired) return NO_DATA_REPAIR;
+        if (!allReplicas) return NOT_ALL_REPLICAS;
+        if (pullRepair) return PULL_REPAIR;
         return new MutationTrackingMigrationRepairResult(minEpoch, true, null);
     }
 }
diff --git 
a/src/java/org/apache/cassandra/service/replication/migration/MutationTrackingMigrationState.java
 
b/src/java/org/apache/cassandra/service/replication/migration/MutationTrackingMigrationState.java
index 1c500c6b10..68ac0ea2a1 100644
--- 
a/src/java/org/apache/cassandra/service/replication/migration/MutationTrackingMigrationState.java
+++ 
b/src/java/org/apache/cassandra/service/replication/migration/MutationTrackingMigrationState.java
@@ -177,8 +177,10 @@ public class MutationTrackingMigrationState implements 
MetadataValue<MutationTra
         if (info == null)
             return this;
 
-        // Subtract repaired ranges from table's pending set
+        // subtract repaired ranges from table's pending set; noop is 
nothing's changed
         KeyspaceMigrationInfo updated = info.withRangesRepairedForTable(epoch, 
tableId, repairedRanges);
+        if (info == updated)
+            return this;
 
         // if all tables fully repaired, remove keyspace (migration complete)
         if (updated.isComplete())
diff --git 
a/src/java/org/apache/cassandra/service/replication/migration/MutationTrackingRepairHandler.java
 
b/src/java/org/apache/cassandra/service/replication/migration/MutationTrackingRepairHandler.java
index b55c362a30..ee8e43879c 100644
--- 
a/src/java/org/apache/cassandra/service/replication/migration/MutationTrackingRepairHandler.java
+++ 
b/src/java/org/apache/cassandra/service/replication/migration/MutationTrackingRepairHandler.java
@@ -63,8 +63,8 @@ public class MutationTrackingRepairHandler
 
                     if (migrationInfo == null)
                     {
-                        logger.info("Repair session {} (parent session {}) 
completed for {}.{} but the keyspace is not migrating, not advancing mutation 
tracking migration",
-                                    desc.sessionId, desc.parentSessionId, 
keyspace, tableName);
+                        logger.debug("Repair session {} (parent session {}) 
completed for {}.{} but the keyspace is not migrating, not advancing mutation 
tracking migration",
+                                     desc.sessionId, desc.parentSessionId, 
keyspace, tableName);
                         return;
                     }
 
@@ -78,10 +78,13 @@ public class MutationTrackingRepairHandler
                         return;
                     }
 
-                    if 
(migrationInfo.getPendingRangesForTable(tableMetadata.id).isEmpty())
+                    NormalizedRanges<Token> pendingRanges = 
migrationInfo.getPendingRangesForTable(tableMetadata.id);
+                    NormalizedRanges<Token> repairedPendingRanges = 
pendingRanges.intersection(NormalizedRanges.normalizedRanges(repairedRanges));
+
+                    if (repairedPendingRanges.isEmpty())
                     {
-                        logger.info("Repair session {} (parent session {}) 
completed for {}.{} but the table has no ranges left to migrate, not advancing 
mutation tracking migration",
-                                    desc.sessionId, desc.parentSessionId, 
keyspace, tableName);
+                        logger.info("Repair session {} (parent session {}) 
completed for {}.{} but none of the repaired ranges {} are still pending 
migration (pending: {}), not advancing mutation tracking migration",
+                                    desc.sessionId, desc.parentSessionId, 
keyspace, tableName, repairedRanges, pendingRanges);
                         return;
                     }
 
@@ -104,7 +107,17 @@ public class MutationTrackingRepairHandler
                     }
 
                     ClusterMetadata committed = 
ClusterMetadataService.instance().commit(
-                        new AdvanceMutationTrackingMigration(keyspace, 
tableMetadata.id, repairedRanges));
+                        new AdvanceMutationTrackingMigration(keyspace, 
tableMetadata.id, repairedPendingRanges),
+                        ignore -> ignore,
+                        (code, message) ->
+                        {
+                            logger.info("Repair session {} (parent session {}) 
did not advance mutation tracking migration of {}.{}: {} ({})",
+                                        desc.sessionId, desc.parentSessionId, 
keyspace, tableName, message, code);
+                            return null;
+                        });
+
+                    if (committed == null)
+                        return;
 
                     // Report from the metadata commit returned, not 
current(), which races with other epochs
                     KeyspaceMigrationInfo advanced = 
committed.mutationTrackingMigrationState.getKeyspaceInfo(keyspace);
@@ -119,7 +132,7 @@ public class MutationTrackingRepairHandler
                                 "contributed {} range(s) {}; {} range(s) 
remain to be repaired {}; {} range(s) already repaired {}; " +
                                 "{} table(s) in the keyspace still migrating",
                                 desc.sessionId, desc.parentSessionId, 
keyspace, tableName, committed.epoch,
-                                repairedRanges.size(), repairedRanges,
+                                repairedPendingRanges.size(), 
repairedPendingRanges,
                                 pending.size(), pending,
                                 repaired.size(), repaired,
                                 keyspaceComplete ? 0 : 
advanced.pendingRangesPerTable.size());
diff --git 
a/src/java/org/apache/cassandra/tcm/transformations/AdvanceMutationTrackingMigration.java
 
b/src/java/org/apache/cassandra/tcm/transformations/AdvanceMutationTrackingMigration.java
index 9245a11349..89e635669d 100644
--- 
a/src/java/org/apache/cassandra/tcm/transformations/AdvanceMutationTrackingMigration.java
+++ 
b/src/java/org/apache/cassandra/tcm/transformations/AdvanceMutationTrackingMigration.java
@@ -23,9 +23,6 @@ import java.util.Collection;
 
 import javax.annotation.Nonnull;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import org.apache.cassandra.db.TypeSizes;
 import org.apache.cassandra.dht.Range;
 import org.apache.cassandra.dht.Token;
@@ -57,7 +54,6 @@ import static 
org.apache.cassandra.utils.CollectionSerializers.serializedCollect
  */
 public class AdvanceMutationTrackingMigration implements Transformation
 {
-    private static final Logger logger = 
LoggerFactory.getLogger(AdvanceMutationTrackingMigration.class);
     public static final Serializer serializer = new Serializer();
 
     @Nonnull
@@ -94,10 +90,7 @@ public class AdvanceMutationTrackingMigration implements 
Transformation
         KeyspaceMigrationInfo ksInfo = 
prev.mutationTrackingMigrationState.getKeyspaceInfo(keyspace);
 
         if (ksInfo == null)
-        {
-            logger.warn("Attempted to advance mutation tracking migration for 
keyspace {} table {} which is not migrating", keyspace, tableId);
             return new Rejected(INVALID, String.format("Keyspace %s is not 
migrating", keyspace));
-        }
 
         Transformer transformer = prev.transformer();
 
@@ -105,14 +98,27 @@ public class AdvanceMutationTrackingMigration implements 
Transformation
         MutationTrackingMigrationState newState = 
prev.mutationTrackingMigrationState
             .withRangesRepairedForTable(keyspace, tableId, repairedRanges, 
transformer.epoch());
 
-        logger.info("Advanced mutation tracking migration for keyspace {}, 
table {}: {} ranges repaired",
-                   keyspace, tableId, repairedRanges.size());
+        if (newState == prev.mutationTrackingMigrationState)
+        {
+            return new Rejected(INVALID, String.format("Keyspace %s table %s 
has no pending ranges intersecting %s",
+                                                       keyspace, tableId, 
repairedRanges));
+        }
 
         return Transformation.success(
             transformer.with(newState),
             LockedRanges.AffectedRanges.EMPTY);
     }
 
+    @Override
+    public String toString()
+    {
+        return "AdvanceMutationTrackingMigration{" +
+               "keyspace='" + keyspace + '\'' +
+               ", tableId=" + tableId +
+               ", repairedRanges=" + repairedRanges +
+               '}';
+    }
+
     public static class Serializer implements 
AsymmetricMetadataSerializer<Transformation, AdvanceMutationTrackingMigration>
     {
         @Override
diff --git 
a/test/unit/org/apache/cassandra/service/replication/migration/KeyspaceMigrationInfoTest.java
 
b/test/unit/org/apache/cassandra/service/replication/migration/KeyspaceMigrationInfoTest.java
index 48a4170b75..3592209115 100644
--- 
a/test/unit/org/apache/cassandra/service/replication/migration/KeyspaceMigrationInfoTest.java
+++ 
b/test/unit/org/apache/cassandra/service/replication/migration/KeyspaceMigrationInfoTest.java
@@ -102,7 +102,7 @@ public class KeyspaceMigrationInfoTest
 
         // info should be unchanged if a repair started before migration 
started
         KeyspaceMigrationInfo noop = info.withRangesRepairedForTable(epoch1, 
testTableId, Collections.singleton(ranges.get(0)));
-        assertSame(info, noop);
+        // assertSame(info, noop); // see the comment in 
withRangesRepairedForTable()
 
         // Subtract first range
         KeyspaceMigrationInfo updated = 
info.withRangesRepairedForTable(epoch2, testTableId, 
Collections.singleton(ranges.get(0)));
@@ -117,6 +117,10 @@ public class KeyspaceMigrationInfoTest
         
assertFalse(updated2.pendingRangesPerTable.get(testTableId).intersects(ranges.get(0).right));
         
assertFalse(updated2.pendingRangesPerTable.get(testTableId).intersects(ranges.get(1).right));
         assertFalse(updated2.isComplete());
+
+        // Subtracting non-intersecting ranges should return `this`
+        assertSame(updated2, updated2.withRangesRepairedForTable(epoch2, 
testTableId, Collections.singleton(ranges.get(0))));
+        assertSame(updated2, updated2.withRangesRepairedForTable(epoch2, 
testTableId, Collections.singleton(ranges.get(1))));
     }
 
     @Test
diff --git 
a/test/unit/org/apache/cassandra/tcm/transformations/AdvanceMutationTrackingMigrationTest.java
 
b/test/unit/org/apache/cassandra/tcm/transformations/AdvanceMutationTrackingMigrationTest.java
index da33dc9958..948395f40a 100644
--- 
a/test/unit/org/apache/cassandra/tcm/transformations/AdvanceMutationTrackingMigrationTest.java
+++ 
b/test/unit/org/apache/cassandra/tcm/transformations/AdvanceMutationTrackingMigrationTest.java
@@ -193,18 +193,9 @@ public class AdvanceMutationTrackingMigrationTest
 
         Transformation.Result result = transformation.execute(prev);
 
-        // confirm noop
-        assertTrue(result.isSuccess());
-        ClusterMetadata updated = result.success().metadata;
-
-        KeyspaceMigrationInfo expected = createExpectedInfo(
-            "test_ks",
-            testTableId,
-            Collections.singleton(fullRing()),
-            epoch1
-        );
-
-        assertEquals(expected, 
updated.mutationTrackingMigrationState.getKeyspaceInfo("test_ks"));
+        // confirm rejection
+        assertTrue(result.isRejected());
+        assertTrue(result.rejected().reason.contains("no pending ranges 
intersecting"));
     }
 
     @Test


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

Reply via email to