From 35d0b2ba8a803eb72be9bba083fa838aa941245a Mon Sep 17 00:00:00 2001 From: ShiroOnigami23 Date: Mon, 20 Apr 2026 02:19:17 +0530 Subject: [PATCH] CASSANDRA-21320: add rows mutated per write request histogram --- .../metrics/ClientRequestSizeMetrics.java | 25 +++++++++++++++++-- .../cassandra/metrics/KeyspaceMetrics.java | 3 +++ .../cassandra/metrics/TableMetrics.java | 3 +++ .../ClientRequestRowAndColumnMetricsTest.java | 10 ++++++++ 4 files changed, 39 insertions(+), 2 deletions(-) diff --git a/src/java/org/apache/cassandra/metrics/ClientRequestSizeMetrics.java b/src/java/org/apache/cassandra/metrics/ClientRequestSizeMetrics.java index f7719762a44..002879e1958 100644 --- a/src/java/org/apache/cassandra/metrics/ClientRequestSizeMetrics.java +++ b/src/java/org/apache/cassandra/metrics/ClientRequestSizeMetrics.java @@ -19,6 +19,8 @@ package org.apache.cassandra.metrics; import java.util.Collection; +import java.util.HashMap; +import java.util.Map; import com.codahale.metrics.Counter; @@ -28,6 +30,7 @@ import org.apache.cassandra.db.IMutation; import org.apache.cassandra.db.partitions.PartitionUpdate; import org.apache.cassandra.schema.ColumnMetadata; +import org.apache.cassandra.schema.TableId; import org.apache.cassandra.transport.messages.ResultMessage; import static org.apache.cassandra.metrics.CassandraMetricsRegistry.Metrics; @@ -66,18 +69,22 @@ public static void recordRowAndColumnCountMetrics(Collection rowsMutatedPerRequest = new HashMap<>(); for (IMutation mutation : mutations) { for (PartitionUpdate update : mutation.getPartitionUpdates()) { columnCount += update.affectedColumnCount(); - rowCount += update.affectedRowCount(); + int affectedRows = update.affectedRowCount(); + rowCount += affectedRows; + rowsMutatedPerRequest.merge(update.metadata().id, affectedRows, Integer::sum); } } ClientRequestSizeMetrics.totalColumnsWritten.inc(columnCount); ClientRequestSizeMetrics.totalRowsWritten.inc(rowCount); + incrementRowsMutatedPerWriteRequest(rowsMutatedPerRequest); } public static void recordRowAndColumnCountMetrics(PartitionUpdate update) @@ -86,6 +93,20 @@ public static void recordRowAndColumnCountMetrics(PartitionUpdate update) return; ClientRequestSizeMetrics.totalColumnsWritten.inc(update.affectedColumnCount()); - ClientRequestSizeMetrics.totalRowsWritten.inc(update.affectedRowCount()); + int affectedRows = update.affectedRowCount(); + ClientRequestSizeMetrics.totalRowsWritten.inc(affectedRows); + ColumnFamilyStore cfs = ColumnFamilyStore.getIfExists(update.metadata().id); + if (cfs != null) + cfs.metric.rowsMutatedPerWriteHistogram.update(affectedRows); + } + + private static void incrementRowsMutatedPerWriteRequest(Map rowsMutatedPerRequest) + { + for (Map.Entry entry : rowsMutatedPerRequest.entrySet()) + { + ColumnFamilyStore cfs = ColumnFamilyStore.getIfExists(entry.getKey()); + if (cfs != null) + cfs.metric.rowsMutatedPerWriteHistogram.update(entry.getValue()); + } } } diff --git a/src/java/org/apache/cassandra/metrics/KeyspaceMetrics.java b/src/java/org/apache/cassandra/metrics/KeyspaceMetrics.java index 4491d64e8b0..a5351d9368a 100644 --- a/src/java/org/apache/cassandra/metrics/KeyspaceMetrics.java +++ b/src/java/org/apache/cassandra/metrics/KeyspaceMetrics.java @@ -83,6 +83,8 @@ public class KeyspaceMetrics public final Histogram sstablesPerReadHistogram; /** Histogram of the number of sstable data files accessed per partition range read */ public final Histogram sstablesPerRangeReadHistogram; + /** Histogram of rows mutated per write request in this keyspace. */ + public final Histogram rowsMutatedPerWriteHistogram; /** Tombstones scanned in queries on this Keyspace */ public final Histogram tombstoneScannedHistogram; /** Purgeable tombstones scanned in queries on this Keyspace */ @@ -255,6 +257,7 @@ public KeyspaceMetrics(final Keyspace ks) // create histograms for TableMetrics to replicate updates to sstablesPerReadHistogram = createKeyspaceHistogram("SSTablesPerReadHistogram", true); sstablesPerRangeReadHistogram = createKeyspaceHistogram("SSTablesPerRangeReadHistogram", true); + rowsMutatedPerWriteHistogram = createKeyspaceHistogram("RowsMutatedPerWriteHistogram", false); tombstoneScannedHistogram = createKeyspaceHistogram("TombstoneScannedHistogram", false); purgeableTombstoneScannedHistogram = createKeyspaceHistogram("PurgeableTombstoneScannedHistogram", false); liveScannedHistogram = createKeyspaceHistogram("LiveScannedHistogram", false); diff --git a/src/java/org/apache/cassandra/metrics/TableMetrics.java b/src/java/org/apache/cassandra/metrics/TableMetrics.java index 9e00988da76..1983cd93f49 100644 --- a/src/java/org/apache/cassandra/metrics/TableMetrics.java +++ b/src/java/org/apache/cassandra/metrics/TableMetrics.java @@ -238,6 +238,8 @@ public class TableMetrics public final SnapshottingTimer coordinatorReadLatency; public final Timer coordinatorScanLatency; public final SnapshottingTimer coordinatorWriteLatency; + /** Histogram of rows mutated per write request on this table. */ + public final TableHistogram rowsMutatedPerWriteHistogram; private final TableMetricNameFactory factory; private final TableMetricNameFactory aliasFactory; @@ -816,6 +818,7 @@ public Long getValue() coordinatorReadLatency = createTableTimer("CoordinatorReadLatency"); coordinatorScanLatency = createTableTimer("CoordinatorScanLatency"); coordinatorWriteLatency = createTableTimer("CoordinatorWriteLatency"); + rowsMutatedPerWriteHistogram = createTableHistogram("RowsMutatedPerWriteHistogram", cfs.keyspace.metric.rowsMutatedPerWriteHistogram, false); // We do not want to capture view mutation specific metrics for a view // They only makes sense to capture on the base table diff --git a/test/unit/org/apache/cassandra/metrics/ClientRequestRowAndColumnMetricsTest.java b/test/unit/org/apache/cassandra/metrics/ClientRequestRowAndColumnMetricsTest.java index b75a7b1f6ce..745371743c4 100644 --- a/test/unit/org/apache/cassandra/metrics/ClientRequestRowAndColumnMetricsTest.java +++ b/test/unit/org/apache/cassandra/metrics/ClientRequestRowAndColumnMetricsTest.java @@ -31,6 +31,7 @@ import org.apache.cassandra.cql3.CQLTester; import org.apache.cassandra.cql3.QueryOptions; import org.apache.cassandra.cql3.statements.BatchStatement; +import org.apache.cassandra.db.ColumnFamilyStore; import org.apache.cassandra.db.ConsistencyLevel; import org.apache.cassandra.service.StorageProxy; import org.apache.cassandra.service.paxos.Paxos; @@ -219,11 +220,13 @@ public void shouldRecordReadMetricsForTokenAndClusteringSlice() public void shouldRecordWriteMetricsForSingleValueRow() { createTable("CREATE TABLE %s (pk int, ck int, v int, PRIMARY KEY (pk, ck))"); + ColumnFamilyStore cfs = currentTableStore(); executeNet(CURRENT, "INSERT INTO %s (pk, ck, v) VALUES (1, 1, 1)"); assertEquals(1, ClientRequestSizeMetrics.totalRowsWritten.getCount()); assertEquals(1, ClientRequestSizeMetrics.totalColumnsWritten.getCount()); + assertEquals(1, cfs.metric.rowsMutatedPerWriteHistogram.cf.getCount()); } @Test @@ -254,6 +257,7 @@ public void shouldRecordWriteMetricsForMultiValueRow() public void shouldRecordWriteMetricsForBatch() throws Exception { createTable("CREATE TABLE %s (pk int PRIMARY KEY, v1 int, v2 int)"); + ColumnFamilyStore cfs = currentTableStore(); try (SimpleClient client = new SimpleClient(nativeAddr.getHostAddress(), nativePort, CURRENT)) { @@ -269,9 +273,15 @@ public void shouldRecordWriteMetricsForBatch() throws Exception // The metrics should reflect the batch as a single write operation with multiple rows and columns. assertEquals(2, ClientRequestSizeMetrics.totalRowsWritten.getCount()); assertEquals(4, ClientRequestSizeMetrics.totalColumnsWritten.getCount()); + assertEquals(1, cfs.metric.rowsMutatedPerWriteHistogram.cf.getCount()); } } + private ColumnFamilyStore currentTableStore() + { + return ColumnFamilyStore.getIfExists(KEYSPACE, currentTable()); + } + @Test public void shouldRecordWriteMetricsForCellDeletes() {