diff --git a/CHANGES.txt b/CHANGES.txt index 28e3305bd8..b6e94ec67d 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 5.0 + * Add MaxSSTableSize and MaxSSTableDuration metrics and propagate them together with local read/write ratio to tablestats (CASSANDRA-18283) * Add more logging around CompactionManager operations (CASSANDRA-18268) * Reduce memory allocations of calls to ByteBufer.duplicate() made in org.apache.cassandra.transport.CBUtil#writeValue (CASSANDRA-18212) * CEP-17: SSTable API (CASSANDRA-17056) diff --git a/NEWS.txt b/NEWS.txt index 363c2deb58..ef582b6aa2 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -126,7 +126,10 @@ New features normally require it, except `system_views.system_logs`. - More accurate skipping of sstables in read path due to better handling of min/max clustering and lower bound; SSTable format has been bumped to 'nc' because there are new fields in stats metadata\ - - SSTal + - Added MaxSSTableSize and MaxSSTableDuration metrics to TableMetrics. The former returns the size of the biggest + 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. Upgrading --------- diff --git a/doc/modules/cassandra/pages/operating/metrics.adoc b/doc/modules/cassandra/pages/operating/metrics.adoc index c650ec1c32..0102285c37 100644 --- a/doc/modules/cassandra/pages/operating/metrics.adoc +++ b/doc/modules/cassandra/pages/operating/metrics.adoc @@ -144,6 +144,13 @@ this table (in bytes). |TotalDiskSpaceUsed |Counter |Total disk space used by SSTables belonging to this table, including obsolete ones waiting to be GC'd. +|MaxSSTableSize |Gauge |Maximum size of SSTable of this table - +the physical size on disk of all components for such SSTable in bytes. Equals to +zero if there is not any SSTable on disk. + +|MaxSSTableDuration |Gauge |Maximum duration in milliseconds of an SSTable for this table, +computed as `maxTimestamp - minTimestamp`. Equals to zero if min or max timestamp is `Long.MAX_VALUE`. + |MinPartitionSize |Gauge |Size of the smallest compacted partition (in bytes). diff --git a/src/java/org/apache/cassandra/db/ColumnFamilyStore.java b/src/java/org/apache/cassandra/db/ColumnFamilyStore.java index edfe831a8c..4c567701b3 100644 --- a/src/java/org/apache/cassandra/db/ColumnFamilyStore.java +++ b/src/java/org/apache/cassandra/db/ColumnFamilyStore.java @@ -3435,6 +3435,18 @@ public class ColumnFamilyStore implements ColumnFamilyStoreMBean, Memtable.Owner return false; } + @Override + public long getMaxSSTableSize() + { + return metric.maxSSTableSize.getValue(); + } + + @Override + public long getMaxSSTableDuration() + { + return metric.maxSSTableDuration.getValue(); + } + @Override public Map getTopSizePartitions() { diff --git a/src/java/org/apache/cassandra/db/ColumnFamilyStoreMBean.java b/src/java/org/apache/cassandra/db/ColumnFamilyStoreMBean.java index 1a90875c4f..2ae77b47f0 100644 --- a/src/java/org/apache/cassandra/db/ColumnFamilyStoreMBean.java +++ b/src/java/org/apache/cassandra/db/ColumnFamilyStoreMBean.java @@ -299,4 +299,23 @@ public interface ColumnFamilyStoreMBean public Long getTopSizePartitionsLastUpdate(); public Map getTopTombstonePartitions(); public Long getTopTombstonePartitionsLastUpdate(); + + /** + * Returns the size of the biggest SSTable of this table. + * + * @return (physical) size of the biggest SSTable of this table on disk or 0 if no SSTable is present + */ + public long getMaxSSTableSize(); + + /** + * Returns the longest duration of an SSTable, in milliseconds, of this table, + * computed as {@code maxTimestamp - minTimestamp}. + * + * It returns 0 if there are no SSTables or if {@code maxTimestamp} or {@code minTimestamp} is + * equal to {@code Long.MAX_VALUE}. Effectively non-zero for tables on {@code TimeWindowCompactionStrategy}. + * + * @return the biggest {@code maxTimestamp - minTimestamp} among all SSTables of this table + * or 0 if no SSTable is present + */ + public long getMaxSSTableDuration(); } diff --git a/src/java/org/apache/cassandra/db/compaction/TimeWindowCompactionStrategyOptions.java b/src/java/org/apache/cassandra/db/compaction/TimeWindowCompactionStrategyOptions.java index 8b2ba2377f..cdb89528c7 100644 --- a/src/java/org/apache/cassandra/db/compaction/TimeWindowCompactionStrategyOptions.java +++ b/src/java/org/apache/cassandra/db/compaction/TimeWindowCompactionStrategyOptions.java @@ -39,11 +39,11 @@ public final class TimeWindowCompactionStrategyOptions protected static final int DEFAULT_EXPIRED_SSTABLE_CHECK_FREQUENCY_SECONDS = 60 * 10; protected static final Boolean DEFAULT_UNSAFE_AGGRESSIVE_SSTABLE_EXPIRATION = false; - protected static final String TIMESTAMP_RESOLUTION_KEY = "timestamp_resolution"; - protected static final String COMPACTION_WINDOW_UNIT_KEY = "compaction_window_unit"; - protected static final String COMPACTION_WINDOW_SIZE_KEY = "compaction_window_size"; - protected static final String EXPIRED_SSTABLE_CHECK_FREQUENCY_SECONDS_KEY = "expired_sstable_check_frequency_seconds"; - protected static final String UNSAFE_AGGRESSIVE_SSTABLE_EXPIRATION_KEY = "unsafe_aggressive_sstable_expiration"; + public static final String TIMESTAMP_RESOLUTION_KEY = "timestamp_resolution"; + public static final String COMPACTION_WINDOW_UNIT_KEY = "compaction_window_unit"; + public static final String COMPACTION_WINDOW_SIZE_KEY = "compaction_window_size"; + public static final String EXPIRED_SSTABLE_CHECK_FREQUENCY_SECONDS_KEY = "expired_sstable_check_frequency_seconds"; + public static final String UNSAFE_AGGRESSIVE_SSTABLE_EXPIRATION_KEY = "unsafe_aggressive_sstable_expiration"; static final String UNSAFE_AGGRESSIVE_SSTABLE_EXPIRATION_PROPERTY = Config.PROPERTY_PREFIX + "allow_unsafe_aggressive_sstable_expiration"; diff --git a/src/java/org/apache/cassandra/metrics/TableMetrics.java b/src/java/org/apache/cassandra/metrics/TableMetrics.java index 688b75b160..a8947aa388 100644 --- a/src/java/org/apache/cassandra/metrics/TableMetrics.java +++ b/src/java/org/apache/cassandra/metrics/TableMetrics.java @@ -126,6 +126,10 @@ public class TableMetrics public final Gauge liveSSTableCount; /** Number of SSTables with old version on disk for this CF */ public final Gauge oldVersionSSTableCount; + /** Maximum duration of an SSTable for this table, computed as maxTimestamp - minTimestamp*/ + public final Gauge maxSSTableDuration; + /** Maximum size of SSTable of this table - the physical size on disk of all components for such SSTable in bytes*/ + public final Gauge maxSSTableSize; /** Disk space used by SSTables belonging to this table */ public final Counter liveDiskSpaceUsed; /** Uncompressed/logical disk space used by SSTables belonging to this table */ @@ -633,6 +637,35 @@ public class TableMetrics return count; } }); + maxSSTableDuration = createTableGauge("MaxSSTableDuration", new Gauge() + { + @Override + public Long getValue() + { + return cfs.getTracker() + .getView() + .liveSSTables() + .stream() + .filter(sstable -> sstable.getMinTimestamp() != Long.MAX_VALUE && sstable.getMaxTimestamp() != Long.MAX_VALUE) + .map(ssTableReader -> ssTableReader.getMaxTimestamp() - ssTableReader.getMinTimestamp()) + .max(Long::compare) + .orElse(0L); + } + }); + maxSSTableSize = createTableGauge("MaxSSTableSize", new Gauge() + { + @Override + public Long getValue() + { + return cfs.getTracker() + .getView() + .liveSSTables() + .stream() + .map(SSTableReader::bytesOnDisk) + .max(Long::compare) + .orElse(0L); + } + }); liveDiskSpaceUsed = createTableCounter("LiveDiskSpaceUsed"); uncompressedLiveDiskSpaceUsed = createTableCounter("UncompressedLiveDiskSpaceUsed"); totalDiskSpaceUsed = createTableCounter("TotalDiskSpaceUsed"); diff --git a/src/java/org/apache/cassandra/tools/NodeProbe.java b/src/java/org/apache/cassandra/tools/NodeProbe.java index 9217ff36c6..e983e2fbef 100644 --- a/src/java/org/apache/cassandra/tools/NodeProbe.java +++ b/src/java/org/apache/cassandra/tools/NodeProbe.java @@ -1802,6 +1802,8 @@ public class NodeProbe implements AutoCloseable case "EstimatedPartitionCount": case "KeyCacheHitRate": case "LiveSSTableCount": + case "MaxSSTableDuration": + case "MaxSSTableSize": case "OldVersionSSTableCount": case "MaxPartitionSize": case "MeanPartitionSize": diff --git a/src/java/org/apache/cassandra/tools/nodetool/TableStats.java b/src/java/org/apache/cassandra/tools/nodetool/TableStats.java index 4a33c64e59..c1a76a04cf 100644 --- a/src/java/org/apache/cassandra/tools/nodetool/TableStats.java +++ b/src/java/org/apache/cassandra/tools/nodetool/TableStats.java @@ -60,7 +60,8 @@ public class TableStats extends NodeToolCmd + "memtable_off_heap_memory_used, memtable_switch_count, number_of_partitions_estimate, " + "off_heap_memory_used_total, pending_flushes, percent_repaired, read_latency, reads, " + "space_used_by_snapshots_total, space_used_live, space_used_total, " - + "sstable_compression_ratio, sstable_count, table_name, write_latency, writes)") + + "sstable_compression_ratio, sstable_count, table_name, write_latency, writes, " + + "max_sstable_size, local_read_write_ratio, twcs_max_duration)") private String sortKey = ""; @Option(title = "top", diff --git a/src/java/org/apache/cassandra/tools/nodetool/stats/StatsTable.java b/src/java/org/apache/cassandra/tools/nodetool/stats/StatsTable.java index 48b795b422..2484570e41 100644 --- a/src/java/org/apache/cassandra/tools/nodetool/stats/StatsTable.java +++ b/src/java/org/apache/cassandra/tools/nodetool/stats/StatsTable.java @@ -31,6 +31,7 @@ public class StatsTable public boolean isLeveledSstable = false; public Object sstableCount; public Object oldSSTableCount; + public Long maxSSTableSize; public String spaceUsedLive; public String spaceUsedTotal; public String spaceUsedBySnapshotsTotal; @@ -78,4 +79,7 @@ public class StatsTable public Map topTombstonePartitions; public String topSizePartitionsLastUpdate; public String topTombstonePartitionsLastUpdate; + public double localReadWriteRatio; + public Long twcsDurationInMillis; + public String twcs; } diff --git a/src/java/org/apache/cassandra/tools/nodetool/stats/StatsTableComparator.java b/src/java/org/apache/cassandra/tools/nodetool/stats/StatsTableComparator.java index 17b5c61a3d..a7dabb2536 100644 --- a/src/java/org/apache/cassandra/tools/nodetool/stats/StatsTableComparator.java +++ b/src/java/org/apache/cassandra/tools/nodetool/stats/StatsTableComparator.java @@ -65,7 +65,8 @@ public class StatsTableComparator implements Comparator "pending_flushes", "percent_repaired", "read_latency", "reads", "space_used_by_snapshots_total", "space_used_live", "space_used_total", "sstable_compression_ratio", "sstable_count", - "table_name", "write_latency", "writes" }; + "table_name", "write_latency", "writes", "max_sstable_size", + "local_read_write_ratio", "twcs_max_duration"}; public StatsTableComparator(String sortKey, boolean humanReadable) { @@ -229,6 +230,10 @@ public class StatsTableComparator implements Comparator { result = compareDoubles(stx.localWriteLatencyMs, sty.localWriteLatencyMs); } + else if (sortKey.equals("local_read_write_ratio")) + { + result = compareDoubles(stx.localReadWriteRatio, sty.localReadWriteRatio); + } else if (sortKey.equals("maximum_live_cells_per_slice_last_five_minutes")) { result = sign * Long.valueOf(stx.maximumLiveCellsPerSliceLastFiveMinutes) @@ -295,6 +300,21 @@ public class StatsTableComparator implements Comparator { result = compareDoubles(stx.percentRepaired, sty.percentRepaired); } + else if (sortKey.equals("max_sstable_size")) + { + result = sign * stx.maxSSTableSize.compareTo(sty.maxSSTableSize); + } + else if (sortKey.equals("twcs_max_duration")) + { + if (stx.twcsDurationInMillis != null && sty.twcsDurationInMillis == null) + return sign; + else if (stx.twcsDurationInMillis == null && sty.twcsDurationInMillis != null) + return sign * -1; + else if (stx.twcsDurationInMillis == null) + return 0; + else + result = sign * stx.twcsDurationInMillis.compareTo(sty.twcsDurationInMillis); + } else if (sortKey.equals("space_used_by_snapshots_total")) { result = compareFileSizes(stx.spaceUsedBySnapshotsTotal, 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 fc6ef145d6..d15948cc9b 100644 --- a/src/java/org/apache/cassandra/tools/nodetool/stats/TableStatsHolder.java +++ b/src/java/org/apache/cassandra/tools/nodetool/stats/TableStatsHolder.java @@ -25,7 +25,12 @@ import java.util.*; import com.google.common.collect.ArrayListMultimap; import javax.management.InstanceNotFoundException; + +import org.apache.commons.lang3.time.DurationFormatUtils; + import org.apache.cassandra.db.*; +import org.apache.cassandra.db.compaction.TimeWindowCompactionStrategy; +import org.apache.cassandra.db.compaction.TimeWindowCompactionStrategyOptions; import org.apache.cassandra.io.util.*; import org.apache.cassandra.metrics.*; import org.apache.cassandra.tools.*; @@ -33,7 +38,7 @@ import org.apache.cassandra.tools.*; public class TableStatsHolder implements StatsHolder { public final List keyspaces; - public final int numberOfTables; + public int numberOfTables = 0; public final boolean humanReadable; public final String sortKey; public final int top; @@ -48,14 +53,7 @@ public class TableStatsHolder implements StatsHolder this.locationCheck = locationCheck; if (!this.isTestTableStatsHolder()) - { - this.numberOfTables = probe.getNumberOfTables(); this.initializeKeyspaces(probe, ignore, tableNames); - } - else - { - this.numberOfTables = 0; - } } @Override @@ -121,6 +119,8 @@ public class TableStatsHolder implements StatsHolder Map mpTable = new HashMap<>(); mpTable.put("sstables_in_each_level", table.sstablesInEachLevel); mpTable.put("sstable_bytes_in_each_level", table.sstableBytesInEachLevel); + mpTable.put("max_sstable_size", table.maxSSTableSize); + mpTable.put("twcs", table.twcs); mpTable.put("space_used_live", table.spaceUsedLive); mpTable.put("space_used_total", table.spaceUsedTotal); mpTable.put("space_used_by_snapshots_total", table.spaceUsedBySnapshotsTotal); @@ -137,6 +137,7 @@ public class TableStatsHolder implements StatsHolder mpTable.put("local_read_latency_ms", String.format("%01.3f", table.localReadLatencyMs)); mpTable.put("local_write_count", table.localWriteCount); mpTable.put("local_write_latency_ms", String.format("%01.3f", table.localWriteLatencyMs)); + mpTable.put("local_read_write_ratio", String.format("%01.5f", table.localReadWriteRatio)); mpTable.put("pending_flushes", table.pendingFlushes); mpTable.put("percent_repaired", table.percentRepaired); mpTable.put("bytes_repaired", table.bytesRepaired); @@ -203,6 +204,8 @@ public class TableStatsHolder implements StatsHolder } } + numberOfTables = selectedTableMbeans.size(); + // make sure all specified keyspace and tables exist filter.verifyKeyspaces(probe.getKeyspaces()); filter.verifyTables(); @@ -225,6 +228,8 @@ public class TableStatsHolder implements StatsHolder statsTable.isIndex = tableName.contains("."); statsTable.sstableCount = probe.getColumnFamilyMetric(keyspaceName, tableName, "LiveSSTableCount"); statsTable.oldSSTableCount = probe.getColumnFamilyMetric(keyspaceName, tableName, "OldVersionSSTableCount"); + Long sstableSize = (Long) probe.getColumnFamilyMetric(keyspaceName, tableName, "MaxSSTableSize"); + statsTable.maxSSTableSize = sstableSize == null ? 0 : sstableSize; int[] leveledSStables = table.getSSTableCountPerLevel(); if (leveledSStables != null) @@ -289,6 +294,9 @@ public class TableStatsHolder implements StatsHolder statsTable.spaceUsedLive = format((Long) probe.getColumnFamilyMetric(keyspaceName, tableName, "LiveDiskSpaceUsed"), humanReadable); statsTable.spaceUsedTotal = format((Long) probe.getColumnFamilyMetric(keyspaceName, tableName, "TotalDiskSpaceUsed"), humanReadable); statsTable.spaceUsedBySnapshotsTotal = format((Long) probe.getColumnFamilyMetric(keyspaceName, tableName, "SnapshotsSize"), humanReadable); + + maybeAddTWCSWindowWithMaxDuration(statsTable, probe, keyspaceName, tableName); + if (offHeapSize != null) { statsTable.offHeapUsed = true; @@ -329,6 +337,9 @@ public class TableStatsHolder implements StatsHolder double localWriteLatency = ((CassandraMetricsRegistry.JmxTimerMBean) probe.getColumnFamilyMetric(keyspaceName, tableName, "WriteLatency")).getMean() / 1000; double localWLatency = localWriteLatency > 0 ? localWriteLatency : Double.NaN; + + statsTable.localReadWriteRatio = statsTable.localWriteCount > 0 ? statsTable.localReadCount / (double) statsTable.localWriteCount : 0; + statsTable.localWriteLatencyMs = localWLatency; statsTable.pendingFlushes = probe.getColumnFamilyMetric(keyspaceName, tableName, "PendingFlushes"); @@ -378,6 +389,27 @@ public class TableStatsHolder implements StatsHolder } } + private void maybeAddTWCSWindowWithMaxDuration(StatsTable statsTable, NodeProbe probe, String keyspaceName, String tableName) + { + Map compactionParameters = probe.getCfsProxy(statsTable.keyspaceName, statsTable.tableName) + .getCompactionParameters(); + + if (compactionParameters == null) + return; + + String compactor = compactionParameters.get("class"); + + if (compactor == null || !compactor.endsWith(TimeWindowCompactionStrategy.class.getSimpleName())) + return; + + String unit = compactionParameters.get(TimeWindowCompactionStrategyOptions.COMPACTION_WINDOW_UNIT_KEY); + String size = compactionParameters.get(TimeWindowCompactionStrategyOptions.COMPACTION_WINDOW_SIZE_KEY); + + statsTable.twcsDurationInMillis = (Long) probe.getColumnFamilyMetric(keyspaceName, tableName, "MaxSSTableDuration"); + String maxDuration = millisToDuration(statsTable.twcsDurationInMillis); + statsTable.twcs = String.format("%s %s, max duration: %s", size, unit, maxDuration); + } + private String format(long bytes, boolean humanReadable) { return humanReadable ? FileUtils.stringifyFileSize(bytes) : Long.toString(bytes); @@ -399,6 +431,11 @@ public class TableStatsHolder implements StatsHolder return df.format(new Date(millis)); } + private String millisToDuration(long millis) + { + return DurationFormatUtils.formatDurationWords(millis / 1000, true, true); + } + /** * Sort and filter this TableStatHolder's tables as specified by its sortKey and top attributes. */ diff --git a/src/java/org/apache/cassandra/tools/nodetool/stats/TableStatsPrinter.java b/src/java/org/apache/cassandra/tools/nodetool/stats/TableStatsPrinter.java index 7f17c21d6d..c30ab6df13 100644 --- a/src/java/org/apache/cassandra/tools/nodetool/stats/TableStatsPrinter.java +++ b/src/java/org/apache/cassandra/tools/nodetool/stats/TableStatsPrinter.java @@ -50,6 +50,9 @@ public class TableStatsPrinter @Override public void print(TableStatsHolder data, PrintStream out) { + if (data.numberOfTables == 0) + return; + out.println("Total number of tables: " + data.numberOfTables); out.println("----------------"); @@ -57,7 +60,7 @@ public class TableStatsPrinter for (StatsKeyspace keyspace : keyspaces) { // print each keyspace's information - out.println("Keyspace : " + keyspace.name); + out.println("Keyspace: " + keyspace.name); out.println("\tRead Count: " + keyspace.readCount); out.println("\tRead Latency: " + keyspace.readLatency() + " ms"); out.println("\tWrite Count: " + keyspace.writeCount); @@ -66,6 +69,9 @@ public class TableStatsPrinter // print each table's information List tables = keyspace.tables; + if (tables.size() == 0) + continue; + for (StatsTable table : tables) { printStatsTable(table, table.tableName, "\t\t", out); @@ -79,6 +85,9 @@ public class TableStatsPrinter out.println(indent + "Table" + (table.isIndex ? " (index): " : ": ") + tableDisplayName); out.println(indent + "SSTable count: " + table.sstableCount); out.println(indent + "Old SSTable count: " + table.oldSSTableCount); + out.println(indent + "Max SSTable size: " + FBUtilities.prettyPrintMemory(table.maxSSTableSize)); + if (table.twcs != null) + out.println(indent + "SSTables Time Window: " + table.twcs); if (table.isLeveledSstable) { out.println(indent + "SSTables in each level: [" + String.join(", ", @@ -93,7 +102,7 @@ public class TableStatsPrinter if (table.offHeapUsed) out.println(indent + "Off heap memory used (total): " + table.offHeapMemoryUsedTotal); - out.println(indent + "SSTable Compression Ratio: " + table.sstableCompressionRatio); + out.printf(indent + "SSTable Compression Ratio: %01.5f%n", table.sstableCompressionRatio); out.println(indent + "Number of partitions (estimate): " + table.numberOfPartitionsEstimate); out.println(indent + "Memtable cell count: " + table.memtableCellCount); out.println(indent + "Memtable data size: " + table.memtableDataSize); @@ -105,6 +114,9 @@ public class TableStatsPrinter out.printf(indent + "Local read latency: %01.3f ms%n", table.localReadLatencyMs); out.println(indent + "Local write count: " + table.localWriteCount); out.printf(indent + "Local write latency: %01.3f ms%n", table.localWriteLatencyMs); + + out.printf(indent + "Local read/write ratio: %01.5f%n", table.localReadWriteRatio); + out.println(indent + "Pending flushes: " + table.pendingFlushes); out.println(indent + "Percent repaired: " + table.percentRepaired); @@ -164,6 +176,10 @@ public class TableStatsPrinter public void print(TableStatsHolder data, PrintStream out) { List tables = data.getSortedFilteredTables(); + + if (tables.size() == 0) + return; + String totalTablesSummary = String.format("Total number of tables: %d", data.numberOfTables); if (data.top > 0) { diff --git a/test/unit/org/apache/cassandra/tools/nodetool/TableStatsTest.java b/test/unit/org/apache/cassandra/tools/nodetool/TableStatsTest.java index 1ba30f0b80..5c57f11db4 100644 --- a/test/unit/org/apache/cassandra/tools/nodetool/TableStatsTest.java +++ b/test/unit/org/apache/cassandra/tools/nodetool/TableStatsTest.java @@ -108,7 +108,8 @@ public class TableStatsTest extends CQLTester " off_heap_memory_used_total, pending_flushes, percent_repaired,\n" + " read_latency, reads, space_used_by_snapshots_total, space_used_live,\n" + " space_used_total, sstable_compression_ratio, sstable_count,\n" + - " table_name, write_latency, writes)\n" + + " table_name, write_latency, writes, max_sstable_size,\n" + + " local_read_write_ratio, twcs_max_duration)\n" + "\n" + " -t , --top \n" + " Show only the top K tables for the sort key (specify the number K of\n" + @@ -134,12 +135,12 @@ public class TableStatsTest extends CQLTester { ToolRunner.ToolResult tool = ToolRunner.invokeNodetool("tablestats"); tool.assertOnCleanExit(); - assertThat(tool.getStdout()).contains("Keyspace : system_schema"); + assertThat(tool.getStdout()).contains("Keyspace: system_schema"); assertThat(StringUtils.countMatches(tool.getStdout(), "Table:")).isGreaterThan(1); tool = ToolRunner.invokeNodetool("tablestats", "system_distributed"); tool.assertOnCleanExit(); - assertThat(tool.getStdout()).contains("Keyspace : system_distributed"); + assertThat(tool.getStdout()).contains("Keyspace: system_distributed"); assertThat(tool.getStdout()).doesNotContain("Keyspace : system_schema"); assertThat(StringUtils.countMatches(tool.getStdout(), "Table:")).isGreaterThan(1); } @@ -149,7 +150,7 @@ public class TableStatsTest extends CQLTester { ToolRunner.ToolResult tool = ToolRunner.invokeNodetool("tablestats", "-i", "system_schema.aggregates"); tool.assertOnCleanExit(); - assertThat(tool.getStdout()).contains("Keyspace : system_schema"); + assertThat(tool.getStdout()).contains("Keyspace: system_schema"); assertThat(tool.getStdout()).doesNotContain("Table: system_schema.aggregates"); assertThat(StringUtils.countMatches(tool.getStdout(), "Table:")).isGreaterThan(1); } diff --git a/test/unit/org/apache/cassandra/tools/nodetool/stats/StatsTableComparatorTest.java b/test/unit/org/apache/cassandra/tools/nodetool/stats/StatsTableComparatorTest.java index ea49899ff7..1710395cfd 100644 --- a/test/unit/org/apache/cassandra/tools/nodetool/stats/StatsTableComparatorTest.java +++ b/test/unit/org/apache/cassandra/tools/nodetool/stats/StatsTableComparatorTest.java @@ -212,6 +212,11 @@ public class StatsTableComparatorTest extends TableStatsTestBase "table1 > table3 > table5 > table2 > table4 > table6", humanReadable, ascending); + runCompareTest(testTables, + "twcs_max_duration", + "table2 > table4 > table1 > table3 > table6 > table5", + humanReadable, + ascending); } @Test diff --git a/test/unit/org/apache/cassandra/tools/nodetool/stats/TableStatsPrinterTest.java b/test/unit/org/apache/cassandra/tools/nodetool/stats/TableStatsPrinterTest.java index d67ef5dd90..0bf4e1ce28 100644 --- a/test/unit/org/apache/cassandra/tools/nodetool/stats/TableStatsPrinterTest.java +++ b/test/unit/org/apache/cassandra/tools/nodetool/stats/TableStatsPrinterTest.java @@ -35,10 +35,11 @@ public class TableStatsPrinterTest extends TableStatsTestBase "\tTable: %s\n" + "\tSSTable count: 60000\n" + "\tOld SSTable count: 0\n" + + "\tMax SSTable size: 0.000KiB\n" + "\tSpace used (live): 0\n" + "\tSpace used (total): 9001\n" + "\tSpace used by snapshots (total): 1111\n" + - "\tSSTable Compression Ratio: 0.68\n" + + "\tSSTable Compression Ratio: 0.68000\n" + "\tNumber of partitions (estimate): 111111\n" + "\tMemtable cell count: 111\n" + "\tMemtable data size: 0\n" + @@ -47,6 +48,7 @@ public class TableStatsPrinterTest extends TableStatsTestBase "\tLocal read latency: 2.000 ms\n" + "\tLocal write count: 5\n" + "\tLocal write latency: 0.050 ms\n" + + "\tLocal read/write ratio: 0.00000\n" + "\tPending flushes: 11111\n" + "\tPercent repaired: 100.0\n" + "\tBytes repaired: 0.000KiB\n" + @@ -70,11 +72,12 @@ public class TableStatsPrinterTest extends TableStatsTestBase "\tTable: %s\n" + "\tSSTable count: 3000\n" + "\tOld SSTable count: 0\n" + + "\tMax SSTable size: 0.000KiB\n" + "\tSpace used (live): 22\n" + "\tSpace used (total): 1024\n" + "\tSpace used by snapshots (total): 222\n" + "\tOff heap memory used (total): 314159367\n" + - "\tSSTable Compression Ratio: 0.68\n" + + "\tSSTable Compression Ratio: 0.68000\n" + "\tNumber of partitions (estimate): 22222\n" + "\tMemtable cell count: 22\n" + "\tMemtable data size: 900\n" + @@ -84,6 +87,7 @@ public class TableStatsPrinterTest extends TableStatsTestBase "\tLocal read latency: 3.000 ms\n" + "\tLocal write count: 4\n" + "\tLocal write latency: 0.000 ms\n" + + "\tLocal read/write ratio: 0.00000\n" + "\tPending flushes: 222222\n" + "\tPercent repaired: 99.9\n" + "\tBytes repaired: 0.000KiB\n" + @@ -110,10 +114,11 @@ public class TableStatsPrinterTest extends TableStatsTestBase "\tTable: %s\n" + "\tSSTable count: 50000\n" + "\tOld SSTable count: 0\n" + + "\tMax SSTable size: 0.000KiB\n" + "\tSpace used (live): 0\n" + "\tSpace used (total): 512\n" + "\tSpace used by snapshots (total): 0\n" + - "\tSSTable Compression Ratio: 0.32\n" + + "\tSSTable Compression Ratio: 0.32000\n" + "\tNumber of partitions (estimate): 3333\n" + "\tMemtable cell count: 333333\n" + "\tMemtable data size: 1999\n" + @@ -122,6 +127,7 @@ public class TableStatsPrinterTest extends TableStatsTestBase "\tLocal read latency: 4.000 ms\n" + "\tLocal write count: 3\n" + "\tLocal write latency: NaN ms\n" + + "\tLocal read/write ratio: 0.00000\n" + "\tPending flushes: 333\n" + "\tPercent repaired: 99.8\n" + "\tBytes repaired: 0.000KiB\n" + @@ -145,11 +151,12 @@ public class TableStatsPrinterTest extends TableStatsTestBase "\tTable: %s\n" + "\tSSTable count: 2000\n" + "\tOld SSTable count: 0\n" + + "\tMax SSTable size: 0.000KiB\n" + "\tSpace used (live): 4444\n" + "\tSpace used (total): 256\n" + "\tSpace used by snapshots (total): 44\n" + "\tOff heap memory used (total): 441213818\n" + - "\tSSTable Compression Ratio: 0.95\n" + + "\tSSTable Compression Ratio: 0.95000\n" + "\tNumber of partitions (estimate): 444\n" + "\tMemtable cell count: 4\n" + "\tMemtable data size: 3000\n" + @@ -159,6 +166,7 @@ public class TableStatsPrinterTest extends TableStatsTestBase "\tLocal read latency: NaN ms\n" + "\tLocal write count: 2\n" + "\tLocal write latency: 2.000 ms\n" + + "\tLocal read/write ratio: 0.00000\n" + "\tPending flushes: 4444\n" + "\tPercent repaired: 50.0\n" + "\tBytes repaired: 0.000KiB\n" + @@ -185,10 +193,11 @@ public class TableStatsPrinterTest extends TableStatsTestBase "\tTable: %s\n" + "\tSSTable count: 40000\n" + "\tOld SSTable count: 0\n" + + "\tMax SSTable size: 0.000KiB\n" + "\tSpace used (live): 55555\n" + "\tSpace used (total): 64\n" + "\tSpace used by snapshots (total): 55555\n" + - "\tSSTable Compression Ratio: 0.99\n" + + "\tSSTable Compression Ratio: 0.99000\n" + "\tNumber of partitions (estimate): 55\n" + "\tMemtable cell count: 55555\n" + "\tMemtable data size: 20000\n" + @@ -197,6 +206,7 @@ public class TableStatsPrinterTest extends TableStatsTestBase "\tLocal read latency: 0.000 ms\n" + "\tLocal write count: 1\n" + "\tLocal write latency: 1.000 ms\n" + + "\tLocal read/write ratio: 0.00000\n" + "\tPending flushes: 5\n" + "\tPercent repaired: 93.0\n" + "\tBytes repaired: 0.000KiB\n" + @@ -220,11 +230,12 @@ public class TableStatsPrinterTest extends TableStatsTestBase "\tTable: %s\n" + "\tSSTable count: 1000\n" + "\tOld SSTable count: 0\n" + + "\tMax SSTable size: 0.000KiB\n" + "\tSpace used (live): 666666\n" + "\tSpace used (total): 0\n" + "\tSpace used by snapshots (total): 0\n" + "\tOff heap memory used (total): 162470810\n" + - "\tSSTable Compression Ratio: 0.68\n" + + "\tSSTable Compression Ratio: 0.68000\n" + "\tNumber of partitions (estimate): 6\n" + "\tMemtable cell count: 6666\n" + "\tMemtable data size: 1000000\n" + @@ -234,6 +245,7 @@ public class TableStatsPrinterTest extends TableStatsTestBase "\tLocal read latency: 1.000 ms\n" + "\tLocal write count: 0\n" + "\tLocal write latency: 0.500 ms\n" + + "\tLocal read/write ratio: 0.00000\n" + "\tPending flushes: 66\n" + "\tPercent repaired: 0.0\n" + "\tBytes repaired: 0.000KiB\n" + @@ -262,9 +274,9 @@ public class TableStatsPrinterTest extends TableStatsTestBase * without leaking test implementation into the TableStatsHolder implementation. */ public static final String expectedDefaultPrinterOutput = - "Total number of tables: 0\n" + + "Total number of tables: 6\n" + "----------------\n" + - "Keyspace : keyspace1\n" + + "Keyspace: keyspace1\n" + "\tRead Count: 3\n" + "\tRead Latency: 0.0 ms\n" + "\tWrite Count: 12\n" + @@ -274,7 +286,7 @@ public class TableStatsPrinterTest extends TableStatsTestBase String.format(duplicateTabs(expectedDefaultTable2Output), "table2") + String.format(duplicateTabs(expectedDefaultTable3Output), "table3") + "----------------\n" + - "Keyspace : keyspace2\n" + + "Keyspace: keyspace2\n" + "\tRead Count: 7\n" + "\tRead Latency: 0.0 ms\n" + "\tWrite Count: 3\n" + @@ -283,7 +295,7 @@ public class TableStatsPrinterTest extends TableStatsTestBase String.format(duplicateTabs(expectedDefaultTable4Output), "table4") + String.format(duplicateTabs(expectedDefaultTable5Output), "table5") + "----------------\n" + - "Keyspace : keyspace3\n" + + "Keyspace: keyspace3\n" + "\tRead Count: 5\n" + "\tRead Latency: 0.0 ms\n" + "\tWrite Count: 0\n" + @@ -340,7 +352,8 @@ public class TableStatsPrinterTest extends TableStatsTestBase @Test public void testDefaultPrinter() throws Exception { - StatsHolder holder = new TestTableStatsHolder(testKeyspaces, "", 0); + TestTableStatsHolder holder = new TestTableStatsHolder(testKeyspaces, "", 0); + holder.numberOfTables = testKeyspaces.stream().map(ks -> ks.tables.size()).mapToInt(Integer::intValue).sum(); StatsPrinter printer = TableStatsPrinter.from("", false); try (ByteArrayOutputStream byteStream = new ByteArrayOutputStream()) { diff --git a/test/unit/org/apache/cassandra/tools/nodetool/stats/TableStatsTestBase.java b/test/unit/org/apache/cassandra/tools/nodetool/stats/TableStatsTestBase.java index 8ef0ea3c94..ab49c6f256 100644 --- a/test/unit/org/apache/cassandra/tools/nodetool/stats/TableStatsTestBase.java +++ b/test/unit/org/apache/cassandra/tools/nodetool/stats/TableStatsTestBase.java @@ -71,6 +71,7 @@ public class TableStatsTestBase template.oldSSTableCount = 0L; template.spaceUsedLive = "0"; template.spaceUsedTotal = "0"; + template.maxSSTableSize = 0L; template.spaceUsedBySnapshotsTotal = "0"; template.percentRepaired = 1.0D; template.bytesRepaired = 0L; @@ -99,6 +100,8 @@ public class TableStatsTestBase template.averageTombstonesPerSliceLastFiveMinutes = Double.NaN; template.maximumTombstonesPerSliceLastFiveMinutes = 0L; template.droppedMutations = "0"; + template.twcs = null; + template.twcsDurationInMillis = 0L; return template; } @@ -337,6 +340,10 @@ public class TableStatsTestBase table2.memtableOffHeapMemoryUsed = "314159265"; table4.memtableOffHeapMemoryUsed = "141421356"; table6.memtableOffHeapMemoryUsed = "161803398"; + // twcs max duration: 2 > 4 > 1 = 3 = 6 = 5 + table2.twcsDurationInMillis = 2000L; + table4.twcsDurationInMillis = 1000L; + table5.twcsDurationInMillis = null; // create test keyspaces from templates testKeyspaces = new ArrayList<>(); StatsKeyspace keyspace1 = createStatsKeyspaceTemplate("keyspace1");