This is an automated email from the ASF dual-hosted git repository. maedhroz pushed a commit to branch cassandra-5.0 in repository https://gitbox.apache.org/repos/asf/cassandra.git
The following commit(s) were added to refs/heads/cassandra-5.0 by this push: new 1d7bae3697 Record latencies for SAI post-filtering reads against local storage 1d7bae3697 is described below commit 1d7bae3697b97e64de2c2b958427ef86a1b17731 Author: Caleb Rackliffe <calebrackli...@gmail.com> AuthorDate: Thu Feb 22 15:08:23 2024 -0600 Record latencies for SAI post-filtering reads against local storage patch by Caleb Rackliffe; reviewed by Mike Adamson for CASSANDRA-18940 --- CHANGES.txt | 1 + .../index/sai/metrics/TableQueryMetrics.java | 4 +++ .../cassandra/index/sai/plan/QueryController.java | 14 +-------- .../sai/plan/StorageAttachedIndexSearcher.java | 33 +++++++++++++--------- .../index/sai/metrics/QueryMetricsTest.java | 6 +++- .../cassandra/index/sai/plan/OperationTest.java | 9 ++---- 6 files changed, 33 insertions(+), 34 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 20e0c6e959..4f35041497 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 5.0-beta2 + * Record latencies for SAI post-filtering reads against local storage (CASSANDRA-18940) * Fix VectorMemoryIndex#update logic to compare vectors. Fix Index view (CASSANDRA-19168) * Deprecate native_transport_port_ssl (CASSANDRA-19392) * Update packaging shell includes (CASSANDRA-19283) diff --git a/src/java/org/apache/cassandra/index/sai/metrics/TableQueryMetrics.java b/src/java/org/apache/cassandra/index/sai/metrics/TableQueryMetrics.java index 7154df241d..987c70ef75 100644 --- a/src/java/org/apache/cassandra/index/sai/metrics/TableQueryMetrics.java +++ b/src/java/org/apache/cassandra/index/sai/metrics/TableQueryMetrics.java @@ -32,6 +32,8 @@ public class TableQueryMetrics extends AbstractMetrics { public static final String TABLE_QUERY_METRIC_TYPE = "TableQueryMetrics"; + public final Timer postFilteringReadLatency; + private final PerQueryMetrics perQueryMetrics; private final Counter totalQueryTimeouts; @@ -45,6 +47,8 @@ public class TableQueryMetrics extends AbstractMetrics perQueryMetrics = new PerQueryMetrics(table); + postFilteringReadLatency = Metrics.timer(createMetricName("PostFilteringReadLatency")); + totalPartitionReads = Metrics.counter(createMetricName("TotalPartitionReads")); totalRowsFiltered = Metrics.counter(createMetricName("TotalRowsFiltered")); totalQueriesCompleted = Metrics.counter(createMetricName("TotalQueriesCompleted")); diff --git a/src/java/org/apache/cassandra/index/sai/plan/QueryController.java b/src/java/org/apache/cassandra/index/sai/plan/QueryController.java index 597e339aaa..d844304812 100644 --- a/src/java/org/apache/cassandra/index/sai/plan/QueryController.java +++ b/src/java/org/apache/cassandra/index/sai/plan/QueryController.java @@ -57,7 +57,6 @@ import org.apache.cassandra.index.sai.iterators.KeyRangeIntersectionIterator; import org.apache.cassandra.index.sai.iterators.KeyRangeIterator; import org.apache.cassandra.index.sai.iterators.KeyRangeOrderingIterator; import org.apache.cassandra.index.sai.iterators.KeyRangeUnionIterator; -import org.apache.cassandra.index.sai.metrics.TableQueryMetrics; import org.apache.cassandra.index.sai.utils.PrimaryKey; import org.apache.cassandra.net.ParamType; import org.apache.cassandra.schema.TableMetadata; @@ -73,7 +72,6 @@ public class QueryController private final ColumnFamilyStore cfs; private final ReadCommand command; private final QueryContext queryContext; - private final TableQueryMetrics tableQueryMetrics; private final RowFilter filterOperation; private final List<DataRange> ranges; private final AbstractBounds<PartitionPosition> mergeRange; @@ -85,13 +83,11 @@ public class QueryController public QueryController(ColumnFamilyStore cfs, ReadCommand command, RowFilter filterOperation, - QueryContext queryContext, - TableQueryMetrics tableQueryMetrics) + QueryContext queryContext) { this.cfs = cfs; this.command = command; this.queryContext = queryContext; - this.tableQueryMetrics = tableQueryMetrics; this.filterOperation = filterOperation; this.ranges = dataRanges(command); DataRange first = ranges.get(0); @@ -249,14 +245,6 @@ public class QueryController return key.kind() == PrimaryKey.Kind.WIDE && !command.clusteringIndexFilter(key.partitionKey()).selects(key.clustering()); } - /** - * Used to release all resources and record metrics when query finishes. - */ - public void finish() - { - if (tableQueryMetrics != null) tableQueryMetrics.record(queryContext); - } - // This is an ANN only query public KeyRangeIterator getTopKRows(RowFilter.Expression expression) { diff --git a/src/java/org/apache/cassandra/index/sai/plan/StorageAttachedIndexSearcher.java b/src/java/org/apache/cassandra/index/sai/plan/StorageAttachedIndexSearcher.java index c5976de48f..a61fb18aca 100644 --- a/src/java/org/apache/cassandra/index/sai/plan/StorageAttachedIndexSearcher.java +++ b/src/java/org/apache/cassandra/index/sai/plan/StorageAttachedIndexSearcher.java @@ -22,6 +22,7 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; +import java.util.concurrent.TimeUnit; import java.util.function.Supplier; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -54,12 +55,14 @@ import org.apache.cassandra.index.sai.utils.PrimaryKey; import org.apache.cassandra.io.util.FileUtils; import org.apache.cassandra.schema.TableMetadata; import org.apache.cassandra.utils.AbstractIterator; +import org.apache.cassandra.utils.Clock; public class StorageAttachedIndexSearcher implements Index.Searcher { private final ReadCommand command; private final QueryController queryController; private final QueryContext queryContext; + private final TableQueryMetrics tableQueryMetrics; public StorageAttachedIndexSearcher(ColumnFamilyStore cfs, TableQueryMetrics tableQueryMetrics, @@ -69,7 +72,8 @@ public class StorageAttachedIndexSearcher implements Index.Searcher { this.command = command; this.queryContext = new QueryContext(command, executionQuotaMs); - this.queryController = new QueryController(cfs, command, filterOperation, queryContext, tableQueryMetrics); + this.queryController = new QueryController(cfs, command, filterOperation, queryContext); + this.tableQueryMetrics = tableQueryMetrics; } @Override @@ -95,10 +99,10 @@ public class StorageAttachedIndexSearcher implements Index.Searcher public UnfilteredPartitionIterator search(ReadExecutionController executionController) throws RequestTimeoutException { if (!command.isTopK()) - return new ResultRetriever(queryController, executionController, queryContext, false); + return new ResultRetriever(executionController, false); else { - Supplier<ResultRetriever> resultSupplier = () -> new ResultRetriever(queryController, executionController, queryContext, true); + Supplier<ResultRetriever> resultSupplier = () -> new ResultRetriever(executionController, true); // VSTODO performance: if there is shadowed primary keys, we have to at least query twice. // First time to find out there are shadow keys, second time to find out there are no more shadow keys. @@ -115,7 +119,7 @@ public class StorageAttachedIndexSearcher implements Index.Searcher } } - private static class ResultRetriever extends AbstractIterator<UnfilteredRowIterator> implements UnfilteredPartitionIterator + private class ResultRetriever extends AbstractIterator<UnfilteredRowIterator> implements UnfilteredPartitionIterator { private final PrimaryKey firstPrimaryKey; private final PrimaryKey lastPrimaryKey; @@ -124,26 +128,20 @@ public class StorageAttachedIndexSearcher implements Index.Searcher private final KeyRangeIterator resultKeyIterator; private final FilterTree filterTree; - private final QueryController queryController; private final ReadExecutionController executionController; - private final QueryContext queryContext; private final PrimaryKey.Factory keyFactory; private final boolean topK; private PrimaryKey lastKey; - private ResultRetriever(QueryController queryController, - ReadExecutionController executionController, - QueryContext queryContext, + private ResultRetriever(ReadExecutionController executionController, boolean topK) { this.keyRanges = queryController.dataRanges().iterator(); this.currentKeyRange = keyRanges.next().keyRange(); this.resultKeyIterator = Operation.buildIterator(queryController); this.filterTree = Operation.buildFilter(queryController); - this.queryController = queryController; this.executionController = executionController; - this.queryContext = queryContext; this.keyFactory = queryController.primaryKeyFactory(); this.firstPrimaryKey = queryController.firstPrimaryKeyInRange(); this.lastPrimaryKey = queryController.lastPrimaryKeyInRange(); @@ -370,13 +368,20 @@ public class StorageAttachedIndexSearcher implements Index.Searcher return null; lastKey = key; + long startTimeNanos = Clock.Global.nanoTime(); try (UnfilteredRowIterator partition = queryController.queryStorage(key, executionController)) { queryContext.partitionsRead++; queryContext.checkpoint(); - return applyIndexFilter(key, partition, filterTree, queryContext); + UnfilteredRowIterator filtered = applyIndexFilter(key, partition, filterTree, queryContext); + + // Note that we record the duration of the read after post-filtering, which actually + // materializes the rows from disk. + tableQueryMetrics.postFilteringReadLatency.update(Clock.Global.nanoTime() - startTimeNanos, TimeUnit.NANOSECONDS); + + return filtered; } } @@ -428,7 +433,7 @@ public class StorageAttachedIndexSearcher implements Index.Searcher return new PartitionIterator(partition, staticRow, Iterators.filter(clusters.iterator(), u -> !((Row)u).isStatic())); } - private static class PartitionIterator extends AbstractUnfilteredRowIterator + private class PartitionIterator extends AbstractUnfilteredRowIterator { private final Iterator<Unfiltered> rows; @@ -462,7 +467,7 @@ public class StorageAttachedIndexSearcher implements Index.Searcher public void close() { FileUtils.closeQuietly(resultKeyIterator); - queryController.finish(); + if (tableQueryMetrics != null) tableQueryMetrics.record(queryContext); } } diff --git a/test/unit/org/apache/cassandra/index/sai/metrics/QueryMetricsTest.java b/test/unit/org/apache/cassandra/index/sai/metrics/QueryMetricsTest.java index e1f1c6933d..846024ebe0 100644 --- a/test/unit/org/apache/cassandra/index/sai/metrics/QueryMetricsTest.java +++ b/test/unit/org/apache/cassandra/index/sai/metrics/QueryMetricsTest.java @@ -38,7 +38,7 @@ public class QueryMetricsTest extends AbstractMetricsTest public ExpectedException exception = ExpectedException.none(); @Test - public void testSameIndexNameAcrossKeyspaces() throws Throwable + public void testSameIndexNameAcrossKeyspaces() { String table = "test_same_index_name_across_keyspaces"; String index = "test_same_index_name_across_keyspaces_index"; @@ -58,7 +58,9 @@ public class QueryMetricsTest extends AbstractMetricsTest assertEquals(1, rows.all().size()); assertEquals(1L, getTableQueryMetrics(keyspace1, table, "TotalQueriesCompleted")); + assertEquals(1L, getTableQueryMetrics(keyspace1, table, "PostFilteringReadLatency")); assertEquals(0L, getTableQueryMetrics(keyspace2, table, "TotalQueriesCompleted")); + assertEquals(0L, getTableQueryMetrics(keyspace2, table, "PostFilteringReadLatency")); execute("INSERT INTO " + keyspace2 + '.' + table + " (id1, v1, v2) VALUES ('0', 0, '0')"); execute("INSERT INTO " + keyspace2 + '.' + table + " (id1, v1, v2) VALUES ('1', 1, '1')"); @@ -71,6 +73,8 @@ public class QueryMetricsTest extends AbstractMetricsTest assertEquals(2L, getTableQueryMetrics(keyspace1, table, "TotalQueriesCompleted")); assertEquals(1L, getTableQueryMetrics(keyspace2, table, "TotalQueriesCompleted")); + assertEquals(2L, getTableQueryMetrics(keyspace1, table, "PostFilteringReadLatency")); + assertEquals(1L, getTableQueryMetrics(keyspace2, table, "PostFilteringReadLatency")); } @Test diff --git a/test/unit/org/apache/cassandra/index/sai/plan/OperationTest.java b/test/unit/org/apache/cassandra/index/sai/plan/OperationTest.java index 9e6b0982ac..b2b65454d7 100644 --- a/test/unit/org/apache/cassandra/index/sai/plan/OperationTest.java +++ b/test/unit/org/apache/cassandra/index/sai/plan/OperationTest.java @@ -115,22 +115,19 @@ public class OperationTest controller = new QueryController(BACKEND, command, null, - new QueryContext(command, DatabaseDescriptor.getRangeRpcTimeout(TimeUnit.MILLISECONDS)), - null); + new QueryContext(command, DatabaseDescriptor.getRangeRpcTimeout(TimeUnit.MILLISECONDS))); command = PartitionRangeReadCommand.allDataRead(CLUSTERING_BACKEND.metadata(), FBUtilities.nowInSeconds()); controllerClustering = new QueryController(CLUSTERING_BACKEND, command, null, - new QueryContext(command, DatabaseDescriptor.getRangeRpcTimeout(TimeUnit.MILLISECONDS)), - null); + new QueryContext(command, DatabaseDescriptor.getRangeRpcTimeout(TimeUnit.MILLISECONDS))); command = PartitionRangeReadCommand.allDataRead(STATIC_BACKEND.metadata(), FBUtilities.nowInSeconds()); controllerStatic = new QueryController(STATIC_BACKEND, command, null, - new QueryContext(command, DatabaseDescriptor.getRangeRpcTimeout(TimeUnit.MILLISECONDS)), - null); + new QueryContext(command, DatabaseDescriptor.getRangeRpcTimeout(TimeUnit.MILLISECONDS))); } @Test --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@cassandra.apache.org For additional commands, e-mail: commits-h...@cassandra.apache.org