This is an automated email from the ASF dual-hosted git repository.

ycai pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/cassandra.git


The following commit(s) were added to refs/heads/trunk by this push:
     new 945a4fc  Add a virtual table for exposing prepared statements metrics
945a4fc is described below

commit 945a4fc23ac1f60b8380be3b60aef89caf3daba2
Author: Shailaja Koppu <[email protected]>
AuthorDate: Tue Feb 1 09:53:49 2022 -0800

    Add a virtual table for exposing prepared statements metrics
    
    patch by Shailaja Koppu; reviewed by Ekaterina Dimitrova, Francisco 
Guerrero, Yifan Cai for CASSANDRA-17224
---
 CHANGES.txt                                        |   1 +
 doc/modules/cassandra/pages/new/virtualtables.adoc |  18 +++
 .../cassandra/db/virtual/CQLMetricsTable.java      |  81 +++++++++++++
 .../cassandra/db/virtual/SystemViewsKeyspace.java  |   1 +
 .../cassandra/db/virtual/CQLMetricsTableTest.java  | 126 +++++++++++++++++++++
 5 files changed, 227 insertions(+)

diff --git a/CHANGES.txt b/CHANGES.txt
index 03a97fa..fe3fb22 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
 4.1
+ * Add a virtual table for exposing prepared statements metrics 
(CASSANDRA-17224)
  * Remove python 2.x support from cqlsh (CASSANDRA-17242)
  * Prewarm role and credential caches to avoid timeouts at startup 
(CASSANDRA-16958)
  * Make capacity/validity/updateinterval/activeupdate for Auth Caches 
configurable via nodetool (CASSANDRA-17063)
diff --git a/doc/modules/cassandra/pages/new/virtualtables.adoc 
b/doc/modules/cassandra/pages/new/virtualtables.adoc
index b18ba31..914bc27 100644
--- a/doc/modules/cassandra/pages/new/virtualtables.adoc
+++ b/doc/modules/cassandra/pages/new/virtualtables.adoc
@@ -74,6 +74,8 @@ recent_hit_rate_per_second, recent_request_rate_per_second, 
request_count, and s
 
 |coordinator_write_latency |Records counts, keyspace_name, table_name, max, 
median, and per_second for coordinator writes.
 
+|cql_metrcs |Metrics specific to CQL prepared statement caching.
+
 |disk_usage |Records disk usage including disk_space, keyspace_name, and 
table_name, sorted by system keyspaces.
 
 |internode_inbound |Lists information about the inbound internode messaging.
@@ -99,6 +101,7 @@ recent_hit_rate_per_second, recent_request_rate_per_second, 
request_count, and s
 |thread_pools |Lists metrics for each thread pool.
 
 |tombstones_per_read |Records counts, keyspace_name, tablek_name, max, and 
median for tombstones.
+
 |===
 
 We shall discuss some of the virtual tables in more detail next.
@@ -170,6 +173,21 @@ counters |       26214400 |           0 |         0 |      
 NaN |
 (4 rows)
 ....
 
+=== CQL metrics Virtual Table
+The `cql_metrics` virtual table lists metrics specific to CQL prepared 
statement caching. A query on `cql_metrics` virtual table lists below metrics.
+
+....
+cqlsh> select * from system_views.cql_metrics ;
+
+ name                         | value
+------------------------------+-------
+    prepared_statements_count |     0
+  prepared_statements_evicted |     0
+ prepared_statements_executed |     0
+    prepared_statements_ratio |     0
+  regular_statements_executed |    17
+....
+
 === Settings Virtual Table
 
 The `settings` table is rather useful and lists all the current
diff --git a/src/java/org/apache/cassandra/db/virtual/CQLMetricsTable.java 
b/src/java/org/apache/cassandra/db/virtual/CQLMetricsTable.java
new file mode 100644
index 0000000..acd8947
--- /dev/null
+++ b/src/java/org/apache/cassandra/db/virtual/CQLMetricsTable.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.db.virtual;
+
+import com.google.common.annotations.VisibleForTesting;
+
+import org.apache.cassandra.db.marshal.DoubleType;
+import org.apache.cassandra.db.marshal.UTF8Type;
+import org.apache.cassandra.dht.LocalPartitioner;
+import org.apache.cassandra.metrics.CQLMetrics;
+import org.apache.cassandra.schema.TableMetadata;
+import org.apache.cassandra.cql3.QueryProcessor;
+
+
+final class CQLMetricsTable extends AbstractVirtualTable
+{
+    public static final String TABLE_NAME = "cql_metrics";
+    public static final String PREPARED_STATEMENTS_COUNT = 
"prepared_statements_count";
+    public static final String PREPARED_STATEMENTS_EVICTED = 
"prepared_statements_evicted";
+    public static final String PREPARED_STATEMENTS_EXECUTED = 
"prepared_statements_executed";
+    public static final String PREPARED_STATEMENTS_RATIO = 
"prepared_statements_ratio";
+    public static final String REGULAR_STATEMENTS_EXECUTED = 
"regular_statements_executed";
+    public static final String NAME_COL = "name";
+    public static final String VALUE_COL = "value";
+
+    private final CQLMetrics cqlMetrics;
+
+    CQLMetricsTable(String keyspace)
+    {
+        this(keyspace, QueryProcessor.metrics);
+    }
+
+    // For dependency injection
+    @VisibleForTesting
+    CQLMetricsTable(String keyspace, CQLMetrics cqlMetrics)
+    {
+        super(TableMetadata.builder(keyspace, TABLE_NAME)
+                           .comment("Metrics specific to CQL prepared 
statement caching")
+                           .kind(TableMetadata.Kind.VIRTUAL)
+                           .partitioner(new 
LocalPartitioner(UTF8Type.instance))
+                           .addPartitionKeyColumn(NAME_COL, UTF8Type.instance)
+                           .addRegularColumn(VALUE_COL, DoubleType.instance)
+                           .build());
+        this.cqlMetrics = cqlMetrics;
+    }
+
+    @Override
+    public DataSet data()
+    {
+        SimpleDataSet result = new SimpleDataSet(metadata());
+        addRow(result, PREPARED_STATEMENTS_COUNT, 
cqlMetrics.preparedStatementsCount.getValue());
+        addRow(result, PREPARED_STATEMENTS_EVICTED, 
cqlMetrics.preparedStatementsEvicted.getCount());
+        addRow(result, PREPARED_STATEMENTS_EXECUTED, 
cqlMetrics.preparedStatementsExecuted.getCount());
+        addRow(result, PREPARED_STATEMENTS_RATIO, 
cqlMetrics.preparedStatementsRatio.getValue());
+        addRow(result, REGULAR_STATEMENTS_EXECUTED, 
cqlMetrics.regularStatementsExecuted.getCount());
+
+        return result;
+    }
+
+    private void addRow(SimpleDataSet dataSet, String name, double value)
+    {
+        dataSet.row(name)
+               .column(VALUE_COL, value);
+    }
+}
diff --git a/src/java/org/apache/cassandra/db/virtual/SystemViewsKeyspace.java 
b/src/java/org/apache/cassandra/db/virtual/SystemViewsKeyspace.java
index 6dfd8a9..6d5582e 100644
--- a/src/java/org/apache/cassandra/db/virtual/SystemViewsKeyspace.java
+++ b/src/java/org/apache/cassandra/db/virtual/SystemViewsKeyspace.java
@@ -43,6 +43,7 @@ public final class SystemViewsKeyspace extends VirtualKeyspace
                     .add(new NetworkPermissionsCacheKeysTable(VIRTUAL_VIEWS))
                     .add(new PermissionsCacheKeysTable(VIRTUAL_VIEWS))
                     .add(new RolesCacheKeysTable(VIRTUAL_VIEWS))
+                    .add(new CQLMetricsTable(VIRTUAL_VIEWS))
                     .build());
     }
 }
diff --git a/test/unit/org/apache/cassandra/db/virtual/CQLMetricsTableTest.java 
b/test/unit/org/apache/cassandra/db/virtual/CQLMetricsTableTest.java
new file mode 100644
index 0000000..658b841
--- /dev/null
+++ b/test/unit/org/apache/cassandra/db/virtual/CQLMetricsTableTest.java
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.db.virtual;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+import com.google.common.collect.ImmutableList;
+
+import com.datastax.driver.core.PreparedStatement;
+import com.datastax.driver.core.ResultSet;
+import com.datastax.driver.core.Session;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+import org.junit.BeforeClass;
+
+import org.apache.cassandra.cql3.CQLTester;
+import org.apache.cassandra.cql3.QueryProcessor;
+import org.apache.cassandra.metrics.CQLMetrics;
+
+public class CQLMetricsTableTest extends CQLTester
+{
+    private static final String KS_NAME = "vts";
+
+    @BeforeClass
+    public static void setUpClass()
+    {
+        CQLTester.setUpClass();
+    }
+
+    private void queryAndValidateMetrics(CQLMetrics expectedMetrics) throws 
Throwable
+    {
+        String getMetricsQuery = "SELECT * FROM " + KS_NAME + "." + 
CQLMetricsTable.TABLE_NAME;
+        ResultSet vtsRows = executeNet(getMetricsQuery);
+
+        assertEquals(2, vtsRows.getColumnDefinitions().size());
+
+        AtomicInteger rowCount = new AtomicInteger(0);
+        vtsRows.forEach(r -> {
+            final double metricValue = r.getDouble(CQLMetricsTable.VALUE_COL);
+            switch (r.getString(CQLMetricsTable.NAME_COL))
+            {
+                case CQLMetricsTable.PREPARED_STATEMENTS_COUNT:
+                    
assertEquals(expectedMetrics.preparedStatementsCount.getValue(), metricValue, 
0);
+                    break;
+                case CQLMetricsTable.PREPARED_STATEMENTS_EVICTED:
+                    
assertEquals(expectedMetrics.preparedStatementsEvicted.getCount(), metricValue, 
0);
+                    break;
+                case CQLMetricsTable.PREPARED_STATEMENTS_EXECUTED:
+                    
assertEquals(expectedMetrics.preparedStatementsExecuted.getCount(), 
metricValue, 0);
+                    break;
+                case CQLMetricsTable.PREPARED_STATEMENTS_RATIO:
+                    
assertEquals(expectedMetrics.preparedStatementsRatio.getValue(), metricValue, 
0.01);
+                    break;
+                case CQLMetricsTable.REGULAR_STATEMENTS_EXECUTED:
+                    
assertEquals(expectedMetrics.regularStatementsExecuted.getCount(), metricValue, 
0);
+                    break;
+            }
+            rowCount.getAndIncrement();
+        });
+
+        assertEquals(5, rowCount.get());
+    }
+
+    @Test
+    public void testUsingPrepareStmts() throws Throwable
+    {
+        CQLMetricsTable table = new CQLMetricsTable(KS_NAME);
+        VirtualKeyspaceRegistry.instance.register(new VirtualKeyspace(KS_NAME, 
ImmutableList.of(table)));
+
+        String ks = createKeyspace("CREATE KEYSPACE %s WITH replication={ 
'class' : 'SimpleStrategy', 'replication_factor' : 1 }");
+        String tbl = createTable(ks, "CREATE TABLE %s (id int PRIMARY KEY, cid 
int, val text)");
+        Session session = sessionNet();
+
+        String insertCQL = "INSERT INTO " + ks + "." + tbl + " (id, cid, val) 
VALUES (?, ?, ?)";
+        PreparedStatement preparedInsert = session.prepare(insertCQL);
+
+        String selectCQL = "Select * from " + ks + "." + tbl + " where id = ?";
+        PreparedStatement preparedSelect = session.prepare(selectCQL);
+
+        for (int i = 0; i < 10; i++)
+        {
+            session.execute(preparedInsert.bind(i, i, "value" + i));
+            session.execute(preparedSelect.bind(i));
+        }
+
+        queryAndValidateMetrics(QueryProcessor.metrics);
+    }
+
+    @Test
+    public void testUsingInjectedValues() throws Throwable
+    {
+        CQLMetrics cqlMetrics = new CQLMetrics();
+        CQLMetricsTable table = new CQLMetricsTable(KS_NAME, cqlMetrics);
+        VirtualKeyspaceRegistry.instance.register(new VirtualKeyspace(KS_NAME, 
ImmutableList.of(table)));
+
+        // With initial injected values
+        cqlMetrics.preparedStatementsExecuted.inc(50);
+        cqlMetrics.regularStatementsExecuted.inc(100);
+        cqlMetrics.preparedStatementsEvicted.inc(25);
+        queryAndValidateMetrics(cqlMetrics);
+
+        // Test again with updated values
+        cqlMetrics.preparedStatementsExecuted.inc(150);
+        cqlMetrics.regularStatementsExecuted.inc(200);
+        cqlMetrics.preparedStatementsEvicted.inc(50);
+        queryAndValidateMetrics(cqlMetrics);
+    }
+}

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to