From a76286795f4b79aaaada46d8d937e1d697c43144 Mon Sep 17 00:00:00 2001 From: Stefan Miklosovic Date: Tue, 14 Mar 2023 21:45:15 +0100 Subject: [PATCH] Add system_views.max_sstable_size and system_views.max_sstable_duration tables patch by Stefan Miklosovic; reviewed by Brandon Williams for CASSANDRA-18333 --- CHANGES.txt | 1 + NEWS.txt | 1 + .../db/virtual/TableMetricTables.java | 4 +- .../cassandra/metrics/TableMetrics.java | 2 +- .../nodetool/stats/TableStatsHolder.java | 2 +- .../cassandra/metrics/TableMetricsTest.java | 44 +++++++++++++++++++ 6 files changed, 51 insertions(+), 3 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index f2b23b1f02..ae7420fbbe 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 5.0 + * Add system_views.max_sstable_size and system_views.max_sstable_duration tables (CASSANDRA-18333) * Extend implicit allow-filtering for virtual tables to clustering columns (CASSANDRA-18331) * Upgrade maven-shade-plugin to 3.4.1 to fix shaded dtest JAR build (CASSANDRA-18136) * Upgrade to Opcodes.ASM9 (CASSANDRA-17971) diff --git a/NEWS.txt b/NEWS.txt index ef582b6aa2..4dc0fe8cc7 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -130,6 +130,7 @@ New features SSTable of a table or 0 when there is not any SSTable. The latter returns the maximum duration, computed as `maxTimestamp - minTimestamp`, effectively non-zero for SSTables produced by TimeWindowCompactionStrategy. - Added local read/write ratio to tablestats. + - Added system_views.max_sstable_size and system_views.max_sstable_duration tables. Upgrading --------- diff --git a/src/java/org/apache/cassandra/db/virtual/TableMetricTables.java b/src/java/org/apache/cassandra/db/virtual/TableMetricTables.java index 9ff421c188..8368fd9ae5 100644 --- a/src/java/org/apache/cassandra/db/virtual/TableMetricTables.java +++ b/src/java/org/apache/cassandra/db/virtual/TableMetricTables.java @@ -77,7 +77,9 @@ public class TableMetricTables new HistogramTableMetric(name, "tombstones_per_read", t -> t.tombstoneScannedHistogram.cf), new HistogramTableMetric(name, "rows_per_read", t -> t.liveScannedHistogram.cf), new StorageTableMetric(name, "disk_usage", (TableMetrics t) -> t.totalDiskSpaceUsed), - new StorageTableMetric(name, "max_partition_size", (TableMetrics t) -> t.maxPartitionSize)); + new StorageTableMetric(name, "max_partition_size", (TableMetrics t) -> t.maxPartitionSize), + new StorageTableMetric(name, "max_sstable_size", (TableMetrics t) -> t.maxSSTableSize), + new TableMetricTable(name, "max_sstable_duration", t -> t.maxSSTableDuration, "max_sstable_duration", LongType.instance, "")); } /** diff --git a/src/java/org/apache/cassandra/metrics/TableMetrics.java b/src/java/org/apache/cassandra/metrics/TableMetrics.java index a8947aa388..dc90318e19 100644 --- a/src/java/org/apache/cassandra/metrics/TableMetrics.java +++ b/src/java/org/apache/cassandra/metrics/TableMetrics.java @@ -649,7 +649,7 @@ public class TableMetrics .filter(sstable -> sstable.getMinTimestamp() != Long.MAX_VALUE && sstable.getMaxTimestamp() != Long.MAX_VALUE) .map(ssTableReader -> ssTableReader.getMaxTimestamp() - ssTableReader.getMinTimestamp()) .max(Long::compare) - .orElse(0L); + .orElse(0L) / 1000; } }); maxSSTableSize = createTableGauge("MaxSSTableSize", new Gauge() diff --git a/src/java/org/apache/cassandra/tools/nodetool/stats/TableStatsHolder.java b/src/java/org/apache/cassandra/tools/nodetool/stats/TableStatsHolder.java index d15948cc9b..d9eece9afa 100644 --- a/src/java/org/apache/cassandra/tools/nodetool/stats/TableStatsHolder.java +++ b/src/java/org/apache/cassandra/tools/nodetool/stats/TableStatsHolder.java @@ -433,7 +433,7 @@ public class TableStatsHolder implements StatsHolder private String millisToDuration(long millis) { - return DurationFormatUtils.formatDurationWords(millis / 1000, true, true); + return DurationFormatUtils.formatDurationWords(millis, true, true); } /** diff --git a/test/unit/org/apache/cassandra/metrics/TableMetricsTest.java b/test/unit/org/apache/cassandra/metrics/TableMetricsTest.java index 4c9de77207..bbcced43db 100644 --- a/test/unit/org/apache/cassandra/metrics/TableMetricsTest.java +++ b/test/unit/org/apache/cassandra/metrics/TableMetricsTest.java @@ -19,10 +19,12 @@ package org.apache.cassandra.metrics; import java.io.IOException; +import java.util.concurrent.TimeUnit; import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; +import com.google.common.util.concurrent.Uninterruptibles; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; @@ -36,6 +38,7 @@ import org.apache.cassandra.config.DatabaseDescriptor; import org.apache.cassandra.db.ColumnFamilyStore; import org.apache.cassandra.exceptions.ConfigurationException; import org.apache.cassandra.service.EmbeddedCassandraService; +import org.apache.cassandra.service.StorageService; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -47,6 +50,7 @@ public class TableMetricsTest private static final String KEYSPACE = "junit"; private static final String TABLE = "tablemetricstest"; private static final String COUNTER_TABLE = "tablemetricscountertest"; + private static final String TWCS_TABLE = "tablemetricstesttwcs"; private static EmbeddedCassandraService cassandra; private static Cluster cluster; @@ -68,6 +72,15 @@ public class TableMetricsTest return recreateTable(TABLE); } + private ColumnFamilyStore recreateTWCSTable() + { + session.execute(String.format("DROP TABLE IF EXISTS %s.%s", KEYSPACE, TWCS_TABLE)); + session.execute(String.format("CREATE TABLE IF NOT EXISTS %s.%s (id int, val1 text, val2 text, PRIMARY KEY(id, val1)) " + + " WITH compaction = {'class': 'TimeWindowCompactionStrategy', 'compaction_window_unit': 'MINUTES', 'compaction_window_size': 1};", + KEYSPACE, TWCS_TABLE)); + return ColumnFamilyStore.getIfExists(KEYSPACE, TWCS_TABLE); + } + private ColumnFamilyStore recreateTable(String table) { session.execute(String.format("DROP TABLE IF EXISTS %s.%s", KEYSPACE, table)); @@ -129,6 +142,37 @@ public class TableMetricsTest assertGreaterThan(cfs.metric.coordinatorWriteLatency.getMeanRate(), 0); } + @Test + public void testMaxSSTableSize() throws Exception + { + ColumnFamilyStore cfs = recreateTable(); + assertEquals(0, cfs.metric.maxSSTableSize.getValue().longValue()); + + for (int i = 0; i < 1000; i++) + { + session.execute(String.format("INSERT INTO %s.%s (id, val1, val2) VALUES (%d, '%s', '%s')", KEYSPACE, TABLE, i, "val" + i, "val" + i)); + } + + StorageService.instance.forceKeyspaceFlush(KEYSPACE); + + assertGreaterThan(cfs.metric.maxSSTableSize.getValue().doubleValue(), 0); + } + + @Test + public void testMaxSSTableDuration() throws Exception + { + ColumnFamilyStore cfs = recreateTWCSTable(); + assertEquals(0, cfs.metric.maxSSTableDuration.getValue().longValue()); + + session.execute(String.format("INSERT INTO %s.%s (id, val1, val2) VALUES (%d, '%s', '%s')", KEYSPACE, TWCS_TABLE, 1, "val1", "val1")); + Uninterruptibles.sleepUninterruptibly(10, TimeUnit.SECONDS); + session.execute(String.format("INSERT INTO %s.%s (id, val1, val2) VALUES (%d, '%s', '%s')", KEYSPACE, TWCS_TABLE, 2, "val2", "val2")); + + StorageService.instance.forceKeyspaceFlush(KEYSPACE); + + assertGreaterThan(cfs.metric.maxSSTableDuration.getValue().doubleValue(), 0); + } + @Test public void testPreparedStatementsExecuted() {