From 41fd7c3e22e36cb8a1f83cebf07804fbc19c82eb Mon Sep 17 00:00:00 2001 From: Alan Wang Date: Tue, 16 Jun 2026 09:32:06 -0700 Subject: [PATCH] Consider first token of SSTable when calculating SSTable intersection in LeveledScanner patch by Alan Wang; reviewed by David Capwell, Marcus Eriksson for CASSANDRA-21369 --- CHANGES.txt | 1 + .../compaction/LeveledCompactionStrategy.java | 5 ++-- .../LeveledCompactionStrategyTest.java | 27 +++++++++++++++++++ 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index e762fb3ec7..5e6426fbc0 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 4.0.21 + * Consider first token of SSTable when calculating SSTable intersection in LeveledScanner (CASSANDRA-21369) * Remove inFlightEcho entry on ECHO_REQ failure (CASSANDRA-21428) * Validate snapshot names (CASSANDRA-21389) * BTree.FastBuilder.reset() fails to clear savedBuffer and savedNextKey, causing ClassCastException and SSTable header corruption during schema disagreement (CASSANDRA-21216, CASSANDRA-21260) diff --git a/src/java/org/apache/cassandra/db/compaction/LeveledCompactionStrategy.java b/src/java/org/apache/cassandra/db/compaction/LeveledCompactionStrategy.java index a39e14bf25..59c163f08e 100644 --- a/src/java/org/apache/cassandra/db/compaction/LeveledCompactionStrategy.java +++ b/src/java/org/apache/cassandra/db/compaction/LeveledCompactionStrategy.java @@ -382,7 +382,7 @@ public class LeveledCompactionStrategy extends AbstractCompactionStrategy // Lazily creates SSTableBoundedScanner for sstable that are assumed to be from the // same level (e.g. non overlapping) - see #4142 - private static class LeveledScanner extends AbstractIterator implements ISSTableScanner + protected static class LeveledScanner extends AbstractIterator implements ISSTableScanner { private final TableMetadata metadata; private final Collection> ranges; @@ -437,8 +437,7 @@ public class LeveledCompactionStrategy extends AbstractCompactionStrategy { for (SSTableReader sstable : sstables) { - Range sstableRange = new Range<>(sstable.first.getToken(), sstable.last.getToken()); - if (range == null || sstableRange.intersects(range)) + if (range == null || range.intersects(sstable.getBounds())) filtered.add(sstable); } } diff --git a/test/unit/org/apache/cassandra/db/compaction/LeveledCompactionStrategyTest.java b/test/unit/org/apache/cassandra/db/compaction/LeveledCompactionStrategyTest.java index f741e1e997..b72cfe7f9d 100644 --- a/test/unit/org/apache/cassandra/db/compaction/LeveledCompactionStrategyTest.java +++ b/test/unit/org/apache/cassandra/db/compaction/LeveledCompactionStrategyTest.java @@ -70,6 +70,7 @@ import org.apache.cassandra.utils.Pair; import org.awaitility.Awaitility; import static java.util.Collections.singleton; +import static org.apache.cassandra.schema.MockSchema.readerBounds; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -990,6 +991,32 @@ public class LeveledCompactionStrategyTest } } + @Test + public void testLevelScannerIntersection() + { + Collection sstable = Collections.singleton(MockSchema.sstableWithLevel(1, 10, 20, 1, cfs)); + + // SSTable range - [10, 20] + // range - (1, 9] + Range range = new Range<>(readerBounds(1).getToken(), readerBounds(9).getToken()); + assertEquals(0, LeveledCompactionStrategy.LeveledScanner.intersecting(sstable, Collections.singleton(range)).size()); + + // SSTable range - [10, 20] + // range - (1, 10] + range = new Range<>(readerBounds(1).getToken(), readerBounds(10).getToken()); + assertEquals(1, LeveledCompactionStrategy.LeveledScanner.intersecting(sstable, Collections.singleton(range)).size()); + + // SSTable range - [10, 20] + // range - (1, 15] + range = new Range<>(readerBounds(1).getToken(), readerBounds(15).getToken()); + assertEquals(1, LeveledCompactionStrategy.LeveledScanner.intersecting(sstable, Collections.singleton(range)).size()); + + // SSTable range - [10, 20] + // range - (20, 25] + range = new Range<>(readerBounds(20).getToken(), readerBounds(25).getToken()); + assertEquals(0, LeveledCompactionStrategy.LeveledScanner.intersecting(sstable, Collections.singleton(range)).size()); + } + private Pair, Set> groupByLevel(Iterable sstables) { Set l1after = new HashSet<>();