From eb0c77ae1ecd1cdc96ce64d91a36e5c4993af691 Mon Sep 17 00:00:00 2001 From: Marcus Eriksson Date: Fri, 4 Apr 2025 08:16:24 +0200 Subject: [PATCH] Fix TreeMap race in CollectionVirtualTableAdapter causing us to lose rows in the virtual table Patch by marcuse; reviewed by Sam Tunnicliffe for CASSANDRA-20524 --- CHANGES.txt | 1 + .../CollectionVirtualTableAdapter.java | 19 ++++++++++--------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index f74d385e83..ba71e542b4 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 5.1 + * Fix TreeMap race in CollectionVirtualTableAdapter causing us to lose rows in the virtual table (CASSANDRA-20524) * Improve metadata log catch up with inter-DC mutation forwarding (CASSANDRA-20523) * Support topology-safe changes to Datacenter & Rack for live nodes (CASSANDRA-20528) * Add SSTableIntervalTree latency metric (CASSANDRA-20502) diff --git a/src/java/org/apache/cassandra/db/virtual/CollectionVirtualTableAdapter.java b/src/java/org/apache/cassandra/db/virtual/CollectionVirtualTableAdapter.java index 47aa3bd5c4..cc311e1a26 100644 --- a/src/java/org/apache/cassandra/db/virtual/CollectionVirtualTableAdapter.java +++ b/src/java/org/apache/cassandra/db/virtual/CollectionVirtualTableAdapter.java @@ -31,7 +31,6 @@ import java.util.Objects; import java.util.TreeMap; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentSkipListMap; import java.util.concurrent.atomic.AtomicReference; import java.util.function.BiFunction; import java.util.function.Function; @@ -366,14 +365,16 @@ public class CollectionVirtualTableAdapter implements VirtualTable private Iterator buildDataRangeIterator(DataRange dataRange, ColumnFilter columnFilter) { - NavigableMap, Row>> partitionMap = new ConcurrentSkipListMap<>(DecoratedKey.comparator); - StreamSupport.stream(data.spliterator(), true) - .map(row -> makeRow(row, columnFilter)) - .filter(cr -> dataRange.keyRange().contains(cr.key.get())) - .forEach(cr -> partitionMap.computeIfAbsent(cr.key.get(), - key -> new TreeMap<>(metadata.comparator)) - .put(cr.clustering, cr.rowSup.get())); - + NavigableMap, Row>> partitionMap = new TreeMap<>(DecoratedKey.comparator); + for (R row : data) + { + CollectionRow cr = makeRow(row, columnFilter); + if (dataRange.keyRange().contains(cr.key.get())) + { + partitionMap.computeIfAbsent(cr.key.get(), + key -> new TreeMap<>(metadata.comparator)).put(cr.clustering, cr.rowSup.get()); + } + } return partitionMap.entrySet().stream().map( e -> new DataRowUnfilteredIterator(e.getKey(), dataRange.clusteringIndexFilter(e.getKey()), columnFilter, e.getValue())).iterator();