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

sarankk 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 330134e231 CASSANDRA-21723 Wrap-around shard silently skipped during 
coordinated SSTable import for mutation tracking enabled tables
330134e231 is described below

commit 330134e2312c8ab60740c3a84d0af3cc709edcbd
Author: Saranya Krishnakumar <[email protected]>
AuthorDate: Tue Oct 20 05:58:59 2026 -0700

    CASSANDRA-21723 Wrap-around shard silently skipped during coordinated 
SSTable import for mutation tracking enabled tables
---
 CHANGES.txt                                        |  1 +
 .../replication/TrackedImportTransfers.java        |  4 +-
 .../test/tracking/TrackedImportTransferTest.java   | 58 ++++++++++++++++++++++
 3 files changed, 61 insertions(+), 2 deletions(-)

diff --git a/CHANGES.txt b/CHANGES.txt
index 55ef96c0a0..f15927c962 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
 cep-45-mutation-tracking
+ * CEP-45: Wrap-around shard silently skipped during coordinated SSTable 
import for tracked tables (CASSANDRA-21723)
  * CEP-45: Migration repair streams can write live SSTables into 
pending/<planId>/ and lose them silently on restart (CASSANDRA-21626)
  * CEP-45: Prevent dropping journal segments referenced by partially 
reconciled sstables (CASSANDRA-21406)
  * CEP-45: Fixes and improvements to mutation tracking migration 
(CASSANDSA-21653)
diff --git 
a/src/java/org/apache/cassandra/replication/TrackedImportTransfers.java 
b/src/java/org/apache/cassandra/replication/TrackedImportTransfers.java
index b2974df4c6..364ae13690 100644
--- a/src/java/org/apache/cassandra/replication/TrackedImportTransfers.java
+++ b/src/java/org/apache/cassandra/replication/TrackedImportTransfers.java
@@ -30,10 +30,10 @@ import java.util.Map;
 
 import org.apache.cassandra.db.ConsistencyLevel;
 import org.apache.cassandra.db.lifecycle.SSTableIntervalTree;
+import org.apache.cassandra.db.lifecycle.View;
 import org.apache.cassandra.dht.Range;
 import org.apache.cassandra.dht.Token;
 import org.apache.cassandra.io.sstable.format.SSTableReader;
-import org.apache.cassandra.utils.Interval;
 
 /**
  * Factory and container for creating multiple {@link TrackedImportTransfer} 
instances from a collection
@@ -69,7 +69,7 @@ public class TrackedImportTransfers implements 
Iterable<TrackedImportTransfer>
 
         shards.forEachShard(shard -> {
             Range<Token> range = shard.tokenRange();
-            Collection<SSTableReader> sstablesForRange = 
intervals.search(Interval.create(range.left.minKeyBound(), 
range.right.maxKeyBound()));
+            Collection<SSTableReader> sstablesForRange = 
View.sstablesInBounds(range.left.minKeyBound(), range.right.maxKeyBound(), 
intervals);
             List<Range<Token>> ranges = Collections.singletonList(range);
             Map<SSTableReader, List<SSTableReader.PartitionPositionBounds>> 
positionForSSTables = new HashMap<>();
             sstablesForRange.removeIf(sstable -> {
diff --git 
a/test/distributed/org/apache/cassandra/distributed/test/tracking/TrackedImportTransferTest.java
 
b/test/distributed/org/apache/cassandra/distributed/test/tracking/TrackedImportTransferTest.java
index 9095d82db3..602d980f4b 100644
--- 
a/test/distributed/org/apache/cassandra/distributed/test/tracking/TrackedImportTransferTest.java
+++ 
b/test/distributed/org/apache/cassandra/distributed/test/tracking/TrackedImportTransferTest.java
@@ -19,8 +19,10 @@
 package org.apache.cassandra.distributed.test.tracking;
 
 import java.io.IOException;
+import java.nio.ByteBuffer;
 import java.nio.file.Files;
 import java.time.Duration;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
@@ -38,6 +40,9 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import org.apache.cassandra.db.ColumnFamilyStore;
+import org.apache.cassandra.dht.Murmur3Partitioner;
+import org.apache.cassandra.dht.Range;
+import org.apache.cassandra.dht.Token;
 import org.apache.cassandra.distributed.Cluster;
 import org.apache.cassandra.distributed.api.ConsistencyLevel;
 import org.apache.cassandra.distributed.api.IInvokableInstance;
@@ -45,6 +50,7 @@ import org.apache.cassandra.distributed.shared.AssertUtils;
 import org.apache.cassandra.distributed.test.sai.SAIUtil;
 import org.apache.cassandra.io.sstable.CQLSSTableWriter;
 import org.apache.cassandra.io.util.File;
+import org.apache.cassandra.replication.MutationTrackingService;
 import org.apache.cassandra.tcm.ClusterMetadata;
 import org.apache.cassandra.tcm.ownership.DataPlacement;
 
@@ -247,6 +253,58 @@ public class TrackedImportTransferTest extends 
TrackedTransferTestBase
         assertLocalSelect(cluster, keyspace, rows -> assertRows(rows, 
row(KEY_100, 1), row(KEY_300, 1)));
     }
 
+    @Test
+    public void importWrapAroundShard() throws IOException
+    {
+        // See CASSANDRA-21723
+        String keyspace = "wrap_around_shard";
+        cluster.schemaChange("CREATE KEYSPACE " + keyspace + " WITH 
replication = {'class': 'SimpleStrategy', 'replication_factor': 3} AND 
replication_type='tracked';");
+        String createTableQuery = "CREATE TABLE " + 
tableWithKeyspace(keyspace) + " (k BLOB PRIMARY KEY, v INT)";
+        cluster.schemaChange(createTableQuery);
+
+        // find wrap around key for write
+        long wrapAroundLeft = cluster.get(1).callOnInstance(() -> {
+            List<Range<Token>> wrapping = new ArrayList<>();
+            
MutationTrackingService.instance().forEachShardInKeyspace(keyspace, shard -> {
+                Range<Token> range = shard.tokenRange();
+                if (range.right.isMinimum())
+                    wrapping.add(range);
+            });
+            assertThat(wrapping).hasSize(1);
+            return wrapping.get(0).left.getLongValue();
+        });
+        ByteBuffer wrapAroundKey = 
Murmur3Partitioner.LongToken.keyForToken(wrapAroundLeft + 1);
+
+        String file = 
Files.createTempDirectory(TrackedTransferTestBase.class.getSimpleName()).toString();
+        CQLSSTableWriter.Builder builder = CQLSSTableWriter.builder()
+                                                           
.forTable(createTableQuery)
+                                                           .inDirectory(file)
+                                                           .using("INSERT INTO 
" + tableWithKeyspace(keyspace) + " (k, v) " + "VALUES (?, ?)");
+
+        // One row per shard
+        try (CQLSSTableWriter writer = builder.build())
+        {
+            writer.addRow(KEY_100, 1);        // -4074457345618258601L
+            writer.addRow(KEY_200, 1);        // 1L
+            writer.addRow(KEY_300, 1);        // 3074457345618258602L
+            writer.addRow(wrapAroundKey, 1);  // wrapAroundLeft + 1
+        }
+
+        assertLocalSelect(cluster, keyspace, AssertUtils::assertRows);
+        List<String> failed = cluster.get(1).callOnInstance(() -> {
+            ColumnFamilyStore cfs = ColumnFamilyStore.getIfExists(keyspace, 
TABLE);
+            Set<String> paths = Set.of(file);
+            logger.info("Importing SSTables {}", paths);
+            return cfs.importNewSSTables(paths, true, true, true, true, true, 
true, true);
+        });
+
+        // Sleep for import
+        Uninterruptibles.sleepUninterruptibly(3, TimeUnit.SECONDS);
+
+        Assertions.assertThat(failed).isEmpty();
+        assertLocalSelect(cluster, keyspace, rows -> assertRows(rows, 
row(KEY_100, 1), row(KEY_200, 1), row(KEY_300, 1), row(wrapAroundKey, 1)));
+    }
+
     @Test
     public void importMoreThanOneSSTable() throws IOException
     {


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

Reply via email to