From 5119cb1c02e77960d1f9891f2bf7f62c29b56c15 Mon Sep 17 00:00:00 2001 From: Dmitry Konstantinov Date: Tue, 28 Jul 2026 20:39:47 +0100 Subject: [PATCH] Make PartitionRowAccountingTest tests robust to memtable flushes (cherry picked from commit 4efc40af90317e2794424fea09c2661fc9b51a2b) --- .../PartitionRowAccountingTest.java | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/test/unit/org/apache/cassandra/db/partitions/PartitionRowAccountingTest.java b/test/unit/org/apache/cassandra/db/partitions/PartitionRowAccountingTest.java index 103ba7e505..48870edac1 100644 --- a/test/unit/org/apache/cassandra/db/partitions/PartitionRowAccountingTest.java +++ b/test/unit/org/apache/cassandra/db/partitions/PartitionRowAccountingTest.java @@ -33,10 +33,12 @@ import org.apache.cassandra.cql3.CQLTester; import org.apache.cassandra.cql3.QueryProcessor; import org.apache.cassandra.cql3.UntypedResultSet; import org.apache.cassandra.db.ColumnFamilyStore; +import org.apache.cassandra.db.Keyspace; import org.apache.cassandra.db.Memtable; import org.apache.cassandra.utils.btree.BTree; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertSame; /** * Row-level analogue of {@link SetCellAccountingTest}. Where that test grows/resets a single {@code set} @@ -63,6 +65,7 @@ public class PartitionRowAccountingTest extends CQLTester confField.setAccessible(true); Config conf = (Config) confField.get(null); conf.memtable_allocation_type = Config.MemtableAllocationType.offheap_objects; + conf.memtable_cleanup_threshold = 0.8f; // to reduce risk of memtable switch during a test } catch (ReflectiveOperationException e) { @@ -71,6 +74,13 @@ public class PartitionRowAccountingTest extends CQLTester CQLTester.prepareServer(); } + private static void flushAllToBaseline() + { + for (Keyspace ks : Keyspace.all()) + for (ColumnFamilyStore c : ks.getColumnFamilyStores()) + c.forceBlockingFlush(); + } + private ColumnFamilyStore createTestTable() { createTable("CREATE TABLE %s (" + @@ -165,6 +175,10 @@ public class PartitionRowAccountingTest extends CQLTester final long insertTs = 1000L; final long deleteTs = 2000L; // newer than insertTs, so the tombstone shadows the cells + flushAllToBaseline(); + Memtable mtRetain = cfsRetain.getTracker().getView().getCurrentMemtable(); + Memtable mtShadow = cfsShadow.getTracker().getView().getCurrentMemtable(); + for (int ck = 0; ck < rows; ck++) { // retain path: write the row, then delete it -> the tombstone shadows existing (owned) cells @@ -176,6 +190,11 @@ public class PartitionRowAccountingTest extends CQLTester QueryProcessor.executeInternal(wideInsert(tblShadow, ck, insertTs)); } + assertSame("retain memtable rolled (flushed) mid-test -- on-heap ownership measurement invalid", + mtRetain, cfsRetain.getTracker().getView().getCurrentMemtable()); + assertSame("removeShadowed memtable rolled (flushed) mid-test -- on-heap ownership measurement invalid", + mtShadow, cfsShadow.getTracker().getView().getCurrentMemtable()); + long onHeapRetain = ownsOnHeapNow(cfsRetain), onHeapShadow = ownsOnHeapNow(cfsShadow); long offHeapRetain = ownsOffHeapNow(cfsRetain), offHeapShadow = ownsOffHeapNow(cfsShadow); logger.info("retain-path onHeap=" + onHeapRetain + " offHeap=" + offHeapRetain + @@ -214,6 +233,10 @@ public class PartitionRowAccountingTest extends CQLTester final long insertTs = 1000L; final long deleteTs = 2000L; // newer than insertTs, so the tombstone shadows the collection cells + flushAllToBaseline(); + Memtable mtRetain = cfsRetain.getTracker().getView().getCurrentMemtable(); + Memtable mtShadow = cfsShadow.getTracker().getView().getCurrentMemtable(); + for (int ck = 0; ck < rows; ck++) { // retain path: write the row (large collection), then delete it -> the tombstone shadows existing (owned) @@ -226,6 +249,11 @@ public class PartitionRowAccountingTest extends CQLTester QueryProcessor.executeInternal(setInsert(tblShadow, ck, insertTs)); } + assertSame("retain memtable rolled (flushed) mid-test -- on-heap ownership measurement invalid", + mtRetain, cfsRetain.getTracker().getView().getCurrentMemtable()); + assertSame("removeShadowed memtable rolled (flushed) mid-test -- on-heap ownership measurement invalid", + mtShadow, cfsShadow.getTracker().getView().getCurrentMemtable()); + long onHeapRetain = ownsOnHeapNow(cfsRetain), onHeapShadow = ownsOnHeapNow(cfsShadow); long offHeapRetain = ownsOffHeapNow(cfsRetain), offHeapShadow = ownsOffHeapNow(cfsShadow); logger.info("collection retain-path onHeap=" + onHeapRetain + " offHeap=" + offHeapRetain + @@ -267,6 +295,10 @@ public class PartitionRowAccountingTest extends CQLTester final long collectionDeleteTs = 1000L; final long rowDeleteTs = 2000L; // newer, so the row tombstone supersedes the collection tombstone + flushAllToBaseline(); + Memtable mtRetain = cfsRetain.getTracker().getView().getCurrentMemtable(); + Memtable mtShadow = cfsShadow.getTracker().getView().getCurrentMemtable(); + for (int ck = 0; ck < rows; ck++) { // retain path: write a collection tombstone (an owned complex deletion over an empty cell tree), @@ -279,6 +311,11 @@ public class PartitionRowAccountingTest extends CQLTester QueryProcessor.executeInternal(collectionDelete(tblShadow, ck, collectionDeleteTs)); } + assertSame("retain memtable rolled (flushed) mid-test -- on-heap ownership measurement invalid", + mtRetain, cfsRetain.getTracker().getView().getCurrentMemtable()); + assertSame("removeShadowed memtable rolled (flushed) mid-test -- on-heap ownership measurement invalid", + mtShadow, cfsShadow.getTracker().getView().getCurrentMemtable()); + long onHeapRetain = ownsOnHeapNow(cfsRetain), onHeapShadow = ownsOnHeapNow(cfsShadow); logger.info("collection-tombstone retain-path onHeap=" + onHeapRetain + "; removeShadowed-path onHeap=" + onHeapShadow);