add -cf option to nodetool snapshot patch by dbrosius; reviewed by jbellis for CASSANDRA-556
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/4797b403 Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/4797b403 Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/4797b403 Branch: refs/heads/cassandra-1.1 Commit: 4797b40339e101d829e8ad15c923d36ce0e0ce8f Parents: 01a8c1c Author: Jonathan Ellis <[email protected]> Authored: Wed Apr 18 09:54:34 2012 -0500 Committer: Jonathan Ellis <[email protected]> Committed: Wed Apr 18 09:54:34 2012 -0500 ---------------------------------------------------------------------- CHANGES.txt | 2 + src/java/org/apache/cassandra/db/Table.java | 20 ++++++++- .../apache/cassandra/service/StorageService.java | 31 +++++++++++++- .../cassandra/service/StorageServiceMBean.java | 11 +++++- src/java/org/apache/cassandra/tools/NodeCmd.java | 23 ++++++++--- src/java/org/apache/cassandra/tools/NodeProbe.java | 19 +++++++-- .../service/StorageServiceServerTest.java | 8 ++++ 7 files changed, 97 insertions(+), 17 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/4797b403/CHANGES.txt ---------------------------------------------------------------------- diff --git a/CHANGES.txt b/CHANGES.txt index 1f3bf09..54e5e41 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,6 @@ 1.1.1-dev + * add -cf option to nodetool snapshot, and takeColumnFamilySnapshot to + StorageService mbean (CASSANDRA-556) * optimize cleanup to drop entire sstables where possible (CASSANDRA-4079) * optimize truncate when autosnapshot is disabled (CASSANDRA-4153) * add support for commitlog archiving and point-in-time recovery http://git-wip-us.apache.org/repos/asf/cassandra/blob/4797b403/src/java/org/apache/cassandra/db/Table.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/db/Table.java b/src/java/org/apache/cassandra/db/Table.java index 51e8258..c93756c 100644 --- a/src/java/org/apache/cassandra/db/Table.java +++ b/src/java/org/apache/cassandra/db/Table.java @@ -194,15 +194,29 @@ public class Table } /** - * Take a snapshot of the entire set of column families with a given timestamp + * Take a snapshot of the specific column family, or the entire set of column families + * if columnFamily is null with a given timestamp * * @param snapshotName the tag associated with the name of the snapshot. This value may not be null + * @param columnFamilyName the column family to snapshot or all on null + * + * @throws IOException if the column family doesn't exist */ - public void snapshot(String snapshotName) + public void snapshot(String snapshotName, String columnFamilyName) throws IOException { assert snapshotName != null; + boolean tookSnapShot = false; for (ColumnFamilyStore cfStore : columnFamilyStores.values()) - cfStore.snapshot(snapshotName); + { + if (columnFamilyName == null || cfStore.columnFamily.equals(columnFamilyName)) + { + tookSnapShot = true; + cfStore.snapshot(snapshotName); + } + } + + if ((columnFamilyName != null) && !tookSnapShot) + throw new IOException("Failed taking snapshot. Column family " + columnFamilyName + " does not exist."); } /** http://git-wip-us.apache.org/repos/asf/cassandra/blob/4797b403/src/java/org/apache/cassandra/service/StorageService.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/service/StorageService.java b/src/java/org/apache/cassandra/service/StorageService.java index 3ae8b0a..01113df 100644 --- a/src/java/org/apache/cassandra/service/StorageService.java +++ b/src/java/org/apache/cassandra/service/StorageService.java @@ -1661,7 +1661,7 @@ public class StorageService implements IEndpointStateChangeSubscriber, StorageSe { return Schema.instance.getVersion().toString(); } - + public List<String> getLeavingNodes() { return stringify(tokenMetadata_.getLeavingEndpoints()); @@ -1802,14 +1802,39 @@ public class StorageService implements IEndpointStateChangeSubscriber, StorageSe for (Table table : tables) - table.snapshot(tag); + table.snapshot(tag, null); + } + + /** + * Takes the snapshot of a specific column family. A snapshot name must be specified. + * + * @param tableName the keyspace which holds the specified column family + * @param columnFamilyName the column family to snapshot + * @param tag the tag given to the snapshot; may not be null or empty + */ + public void takeColumnFamilySnapshot(String tableName, String columnFamilyName, String tag) throws IOException + { + if (tableName == null) + throw new IOException("You must supply a table name"); + + if (columnFamilyName == null) + throw new IOException("You mus supply a column family name"); + + if (tag == null || tag.equals("")) + throw new IOException("You must supply a snapshot name."); + + Table table = getValidTable(tableName); + if (table.snapshotExists(tag)) + throw new IOException("Snapshot " + tag + " already exists."); + + table.snapshot(tag, columnFamilyName); } private Table getValidTable(String tableName) throws IOException { if (!Schema.instance.getTables().contains(tableName)) { - throw new IOException("Table " + tableName + "does not exist"); + throw new IOException("Table " + tableName + " does not exist"); } return Table.open(tableName); } http://git-wip-us.apache.org/repos/asf/cassandra/blob/4797b403/src/java/org/apache/cassandra/service/StorageServiceMBean.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/service/StorageServiceMBean.java b/src/java/org/apache/cassandra/service/StorageServiceMBean.java index 9da3896..72d03d1 100644 --- a/src/java/org/apache/cassandra/service/StorageServiceMBean.java +++ b/src/java/org/apache/cassandra/service/StorageServiceMBean.java @@ -89,7 +89,7 @@ public interface StorageServiceMBean */ public String getSchemaVersion(); - + /** * Get the list of all data file locations from conf * @return String array of all locations @@ -194,6 +194,15 @@ public interface StorageServiceMBean public void takeSnapshot(String tag, String... tableNames) throws IOException; /** + * Takes the snapshot of a specific column family. A snapshot name must be specified. + * + * @param tableName the keyspace which holds the specified column family + * @param columnFamilyName the column family to snapshot + * @param tag the tag given to the snapshot; may not be null or empty + */ + public void takeColumnFamilySnapshot(String tableName, String columnFamilyName, String tag) throws IOException; + + /** * Remove the snapshot with the given name from the given tables. * If no tag is specified we will remove all snapshots. */ http://git-wip-us.apache.org/repos/asf/cassandra/blob/4797b403/src/java/org/apache/cassandra/tools/NodeCmd.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/tools/NodeCmd.java b/src/java/org/apache/cassandra/tools/NodeCmd.java index b18d63b..346ee3b 100644 --- a/src/java/org/apache/cassandra/tools/NodeCmd.java +++ b/src/java/org/apache/cassandra/tools/NodeCmd.java @@ -45,6 +45,7 @@ import org.apache.cassandra.utils.Pair; public class NodeCmd { + private static final Pair<String, String> SNAPSHOT_COLUMNFAMILY_OPT = new Pair<String, String>("cf", "column-family"); private static final Pair<String, String> HOST_OPT = new Pair<String, String>("h", "host"); private static final Pair<String, String> PORT_OPT = new Pair<String, String>("p", "port"); private static final Pair<String, String> USERNAME_OPT = new Pair<String, String>("u", "username"); @@ -64,6 +65,7 @@ public class NodeCmd { options = new ToolOptions(); + options.addOption(SNAPSHOT_COLUMNFAMILY_OPT, true, "only take a snapshot of the specified column family"); options.addOption(HOST_OPT, true, "node hostname or ip address"); options.addOption(PORT_OPT, true, "remote jmx agent port number"); options.addOption(USERNAME_OPT, true, "remote jmx agent username"); @@ -164,7 +166,7 @@ public class NodeCmd addCmdHelp(header, "rebuild [src-dc-name]", "Rebuild data by streaming from other nodes (similarly to bootstrap)"); // Two args - addCmdHelp(header, "snapshot [keyspaces...] -t [snapshotName]", "Take a snapshot of the specified keyspaces using optional name snapshotName"); + addCmdHelp(header, "snapshot [keyspaces...] -cf [columnfamilyName] -t [snapshotName]", "Take a snapshot of the optionally specified column family of the specified keyspaces using optional name snapshotName"); addCmdHelp(header, "clearsnapshot [keyspaces...] -t [snapshotName]", "Remove snapshots for the specified keyspaces. Either remove all snapshots or remove the snapshots with the given name."); addCmdHelp(header, "flush [keyspace] [cfnames]", "Flush one or more column family"); addCmdHelp(header, "repair [keyspace] [cfnames]", "Repair one or more column family (use -pr to repair only the first range returned by the partitioner)"); @@ -665,6 +667,8 @@ public class NodeCmd // Execute the requested command. String[] arguments = cmd.getCommandArguments(); + String tag; + String columnFamilyName = null; switch (command) { @@ -697,9 +701,11 @@ public class NodeCmd break; case SNAPSHOT : + columnFamilyName = cmd.getOptionValue(SNAPSHOT_COLUMNFAMILY_OPT.left); + /* FALL THRU */ case CLEARSNAPSHOT : - String tag = cmd.getOptionValue(TAG_OPT.left); - handleSnapshots(command, tag, arguments, probe); + tag = cmd.getOptionValue(TAG_OPT.left); + handleSnapshots(command, tag, arguments, columnFamilyName, probe); break; case MOVE : @@ -891,7 +897,7 @@ public class NodeCmd } } - private static void handleSnapshots(NodeCommand nc, String tag, String[] cmdArgs, NodeProbe probe) throws InterruptedException, IOException + private static void handleSnapshots(NodeCommand nc, String tag, String[] cmdArgs, String columnFamily, NodeProbe probe) throws InterruptedException, IOException { String[] keyspaces = Arrays.copyOfRange(cmdArgs, 0, cmdArgs.length); System.out.print("Requested snapshot for: "); @@ -902,7 +908,12 @@ public class NodeCmd } else { - System.out.print("all keyspaces"); + System.out.print("all keyspaces "); + } + + if (columnFamily != null) + { + System.out.print("and column family: " + columnFamily); } System.out.println(); @@ -911,7 +922,7 @@ public class NodeCmd case SNAPSHOT : if (tag == null || tag.equals("")) tag = new Long(System.currentTimeMillis()).toString(); - probe.takeSnapshot(tag, keyspaces); + probe.takeSnapshot(tag, columnFamily, keyspaces); System.out.println("Snapshot directory: " + tag); break; case CLEARSNAPSHOT : http://git-wip-us.apache.org/repos/asf/cassandra/blob/4797b403/src/java/org/apache/cassandra/tools/NodeProbe.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/tools/NodeProbe.java b/src/java/org/apache/cassandra/tools/NodeProbe.java index f042353..077a8b4 100644 --- a/src/java/org/apache/cassandra/tools/NodeProbe.java +++ b/src/java/org/apache/cassandra/tools/NodeProbe.java @@ -339,13 +339,24 @@ public class NodeProbe } /** - * Take a snapshot of all the tables. + * Take a snapshot of all the tables, optionally specifying only a specific column family. * * @param snapshotName the name of the snapshot. + * @param columnFamily the column family to snapshot or all on null + * @param keyspaces the keyspaces to snapshot */ - public void takeSnapshot(String snapshotName, String... keyspaces) throws IOException + public void takeSnapshot(String snapshotName, String columnFamily, String... keyspaces) throws IOException { - ssProxy.takeSnapshot(snapshotName, keyspaces); + if (columnFamily != null) + { + if (keyspaces.length != 1) + { + throw new IOException("When specifying the column family for a snapshot, you must specify one and only one keyspace"); + } + ssProxy.takeColumnFamilySnapshot(keyspaces[0], columnFamily, snapshotName); + } + else + ssProxy.takeSnapshot(snapshotName, keyspaces); } /** @@ -657,7 +668,7 @@ public class NodeProbe { return ssProxy.getSchemaVersion(); } - + public List<String> describeRing(String keyspaceName) throws InvalidRequestException { return ssProxy.describeRingJMX(keyspaceName); http://git-wip-us.apache.org/repos/asf/cassandra/blob/4797b403/test/unit/org/apache/cassandra/service/StorageServiceServerTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/service/StorageServiceServerTest.java b/test/unit/org/apache/cassandra/service/StorageServiceServerTest.java index ce88d59..0bcaff4 100644 --- a/test/unit/org/apache/cassandra/service/StorageServiceServerTest.java +++ b/test/unit/org/apache/cassandra/service/StorageServiceServerTest.java @@ -67,4 +67,12 @@ public class StorageServiceServerTest // no need to insert extra data, even an "empty" database will have a little information in the system keyspace StorageService.instance.takeSnapshot("snapshot", new String[0]); } + + @Test + public void testColumnFamilySnapshot() throws IOException + { + // no need to insert extra data, even an "empty" database will have a little information in the system keyspace + StorageService.instance.takeColumnFamilySnapshot("system", "Schema", "cf_snapshot"); + } + }
