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");
+    }
+
 }

Reply via email to