From 54f6c5fe37d23880fe67c21d29ce68a1908b179d Mon Sep 17 00:00:00 2001 From: Ruslan Fomkin Date: Fri, 20 Dec 2024 00:19:53 +0100 Subject: [PATCH 1/4] Allow to run optimizer There is no need to disable the optimizer, since it cannot optimize away anything. It was necessary originally during introducing anti-join node. --- .../SingleRestrictionEstimatedRowCountTest.java | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/test/unit/org/apache/cassandra/index/sai/plan/SingleRestrictionEstimatedRowCountTest.java b/test/unit/org/apache/cassandra/index/sai/plan/SingleRestrictionEstimatedRowCountTest.java index 757b9ae2939a..0eb5ebdc1892 100644 --- a/test/unit/org/apache/cassandra/index/sai/plan/SingleRestrictionEstimatedRowCountTest.java +++ b/test/unit/org/apache/cassandra/index/sai/plan/SingleRestrictionEstimatedRowCountTest.java @@ -21,8 +21,6 @@ import java.math.BigDecimal; import java.math.BigInteger; -import org.junit.After; -import org.junit.Before; import org.junit.Test; import org.apache.cassandra.Util; @@ -44,8 +42,6 @@ public class SingleRestrictionEstimatedRowCountTest extends SAITester { - private int queryOptLevel; - static protected Object getFilterValue(CQL3Type.Native type, int value) { switch (type) @@ -61,19 +57,6 @@ static protected Object getFilterValue(CQL3Type.Native type, int value) return null; } - @Before - public void setup() - { - queryOptLevel = QueryController.QUERY_OPT_LEVEL; - QueryController.QUERY_OPT_LEVEL = 0; - } - - @After - public void teardown() - { - QueryController.QUERY_OPT_LEVEL = queryOptLevel; - } - @Test public void testInequality() { From 464948e9cbb22423aa8d557aab01f8e6118735f0 Mon Sep 17 00:00:00 2001 From: Ruslan Fomkin Date: Sun, 22 Dec 2024 11:54:50 +0100 Subject: [PATCH 2/4] Store created CFS in a map Fails due to flush when next table is created, and on cleanup after a test run. --- ...ingleRestrictionEstimatedRowCountTest.java | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/test/unit/org/apache/cassandra/index/sai/plan/SingleRestrictionEstimatedRowCountTest.java b/test/unit/org/apache/cassandra/index/sai/plan/SingleRestrictionEstimatedRowCountTest.java index 0eb5ebdc1892..2ea6110a7433 100644 --- a/test/unit/org/apache/cassandra/index/sai/plan/SingleRestrictionEstimatedRowCountTest.java +++ b/test/unit/org/apache/cassandra/index/sai/plan/SingleRestrictionEstimatedRowCountTest.java @@ -20,6 +20,9 @@ import java.math.BigDecimal; import java.math.BigInteger; +import java.util.AbstractMap; +import java.util.HashMap; +import java.util.Map; import org.junit.Test; @@ -42,6 +45,8 @@ public class SingleRestrictionEstimatedRowCountTest extends SAITester { + static protected Map, ColumnFamilyStore> map = new HashMap<>(); + static protected Object getFilterValue(CQL3Type.Native type, int value) { switch (type) @@ -103,7 +108,17 @@ protected ColumnFamilyStore prepareTable(CQL3Type.Native type) { createTable("CREATE TABLE %s (pk text PRIMARY KEY, age " + type + ')'); createIndex("CREATE CUSTOM INDEX ON %s(age) USING 'StorageAttachedIndex'"); - return getCurrentColumnFamilyStore(); + ColumnFamilyStore cfs = getCurrentColumnFamilyStore(); + + // Avoid race condition of flushing after the index creation + cfs.unsafeRunWithoutFlushing(() -> { + for (int i = 0; i < 100; i++) + { + execute("INSERT INTO %s (pk, age) VALUES (?," + i + ')', "key" + i); + } + }); + + return cfs; } class RowCountTest @@ -122,15 +137,10 @@ void doTest(Version version, CQL3Type.Native type, double expectedRows) Version latest = Version.latest(); SAIUtil.setLatestVersion(version); - ColumnFamilyStore cfs = prepareTable(type); - // Avoid race condition of flushing after the index creation - cfs.unsafeRunWithoutFlushing(() -> { - for (int i = 0; i < 100; i++) - { - execute("INSERT INTO %s (pk, age) VALUES (?," + i + ')', "key" + i); - } - }); + var key = new AbstractMap.SimpleEntry<>(version, type); + ColumnFamilyStore cfs = map.computeIfAbsent(key, k -> prepareTable(type)); +// ColumnFamilyStore cfs = prepareTable(type); Object filter = getFilterValue(type, filterValue); ReadCommand rc = Util.cmd(cfs) From 0b231f91f463c0f3d3c39b715acf8cef440a6f11 Mon Sep 17 00:00:00 2001 From: Ruslan Fomkin Date: Tue, 14 Jan 2025 18:10:36 +0100 Subject: [PATCH 3/4] Improve performance of SingleRestrictionEstimatedRowCountTest Reduces amount of created tables by creating all needed tables in advance. As the result the test can be placed into single test function. This improves local test execution time from 5.5 seconds down to 1.4 seconds. --- ...ingleRestrictionEstimatedRowCountTest.java | 74 ++++++++++--------- 1 file changed, 38 insertions(+), 36 deletions(-) diff --git a/test/unit/org/apache/cassandra/index/sai/plan/SingleRestrictionEstimatedRowCountTest.java b/test/unit/org/apache/cassandra/index/sai/plan/SingleRestrictionEstimatedRowCountTest.java index 2ea6110a7433..99acb07aaf34 100644 --- a/test/unit/org/apache/cassandra/index/sai/plan/SingleRestrictionEstimatedRowCountTest.java +++ b/test/unit/org/apache/cassandra/index/sai/plan/SingleRestrictionEstimatedRowCountTest.java @@ -45,7 +45,9 @@ public class SingleRestrictionEstimatedRowCountTest extends SAITester { - static protected Map, ColumnFamilyStore> map = new HashMap<>(); + static protected Map, ColumnFamilyStore> tables = new HashMap<>(); + static Version[] versions = new Version[]{ Version.DB, Version.EB }; + static CQL3Type.Native[] types = new CQL3Type.Native[]{ INT, DECIMAL, VARINT }; static protected Object getFilterValue(CQL3Type.Native type, int value) { @@ -62,9 +64,16 @@ static protected Object getFilterValue(CQL3Type.Native type, int value) return null; } + static Map.Entry tablesEntrykey(Version version, CQL3Type.Native type) + { + return new AbstractMap.SimpleEntry<>(version, type); + } + @Test - public void testInequality() + public void testMemtablesSAI() { + createTables(); + var test = new RowCountTest(Operator.NEQ, 25); test.doTest(Version.DB, INT, 97.0); test.doTest(Version.EB, INT, 97.0); @@ -72,56 +81,57 @@ public void testInequality() test.doTest(Version.DB, DECIMAL, 97.0); test.doTest(Version.EB, DECIMAL, 97.0); test.doTest(Version.EB, VARINT, 97.0); - } - @Test - public void testHalfRangeMiddle() - { - var test = new RowCountTest(Operator.LT, 50); + test = new RowCountTest(Operator.LT, 50); test.doTest(Version.DB, INT, 48); test.doTest(Version.EB, INT, 48); test.doTest(Version.DB, DECIMAL, 48); test.doTest(Version.EB, DECIMAL, 48); - } - @Test - public void testHalfRangeEverything() - { - var test = new RowCountTest(Operator.LT, 150); + test = new RowCountTest(Operator.LT, 150); test.doTest(Version.DB, INT, 97); test.doTest(Version.EB, INT, 97); test.doTest(Version.DB, DECIMAL, 97); test.doTest(Version.EB, DECIMAL, 97); - } - @Test - public void testEquality() - { - var test = new RowCountTest(Operator.EQ, 31); + test = new RowCountTest(Operator.EQ, 31); test.doTest(Version.DB, INT, 15); test.doTest(Version.EB, INT, 0); test.doTest(Version.DB, DECIMAL, 15); test.doTest(Version.EB, DECIMAL, 0); } - protected ColumnFamilyStore prepareTable(CQL3Type.Native type) + + void createTables() { - createTable("CREATE TABLE %s (pk text PRIMARY KEY, age " + type + ')'); - createIndex("CREATE CUSTOM INDEX ON %s(age) USING 'StorageAttachedIndex'"); - ColumnFamilyStore cfs = getCurrentColumnFamilyStore(); + for (Version version : versions) + { + SAIUtil.setLatestVersion(version); + for (CQL3Type.Native type : types) + { + createTable("CREATE TABLE %s (pk text PRIMARY KEY, age " + type + ')'); + createIndex("CREATE CUSTOM INDEX ON %s(age) USING 'StorageAttachedIndex'"); + tables.put(tablesEntrykey(version, type), getCurrentColumnFamilyStore()); + } + } + flush(); + for (ColumnFamilyStore cfs : tables.values()) + populateTable(cfs); + } - // Avoid race condition of flushing after the index creation + void populateTable(ColumnFamilyStore cfs) + { + // Avoid race condition of starting before flushing completed cfs.unsafeRunWithoutFlushing(() -> { for (int i = 0; i < 100; i++) { - execute("INSERT INTO %s (pk, age) VALUES (?," + i + ')', "key" + i); + String query = String.format("INSERT INTO %s (pk, age) VALUES (?, " + i + ')', cfs.keyspace.getName() + '.' + cfs.name); + executeFormattedQuery(query, "key" + i); } }); - - return cfs; } - class RowCountTest + static class RowCountTest { final Operator op; final int filterValue; @@ -134,15 +144,8 @@ class RowCountTest void doTest(Version version, CQL3Type.Native type, double expectedRows) { - Version latest = Version.latest(); - SAIUtil.setLatestVersion(version); - - var key = new AbstractMap.SimpleEntry<>(version, type); - ColumnFamilyStore cfs = map.computeIfAbsent(key, k -> prepareTable(type)); - -// ColumnFamilyStore cfs = prepareTable(type); + ColumnFamilyStore cfs = tables.get(new AbstractMap.SimpleEntry<>(version, type)); Object filter = getFilterValue(type, filterValue); - ReadCommand rc = Util.cmd(cfs) .columns("age") .filterOn("age", op, filter) @@ -152,6 +155,7 @@ void doTest(Version version, CQL3Type.Native type, double expectedRows) version.onDiskFormat().indexFeatureSet(), new QueryContext(), null); + long totalRows = controller.planFactory.tableMetrics.rows; assertEquals(0, cfs.metrics().liveSSTableCount.getValue().intValue()); assertEquals(97, totalRows); @@ -165,8 +169,6 @@ void doTest(Version version, CQL3Type.Native type, double expectedRows) assertEquals(expectedRows, root.expectedRows(), 0.1); assertEquals(expectedRows, planNode.expectedKeys(), 0.1); assertEquals(expectedRows / totalRows, planNode.selectivity(), 0.001); - - SAIUtil.setLatestVersion(latest); } } } From 44974c0f74d0c7ccbf6539bed1098acde7eb741c Mon Sep 17 00:00:00 2001 From: Ruslan Fomkin Date: Wed, 15 Jan 2025 10:55:07 +0100 Subject: [PATCH 4/4] Remove use of var and other minor improvements --- .../sai/plan/SingleRestrictionEstimatedRowCountTest.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/test/unit/org/apache/cassandra/index/sai/plan/SingleRestrictionEstimatedRowCountTest.java b/test/unit/org/apache/cassandra/index/sai/plan/SingleRestrictionEstimatedRowCountTest.java index 99acb07aaf34..d29c62f19b15 100644 --- a/test/unit/org/apache/cassandra/index/sai/plan/SingleRestrictionEstimatedRowCountTest.java +++ b/test/unit/org/apache/cassandra/index/sai/plan/SingleRestrictionEstimatedRowCountTest.java @@ -64,7 +64,7 @@ static protected Object getFilterValue(CQL3Type.Native type, int value) return null; } - static Map.Entry tablesEntrykey(Version version, CQL3Type.Native type) + static Map.Entry tablesEntryKey(Version version, CQL3Type.Native type) { return new AbstractMap.SimpleEntry<>(version, type); } @@ -74,7 +74,7 @@ public void testMemtablesSAI() { createTables(); - var test = new RowCountTest(Operator.NEQ, 25); + RowCountTest test = new RowCountTest(Operator.NEQ, 25); test.doTest(Version.DB, INT, 97.0); test.doTest(Version.EB, INT, 97.0); // Truncated numeric types planned differently @@ -111,7 +111,7 @@ void createTables() { createTable("CREATE TABLE %s (pk text PRIMARY KEY, age " + type + ')'); createIndex("CREATE CUSTOM INDEX ON %s(age) USING 'StorageAttachedIndex'"); - tables.put(tablesEntrykey(version, type), getCurrentColumnFamilyStore()); + tables.put(tablesEntryKey(version, type), getCurrentColumnFamilyStore()); } } flush(); @@ -125,7 +125,8 @@ void populateTable(ColumnFamilyStore cfs) cfs.unsafeRunWithoutFlushing(() -> { for (int i = 0; i < 100; i++) { - String query = String.format("INSERT INTO %s (pk, age) VALUES (?, " + i + ')', cfs.keyspace.getName() + '.' + cfs.name); + String query = String.format("INSERT INTO %s (pk, age) VALUES (?, " + i + ')', + cfs.keyspace.getName() + '.' + cfs.name); executeFormattedQuery(query, "key" + i); } });