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

brandonwilliams pushed a commit to branch cassandra-4.0
in repository https://gitbox.apache.org/repos/asf/cassandra.git

commit fb395c6b8b005d44342aba3ebe1ad5dc4d62e586
Merge: b1f9b08578 c870641475
Author: Brandon Williams <brandonwilli...@apache.org>
AuthorDate: Fri Aug 18 05:10:27 2023 -0500

    Merge branch 'cassandra-3.11' into cassandra-4.0

 CHANGES.txt                                                       | 1 +
 .../org/apache/cassandra/tools/nodetool/stats/StatsTable.java     | 1 +
 .../apache/cassandra/tools/nodetool/stats/TableStatsHolder.java   | 2 ++
 .../apache/cassandra/tools/nodetool/stats/TableStatsPrinter.java  | 1 +
 .../cassandra/tools/nodetool/stats/TableStatsPrinterTest.java     | 8 ++++++++
 .../apache/cassandra/tools/nodetool/stats/TableStatsTestBase.java | 1 +
 6 files changed, 14 insertions(+)

diff --cc CHANGES.txt
index 43ee80e863,b8f489b183..90f8f99dfe
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@@ -1,23 -1,10 +1,24 @@@
 -3.11.17
 +4.0.12
 + * Fix NTS log message when an unrecognized strategy option is passed 
(CASSANDRA-18679)
 + * Fix BulkLoader ignoring cipher suites options (CASSANDRA-18582)
 + * Migrate Python optparse to argparse (CASSANDRA-17914)
 +Merged from 3.11:
 + * Moved jflex from runtime to build dependencies (CASSANDRA-18664)
  Merged from 3.0:
+  * Fix missing speculative retries in tablestats (CASSANDRA-18767)
 + * Fix Requires for Java for RPM package (CASSANDRA-18751)
 + * Fix CQLSH online help topic link (CASSANDRA-17534)
 + * Remove unused suppressions (CASSANDRA-18724)
  
  
 -3.11.16
 - * Moved jflex from runtime to build dependencies (CASSANDRA-18664)
 +4.0.11
 + * Revert CASSANDRA-16718 (CASSANDRA-18560)
 + * Upgrade snappy to 1.1.10.1 (CASSANDRA-18608)
 + * Fix assertion error when describing mv as table (CASSANDRA-18596)
 + * Track the amount of read data per row (CASSANDRA-18513)
 + * Fix Down nodes counter in nodetool describecluster (CASSANDRA-18512)
 + * Remove unnecessary shuffling of GossipDigests in 
Gossiper#makeRandomGossipDigest (CASSANDRA-18546)
 +Merged from 3.11:
   * Fix CAST function for float to decimal (CASSANDRA-18647)
   * Suppress CVE-2022-45688 (CASSANDRA-18643)
   * Remove unrepaired SSTables from garbage collection when 
only_purge_repaired_tombstones is true (CASSANDRA-14204)
diff --cc 
src/java/org/apache/cassandra/tools/nodetool/stats/TableStatsHolder.java
index 3cd2570185,35b2481c1a..7128dda767
--- a/src/java/org/apache/cassandra/tools/nodetool/stats/TableStatsHolder.java
+++ b/src/java/org/apache/cassandra/tools/nodetool/stats/TableStatsHolder.java
@@@ -97,80 -116,7 +97,81 @@@ public class TableStatsHolder implement
          return mpRet;
      }
  
 -    private void initializeKeyspaces(NodeProbe probe, boolean humanReadable, 
boolean ignore, List<String> tableNames)
 +    /**
 +     * @returns Map<String, Object> a nested HashMap of the sorted and 
filtered table names and the HashMaps of their statistics.
 +     */
 +    private Map<String, Object> convertSortedFilteredSubsetToMap()
 +    {
 +        HashMap<String, Object> mpRet = new HashMap<>();
 +        mpRet.put("total_number_of_tables", numberOfTables);
 +        List<StatsTable> sortedFilteredTables = getSortedFilteredTables();
 +        for (StatsTable table : sortedFilteredTables)
 +        {
 +            String tableDisplayName = table.keyspaceName + "." + 
table.tableName;
 +            Map<String, Object> mpTable = convertStatsTableToMap(table);
 +            mpRet.put(tableDisplayName, mpTable);
 +        }
 +        return mpRet;
 +    }
 +
 +    private Map<String, Object> convertStatsTableToMap(StatsTable table)
 +    {
 +        Map<String, Object> mpTable = new HashMap<>();
 +        mpTable.put("sstable_count", table.sstableCount);
 +        mpTable.put("old_sstable_count", table.oldSSTableCount);
 +        mpTable.put("sstables_in_each_level", table.sstablesInEachLevel);
 +        mpTable.put("space_used_live", table.spaceUsedLive);
 +        mpTable.put("space_used_total", table.spaceUsedTotal);
 +        mpTable.put("space_used_by_snapshots_total", 
table.spaceUsedBySnapshotsTotal);
 +        if (table.offHeapUsed)
 +            mpTable.put("off_heap_memory_used_total", 
table.offHeapMemoryUsedTotal);
 +        mpTable.put("sstable_compression_ratio", 
table.sstableCompressionRatio);
 +        mpTable.put("number_of_partitions_estimate", 
table.numberOfPartitionsEstimate);
 +        mpTable.put("memtable_cell_count", table.memtableCellCount);
 +        mpTable.put("memtable_data_size", table.memtableDataSize);
 +        if (table.memtableOffHeapUsed)
 +            mpTable.put("memtable_off_heap_memory_used", 
table.memtableOffHeapMemoryUsed);
 +        mpTable.put("memtable_switch_count", table.memtableSwitchCount);
++        mpTable.put("speculative_retries", table.speculativeRetries);
 +        mpTable.put("local_read_count", table.localReadCount);
 +        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("pending_flushes", table.pendingFlushes);
 +        mpTable.put("percent_repaired", table.percentRepaired);
 +        mpTable.put("bytes_repaired", table.bytesRepaired);
 +        mpTable.put("bytes_unrepaired", table.bytesUnrepaired);
 +        mpTable.put("bytes_pending_repair", table.bytesPendingRepair);
 +        mpTable.put("bloom_filter_false_positives", 
table.bloomFilterFalsePositives);
 +        mpTable.put("bloom_filter_false_ratio", String.format("%01.5f", 
table.bloomFilterFalseRatio));
 +        mpTable.put("bloom_filter_space_used", table.bloomFilterSpaceUsed);
 +        if (table.bloomFilterOffHeapUsed)
 +            mpTable.put("bloom_filter_off_heap_memory_used", 
table.bloomFilterOffHeapMemoryUsed);
 +        if (table.indexSummaryOffHeapUsed)
 +            mpTable.put("index_summary_off_heap_memory_used", 
table.indexSummaryOffHeapMemoryUsed);
 +        if (table.compressionMetadataOffHeapUsed)
 +            mpTable.put("compression_metadata_off_heap_memory_used",
 +                        table.compressionMetadataOffHeapMemoryUsed);
 +        mpTable.put("compacted_partition_minimum_bytes", 
table.compactedPartitionMinimumBytes);
 +        mpTable.put("compacted_partition_maximum_bytes", 
table.compactedPartitionMaximumBytes);
 +        mpTable.put("compacted_partition_mean_bytes", 
table.compactedPartitionMeanBytes);
 +        mpTable.put("average_live_cells_per_slice_last_five_minutes",
 +                    table.averageLiveCellsPerSliceLastFiveMinutes);
 +        mpTable.put("maximum_live_cells_per_slice_last_five_minutes",
 +                    table.maximumLiveCellsPerSliceLastFiveMinutes);
 +        mpTable.put("average_tombstones_per_slice_last_five_minutes",
 +                    table.averageTombstonesPerSliceLastFiveMinutes);
 +        mpTable.put("maximum_tombstones_per_slice_last_five_minutes",
 +                    table.maximumTombstonesPerSliceLastFiveMinutes);
 +        mpTable.put("dropped_mutations", table.droppedMutations);
 +        mpTable.put("droppable_tombstone_ratio",
 +                    String.format("%01.5f", table.droppableTombstoneRatio));
 +        if (locationCheck)
 +            mpTable.put("sstables_in_correct_location", 
table.isInCorrectLocation);
 +        return mpTable;
 +    }
 +
 +    private void initializeKeyspaces(NodeProbe probe, boolean ignore, 
List<String> tableNames)
      {
          OptionFilter filter = new OptionFilter(ignore, tableNames);
          ArrayListMultimap<String, ColumnFamilyStoreMBean> selectedTableMbeans 
= ArrayListMultimap.create();
diff --cc 
src/java/org/apache/cassandra/tools/nodetool/stats/TableStatsPrinter.java
index d8e4d4a2e7,dbca4bf8e6..33c065f9e6
--- a/src/java/org/apache/cassandra/tools/nodetool/stats/TableStatsPrinter.java
+++ b/src/java/org/apache/cassandra/tools/nodetool/stats/TableStatsPrinter.java
@@@ -72,89 -111,5 +72,90 @@@ public class TableStatsPrinter<T extend
                  out.println("----------------");
              }
          }
 +
 +        protected void printStatsTable(StatsTable table, String 
tableDisplayName, String indent, PrintStream out)
 +        {
 +            out.println(indent + "Table" + (table.isIndex ? " (index): " : ": 
") + tableDisplayName);
 +            out.println(indent + "SSTable count: " + table.sstableCount);
 +            out.println(indent + "Old SSTable count: " + 
table.oldSSTableCount);
 +            if (table.isLeveledSstable)
 +                out.println(indent + "SSTables in each level: [" + 
String.join(", ",
 +                                                                          
table.sstablesInEachLevel) + "]");
 +
 +            out.println(indent + "Space used (live): " + table.spaceUsedLive);
 +            out.println(indent + "Space used (total): " + 
table.spaceUsedTotal);
 +            out.println(indent + "Space used by snapshots (total): " + 
table.spaceUsedBySnapshotsTotal);
 +
 +            if (table.offHeapUsed)
 +                out.println(indent + "Off heap memory used (total): " + 
table.offHeapMemoryUsedTotal);
 +            out.println(indent + "SSTable Compression Ratio: " + 
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);
 +
 +            if (table.memtableOffHeapUsed)
 +                out.println(indent + "Memtable off heap memory used: " + 
table.memtableOffHeapMemoryUsed);
 +            out.println(indent + "Memtable switch count: " + 
table.memtableSwitchCount);
++            out.println(indent + "Speculative retries: " + 
table.speculativeRetries);
 +            out.println(indent + "Local read count: " + table.localReadCount);
 +            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.println(indent + "Pending flushes: " + table.pendingFlushes);
 +            out.println(indent + "Percent repaired: " + 
table.percentRepaired);
 +
 +            out.println(indent +"Bytes repaired: " + 
FBUtilities.prettyPrintMemory(table.bytesRepaired));
 +            out.println(indent +"Bytes unrepaired: " + 
FBUtilities.prettyPrintMemory(table.bytesUnrepaired));
 +            out.println(indent +"Bytes pending repair: " + 
FBUtilities.prettyPrintMemory(table.bytesPendingRepair));
 +
 +            out.println(indent + "Bloom filter false positives: " + 
table.bloomFilterFalsePositives);
 +            out.printf(indent + "Bloom filter false ratio: %01.5f%n", 
table.bloomFilterFalseRatio);
 +            out.println(indent + "Bloom filter space used: " + 
table.bloomFilterSpaceUsed);
 +
 +            if (table.bloomFilterOffHeapUsed)
 +                out.println(indent + "Bloom filter off heap memory used: " + 
table.bloomFilterOffHeapMemoryUsed);
 +            if (table.indexSummaryOffHeapUsed)
 +                out.println(indent + "Index summary off heap memory used: " + 
table.indexSummaryOffHeapMemoryUsed);
 +            if (table.compressionMetadataOffHeapUsed)
 +                out.println(indent + "Compression metadata off heap memory 
used: " + table.compressionMetadataOffHeapMemoryUsed);
 +
 +            out.println(indent + "Compacted partition minimum bytes: " + 
table.compactedPartitionMinimumBytes);
 +            out.println(indent + "Compacted partition maximum bytes: " + 
table.compactedPartitionMaximumBytes);
 +            out.println(indent + "Compacted partition mean bytes: " + 
table.compactedPartitionMeanBytes);
 +            out.println(indent + "Average live cells per slice (last five 
minutes): " + table.averageLiveCellsPerSliceLastFiveMinutes);
 +            out.println(indent + "Maximum live cells per slice (last five 
minutes): " + table.maximumLiveCellsPerSliceLastFiveMinutes);
 +            out.println(indent + "Average tombstones per slice (last five 
minutes): " + table.averageTombstonesPerSliceLastFiveMinutes);
 +            out.println(indent + "Maximum tombstones per slice (last five 
minutes): " + table.maximumTombstonesPerSliceLastFiveMinutes);
 +            out.println(indent + "Dropped Mutations: " + 
table.droppedMutations);
 +            out.printf(indent + "Droppable tombstone ratio: %01.5f%n", 
table.droppableTombstoneRatio);
 +            if (table.isInCorrectLocation != null)
 +                out.println(indent + "SSTables in correct location: " + 
table.isInCorrectLocation);
 +            out.println("");
 +        }
 +    }
 +
 +    /**
 +     * A StatsPrinter to print stats in a sorted, table-centric way.
 +     */
 +    private static class SortedDefaultPrinter extends DefaultPrinter
 +    {
 +        @Override
 +        public void print(TableStatsHolder data, PrintStream out)
 +        {
 +            List<StatsTable> tables = data.getSortedFilteredTables();
 +            String totalTablesSummary = String.format("Total number of 
tables: %d", data.numberOfTables);
 +            if (data.top > 0)
 +            {
 +                int k = (data.top <= data.numberOfTables) ? data.top : 
data.numberOfTables;
 +                totalTablesSummary += String.format(" (showing top %d by 
%s)", k, data.sortKey);
 +            }
 +            out.println(totalTablesSummary);
 +            out.println("----------------");
 +            for (StatsTable table : tables)
 +            {
 +                printStatsTable(table, table.keyspaceName + "." + 
table.tableName, "\t", out);
 +            }
 +            out.println("----------------");
 +        }
      }
  }
diff --cc 
test/unit/org/apache/cassandra/tools/nodetool/stats/TableStatsPrinterTest.java
index 025f812a39,0000000000..9e0206341f
mode 100644,000000..100644
--- 
a/test/unit/org/apache/cassandra/tools/nodetool/stats/TableStatsPrinterTest.java
+++ 
b/test/unit/org/apache/cassandra/tools/nodetool/stats/TableStatsPrinterTest.java
@@@ -1,529 -1,0 +1,537 @@@
 +/*
 + * 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.stats;
 +
 +import java.io.ByteArrayOutputStream;
 +import java.io.PrintStream;
 +import java.util.ArrayList;
 +import java.util.List;
 +import java.util.regex.Pattern;
 +
 +import org.junit.Test;
 +
 +import org.assertj.core.api.Assertions;
 +
 +import static org.junit.Assert.assertEquals;
 +
 +public class TableStatsPrinterTest extends TableStatsTestBase
 +{
 +    public static final String expectedDefaultTable1Output =
 +        "\tTable: %s\n" +
 +        "\tSSTable count: 60000\n" +
 +        "\tOld SSTable count: 0\n" +
 +        "\tSpace used (live): 0\n" +
 +        "\tSpace used (total): 9001\n" +
 +        "\tSpace used by snapshots (total): 1111\n" +
 +        "\tSSTable Compression Ratio: 0.68\n" +
 +        "\tNumber of partitions (estimate): 111111\n" +
 +        "\tMemtable cell count: 111\n" +
 +        "\tMemtable data size: 0\n" +
 +        "\tMemtable switch count: 1\n" +
++        "\tSpeculative retries: 0\n" +
 +        "\tLocal read count: 0\n" +
 +        "\tLocal read latency: 2.000 ms\n" +
 +        "\tLocal write count: 5\n" +
 +        "\tLocal write latency: 0.050 ms\n" +
 +        "\tPending flushes: 11111\n" +
 +        "\tPercent repaired: 100.0\n" +
 +        "\tBytes repaired: 0.000KiB\n" +
 +        "\tBytes unrepaired: 0.000KiB\n" +
 +        "\tBytes pending repair: 0.000KiB\n" +
 +        "\tBloom filter false positives: 30\n" +
 +        "\tBloom filter false ratio: 0.40000\n" +
 +        "\tBloom filter space used: 789\n" +
 +        "\tCompacted partition minimum bytes: 2\n" +
 +        "\tCompacted partition maximum bytes: 60\n" +
 +        "\tCompacted partition mean bytes: 6\n" +
 +        "\tAverage live cells per slice (last five minutes): 6.0\n" +
 +        "\tMaximum live cells per slice (last five minutes): 6\n" +
 +        "\tAverage tombstones per slice (last five minutes): 5.0\n" +
 +        "\tMaximum tombstones per slice (last five minutes): 1\n" +
 +        "\tDropped Mutations: 0\n" +
 +        "\tDroppable tombstone ratio: 0.00000\n" +
 +        "\n";
 +
 +    public static final String expectedDefaultTable2Output =
 +        "\tTable: %s\n" +
 +        "\tSSTable count: 3000\n" +
 +        "\tOld SSTable count: 0\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" +
 +        "\tNumber of partitions (estimate): 22222\n" +
 +        "\tMemtable cell count: 22\n" +
 +        "\tMemtable data size: 900\n" +
 +        "\tMemtable off heap memory used: 314159265\n" +
 +        "\tMemtable switch count: 22222\n" +
++        "\tSpeculative retries: 0\n" +
 +        "\tLocal read count: 1\n" +
 +        "\tLocal read latency: 3.000 ms\n" +
 +        "\tLocal write count: 4\n" +
 +        "\tLocal write latency: 0.000 ms\n" +
 +        "\tPending flushes: 222222\n" +
 +        "\tPercent repaired: 99.9\n" +
 +        "\tBytes repaired: 0.000KiB\n" +
 +        "\tBytes unrepaired: 0.000KiB\n" +
 +        "\tBytes pending repair: 0.000KiB\n" +
 +        "\tBloom filter false positives: 600\n" +
 +        "\tBloom filter false ratio: 0.01000\n" +
 +        "\tBloom filter space used: 161718\n" +
 +        "\tBloom filter off heap memory used: 98\n" +
 +        "\tIndex summary off heap memory used: 1\n" +
 +        "\tCompression metadata off heap memory used: 3\n" +
 +        "\tCompacted partition minimum bytes: 4\n" +
 +        "\tCompacted partition maximum bytes: 30\n" +
 +        "\tCompacted partition mean bytes: 4\n" +
 +        "\tAverage live cells per slice (last five minutes): 4.01\n" +
 +        "\tMaximum live cells per slice (last five minutes): 5\n" +
 +        "\tAverage tombstones per slice (last five minutes): 4.001\n" +
 +        "\tMaximum tombstones per slice (last five minutes): 2\n" +
 +        "\tDropped Mutations: 222\n" +
 +        "\tDroppable tombstone ratio: 0.22222\n" +
 +        "\n";
 +
 +    public static final String expectedDefaultTable3Output =
 +        "\tTable: %s\n" +
 +        "\tSSTable count: 50000\n" +
 +        "\tOld SSTable count: 0\n" +
 +        "\tSpace used (live): 0\n" +
 +        "\tSpace used (total): 512\n" +
 +        "\tSpace used by snapshots (total): 0\n" +
 +        "\tSSTable Compression Ratio: 0.32\n" +
 +        "\tNumber of partitions (estimate): 3333\n" +
 +        "\tMemtable cell count: 333333\n" +
 +        "\tMemtable data size: 1999\n" +
 +        "\tMemtable switch count: 3333\n" +
++        "\tSpeculative retries: 0\n" +
 +        "\tLocal read count: 2\n" +
 +        "\tLocal read latency: 4.000 ms\n" +
 +        "\tLocal write count: 3\n" +
 +        "\tLocal write latency: NaN ms\n" +
 +        "\tPending flushes: 333\n" +
 +        "\tPercent repaired: 99.8\n" +
 +        "\tBytes repaired: 0.000KiB\n" +
 +        "\tBytes unrepaired: 0.000KiB\n" +
 +        "\tBytes pending repair: 0.000KiB\n" +
 +        "\tBloom filter false positives: 20\n" +
 +        "\tBloom filter false ratio: 0.50000\n" +
 +        "\tBloom filter space used: 456\n" +
 +        "\tCompacted partition minimum bytes: 2\n" +
 +        "\tCompacted partition maximum bytes: 50\n" +
 +        "\tCompacted partition mean bytes: 5\n" +
 +        "\tAverage live cells per slice (last five minutes): 0.0\n" +
 +        "\tMaximum live cells per slice (last five minutes): 5\n" +
 +        "\tAverage tombstones per slice (last five minutes): NaN\n" +
 +        "\tMaximum tombstones per slice (last five minutes): 3\n" +
 +        "\tDropped Mutations: 33333\n" +
 +        "\tDroppable tombstone ratio: 0.33333\n" +
 +        "\n";
 +
 +    public static final String expectedDefaultTable4Output =
 +        "\tTable: %s\n" +
 +        "\tSSTable count: 2000\n" +
 +        "\tOld SSTable count: 0\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" +
 +        "\tNumber of partitions (estimate): 444\n" +
 +        "\tMemtable cell count: 4\n" +
 +        "\tMemtable data size: 3000\n" +
 +        "\tMemtable off heap memory used: 141421356\n" +
 +        "\tMemtable switch count: 444444\n" +
++        "\tSpeculative retries: 0\n" +
 +        "\tLocal read count: 3\n" +
 +        "\tLocal read latency: NaN ms\n" +
 +        "\tLocal write count: 2\n" +
 +        "\tLocal write latency: 2.000 ms\n" +
 +        "\tPending flushes: 4444\n" +
 +        "\tPercent repaired: 50.0\n" +
 +        "\tBytes repaired: 0.000KiB\n" +
 +        "\tBytes unrepaired: 0.000KiB\n" +
 +        "\tBytes pending repair: 0.000KiB\n" +
 +        "\tBloom filter false positives: 500\n" +
 +        "\tBloom filter false ratio: 0.02000\n" +
 +        "\tBloom filter space used: 131415\n" +
 +        "\tBloom filter off heap memory used: 299792458\n" +
 +        "\tIndex summary off heap memory used: 2\n" +
 +        "\tCompression metadata off heap memory used: 2\n" +
 +        "\tCompacted partition minimum bytes: 5\n" +
 +        "\tCompacted partition maximum bytes: 20\n" +
 +        "\tCompacted partition mean bytes: 4\n" +
 +        "\tAverage live cells per slice (last five minutes): NaN\n" +
 +        "\tMaximum live cells per slice (last five minutes): 3\n" +
 +        "\tAverage tombstones per slice (last five minutes): 0.0\n" +
 +        "\tMaximum tombstones per slice (last five minutes): 3\n" +
 +        "\tDropped Mutations: 4444\n" +
 +        "\tDroppable tombstone ratio: 0.44444\n" +
 +        "\n";
 +
 +    public static final String expectedDefaultTable5Output =
 +        "\tTable: %s\n" +
 +        "\tSSTable count: 40000\n" +
 +        "\tOld SSTable count: 0\n" +
 +        "\tSpace used (live): 55555\n" +
 +        "\tSpace used (total): 64\n" +
 +        "\tSpace used by snapshots (total): 55555\n" +
 +        "\tSSTable Compression Ratio: 0.99\n" +
 +        "\tNumber of partitions (estimate): 55\n" +
 +        "\tMemtable cell count: 55555\n" +
 +        "\tMemtable data size: 20000\n" +
 +        "\tMemtable switch count: 5\n" +
++        "\tSpeculative retries: 0\n" +
 +        "\tLocal read count: 4\n" +
 +        "\tLocal read latency: 0.000 ms\n" +
 +        "\tLocal write count: 1\n" +
 +        "\tLocal write latency: 1.000 ms\n" +
 +        "\tPending flushes: 5\n" +
 +        "\tPercent repaired: 93.0\n" +
 +        "\tBytes repaired: 0.000KiB\n" +
 +        "\tBytes unrepaired: 0.000KiB\n" +
 +        "\tBytes pending repair: 0.000KiB\n" +
 +        "\tBloom filter false positives: 10\n" +
 +        "\tBloom filter false ratio: 0.60000\n" +
 +        "\tBloom filter space used: 123\n" +
 +        "\tCompacted partition minimum bytes: 3\n" +
 +        "\tCompacted partition maximum bytes: 40\n" +
 +        "\tCompacted partition mean bytes: 4\n" +
 +        "\tAverage live cells per slice (last five minutes): 4.0\n" +
 +        "\tMaximum live cells per slice (last five minutes): 3\n" +
 +        "\tAverage tombstones per slice (last five minutes): 4.01\n" +
 +        "\tMaximum tombstones per slice (last five minutes): 5\n" +
 +        "\tDropped Mutations: 0\n" +
 +        "\tDroppable tombstone ratio: 0.55556\n" +
 +        "\n";
 +
 +    public static final String expectedDefaultTable6Output =
 +        "\tTable: %s\n" +
 +        "\tSSTable count: 1000\n" +
 +        "\tOld SSTable count: 0\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" +
 +        "\tNumber of partitions (estimate): 6\n" +
 +        "\tMemtable cell count: 6666\n" +
 +        "\tMemtable data size: 1000000\n" +
 +        "\tMemtable off heap memory used: 161803398\n" +
 +        "\tMemtable switch count: 6\n" +
++        "\tSpeculative retries: 0\n" +
 +        "\tLocal read count: 5\n" +
 +        "\tLocal read latency: 1.000 ms\n" +
 +        "\tLocal write count: 0\n" +
 +        "\tLocal write latency: 0.500 ms\n" +
 +        "\tPending flushes: 66\n" +
 +        "\tPercent repaired: 0.0\n" +
 +        "\tBytes repaired: 0.000KiB\n" +
 +        "\tBytes unrepaired: 0.000KiB\n" +
 +        "\tBytes pending repair: 0.000KiB\n" +
 +        "\tBloom filter false positives: 400\n" +
 +        "\tBloom filter false ratio: 0.03000\n" +
 +        "\tBloom filter space used: 101112\n" +
 +        "\tBloom filter off heap memory used: 667408\n" +
 +        "\tIndex summary off heap memory used: 3\n" +
 +        "\tCompression metadata off heap memory used: 1\n" +
 +        "\tCompacted partition minimum bytes: 6\n" +
 +        "\tCompacted partition maximum bytes: 20\n" +
 +        "\tCompacted partition mean bytes: 3\n" +
 +        "\tAverage live cells per slice (last five minutes): 5.0\n" +
 +        "\tMaximum live cells per slice (last five minutes): 2\n" +
 +        "\tAverage tombstones per slice (last five minutes): 6.0\n" +
 +        "\tMaximum tombstones per slice (last five minutes): 6\n" +
 +        "\tDropped Mutations: 666666\n" +
 +        "\tDroppable tombstone ratio: 0.66667\n" +
 +        "\n";
 +
 +    /**
 +     * Expected output of TableStatsPrinter DefaultPrinter for this dataset.
 +     * Total number of tables is zero because it's non-trivial to simulate 
that metric
 +     * without leaking test implementation into the TableStatsHolder 
implementation.
 +     */
 +    public static final String expectedDefaultPrinterOutput =
 +        "Total number of tables: 0\n" +
 +        "----------------\n" +
 +        "Keyspace : keyspace1\n" +
 +        "\tRead Count: 3\n" +
 +        "\tRead Latency: 0.0 ms\n" +
 +        "\tWrite Count: 12\n" +
 +        "\tWrite Latency: 0.0 ms\n" +
 +        "\tPending Flushes: 233666\n" +
 +        String.format(duplicateTabs(expectedDefaultTable1Output), "table1") +
 +        String.format(duplicateTabs(expectedDefaultTable2Output), "table2") +
 +        String.format(duplicateTabs(expectedDefaultTable3Output), "table3") +
 +        "----------------\n" +
 +        "Keyspace : keyspace2\n" +
 +        "\tRead Count: 7\n" +
 +        "\tRead Latency: 0.0 ms\n" +
 +        "\tWrite Count: 3\n" +
 +        "\tWrite Latency: 0.0 ms\n" +
 +        "\tPending Flushes: 4449\n" +
 +        String.format(duplicateTabs(expectedDefaultTable4Output), "table4") +
 +        String.format(duplicateTabs(expectedDefaultTable5Output), "table5") +
 +        "----------------\n" +
 +        "Keyspace : keyspace3\n" +
 +        "\tRead Count: 5\n" +
 +        "\tRead Latency: 0.0 ms\n" +
 +        "\tWrite Count: 0\n" +
 +        "\tWrite Latency: NaN ms\n" +
 +        "\tPending Flushes: 66\n" +
 +        String.format(duplicateTabs(expectedDefaultTable6Output), "table6") +
 +        "----------------\n";
 +
 +    /**
 +     * Expected output from SortedDefaultPrinter for data sorted by reads in 
this test.
 +     */
 +    private static final String expectedSortedDefaultPrinterOutput =
 +        "Total number of tables: 0\n" +
 +        "----------------\n" +
 +        String.format(expectedDefaultTable6Output, "keyspace3.table6") +
 +        String.format(expectedDefaultTable5Output, "keyspace2.table5") +
 +        String.format(expectedDefaultTable4Output, "keyspace2.table4") +
 +        String.format(expectedDefaultTable3Output, "keyspace1.table3") +
 +        String.format(expectedDefaultTable2Output, "keyspace1.table2") +
 +        String.format(expectedDefaultTable1Output, "keyspace1.table1") +
 +        "----------------\n";
 +
 +    /**
 +     * Expected output from SortedDefaultPrinter for data sorted by reads and 
limited to the top 4 tables.
 +     */
 +    private static final String expectedSortedDefaultPrinterTopOutput =
 +        "Total number of tables: 0 (showing top 0 by %s)\n" +
 +        "----------------\n" +
 +        String.format(expectedDefaultTable6Output, "keyspace3.table6") +
 +        String.format(expectedDefaultTable5Output, "keyspace2.table5") +
 +        String.format(expectedDefaultTable4Output, "keyspace2.table4") +
 +        String.format(expectedDefaultTable3Output, "keyspace1.table3") +
 +        "----------------\n";
 +
 +    /**
 +     * Expected output from SortedDefaultPrinter for data sorted by reads and 
limited to the top 10 tables.
 +     */
 +    private static final String expectedSortedDefaultPrinterLargeTopOutput =
 +        "Total number of tables: 0 (showing top 0 by %s)\n" +
 +        "----------------\n" +
 +        String.format(expectedDefaultTable6Output, "keyspace3.table6") +
 +        String.format(expectedDefaultTable5Output, "keyspace2.table5") +
 +        String.format(expectedDefaultTable4Output, "keyspace2.table4") +
 +        String.format(expectedDefaultTable3Output, "keyspace1.table3") +
 +        String.format(expectedDefaultTable2Output, "keyspace1.table2") +
 +        String.format(expectedDefaultTable1Output, "keyspace1.table1") +
 +        "----------------\n";
 +
 +    private static String duplicateTabs(String s)
 +    {
 +        return Pattern.compile("\t").matcher(s).replaceAll("\t\t");
 +    }
 +
 +    @Test
 +    public void testDefaultPrinter() throws Exception
 +    {
 +        StatsHolder holder = new TestTableStatsHolder(testKeyspaces, "", 0);
 +        StatsPrinter<StatsHolder> printer = TableStatsPrinter.from("", false);
 +        try (ByteArrayOutputStream byteStream = new ByteArrayOutputStream())
 +        {
 +            printer.print(holder, new PrintStream(byteStream));
 +            assertEquals("StatsTablePrinter.DefaultPrinter does not print 
test vector as expected", expectedDefaultPrinterOutput, byteStream.toString());
 +        }
 +    }
 +
 +    @Test
 +    public void testSortedDefaultPrinter() throws Exception
 +    {
 +        // test sorting
 +        StatsHolder holder = new TestTableStatsHolder(testKeyspaces, "reads", 
0);
 +        StatsPrinter<StatsHolder> printer = TableStatsPrinter.from("reads", 
true);
 +        try (ByteArrayOutputStream byteStream = new ByteArrayOutputStream())
 +        {
 +            printer.print(holder, new PrintStream(byteStream));
 +            assertEquals("StatsTablePrinter.SortedDefaultPrinter does not 
print sorted tables as expected",
 +                         expectedSortedDefaultPrinterOutput, 
byteStream.toString());
 +            byteStream.reset();
 +            // test sorting and filtering top k, where k < total number of 
tables
 +            String sortKey = "reads";
 +            int top = 4;
 +            holder = new TestTableStatsHolder(testKeyspaces, sortKey, top);
 +            printer = TableStatsPrinter.from(sortKey, true);
 +            printer.print(holder, new PrintStream(byteStream));
 +            assertEquals("StatsTablePrinter.SortedDefaultPrinter does not 
print top K sorted tables as expected",
 +                         String.format(expectedSortedDefaultPrinterTopOutput, 
sortKey), byteStream.toString());
 +            byteStream.reset();
 +            // test sorting and filtering top k, where k >= total number of 
tables
 +            sortKey = "reads";
 +            top = 10;
 +            holder = new TestTableStatsHolder(testKeyspaces, sortKey, top);
 +            printer = TableStatsPrinter.from(sortKey, true);
 +            printer.print(holder, new PrintStream(byteStream));
 +            assertEquals("StatsTablePrinter.SortedDefaultPrinter does not 
print top K sorted tables as expected for large values of K",
 +                         
String.format(expectedSortedDefaultPrinterLargeTopOutput, sortKey), 
byteStream.toString());
 +        }
 +    }
 +
 +    @Test
 +    public void testJsonPrinter() throws Exception
 +    {
 +        TestTableStatsHolder holder = new 
TestTableStatsHolder(testKeyspaces.subList(2, 3), "", 0); // kesypace3
 +        StatsPrinter<StatsHolder> printer = TableStatsPrinter.from("json", 
false);
 +        try (ByteArrayOutputStream byteStream = new ByteArrayOutputStream())
 +        {
 +            printer.print(holder, new PrintStream(byteStream));
 +            Assertions.assertThat(byteStream.toString())
 +                      .isEqualTo("{\n" +
 +                                 "  \"keyspace3\" : {\n" +
 +                                 "    \"write_latency_ms\" : \"NaN\",\n" +
 +                                 "    \"tables\" : {\n" +
 +                                 "      \"table6\" : {\n" +
 +                                 "        
\"average_tombstones_per_slice_last_five_minutes\" : 6.0,\n" +
 +                                 "        
\"bloom_filter_off_heap_memory_used\" : \"667408\",\n" +
 +                                 "        \"bytes_pending_repair\" : 0,\n" +
 +                                 "        \"memtable_switch_count\" : 6,\n" +
++                                 "        \"speculative_retries\" : 0,\n" +
 +                                 "        
\"maximum_tombstones_per_slice_last_five_minutes\" : 6,\n" +
 +                                 "        \"memtable_cell_count\" : 6666,\n" +
 +                                 "        \"memtable_data_size\" : 
\"1000000\",\n" +
 +                                 "        
\"average_live_cells_per_slice_last_five_minutes\" : 5.0,\n" +
 +                                 "        \"local_read_latency_ms\" : 
\"1.000\",\n" +
 +                                 "        \"sstable_count\" : 1000,\n" +
 +                                 "        \"local_write_latency_ms\" : 
\"0.500\",\n" +
 +                                 "        \"pending_flushes\" : 66,\n" +
 +                                 "        
\"compacted_partition_minimum_bytes\" : 6,\n" +
 +                                 "        \"local_read_count\" : 5,\n" +
 +                                 "        \"sstable_compression_ratio\" : 
0.68,\n" +
 +                                 "        \"dropped_mutations\" : 
\"666666\",\n" +
 +                                 "        \"bloom_filter_false_positives\" : 
400,\n" +
 +                                 "        \"off_heap_memory_used_total\" : 
\"162470810\",\n" +
 +                                 "        \"memtable_off_heap_memory_used\" : 
\"161803398\",\n" +
 +                                 "        
\"index_summary_off_heap_memory_used\" : \"3\",\n" +
 +                                 "        \"bloom_filter_space_used\" : 
\"101112\",\n" +
 +                                 "        \"sstables_in_each_level\" : [ 
],\n" +
 +                                 "        
\"compacted_partition_maximum_bytes\" : 20,\n" +
 +                                 "        \"space_used_total\" : \"0\",\n" +
 +                                 "        \"local_write_count\" : 0,\n" +
 +                                 "        \"droppable_tombstone_ratio\" : 
\"0.66667\",\n" +
 +                                 "        
\"compression_metadata_off_heap_memory_used\" : \"1\",\n" +
 +                                 "        \"number_of_partitions_estimate\" : 
6,\n" +
 +                                 "        \"bytes_repaired\" : 0,\n" +
 +                                 "        
\"maximum_live_cells_per_slice_last_five_minutes\" : 2,\n" +
 +                                 "        \"space_used_live\" : 
\"666666\",\n" +
 +                                 "        \"compacted_partition_mean_bytes\" 
: 3,\n" +
 +                                 "        \"bloom_filter_false_ratio\" : 
\"0.03000\",\n" +
 +                                 "        \"old_sstable_count\" : 0,\n" +
 +                                 "        \"bytes_unrepaired\" : 0,\n" +
 +                                 "        \"percent_repaired\" : 0.0,\n" +
 +                                 "        \"space_used_by_snapshots_total\" : 
\"0\"\n" +
 +                                 "      }\n" +
 +                                 "    },\n" +
 +                                 "    \"read_latency_ms\" : 0.0,\n" +
 +                                 "    \"pending_flushes\" : 66,\n" +
 +                                 "    \"write_count\" : 0,\n" +
 +                                 "    \"read_latency\" : 0.0,\n" +
 +                                 "    \"read_count\" : 5\n" +
 +                                 "  },\n" +
 +                                 "  \"total_number_of_tables\" : 0\n" +
 +                                 "}\n");
 +        }
 +    }
 +
 +    @Test
 +    public void testYamlPrinter() throws Exception
 +    {
 +        TestTableStatsHolder holder = new 
TestTableStatsHolder(testKeyspaces.subList(2, 3), "", 0); // kesypace3
 +        StatsPrinter<StatsHolder> printer = TableStatsPrinter.from("yaml", 
false);
 +        try (ByteArrayOutputStream byteStream = new ByteArrayOutputStream())
 +        {
 +            printer.print(holder, new PrintStream(byteStream));
 +            Assertions.assertThat(byteStream.toString())
 +                      .isEqualTo("keyspace3:\n" +
 +                                 "  write_latency_ms: .NaN\n" +
 +                                 "  tables:\n" +
 +                                 "    table6:\n" +
 +                                 "      
average_tombstones_per_slice_last_five_minutes: 6.0\n" +
 +                                 "      bloom_filter_off_heap_memory_used: 
'667408'\n" +
 +                                 "      bytes_pending_repair: 0\n" +
 +                                 "      memtable_switch_count: 6\n" +
++                                 "      speculative_retries: 0\n" +
 +                                 "      
maximum_tombstones_per_slice_last_five_minutes: 6\n" +
 +                                 "      memtable_cell_count: 6666\n" +
 +                                 "      memtable_data_size: '1000000'\n" +
 +                                 "      
average_live_cells_per_slice_last_five_minutes: 5.0\n" +
 +                                 "      local_read_latency_ms: '1.000'\n" +
 +                                 "      sstable_count: 1000\n" +
 +                                 "      local_write_latency_ms: '0.500'\n" +
 +                                 "      pending_flushes: 66\n" +
 +                                 "      compacted_partition_minimum_bytes: 
6\n" +
 +                                 "      local_read_count: 5\n" +
 +                                 "      sstable_compression_ratio: 0.68\n" +
 +                                 "      dropped_mutations: '666666'\n" +
 +                                 "      bloom_filter_false_positives: 400\n" +
 +                                 "      off_heap_memory_used_total: 
'162470810'\n" +
 +                                 "      memtable_off_heap_memory_used: 
'161803398'\n" +
 +                                 "      index_summary_off_heap_memory_used: 
'3'\n" +
 +                                 "      bloom_filter_space_used: '101112'\n" +
 +                                 "      sstables_in_each_level: []\n" +
 +                                 "      compacted_partition_maximum_bytes: 
20\n" +
 +                                 "      space_used_total: '0'\n" +
 +                                 "      local_write_count: 0\n" +
 +                                 "      droppable_tombstone_ratio: 
'0.66667'\n" +
 +                                 "      
compression_metadata_off_heap_memory_used: '1'\n" +
 +                                 "      number_of_partitions_estimate: 6\n" +
 +                                 "      bytes_repaired: 0\n" +
 +                                 "      
maximum_live_cells_per_slice_last_five_minutes: 2\n" +
 +                                 "      space_used_live: '666666'\n" +
 +                                 "      compacted_partition_mean_bytes: 3\n" +
 +                                 "      bloom_filter_false_ratio: 
'0.03000'\n" +
 +                                 "      old_sstable_count: 0\n" +
 +                                 "      bytes_unrepaired: 0\n" +
 +                                 "      percent_repaired: 0.0\n" +
 +                                 "      space_used_by_snapshots_total: '0'\n" 
+
 +                                 "  read_latency_ms: 0.0\n" +
 +                                 "  pending_flushes: 66\n" +
 +                                 "  write_count: 0\n" +
 +                                 "  read_latency: 0.0\n" +
 +                                 "  read_count: 5\n" +
 +                                 "total_number_of_tables: 0\n" +
 +                                 "\n");
 +        }
 +    }
 +
 +    /**
 +     * A test version of TableStatsHolder to hold a test vector instead of 
gathering stats from a live cluster.
 +     */
 +    private static class TestTableStatsHolder extends TableStatsHolder
 +    {
 +
 +        public TestTableStatsHolder(List<StatsKeyspace> testKeyspaces, String 
sortKey, int top)
 +        {
 +            super(null, false, false, new ArrayList<>(), sortKey, top, false);
 +            this.keyspaces.clear();
 +            this.keyspaces.addAll(testKeyspaces);
 +        }
 +
 +        @Override
 +        protected boolean isTestTableStatsHolder()
 +        {
 +            return true;
 +        }
 +    }
 +
 +}
diff --cc 
test/unit/org/apache/cassandra/tools/nodetool/stats/TableStatsTestBase.java
index 8ef0ea3c94,0000000000..3902bba228
mode 100644,000000..100644
--- 
a/test/unit/org/apache/cassandra/tools/nodetool/stats/TableStatsTestBase.java
+++ 
b/test/unit/org/apache/cassandra/tools/nodetool/stats/TableStatsTestBase.java
@@@ -1,435 -1,0 +1,436 @@@
 +/*
 + * 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.stats;
 +
 +import java.util.ArrayList;
 +import java.util.List;
 +
 +import org.junit.BeforeClass;
 +
 +/**
 + * Create a test vector for unit testing of TableStats features.
 + */
 +public class TableStatsTestBase
 +{
 +
 +    /**
 +     * A test vector of StatsKeyspace and StatsTable objects loaded with 
human readable stats.
 +     */
 +    protected static List<StatsKeyspace> humanReadableKeyspaces;
 +
 +    /**
 +     * A test vector of StatsTable objects loaded with human readable 
statistics.
 +     */
 +    protected static List<StatsTable> humanReadableTables;
 +
 +    /**
 +     * A test vector of StatsKeyspace and StatsTable objects.
 +     */
 +    protected static List<StatsKeyspace> testKeyspaces;
 +
 +    /**
 +     * A test vector of StatsTable objects.
 +     */
 +    protected static List<StatsTable> testTables;
 +
 +    /**
 +     * @return StatsKeyspace an instance of StatsKeyspace preset with values 
for use in a test vector
 +     */
 +    private static StatsKeyspace createStatsKeyspaceTemplate(String 
keyspaceName)
 +    {
 +        return new StatsKeyspace(null, keyspaceName);
 +    }
 +
 +    /**
 +     * @return StatsTable an instance of StatsTable preset with values for 
use in a test vector
 +     */
 +    private static StatsTable createStatsTableTemplate(String keyspaceName, 
String tableName)
 +    {
 +        StatsTable template = new StatsTable();
 +        template.fullName = keyspaceName + "." + tableName;
 +        template.keyspaceName = keyspaceName;
 +        template.tableName = tableName;
 +        template.isIndex = false;
 +        template.sstableCount = 0L;
 +        template.oldSSTableCount = 0L;
 +        template.spaceUsedLive = "0";
 +        template.spaceUsedTotal = "0";
 +        template.spaceUsedBySnapshotsTotal = "0";
 +        template.percentRepaired = 1.0D;
 +        template.bytesRepaired = 0L;
 +        template.bytesUnrepaired = 0L;
 +        template.bytesPendingRepair = 0L;
 +        template.sstableCompressionRatio = -1.0D;
 +        template.numberOfPartitionsEstimate = 0L;
 +        template.memtableCellCount = 0L;
 +        template.memtableDataSize = "0";
 +        template.memtableSwitchCount = 0L;
++        template.speculativeRetries = 0L;
 +        template.localReadCount =0L;
 +        template.localReadLatencyMs = Double.NaN;
 +        template.localWriteCount = 0L;
 +        template.localWriteLatencyMs = 0D;
 +        template.pendingFlushes = 0L;
 +        template.bloomFilterFalsePositives = 0L;
 +        template.bloomFilterFalseRatio = 0D;
 +        template.bloomFilterSpaceUsed = "0";
 +        template.indexSummaryOffHeapMemoryUsed = "0";
 +        template.compressionMetadataOffHeapMemoryUsed = "0";
 +        template.compactedPartitionMinimumBytes = 0L;
 +        template.compactedPartitionMaximumBytes = 0L;
 +        template.compactedPartitionMeanBytes = 0L;
 +        template.averageLiveCellsPerSliceLastFiveMinutes = Double.NaN;
 +        template.maximumLiveCellsPerSliceLastFiveMinutes = 0L;
 +        template.averageTombstonesPerSliceLastFiveMinutes = Double.NaN;
 +        template.maximumTombstonesPerSliceLastFiveMinutes = 0L;
 +        template.droppedMutations = "0";
 +        return template;
 +    }
 +
 +    @BeforeClass
 +    public static void createTestVector()
 +    {
 +        // create test tables from templates
 +        StatsTable table1 = createStatsTableTemplate("keyspace1", "table1");
 +        StatsTable table2 = createStatsTableTemplate("keyspace1", "table2");
 +        StatsTable table3 = createStatsTableTemplate("keyspace1", "table3");
 +        StatsTable table4 = createStatsTableTemplate("keyspace2", "table4");
 +        StatsTable table5 = createStatsTableTemplate("keyspace2", "table5");
 +        StatsTable table6 = createStatsTableTemplate("keyspace3", "table6");
 +        // average live cells: 1 > 6 > 2 > 5 > 3 > 4
 +        table1.averageLiveCellsPerSliceLastFiveMinutes = 6D;
 +        table2.averageLiveCellsPerSliceLastFiveMinutes = 4.01D;
 +        table3.averageLiveCellsPerSliceLastFiveMinutes = 0D;
 +        table4.averageLiveCellsPerSliceLastFiveMinutes = Double.NaN;
 +        table5.averageLiveCellsPerSliceLastFiveMinutes = 4D;
 +        table6.averageLiveCellsPerSliceLastFiveMinutes = 5D;
 +        // average tombstones: 6 > 1 > 5 > 2 > 3 > 4
 +        table1.averageTombstonesPerSliceLastFiveMinutes = 5D;
 +        table2.averageTombstonesPerSliceLastFiveMinutes = 4.001D;
 +        table3.averageTombstonesPerSliceLastFiveMinutes = Double.NaN; 
 +        table4.averageTombstonesPerSliceLastFiveMinutes = 0D;
 +        table5.averageTombstonesPerSliceLastFiveMinutes = 4.01D;
 +        table6.averageTombstonesPerSliceLastFiveMinutes = 6D;
 +        // bloom filter false positives: 2 > 4 > 6 > 1 > 3 > 5
 +        table1.bloomFilterFalsePositives = 30L;
 +        table2.bloomFilterFalsePositives = 600L;
 +        table3.bloomFilterFalsePositives = 20L;
 +        table4.bloomFilterFalsePositives = 500L;
 +        table5.bloomFilterFalsePositives = 10L;
 +        table6.bloomFilterFalsePositives = 400L;
 +        // bloom filter false positive ratio: 5 > 3 > 1 > 6 > 4 > 2
 +        table1.bloomFilterFalseRatio = 0.40D;
 +        table2.bloomFilterFalseRatio = 0.01D;
 +        table3.bloomFilterFalseRatio = 0.50D;
 +        table4.bloomFilterFalseRatio = 0.02D;
 +        table5.bloomFilterFalseRatio = 0.60D;
 +        table6.bloomFilterFalseRatio = 0.03D;
 +        // bloom filter space used: 2 > 4 > 6 > 1 > 3 > 5
 +        table1.bloomFilterSpaceUsed = "789";
 +        table2.bloomFilterSpaceUsed = "161718";
 +        table3.bloomFilterSpaceUsed = "456";
 +        table4.bloomFilterSpaceUsed = "131415";
 +        table5.bloomFilterSpaceUsed = "123";
 +        table6.bloomFilterSpaceUsed = "101112";
 +        // compacted partition maximum bytes: 1 > 3 > 5 > 2 > 4 = 6 
 +        table1.compactedPartitionMaximumBytes = 60L;
 +        table2.compactedPartitionMaximumBytes = 30L;
 +        table3.compactedPartitionMaximumBytes = 50L;
 +        table4.compactedPartitionMaximumBytes = 20L;
 +        table5.compactedPartitionMaximumBytes = 40L;
 +        table6.compactedPartitionMaximumBytes = 20L;
 +        // compacted partition mean bytes: 1 > 3 > 2 = 4 = 5 > 6
 +        table1.compactedPartitionMeanBytes = 6L;
 +        table2.compactedPartitionMeanBytes = 4L;
 +        table3.compactedPartitionMeanBytes = 5L;
 +        table4.compactedPartitionMeanBytes = 4L;
 +        table5.compactedPartitionMeanBytes = 4L;
 +        table6.compactedPartitionMeanBytes = 3L;
 +        // compacted partition minimum bytes: 6 > 4 > 2 > 5 > 1 = 3
 +        table1.compactedPartitionMinimumBytes = 2L;
 +        table2.compactedPartitionMinimumBytes = 4L;
 +        table3.compactedPartitionMinimumBytes = 2L;
 +        table4.compactedPartitionMinimumBytes = 5L;
 +        table5.compactedPartitionMinimumBytes = 3L;
 +        table6.compactedPartitionMinimumBytes = 6L;
 +        // dropped mutations: 6 > 3 > 4 > 2 > 1 = 5
 +        table1.droppedMutations = "0";
 +        table2.droppedMutations = "222";
 +        table3.droppedMutations = "33333";
 +        table4.droppedMutations = "4444";
 +        table5.droppedMutations = "0";
 +        table6.droppedMutations = "666666";
 +        // local reads: 6 > 5 > 4 > 3 > 2 > 1
 +        table1.localReadCount = 0L;
 +        table2.localReadCount = 1L;
 +        table3.localReadCount = 2L;
 +        table4.localReadCount = 3L;
 +        table5.localReadCount = 4L;
 +        table6.localReadCount = 5L;
 +        // local read latency: 3 > 2 > 1 > 6 > 4 > 5
 +        table1.localReadLatencyMs = 2D;
 +        table2.localReadLatencyMs = 3D;
 +        table3.localReadLatencyMs = 4D;
 +        table4.localReadLatencyMs = Double.NaN;
 +        table5.localReadLatencyMs = 0D;
 +        table6.localReadLatencyMs = 1D;
 +        // local writes: 1 > 2 > 3 > 4 > 5 > 6
 +        table1.localWriteCount = 5L;
 +        table2.localWriteCount = 4L;
 +        table3.localWriteCount = 3L;
 +        table4.localWriteCount = 2L;
 +        table5.localWriteCount = 1L;
 +        table6.localWriteCount = 0L;
 +        // local write latency: 4 > 5 > 6 > 1 > 2 > 3
 +        table1.localWriteLatencyMs = 0.05D;
 +        table2.localWriteLatencyMs = 0D;
 +        table3.localWriteLatencyMs = Double.NaN;
 +        table4.localWriteLatencyMs = 2D;
 +        table5.localWriteLatencyMs = 1D;
 +        table6.localWriteLatencyMs = 0.5D;
 +        // maximum live cells last five minutes: 1 > 2 = 3 > 4 = 5 > 6
 +        table1.maximumLiveCellsPerSliceLastFiveMinutes = 6L;
 +        table2.maximumLiveCellsPerSliceLastFiveMinutes = 5L;
 +        table3.maximumLiveCellsPerSliceLastFiveMinutes = 5L;
 +        table4.maximumLiveCellsPerSliceLastFiveMinutes = 3L;
 +        table5.maximumLiveCellsPerSliceLastFiveMinutes = 3L;
 +        table6.maximumLiveCellsPerSliceLastFiveMinutes = 2L;
 +        // maximum tombstones last five minutes: 6 > 5 > 3 = 4 > 2 > 1
 +        table1.maximumTombstonesPerSliceLastFiveMinutes = 1L;
 +        table2.maximumTombstonesPerSliceLastFiveMinutes = 2L;
 +        table3.maximumTombstonesPerSliceLastFiveMinutes = 3L;
 +        table4.maximumTombstonesPerSliceLastFiveMinutes = 3L;
 +        table5.maximumTombstonesPerSliceLastFiveMinutes = 5L;
 +        table6.maximumTombstonesPerSliceLastFiveMinutes = 6L;
 +        // memtable cell count: 3 > 5 > 6 > 1 > 2 > 4
 +        table1.memtableCellCount = 111L;
 +        table2.memtableCellCount = 22L;
 +        table3.memtableCellCount = 333333L;
 +        table4.memtableCellCount = 4L;
 +        table5.memtableCellCount = 55555L;
 +        table6.memtableCellCount = 6666L;
 +        // memtable data size: 6 > 5 > 4 > 3 > 2 > 1
 +        table1.memtableDataSize = "0";
 +        table2.memtableDataSize = "900";
 +        table3.memtableDataSize = "1999";
 +        table4.memtableDataSize = "3000";
 +        table5.memtableDataSize = "20000";
 +        table6.memtableDataSize = "1000000";
 +        // memtable switch count: 4 > 2 > 3 > 6 > 5 > 1
 +        table1.memtableSwitchCount = 1L;
 +        table2.memtableSwitchCount = 22222L;
 +        table3.memtableSwitchCount = 3333L;
 +        table4.memtableSwitchCount = 444444L;
 +        table5.memtableSwitchCount = 5L;
 +        table6.memtableSwitchCount = 6L;
 +        // number of partitions estimate: 1 > 2 > 3 > 4 > 5 > 6
 +        table1.numberOfPartitionsEstimate = 111111L;
 +        table2.numberOfPartitionsEstimate = 22222L;
 +        table3.numberOfPartitionsEstimate = 3333L;
 +        table4.numberOfPartitionsEstimate = 444L;
 +        table5.numberOfPartitionsEstimate = 55L;
 +        table6.numberOfPartitionsEstimate = 6L;
 +        // pending flushes: 2 > 1 > 4 > 3 > 6 > 5
 +        table1.pendingFlushes = 11111L;
 +        table2.pendingFlushes = 222222L;
 +        table3.pendingFlushes = 333L;
 +        table4.pendingFlushes = 4444L;
 +        table5.pendingFlushes = 5L;
 +        table6.pendingFlushes = 66L;
 +        // percent repaired: 1 > 2 > 3 > 5 > 4 > 6
 +        table1.percentRepaired = 100.0D;
 +        table2.percentRepaired = 99.9D;
 +        table3.percentRepaired = 99.8D;
 +        table4.percentRepaired = 50.0D;
 +        table5.percentRepaired = 93.0D;
 +        table6.percentRepaired = 0.0D;
 +        // space used by snapshots: 5 > 1 > 2 > 4 > 3 = 6
 +        table1.spaceUsedBySnapshotsTotal = "1111";
 +        table2.spaceUsedBySnapshotsTotal = "222";
 +        table3.spaceUsedBySnapshotsTotal = "0";
 +        table4.spaceUsedBySnapshotsTotal = "44";
 +        table5.spaceUsedBySnapshotsTotal = "55555";
 +        table6.spaceUsedBySnapshotsTotal = "0";
 +        // space used live: 6 > 5 > 4 > 2 > 1 = 3
 +        table1.spaceUsedLive = "0";
 +        table2.spaceUsedLive = "22";
 +        table3.spaceUsedLive = "0";
 +        table4.spaceUsedLive = "4444";
 +        table5.spaceUsedLive = "55555";
 +        table6.spaceUsedLive = "666666";
 +        // space used total: 1 > 2 > 3 > 4 > 5 > 6
 +        table1.spaceUsedTotal = "9001";
 +        table2.spaceUsedTotal = "1024";
 +        table3.spaceUsedTotal = "512";
 +        table4.spaceUsedTotal = "256";
 +        table5.spaceUsedTotal = "64";
 +        table6.spaceUsedTotal = "0";
 +        // sstable compression ratio: 5 > 4 > 1 = 2 = 6 > 3
 +        table1.sstableCompressionRatio = 0.68D;
 +        table2.sstableCompressionRatio = 0.68D;
 +        table3.sstableCompressionRatio = 0.32D;
 +        table4.sstableCompressionRatio = 0.95D;
 +        table5.sstableCompressionRatio = 0.99D;
 +        table6.sstableCompressionRatio = 0.68D;
 +        // sstable count: 1 > 3 > 5 > 2 > 4 > 6
 +        table1.sstableCount = 60000;
 +        table2.sstableCount = 3000;
 +        table3.sstableCount = 50000;
 +        table4.sstableCount = 2000;
 +        table5.sstableCount = 40000;
 +        table6.sstableCount = 1000;
 +        // Droppable Tombstone ratio
 +        table1.droppableTombstoneRatio = 0;
 +        table2.droppableTombstoneRatio = 0.222222;
 +        table3.droppableTombstoneRatio = 0.333333;
 +        table4.droppableTombstoneRatio = 0.444444;
 +        table5.droppableTombstoneRatio = 0.555555;
 +        table6.droppableTombstoneRatio = 0.666666;
 +        // set even numbered tables to have some offheap usage
 +        table2.offHeapUsed = true;
 +        table4.offHeapUsed = true;
 +        table6.offHeapUsed = true;
 +        table2.memtableOffHeapUsed = true;
 +        table4.memtableOffHeapUsed = true;
 +        table6.memtableOffHeapUsed = true;
 +        table2.bloomFilterOffHeapUsed = true;
 +        table4.bloomFilterOffHeapUsed = true;
 +        table6.bloomFilterOffHeapUsed = true;
 +        table2.compressionMetadataOffHeapUsed = true;
 +        table4.compressionMetadataOffHeapUsed = true;
 +        table6.compressionMetadataOffHeapUsed = true;
 +        table2.indexSummaryOffHeapUsed = true;
 +        table4.indexSummaryOffHeapUsed = true;
 +        table6.indexSummaryOffHeapUsed = true;
 +        // offheap memory total: 4 > 2 > 6 > 1 = 3 = 5
 +        table2.offHeapMemoryUsedTotal = "314159367";
 +        table4.offHeapMemoryUsedTotal = "441213818";
 +        table6.offHeapMemoryUsedTotal = "162470810";
 +        // bloom filter offheap: 4 > 6 > 2 > 1 = 3 = 5
 +        table2.bloomFilterOffHeapMemoryUsed = "98";
 +        table4.bloomFilterOffHeapMemoryUsed = "299792458";
 +        table6.bloomFilterOffHeapMemoryUsed = "667408";
 +        // compression metadata offheap: 2 > 4 > 6 > 1 = 3 = 5
 +        table2.compressionMetadataOffHeapMemoryUsed = "3";
 +        table4.compressionMetadataOffHeapMemoryUsed = "2";
 +        table6.compressionMetadataOffHeapMemoryUsed = "1";
 +        // index summary offheap: 6 > 4 > 2 > 1 = 3 = 5
 +        table2.indexSummaryOffHeapMemoryUsed = "1";
 +        table4.indexSummaryOffHeapMemoryUsed = "2";
 +        table6.indexSummaryOffHeapMemoryUsed = "3";
 +        // memtable offheap: 2 > 6 > 4 > 1 = 3 = 5
 +        table2.memtableOffHeapMemoryUsed = "314159265";
 +        table4.memtableOffHeapMemoryUsed = "141421356";
 +        table6.memtableOffHeapMemoryUsed = "161803398";
 +        // create test keyspaces from templates
 +        testKeyspaces = new ArrayList<>();
 +        StatsKeyspace keyspace1 = createStatsKeyspaceTemplate("keyspace1");
 +        StatsKeyspace keyspace2 = createStatsKeyspaceTemplate("keyspace2");
 +        StatsKeyspace keyspace3 = createStatsKeyspaceTemplate("keyspace3");
 +        // populate StatsKeyspace tables lists
 +        keyspace1.tables.add(table1);
 +        keyspace1.tables.add(table2);
 +        keyspace1.tables.add(table3);
 +        keyspace2.tables.add(table4);
 +        keyspace2.tables.add(table5);
 +        keyspace3.tables.add(table6);
 +        // populate testKeyspaces test vector
 +        testKeyspaces.add(keyspace1);
 +        testKeyspaces.add(keyspace2);
 +        testKeyspaces.add(keyspace3);
 +        // compute keyspace statistics from relevant table metrics
 +        for (int i = 0; i < testKeyspaces.size(); i++)
 +        {
 +            StatsKeyspace ks = testKeyspaces.get(i);
 +            for (StatsTable st : ks.tables)
 +            {
 +                ks.readCount += st.localReadCount;
 +                ks.writeCount += st.localWriteCount;
 +                ks.pendingFlushes += (long) st.pendingFlushes;
 +            }
 +            testKeyspaces.set(i, ks);
 +        }
 +        // populate testTables test vector
 +        testTables = new ArrayList<>();
 +        testTables.add(table1);
 +        testTables.add(table2);
 +        testTables.add(table3);
 +        testTables.add(table4);
 +        testTables.add(table5);
 +        testTables.add(table6);
 +        //
 +        // create test vector for human readable case
 +        StatsTable humanReadableTable1 = 
createStatsTableTemplate("keyspace1", "table1");
 +        StatsTable humanReadableTable2 = 
createStatsTableTemplate("keyspace1", "table2");
 +        StatsTable humanReadableTable3 = 
createStatsTableTemplate("keyspace1", "table3");
 +        StatsTable humanReadableTable4 = 
createStatsTableTemplate("keyspace2", "table4");
 +        StatsTable humanReadableTable5 = 
createStatsTableTemplate("keyspace2", "table5");
 +        StatsTable humanReadableTable6 = 
createStatsTableTemplate("keyspace3", "table6");
 +        // human readable space used total: 6 > 5 > 4 > 3 > 2 > 1
 +        humanReadableTable1.spaceUsedTotal = "999 bytes";
 +        humanReadableTable2.spaceUsedTotal = "5 KiB";
 +        humanReadableTable3.spaceUsedTotal = "40 KiB";
 +        humanReadableTable4.spaceUsedTotal = "3 MiB";
 +        humanReadableTable5.spaceUsedTotal = "2 GiB";
 +        humanReadableTable6.spaceUsedTotal = "1 TiB";
 +        // human readable memtable data size: 1 > 3 > 5 > 2 > 4 > 6
 +        humanReadableTable1.memtableDataSize = "1.21 TiB";
 +        humanReadableTable2.memtableDataSize = "42 KiB";
 +        humanReadableTable3.memtableDataSize = "2.71 GiB";
 +        humanReadableTable4.memtableDataSize = "999 bytes";
 +        humanReadableTable5.memtableDataSize = "3.14 MiB";
 +        humanReadableTable6.memtableDataSize = "0 bytes";
 +        // create human readable keyspaces from template
 +        humanReadableKeyspaces = new ArrayList<>();
 +        StatsKeyspace humanReadableKeyspace1 = 
createStatsKeyspaceTemplate("keyspace1");
 +        StatsKeyspace humanReadableKeyspace2 = 
createStatsKeyspaceTemplate("keyspace2");
 +        StatsKeyspace humanReadableKeyspace3 = 
createStatsKeyspaceTemplate("keyspace3");
 +        // populate human readable StatsKeyspace tables lists
 +        humanReadableKeyspace1.tables.add(humanReadableTable1);
 +        humanReadableKeyspace1.tables.add(humanReadableTable2);
 +        humanReadableKeyspace1.tables.add(humanReadableTable3);
 +        humanReadableKeyspace2.tables.add(humanReadableTable4);
 +        humanReadableKeyspace2.tables.add(humanReadableTable5);
 +        humanReadableKeyspace3.tables.add(humanReadableTable6);
 +        // populate human readable keyspaces test vector
 +        humanReadableKeyspaces.add(humanReadableKeyspace1);
 +        humanReadableKeyspaces.add(humanReadableKeyspace2);
 +        humanReadableKeyspaces.add(humanReadableKeyspace3);
 +        // compute human readable keyspace statistics from relevant table 
metrics
 +        for (int i = 0; i < humanReadableKeyspaces.size(); i++)
 +        {
 +            StatsKeyspace ks = humanReadableKeyspaces.get(i);
 +            for (StatsTable st : ks.tables)
 +            {
 +                ks.readCount += st.localReadCount;
 +                ks.writeCount += st.localWriteCount;
 +                ks.pendingFlushes += (long) st.pendingFlushes;
 +            }
 +            humanReadableKeyspaces.set(i, ks);
 +        }
 +        // populate human readable tables test vector
 +        humanReadableTables = new ArrayList<>();
 +        humanReadableTables.add(humanReadableTable1);
 +        humanReadableTables.add(humanReadableTable2);
 +        humanReadableTables.add(humanReadableTable3);
 +        humanReadableTables.add(humanReadableTable4);
 +        humanReadableTables.add(humanReadableTable5);
 +        humanReadableTables.add(humanReadableTable6);
 +    }
 +}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@cassandra.apache.org
For additional commands, e-mail: commits-h...@cassandra.apache.org

Reply via email to