blob: 247fa8a1e6bcd12e3712a26f72ec0f3f5c7edb11 [file] [log] [blame]
/*
* 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;
import java.io.IOException;
import org.junit.After;
import org.junit.BeforeClass;
import org.junit.Test;
import org.apache.cassandra.db.Directories;
import org.apache.cassandra.io.util.File;
import org.apache.cassandra.io.util.FileUtils;
import org.apache.cassandra.tools.ToolRunner.ToolResult;
import org.apache.cassandra.utils.FBUtilities;
import org.assertj.core.api.AbstractStringAssert;
import org.assertj.core.api.Assertions;
import static java.lang.String.format;
/**
* Tests for {@link SSTablePartitions}.
*/
public class SSTablePartitionsTest extends OfflineToolUtils
{
private static final String SSTABLE_1 = sstable("legacy_ma_simple");
private static final String SSTABLE_2 = sstable("legacy_ma_clust");
private static final String HEADER_1 = "\nProcessing #1 (big-ma) (0.169 KiB uncompressed, 0.086 KiB on disk)\n";
private static final String HEADER_2 = "\nProcessing #1 (big-ma) (328.145 KiB uncompressed, 5.096 KiB on disk)\n";
private static final String BACKUPS_HEADER_1 = "\nProcessing Backup:backups #1 (big-ma) (0.169 KiB uncompressed, 0.086 KiB on disk)\n";
private static final String BACKUPS_HEADER_2 = "\nProcessing Backup:backups #1 (big-ma) (328.145 KiB uncompressed, 5.096 KiB on disk)\n";
private static final String SNAPSHOTS_HEADER_1 = "\nProcessing Snapshot:snapshot-1 #1 (big-ma) (0.169 KiB uncompressed, 0.086 KiB on disk)\n";
private static final String SNAPSHOTS_HEADER_2 = "\nProcessing Snapshot:snapshot-1 #1 (big-ma) (328.145 KiB uncompressed, 5.096 KiB on disk)\n";
private static final String SUMMARY_1 = " Partition size Row count Cell count Tombstone count\n" +
" ~p50 0.034 KiB 1 1 0\n" +
" ~p75 0.034 KiB 1 1 0\n" +
" ~p90 0.034 KiB 1 1 0\n" +
" ~p95 0.034 KiB 1 1 0\n" +
" ~p99 0.034 KiB 1 1 0\n" +
" ~p999 0.034 KiB 1 1 0\n" +
" min 0.032 KiB 1 1 0\n" +
" max 0.034 KiB 1 1 0\n" +
" count 5\n";
private static final String SUMMARY_2 = " Partition size Row count Cell count Tombstone count\n" +
" ~p50 71.735 KiB 50 50 0\n" +
" ~p75 71.735 KiB 50 50 0\n" +
" ~p90 71.735 KiB 50 50 0\n" +
" ~p95 71.735 KiB 50 50 0\n" +
" ~p99 71.735 KiB 50 50 0\n" +
" ~p999 71.735 KiB 50 50 0\n" +
" min 65.625 KiB 50 50 0\n" +
" max 65.630 KiB 50 50 0\n" +
" count 5\n";
@BeforeClass
public static void prepareDirectories()
{
createBackupsAndSnapshots(SSTABLE_1);
createBackupsAndSnapshots(SSTABLE_2);
}
private static void createBackupsAndSnapshots(String sstable)
{
File parentDir = new File(sstable).parent();
File backupsDir = new File(parentDir, Directories.BACKUPS_SUBDIR);
backupsDir.tryCreateDirectory();
File snapshotsDir = new File(parentDir, Directories.SNAPSHOT_SUBDIR);
snapshotsDir.tryCreateDirectory();
File snapshotDir = new File(snapshotsDir, "snapshot-1");
snapshotDir.tryCreateDirectory();
for (File f : parentDir.tryList(File::isFile))
{
FileUtils.copyWithOutConfirm(f, new File(backupsDir, f.name()));
FileUtils.copyWithOutConfirm(f, new File(snapshotDir, f.name()));
}
}
/**
* Runs post-test assertions about loaded classed and started threads.
*/
@After
public void assertPostTestEnv()
{
assertNoUnexpectedThreadsStarted(OPTIONAL_THREADS_WITH_SCHEMA, false);
assertCLSMNotLoaded();
assertSystemKSNotLoaded();
assertKeyspaceNotLoaded();
assertServerNotLoaded();
}
/**
* Verify that the tool prints help when no arguments are provided.
*/
@Test
public void testNoArgsPrintsHelp()
{
ToolResult tool = ToolRunner.invokeClass(SSTablePartitions.class);
Assertions.assertThat(tool.getExitCode()).isOne();
Assertions.assertThat(tool.getCleanedStderr()).contains("You must supply at least one sstable or directory");
Assertions.assertThat(tool.getStdout()).contains("usage");
}
/**
* Verify that the tool prints the right help contents.
* If you added, modified options or help, please update docs if necessary.
*/
@Test
public void testMaybeChangeDocs()
{
ToolResult tool = ToolRunner.invokeClass(SSTablePartitions.class);
Assertions.assertThat(tool.getStdout())
.isEqualTo("usage: sstablepartitions <options> <sstable files or directories>\n" +
" \n" +
"Print partition statistics of one or more sstables.\n" +
" -b,--backups include backups present in data\n" +
" directories (recursive scans)\n" +
" -c,--min-cells <arg> partition cell count threshold\n" +
" -k,--key <arg> Partition keys to include\n" +
" -m,--csv CSV output (machine readable)\n" +
" -o,--min-tombstones <arg> partition tombstone count threshold\n" +
" -r,--recursive scan for sstables recursively\n" +
" -s,--snapshots include snapshots present in data\n" +
" directories (recursive scans)\n" +
" -t,--min-size <arg> partition size threshold, expressed as\n" +
" either the number of bytes or a size with unit of the form 10KiB, 20MiB,\n" +
" 30GiB, etc.\n" +
" -u,--current-timestamp <arg> timestamp (seconds since epoch, unit time)\n" +
" for TTL expired calculation\n" +
" -w,--min-rows <arg> partition row count threshold\n" +
" -x,--exclude-key <arg> Excluded partition key(s) from partition\n" +
" detailed row/cell/tombstone information (irrelevant, if --partitions-only\n" +
" is given)\n" +
" -y,--partitions-only Do not process per-partition detailed\n" +
" row/cell/tombstone information, only brief information\n");
}
/**
* Verify that the tool can select single sstable file.
*/
@Test
public void testSingleSSTable()
{
assertThatToolSucceds(SSTABLE_1).isEqualTo(HEADER_1 + SUMMARY_1);
assertThatToolSucceds(SSTABLE_2).isEqualTo(HEADER_2 + SUMMARY_2);
}
/**
* Verify that the tool can select multiple sstable files.
*/
@Test
public void testMultipleSSTables()
{
assertThatToolSucceds(SSTABLE_1, SSTABLE_2)
.isEqualTo(HEADER_2 + SUMMARY_2 + HEADER_1 + SUMMARY_1);
}
/**
* Verify that the tool can select all the sstable files in a directory.
*/
@Test
public void testDirectory()
{
assertThatToolSucceds(new File(SSTABLE_1).parentPath())
.isEqualTo(HEADER_1 + SUMMARY_1);
assertThatToolSucceds("-r", new File(SSTABLE_1).parent().parentPath())
.contains(HEADER_1 + SUMMARY_1)
.contains(HEADER_2 + SUMMARY_2);
assertThatToolSucceds("--recursive", new File(SSTABLE_2).parent().parentPath())
.contains(HEADER_1 + SUMMARY_1)
.contains(HEADER_2 + SUMMARY_2);
}
/**
* Test the flag for collecting and printing sstable partition sizes only.
*/
@Test
public void testPartitionsOnly()
{
testPartitionsOnly("-y");
testPartitionsOnly("--partitions-only");
}
private static void testPartitionsOnly(String option)
{
assertThatToolSucceds(SSTABLE_1, option)
.isEqualTo(HEADER_1 +
" Partition size\n" +
" ~p50 0.034 KiB\n" +
" ~p75 0.034 KiB\n" +
" ~p90 0.034 KiB\n" +
" ~p95 0.034 KiB\n" +
" ~p99 0.034 KiB\n" +
" ~p999 0.034 KiB\n" +
" min 0.032 KiB\n" +
" max 0.034 KiB\n" +
" count 5\n");
assertThatToolSucceds(SSTABLE_2, "--partitions-only")
.isEqualTo(HEADER_2 +
" Partition size\n" +
" ~p50 71.735 KiB\n" +
" ~p75 71.735 KiB\n" +
" ~p90 71.735 KiB\n" +
" ~p95 71.735 KiB\n" +
" ~p99 71.735 KiB\n" +
" ~p999 71.735 KiB\n" +
" min 65.625 KiB\n" +
" max 65.630 KiB\n" +
" count 5\n");
}
/**
* Test the flag for detecting partitions over a certain size threshold.
*/
@Test
public void testMinSize()
{
testMinSize("-t");
testMinSize("--min-size");
}
private static void testMinSize(String option)
{
assertThatToolSucceds(SSTABLE_1, SSTABLE_2, option, "35")
.isEqualTo(HEADER_2 +
" Partition: '0' (30) live, size: 65.625 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '1' (31) live, size: 65.630 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '2' (32) live, size: 65.630 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '3' (33) live, size: 65.630 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '4' (34) live, size: 65.630 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
"Summary of #1 (big-ma):\n" +
" File: " + SSTABLE_2 + "\n" +
" 5 partitions match\n" +
" Keys: 0 1 2 3 4\n" +
SUMMARY_2 +
HEADER_1 +
" Partition: '1' (31) live, size: 0.034 KiB, rows: 1, cells: 1, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '2' (32) live, size: 0.034 KiB, rows: 1, cells: 1, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '3' (33) live, size: 0.034 KiB, rows: 1, cells: 1, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '4' (34) live, size: 0.034 KiB, rows: 1, cells: 1, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
"Summary of #1 (big-ma):\n" +
" File: " + SSTABLE_1 + "\n" +
" 4 partitions match\n" +
" Keys: 1 2 3 4\n" +
SUMMARY_1);
assertThatToolSucceds(SSTABLE_1, SSTABLE_2, "--min-size", "36")
.isEqualTo(HEADER_2 +
" Partition: '0' (30) live, size: 65.625 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '1' (31) live, size: 65.630 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '2' (32) live, size: 65.630 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '3' (33) live, size: 65.630 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '4' (34) live, size: 65.630 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
"Summary of #1 (big-ma):\n" +
" File: " + SSTABLE_2 + "\n" +
" 5 partitions match\n" +
" Keys: 0 1 2 3 4\n" +
SUMMARY_2 + HEADER_1 + SUMMARY_1);
assertThatToolSucceds(SSTABLE_1, SSTABLE_2, "--min-size", "67201")
.isEqualTo(HEADER_2 +
" Partition: '1' (31) live, size: 65.630 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '2' (32) live, size: 65.630 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '3' (33) live, size: 65.630 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '4' (34) live, size: 65.630 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
"Summary of #1 (big-ma):\n" +
" File: " + SSTABLE_2 + "\n" +
" 4 partitions match\n" +
" Keys: 1 2 3 4\n" +
SUMMARY_2 + HEADER_1 + SUMMARY_1);
assertThatToolSucceds(SSTABLE_1, SSTABLE_2, "--min-size", "67201B")
.isEqualTo(HEADER_2 +
" Partition: '1' (31) live, size: 65.630 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '2' (32) live, size: 65.630 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '3' (33) live, size: 65.630 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '4' (34) live, size: 65.630 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
"Summary of #1 (big-ma):\n" +
" File: " + SSTABLE_2 + "\n" +
" 4 partitions match\n" +
" Keys: 1 2 3 4\n" +
SUMMARY_2 + HEADER_1 + SUMMARY_1);
assertThatToolSucceds(SSTABLE_1, SSTABLE_2, "--min-size", "65KiB")
.isEqualTo(HEADER_2 +
" Partition: '0' (30) live, size: 65.625 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '1' (31) live, size: 65.630 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '2' (32) live, size: 65.630 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '3' (33) live, size: 65.630 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '4' (34) live, size: 65.630 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
"Summary of #1 (big-ma):\n" +
" File: " + SSTABLE_2 + "\n" +
" 5 partitions match\n" +
" Keys: 0 1 2 3 4\n" +
SUMMARY_2 + HEADER_1 + SUMMARY_1);
}
/**
* Test the flag for detecting partitions with more cells than a certain threshold.
*/
@Test
public void testMinCells()
{
testMinCells("-c");
testMinCells("--min-cells");
}
private static void testMinCells(String option)
{
assertThatToolSucceds(SSTABLE_1, SSTABLE_2, option, "0")
.isEqualTo(HEADER_2 +
" Partition: '0' (30) live, size: 65.625 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '1' (31) live, size: 65.630 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '2' (32) live, size: 65.630 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '3' (33) live, size: 65.630 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '4' (34) live, size: 65.630 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
"Summary of #1 (big-ma):\n" +
" File: " + SSTABLE_2 + "\n" +
" 5 partitions match\n" +
" Keys: 0 1 2 3 4\n" +
SUMMARY_2 +
HEADER_1 +
" Partition: '0' (30) live, size: 0.032 KiB, rows: 1, cells: 1, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '1' (31) live, size: 0.034 KiB, rows: 1, cells: 1, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '2' (32) live, size: 0.034 KiB, rows: 1, cells: 1, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '3' (33) live, size: 0.034 KiB, rows: 1, cells: 1, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '4' (34) live, size: 0.034 KiB, rows: 1, cells: 1, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
"Summary of #1 (big-ma):\n" +
" File: " + SSTABLE_1 + "\n" +
" 5 partitions match\n" +
" Keys: 0 1 2 3 4\n" +
SUMMARY_1);
assertThatToolSucceds(SSTABLE_1, SSTABLE_2, option, "2")
.isEqualTo(HEADER_2 +
" Partition: '0' (30) live, size: 65.625 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '1' (31) live, size: 65.630 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '2' (32) live, size: 65.630 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '3' (33) live, size: 65.630 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '4' (34) live, size: 65.630 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
"Summary of #1 (big-ma):\n" +
" File: " + SSTABLE_2 + "\n" +
" 5 partitions match\n" +
" Keys: 0 1 2 3 4\n" +
SUMMARY_2 + HEADER_1 + SUMMARY_1);
assertThatToolSucceds(SSTABLE_1, SSTABLE_2, option, "51")
.isEqualTo(HEADER_2 + SUMMARY_2 +
HEADER_1 + SUMMARY_1);
}
/**
* Test the flag for detecting partitions with more rows than a certain threshold.
*/
@Test
public void testMinRows()
{
testMinRows("-w");
testMinRows("--min-rows");
}
private static void testMinRows(String option)
{
assertThatToolSucceds(SSTABLE_1, SSTABLE_2, option, "0")
.isEqualTo(HEADER_2 +
" Partition: '0' (30) live, size: 65.625 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '1' (31) live, size: 65.630 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '2' (32) live, size: 65.630 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '3' (33) live, size: 65.630 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '4' (34) live, size: 65.630 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
"Summary of #1 (big-ma):\n" +
" File: " + SSTABLE_2 + "\n" +
" 5 partitions match\n" +
" Keys: 0 1 2 3 4\n" +
SUMMARY_2 +
HEADER_1 +
" Partition: '0' (30) live, size: 0.032 KiB, rows: 1, cells: 1, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '1' (31) live, size: 0.034 KiB, rows: 1, cells: 1, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '2' (32) live, size: 0.034 KiB, rows: 1, cells: 1, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '3' (33) live, size: 0.034 KiB, rows: 1, cells: 1, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '4' (34) live, size: 0.034 KiB, rows: 1, cells: 1, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
"Summary of #1 (big-ma):\n" +
" File: " + SSTABLE_1 + "\n" +
" 5 partitions match\n" +
" Keys: 0 1 2 3 4\n" +
SUMMARY_1);
assertThatToolSucceds(SSTABLE_1, SSTABLE_2, option, "50")
.isEqualTo(HEADER_2 +
" Partition: '0' (30) live, size: 65.625 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '1' (31) live, size: 65.630 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '2' (32) live, size: 65.630 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '3' (33) live, size: 65.630 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '4' (34) live, size: 65.630 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
"Summary of #1 (big-ma):\n" +
" File: " + SSTABLE_2 + "\n" +
" 5 partitions match\n" +
" Keys: 0 1 2 3 4\n" +
SUMMARY_2 + HEADER_1 + SUMMARY_1);
assertThatToolSucceds(SSTABLE_1, SSTABLE_2, option, "51")
.isEqualTo(HEADER_2 + SUMMARY_2 +
HEADER_1 + SUMMARY_1);
}
/**
* Test the flag for detecting partitions with more tombstones than a certain threshold.
*/
@Test
public void testMinTombstones()
{
testMinTombstones("-o");
testMinTombstones("--min-tombstones");
}
private static void testMinTombstones(String option)
{
assertThatToolSucceds(SSTABLE_1, SSTABLE_2, option, "0")
.isEqualTo(HEADER_2 +
" Partition: '0' (30) live, size: 65.625 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '1' (31) live, size: 65.630 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '2' (32) live, size: 65.630 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '3' (33) live, size: 65.630 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '4' (34) live, size: 65.630 KiB, rows: 50, cells: 50, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
"Summary of #1 (big-ma):\n" +
" File: " + SSTABLE_2 + "\n" +
" 5 partitions match\n" +
" Keys: 0 1 2 3 4\n" +
SUMMARY_2 +
HEADER_1 +
" Partition: '0' (30) live, size: 0.032 KiB, rows: 1, cells: 1, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '1' (31) live, size: 0.034 KiB, rows: 1, cells: 1, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '2' (32) live, size: 0.034 KiB, rows: 1, cells: 1, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '3' (33) live, size: 0.034 KiB, rows: 1, cells: 1, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '4' (34) live, size: 0.034 KiB, rows: 1, cells: 1, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
"Summary of #1 (big-ma):\n" +
" File: " + SSTABLE_1 + "\n" +
" 5 partitions match\n" +
" Keys: 0 1 2 3 4\n" +
SUMMARY_1);
assertThatToolSucceds(SSTABLE_1, SSTABLE_2, "--min-tombstones", "1")
.isEqualTo(HEADER_2 + SUMMARY_2 + HEADER_1 + SUMMARY_1);
}
/**
* Test the flag for providing a current time.
*/
@Test
public void testCurrentTimestamp()
{
testCurrentTimestamp("-u");
testCurrentTimestamp("--current-timestamp");
}
private static void testCurrentTimestamp(String option)
{
String now = String.valueOf(FBUtilities.nowInSeconds());
assertThatToolSucceds(SSTABLE_1, option, now).isEqualTo(HEADER_1 + SUMMARY_1);
}
/**
* Test the flag for including backup sstables.
*/
@Test
public void testBackups()
{
testBackups("-b");
testBackups("--backups");
}
private static void testBackups(String option)
{
assertThatToolSucceds(new File(SSTABLE_1).parentPath(), "-r", option)
.isEqualTo(HEADER_1 + SUMMARY_1 + BACKUPS_HEADER_1 + SUMMARY_1);
assertThatToolSucceds(new File(SSTABLE_2).parentPath(), "-r", option)
.isEqualTo(HEADER_2 + SUMMARY_2 + BACKUPS_HEADER_2 + SUMMARY_2);
}
/**
* Test the flag for including snapshot sstables.
*/
@Test
public void testSnapshots()
{
testSnapshots("-s");
testSnapshots("--snapshots");
}
private static void testSnapshots(String option)
{
assertThatToolSucceds(new File(SSTABLE_1).parentPath(), "-r", option)
.isEqualTo(HEADER_1 + SUMMARY_1 + SNAPSHOTS_HEADER_1 + SUMMARY_1);
assertThatToolSucceds(new File(SSTABLE_2).parentPath(), "-r", option)
.isEqualTo(HEADER_2 + SUMMARY_2 + SNAPSHOTS_HEADER_2 + SUMMARY_2);
}
/**
* Test the flag for specifying partiton keys to be considered.
*/
@Test
public void testIncludedKeys()
{
testIncludedKeys("-k");
testIncludedKeys("--key");
}
private static void testIncludedKeys(String option)
{
assertThatToolSucceds(SSTABLE_1, "--min-size", "0", option, "1", option, "3")
.contains(HEADER_1 +
" Partition: '1' (31) live, size: 0.034 KiB, rows: 1, cells: 1, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '3' (33) live, size: 0.034 KiB, rows: 1, cells: 1, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
"Summary of #1 (big-ma):\n" +
" File: " + SSTABLE_1 + "\n" +
" 2 partitions match\n" +
" Keys: 1 3\n")
.contains("count 2\n");
assertThatToolSucceds(SSTABLE_1, "--min-size", "0", option, "0", option, "2", option, "4")
.contains(HEADER_1 +
" Partition: '0' (30) live, size: 0.032 KiB, rows: 1, cells: 1, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '2' (32) live, size: 0.034 KiB, rows: 1, cells: 1, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '4' (34) live, size: 0.034 KiB, rows: 1, cells: 1, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
"Summary of #1 (big-ma):\n" +
" File: " + SSTABLE_1 + "\n" +
" 3 partitions match\n" +
" Keys: 0 2 4\n")
.contains("count 3\n");
assertThatToolSucceds(SSTABLE_1, "-y","--min-size", "0", option, "0", option, "2", option, "4")
.contains(HEADER_1 +
" Partition: '0' (30) live, size: 0.032 KiB\n" +
" Partition: '2' (32) live, size: 0.034 KiB\n" +
" Partition: '4' (34) live, size: 0.034 KiB\n" +
"Summary of #1 (big-ma):\n" +
" File: " + SSTABLE_1 + "\n" +
" 3 partitions match\n" +
" Keys: 0 2 4\n")
.contains("count 3\n");
}
/**
* Test the flag for specifying partiton keys to be excluded.
*/
@Test
public void testExcludedKeys()
{
testExcludedKeys("-x");
testExcludedKeys("--exclude-key");
}
private static void testExcludedKeys(String option)
{
assertThatToolSucceds(SSTABLE_1, "--min-size", "0", option, "1", option, "3")
.contains(HEADER_1 +
" Partition: '0' (30) live, size: 0.032 KiB, rows: 1, cells: 1, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '2' (32) live, size: 0.034 KiB, rows: 1, cells: 1, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '4' (34) live, size: 0.034 KiB, rows: 1, cells: 1, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
"Summary of #1 (big-ma):\n" +
" File: " + SSTABLE_1 + "\n" +
" 3 partitions match\n" +
" Keys: 0 2 4\n")
.contains("count 3\n");
assertThatToolSucceds(SSTABLE_1, "--min-size", "0", option, "0", option, "2", option, "4")
.contains(HEADER_1 +
" Partition: '1' (31) live, size: 0.034 KiB, rows: 1, cells: 1, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
" Partition: '3' (33) live, size: 0.034 KiB, rows: 1, cells: 1, tombstones: 0 (row:0, range:0, complex:0, cell:0, row-TTLd:0, cell-TTLd:0)\n" +
"Summary of #1 (big-ma):\n" +
" File: " + SSTABLE_1 + "\n" +
" 2 partitions match\n" +
" Keys: 1 3\n")
.contains("count 2\n");
}
/**
* Test the flag for producing machine-readable CSV output.
*/
@Test
public void testCSV()
{
testCSV("-m");
testCSV("--csv");
}
private static void testCSV(String option)
{
assertThatToolSucceds(option, "--min-size", "35", SSTABLE_1, SSTABLE_2)
.isEqualTo(format("key,keyBinary,live,offset,size,rowCount,cellCount,tombstoneCount," +
"rowTombstoneCount,rangeTombstoneCount,complexTombstoneCount,cellTombstoneCount," +
"rowTtlExpired,cellTtlExpired,directory,keyspace,table,index,snapshot,backup," +
"generation,format,version\n" +
"\"0\",30,true,0,67200,50,50,0,0,0,0,0,0,0,%s,,,,,,1,big,ma\n" +
"\"1\",31,true,67200,67205,50,50,0,0,0,0,0,0,0,%<s,,,,,,1,big,ma\n" +
"\"2\",32,true,134405,67205,50,50,0,0,0,0,0,0,0,%<s,,,,,,1,big,ma\n" +
"\"3\",33,true,201610,67205,50,50,0,0,0,0,0,0,0,%<s,,,,,,1,big,ma\n" +
"\"4\",34,true,268815,67205,50,50,0,0,0,0,0,0,0,%<s,,,,,,1,big,ma\n" +
"\"1\",31,true,33,35,1,1,0,0,0,0,0,0,0,%s,,,,,,1,big,ma\n" +
"\"2\",32,true,68,35,1,1,0,0,0,0,0,0,0,%<s,,,,,,1,big,ma\n" +
"\"3\",33,true,103,35,1,1,0,0,0,0,0,0,0,%<s,,,,,,1,big,ma\n" +
"\"4\",34,true,138,35,1,1,0,0,0,0,0,0,0,%<s,,,,,,1,big,ma\n",
SSTABLE_2, SSTABLE_1));
}
private static AbstractStringAssert<?> assertThatToolSucceds(String... args)
{
ToolResult tool = invokeTool(args);
Assertions.assertThat(tool.getExitCode()).isZero();
tool.assertOnCleanExit();
return Assertions.assertThat(tool.getStdout());
}
private static String sstable(String table)
{
try
{
return findOneSSTable("legacy_sstables", table);
}
catch (IOException e)
{
throw new RuntimeException(e);
}
}
private static ToolResult invokeTool(String... args)
{
return ToolRunner.invokeClass(SSTablePartitions.class, args);
}
}