From c63ec3e96bf1a94bf92a3e498e30bb26586e6ff9 Mon Sep 17 00:00:00 2001 From: Amnon Heiman Date: Tue, 26 Apr 2016 11:34:38 +0300 Subject: [PATCH] StorageService: Add takeMultipleColumnFamilySnapshot support This patch adds the functionality of takeMultipleColumnFamilySnapshot to StorageService. It follow origin logic of first check that all keyspaces and column families exists and has no snapshot with that name and then run snapshot on each of the combinations. Two methods where added to simplify the implementation, but that can be reused. One to get a map from keyspace to column family and one with the current snapshots. Fixes scylladb/scylla#1133 Signed-off-by: Amnon Heiman Message-Id: <1461659678-22030-1-git-send-email-amnon@scylladb.com> --- .../cassandra/service/StorageService.java | 93 ++++++++++++++++++- 1 file changed, 92 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/apache/cassandra/service/StorageService.java b/src/main/java/org/apache/cassandra/service/StorageService.java index 52b44bc..effff96 100644 --- a/src/main/java/org/apache/cassandra/service/StorageService.java +++ b/src/main/java/org/apache/cassandra/service/StorageService.java @@ -28,6 +28,7 @@ import java.net.InetAddress; import java.net.UnknownHostException; import java.nio.ByteBuffer; import java.util.*; +import java.util.Map.Entry; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicLong; @@ -519,6 +520,27 @@ public class StorageService extends NotificationBroadcasterSupport "/storage_service/snapshots", null); } + public Map>> getSnapshotKeyspaceColumnFamily() { + JsonArray arr = c.getJsonArray("/storage_service/snapshots"); + Map>> res = new HashMap>>(); + for (int i = 0; i < arr.size(); i++) { + JsonObject obj = arr.getJsonObject(i); + Map> kscf = new HashMap>(); + JsonArray snapshots = obj.getJsonArray("value"); + for (int j = 0; j < snapshots.size(); j++) { + JsonObject s = snapshots.getJsonObject(j); + String ks = s.getString("ks"); + String cf = s.getString("cf"); + if (!kscf.containsKey(ks)) { + kscf.put(ks, new HashSet()); + } + kscf.get(ks).add(cf); + } + res.put(obj.getString("key"), kscf); + } + return res; + } + /** * Get the true size taken by all snapshots across all keyspaces. * @@ -934,6 +956,23 @@ public class StorageService extends NotificationBroadcasterSupport return c.getListStrValue("/storage_service/keyspaces", queryParams); } + public Map> getColumnFamilyPerKeyspace() { + Map> res = new HashMap>(); + + JsonArray mbeans = c.getJsonArray("/column_family/"); + + for (int i = 0; i < mbeans.size(); i++) { + JsonObject mbean = mbeans.getJsonObject(i); + String ks = mbean.getString("ks"); + String cf = mbean.getString("cf"); + if (!res.containsKey(ks)) { + res.put(ks, new HashSet()); + } + res.get(ks).add(cf); + } + return res; + } + public List getNonSystemKeyspaces() { log(" getNonSystemKeyspaces()"); return c.getListStrValue("/storage_service/keyspaces"); @@ -1305,8 +1344,60 @@ public class StorageService extends NotificationBroadcasterSupport @Override public void takeMultipleColumnFamilySnapshot(String tag, String... columnFamilyList) throws IOException { - // TODO Auto-generated method stub log(" takeMultipleColumnFamilySnapshot"); + Map> keyspaceColumnfamily = new HashMap>(); + Map> kss = getColumnFamilyPerKeyspace(); + Map>> snapshots = getSnapshotKeyspaceColumnFamily(); + for (String columnFamily : columnFamilyList) + { + String splittedString[] = columnFamily.split("\\."); + if (splittedString.length == 2) + { + String keyspaceName = splittedString[0]; + String columnFamilyName = splittedString[1]; + + if (keyspaceName == null) + throw new IOException("You must supply a keyspace name"); + if (columnFamilyName == null) + throw new IOException("You must supply a column family name"); + if (tag == null || tag.equals("")) + throw new IOException("You must supply a snapshot name."); + if (!kss.containsKey(keyspaceName)) + { + throw new IOException("Keyspace " + keyspaceName + " does not exist"); + } + if (!kss.get(keyspaceName).contains(columnFamilyName)) { + throw new IllegalArgumentException(String.format("Unknown keyspace/cf pair (%s.%s)", keyspaceName, columnFamilyName)); + } + // As there can be multiple column family from same keyspace check if snapshot exist for that specific + // columnfamily and not for whole keyspace + + if (snapshots.containsKey(tag) && snapshots.get(tag).containsKey(keyspaceName) && snapshots.get(tag).get(keyspaceName).contains(columnFamilyName)) { + throw new IOException("Snapshot " + tag + " already exists."); + } + + if (!keyspaceColumnfamily.containsKey(keyspaceName)) + { + keyspaceColumnfamily.put(keyspaceName, new ArrayList()); + } + + // Add Keyspace columnfamily to map in order to support atomicity for snapshot process. + // So no snapshot should happen if any one of the above conditions fail for any keyspace or columnfamily + keyspaceColumnfamily.get(keyspaceName).add(columnFamilyName); + + } + else + { + throw new IllegalArgumentException( + "Cannot take a snapshot on secondary index or invalid column family name. You must supply a column family name in the form of keyspace.columnfamily"); + } + } + + for (Entry> entry : keyspaceColumnfamily.entrySet()) + { + for (String columnFamily : entry.getValue()) + takeColumnFamilySnapshot(entry.getKey(), columnFamily, tag); + } } @Override