CASSANDRA-14366: Add prepared statement cache stats to nodetool info

Assisted-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Arvind Kandpal 2026-07-24 13:48:29 +05:30
parent ca42cfe68d
commit a5569da3c9
5 changed files with 95 additions and 0 deletions

View File

@ -39,6 +39,7 @@ public class CQLMetrics
public final Gauge<Integer> preparedStatementsCount;
public final Gauge<Double> preparedStatementsRatio;
public final Gauge<Long> preparedStatementsCacheSize;
public final Gauge<Long> preparedStatementsCacheCapacity;
public CQLMetrics()
{
@ -67,5 +68,6 @@ public class CQLMetrics
}
});
preparedStatementsCacheSize = Metrics.register(factory.createMetricName("PreparedStatementsCacheSize"), QueryProcessor::preparedStatementsCacheMemoryUsedBytes);
preparedStatementsCacheCapacity = Metrics.register(factory.createMetricName("PreparedStatementsCacheCapacity"), () -> QueryProcessor.PREPARED_STATEMENT_CACHE_SIZE_BYTES);
}
}

View File

@ -1939,6 +1939,38 @@ public class NodeProbe implements AutoCloseable
}
}
/**
* Retrieve CQL metrics by name.
* @param metricName PreparedStatementsCount, PreparedStatementsCacheSize, PreparedStatementsCacheCapacity,
* PreparedStatementsExecuted, or PreparedStatementsEvicted.
*/
public Object getCQLMetric(String metricName)
{
try
{
switch (metricName)
{
case "PreparedStatementsCount":
case "PreparedStatementsCacheSize":
case "PreparedStatementsCacheCapacity":
return JMX.newMBeanProxy(mbeanServerConn,
new ObjectName("org.apache.cassandra.metrics:type=CQL,name=" + metricName),
CassandraMetricsRegistry.JmxGaugeMBean.class).getValue();
case "PreparedStatementsExecuted":
case "PreparedStatementsEvicted":
return JMX.newMBeanProxy(mbeanServerConn,
new ObjectName("org.apache.cassandra.metrics:type=CQL,name=" + metricName),
CassandraMetricsRegistry.JmxCounterMBean.class).getCount();
default:
throw new RuntimeException("Unknown CQL metric name " + metricName);
}
}
catch (MalformedObjectNameException e)
{
throw new RuntimeException(e);
}
}
private static Multimap<String, String> getJmxThreadPools(MBeanServerConnection mbeanServerConn)
{
try

View File

@ -119,6 +119,15 @@ public class Info extends AbstractCommand
probe.getCacheMetric("CounterCache", "HitRate"),
cacheService.getCounterCacheSavePeriodInSeconds());
// Prepared Statement Cache: entries, size, capacity, executions, evictions
out.printf("%-23s: entries %d, size %s, capacity %s, %d executions, %d evictions%n",
"Prepared Stmt Cache",
probe.getCQLMetric("PreparedStatementsCount"),
FileUtils.stringifyFileSize((long) probe.getCQLMetric("PreparedStatementsCacheSize")),
FileUtils.stringifyFileSize((long) probe.getCQLMetric("PreparedStatementsCacheCapacity")),
probe.getCQLMetric("PreparedStatementsExecuted"),
probe.getCQLMetric("PreparedStatementsEvicted"));
// Chunk Cache: Hits, Requests, RecentHitRate, SavePeriodInSeconds
try
{

View File

@ -174,6 +174,12 @@ public class InternalNodeProbe extends NodeProbe
throw new UnsupportedOperationException();
}
@Override
public Object getCQLMetric(String metricName)
{
throw new UnsupportedOperationException();
}
@Override
public Object getClientMetric(String metricName)
{

View File

@ -0,0 +1,46 @@
/*
* 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.tools.nodetool;
import org.junit.BeforeClass;
import org.junit.Test;
import org.apache.cassandra.cql3.CQLTester;
import org.apache.cassandra.tools.ToolRunner;
import static org.assertj.core.api.Assertions.assertThat;
public class InfoTest extends CQLTester
{
@BeforeClass
public static void setup() throws Exception
{
requireNetwork();
startJMXServer();
}
@Test
public void testInfoContainsPreparedStmtCache()
{
ToolRunner.ToolResult tool = ToolRunner.invokeNodetool("info");
tool.assertOnCleanExit();
String stdout = tool.getStdout();
assertThat(stdout).contains("Prepared Stmt Cache");
assertThat(stdout).containsPattern("Prepared Stmt Cache\\s+: entries \\d+, size .+, capacity .+, \\d+ executions, \\d+ evictions");
}
}