Skip to content

Commit

Permalink
CASSANDRA-20151 enable filtering of snapshots on keyspace, table and …
Browse files Browse the repository at this point in the history
…snapshot name
  • Loading branch information
smiklosovic committed Dec 18, 2024
1 parent 410b733 commit 37df341
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,17 @@ public interface SnapshotManagerMBean
void clearSnapshot(String tag, Map<String, Object> options, String... keyspaceNames) throws IOException;

/**
* Get the details of all the snapshots
* Get the details of all the snapshots. Options might be:
*
* <pre>
* no_ttl: "true" or "false"
* include_ephemeral: "true" or "false"
* keyspace: name of keyspace to get snapshots of
* table: name of table to get tables of
* snapshot: name of snapshot to list
* </pre>
*
* There is no requirement as what option has to be specified.
*
* @param options map of options used for filtering of snapshots
* @return A map of snapshotName to all its details in Tabular form.
Expand Down
18 changes: 18 additions & 0 deletions src/java/org/apache/cassandra/tools/nodetool/ListSnapshots.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,21 @@ public class ListSnapshots extends NodeToolCmd
description = "Include ephememeral snapshots")
private boolean includeEphemeral = false;

@Option(title = "keyspace",
name = { "-k", "--keyspace" },
description = "Include snapshots of specified keyspace name")
private String keyspace = null;

@Option(title = "table",
name = { "-t", "--table" },
description = "Include snapshots of specified table name")
private String table = null;

@Option(title = "snapshot",
name = { "-n", "--snapshot"},
description = "Include snapshots of specified name")
private String snapshotName = null;

@Override
public void execute(NodeProbe probe)
{
Expand All @@ -56,6 +71,9 @@ public void execute(NodeProbe probe)
Map<String, String> options = new HashMap<>();
options.put("no_ttl", Boolean.toString(noTTL));
options.put("include_ephemeral", Boolean.toString(includeEphemeral));
options.put("keyspace", keyspace);
options.put("table", table);
options.put("snapshot", snapshotName);

final Map<String, TabularData> snapshotDetails = probe.getSnapshotDetails(options);
if (snapshotDetails.isEmpty())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,49 @@ public void testTakingSnapshoWithSameNameOnDifferentTablesDoesNotFail()
cluster.get(1).nodetoolResult("snapshot", "-t", "somename", "-kt", String.format("%s.tbl2", KEYSPACE)).asserts().success();
}

@Test
public void testListingOfSnapshotsByKeyspaceAndTable()
{
IInvokableInstance instance = cluster.get(1);
cluster.schemaChange("CREATE KEYSPACE IF NOT EXISTS ks1 WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1};");
cluster.schemaChange("CREATE KEYSPACE IF NOT EXISTS ks2 WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1};");
cluster.schemaChange("CREATE TABLE IF NOT EXISTS ks1.tbl (key int, value text, PRIMARY KEY (key))");
cluster.schemaChange("CREATE TABLE IF NOT EXISTS ks1.tbl2 (key int, value text, PRIMARY KEY (key))");
cluster.schemaChange("CREATE TABLE IF NOT EXISTS ks2.tbl (key int, value text, PRIMARY KEY (key))");
cluster.schemaChange("CREATE TABLE IF NOT EXISTS ks2.tbl2 (key int, value text, PRIMARY KEY (key))");

populate(cluster, "ks1", "tbl");
populate(cluster, "ks1", "tbl2");
populate(cluster, "ks2", "tbl");
populate(cluster, "ks2", "tbl2");

instance.nodetoolResult("snapshot", "-t", "tagks1tbl", "-kt", "ks1.tbl").asserts().success();
instance.nodetoolResult("snapshot", "-t", "tagks1tbl2", "-kt", "ks1.tbl2").asserts().success();
instance.nodetoolResult("snapshot", "-t", "tagks2tbl", "-kt", "ks2.tbl").asserts().success();
instance.nodetoolResult("snapshot", "-t", "tagks2tbl2", "-kt", "ks2.tbl2").asserts().success();

waitForSnapshot("ks1", null, "tagks1tbl", true, false);
waitForSnapshot("ks1", null, "tagks1tbl2", true, false);
waitForSnapshot("ks1", null, "tagks2tbl", false, false);
waitForSnapshot("ks1", null, "tagks2tbl2", false, false);

waitForSnapshot("ks1", "tbl", "tagks1tbl", true, false);
waitForSnapshot("ks1", "tbl", "tagks1tbl2", false, false);
waitForSnapshot("ks1", "tbl", "tagks2tbl", false, false);
waitForSnapshot("ks1", "tbl", "tagks2tbl2", false, false);

waitForSnapshot(null, "tbl", "tagks1tbl", true, false);
waitForSnapshot(null, "tbl", "tagks1tbl2", false, false);
waitForSnapshot(null, "tbl", "tagks2tbl", true, false);
waitForSnapshot(null, "tbl", "tagks2tbl2", false, false);

NodeToolResult nodeToolResult = instance.nodetoolResult("listsnapshots", "-n", "tagks1tbl");
nodeToolResult.asserts().success();
List<String> snapshots = extractSnapshots(nodeToolResult.getStdout());
assertEquals(1, snapshots.size());
assertTrue(snapshots.get(0).contains("tagks1tbl"));
}

private void populate(Cluster cluster)
{
for (int i = 0; i < 100; i++)
Expand Down Expand Up @@ -440,13 +483,27 @@ private boolean waitForSnapshotInternal(String keyspaceName, String tableName, S
if (noTTL)
args.add("-nt");

if (keyspaceName != null)
{
args.add("-k");
args.add(keyspaceName);
}

if (tableName != null)
{
args.add("-t");
args.add(tableName);
}

if (snapshotName != null)
{
args.add("-n");
args.add(snapshotName);
}

listsnapshots = cluster.get(1).nodetoolResult(args.toArray(new String[0]));

List<String> lines = Arrays.stream(listsnapshots.getStdout().split("\n"))
.filter(line -> !line.isEmpty())
.filter(line -> !line.startsWith("Snapshot Details:") && !line.startsWith("There are no snapshots"))
.filter(line -> !line.startsWith("Snapshot name") && !line.startsWith("Total TrueDiskSpaceUsed"))
.collect(toList());
List<String> lines = extractSnapshots(listsnapshots.getStdout());

return expectPresent == lines.stream().anyMatch(line -> line.startsWith(snapshotName));
}
Expand All @@ -469,4 +526,13 @@ private void exoticSnapshotNamesInternal(String[] exoticSnapshotNames)
waitForSnapshot(tag, true, true);
}
}

private List<String> extractSnapshots(String listSnapshotsStdOut)
{
return Arrays.stream(listSnapshotsStdOut.split("\n"))
.filter(line -> !line.isEmpty())
.filter(line -> !line.startsWith("Snapshot Details:") && !line.startsWith("There are no snapshots"))
.filter(line -> !line.startsWith("Snapshot name") && !line.startsWith("Total TrueDiskSpaceUsed"))
.collect(toList());
}
}

0 comments on commit 37df341

Please sign in to comment.