[sheepdog] [PATCH] dog/cluster: cluster-wide snapshot save or load specified vdi

Ruoyu liangry at ucweb.com
Wed May 28 14:43:02 CEST 2014


It is useful for users who want to backup or restore only part of
all vdi from cluster-wide snapshot.

Usage and example:

1. save all vdi:
   dog cluster snapshot save all /tmp/ss

2. save some specified vdi:
   dog cluster snapshot save test0_1_2 /tmp/ss test0 test1 test2

3. load all vdi:
   dog cluster snapshot load all /tmp/ss

4. load some specified vdi:
   dog cluster snapshot load all /tmp/ss test6 test0 test3

Signed-off-by: Ruoyu <liangry at ucweb.com>
---
 dog/cluster.c   | 74 +++++++++++++++++++++++++++++++++++++++++++++++++--------
 dog/farm/farm.c | 19 ++++++++++++---
 dog/farm/farm.h | 19 ++++++++++++++-
 3 files changed, 98 insertions(+), 14 deletions(-)

diff --git a/dog/cluster.c b/dog/cluster.c
index 69ec07c..2c69650 100644
--- a/dog/cluster.c
+++ b/dog/cluster.c
@@ -17,6 +17,8 @@
 #include "dog.h"
 #include "farm/farm.h"
 
+struct rb_root snap_vdi_tree = RB_ROOT;
+
 static struct sd_option cluster_options[] = {
 	{'b', "store", true, "specify backend store"},
 	{'c', "copies", true, "specify the default data redundancy (number of copies)"},
@@ -326,11 +328,21 @@ static void fill_object_tree(uint32_t vid, const char *name, const char *tag,
 	uint64_t vdi_oid = vid_to_vdi_oid(vid), vmstate_oid;
 	uint32_t vdi_id;
 	uint32_t nr_objs, nr_vmstate_object;
+	bool specified_vdi = *(bool *)data;
 
 	/* ignore active vdi */
 	if (!vdi_is_snapshot(i))
 		return;
 
+	/* iff vdi name specified in command line */
+	if (specified_vdi) {
+		struct snap_vdi_entry key = {
+			.vdiname = (char *) name
+		};
+		if (!rb_search(&snap_vdi_tree, &key, rb, snap_vdi_entry_cmp))
+			return;
+	}
+
 	/* fill vdi object id */
 	object_tree_insert(vdi_oid, i->nr_copies, i->copy_policy);
 
@@ -355,11 +367,27 @@ static void fill_object_tree(uint32_t vid, const char *name, const char *tag,
 	}
 }
 
+static bool build_specified_vdi_tree(int argc, char **argv)
+{
+	bool specified_vdi = false;
+	char *vdiname;
+
+	while ((vdiname = argv[optind++]) != NULL) {
+		struct snap_vdi_entry *entry = xmalloc(sizeof(*entry));
+		entry->vdiname = vdiname;
+		rb_insert(&snap_vdi_tree, entry, rb, snap_vdi_entry_cmp);
+		specified_vdi = true;
+	}
+
+	return specified_vdi;
+}
+
 static int save_snapshot(int argc, char **argv)
 {
 	const char *tag = argv[optind++];
 	char *path, *p;
 	int ret = EXIT_SYSFAIL, uninitialized_var(unused);
+	bool specified_vdi;
 
 	unused = strtol(tag, &p, 10);
 	if (tag != p) {
@@ -367,11 +395,11 @@ static int save_snapshot(int argc, char **argv)
 		return EXIT_USAGE;
 	}
 
-	if (!argv[optind]) {
+	path = argv[optind++];
+	if (!path) {
 		sd_err("Please specify the path to save snapshot.");
 		return EXIT_USAGE;
 	}
-	path = argv[optind];
 
 	if (farm_init(path) != SD_RES_SUCCESS)
 		goto out;
@@ -382,13 +410,32 @@ static int save_snapshot(int argc, char **argv)
 		goto out;
 	}
 
-	if (parse_vdi(fill_object_tree, SD_INODE_SIZE, NULL) != SD_RES_SUCCESS)
-		goto out;
+	specified_vdi = build_specified_vdi_tree(argc, argv);
+	if (parse_vdi(fill_object_tree, SD_INODE_SIZE, &specified_vdi)
+				!= SD_RES_SUCCESS)
+		goto cleanup;
+
+	if (object_tree_size() == 0) {
+		sd_err("Object not found. It may be caused by:");
+		if (specified_vdi) {
+			sd_err("1. The specified VDIs are not found.");
+			sd_err("2. The specified VDIs don't have snapshots.");
+		} else {
+			sd_err("1. The cluster is empty.");
+			sd_err("2. All VDIs of the cluster "
+					  "don't have snapshots.");
+		}
+		goto cleanup;
+	}
 
 	if (farm_save_snapshot(tag) != SD_RES_SUCCESS)
-		goto out;
+		goto cleanup;
 
 	ret = EXIT_SUCCESS;
+
+cleanup:
+	rb_destroy(&snap_vdi_tree, struct snap_vdi_entry, rb);
+
 out:
 	if (ret)
 		sd_err("Fail to save snapshot to path: %s.", path);
@@ -403,16 +450,17 @@ static int load_snapshot(int argc, char **argv)
 	uint32_t idx;
 	int ret = EXIT_SYSFAIL;
 	struct snap_log_hdr hdr;
+	bool specified_vdi;
 
 	idx = strtol(tag, &p, 10);
 	if (tag == p)
 		idx = 0;
 
-	if (!argv[optind]) {
+	path = argv[optind++];
+	if (!path) {
 		sd_err("Please specify the path to save snapshot.");
 		return EXIT_USAGE;
 	}
-	path = argv[optind];
 
 	if (farm_init(path) != SD_RES_SUCCESS)
 		goto out;
@@ -430,10 +478,15 @@ static int load_snapshot(int argc, char **argv)
 	if (cluster_format(0, NULL) != SD_RES_SUCCESS)
 		goto out;
 
-	if (farm_load_snapshot(idx, tag) != SD_RES_SUCCESS)
-		goto out;
+	specified_vdi = build_specified_vdi_tree(argc, argv);
+	if (farm_load_snapshot(idx, tag, specified_vdi) != SD_RES_SUCCESS)
+		goto cleanup;
 
 	ret = EXIT_SUCCESS;
+
+cleanup:
+	rb_destroy(&snap_vdi_tree, struct snap_vdi_entry, rb);
+
 out:
 	if (ret)
 		sd_err("Fail to load snapshot");
@@ -578,7 +631,8 @@ static struct subcommand cluster_cmd[] = {
 	 NULL, CMD_NEED_NODELIST, cluster_format, cluster_options},
 	{"shutdown", NULL, "aph", "stop Sheepdog",
 	 NULL, 0, cluster_shutdown, cluster_options},
-	{"snapshot", "<tag|idx> <path>", "aph", "snapshot/restore the cluster",
+	{"snapshot", "<tag|idx> <path> [vdi1] [vdi2] ...", "aph",
+	 "snapshot/restore the cluster",
 	 cluster_snapshot_cmd, CMD_NEED_ARG,
 	 cluster_snapshot, cluster_options},
 	{"recover", NULL, "afph",
diff --git a/dog/farm/farm.c b/dog/farm/farm.c
index fb2b08d..19ea226 100644
--- a/dog/farm/farm.c
+++ b/dog/farm/farm.c
@@ -49,6 +49,7 @@ struct snapshot_work {
 	struct trunk_entry entry;
 	struct strbuf *trunk_buf;
 	struct work work;
+	bool specified_vdi;
 };
 static struct work_queue *wq;
 static uatomic_bool work_error;
@@ -117,6 +118,7 @@ static int create_active_vdis(void)
 {
 	struct active_vdi_entry *vdi;
 	uint32_t new_vid;
+	int vdi_count = 0;
 	rb_for_each_entry(vdi, &active_vdi_tree, rb) {
 		if (do_vdi_create(vdi->name,
 				  vdi->vdi_size,
@@ -125,8 +127,9 @@ static int create_active_vdis(void)
 				  vdi->copy_policy,
 				  vdi->store_policy) < 0)
 			return -1;
+		vdi_count++;
 	}
-	return 0;
+	return (vdi_count > 0) ? 0 : -1;
 }
 
 char *get_object_directory(void)
@@ -398,6 +401,14 @@ static void do_load_object(struct work *work)
 	if (!buffer)
 		goto error;
 
+	if (sw->specified_vdi) {
+		struct snap_vdi_entry key = {
+			.vdiname = ((struct sd_inode *)buffer)->name
+		};
+		if (!rb_search(&snap_vdi_tree, &key, rb, snap_vdi_entry_cmp))
+			goto success;
+	}
+
 	vid = oid_to_vid(sw->entry.oid);
 	if (register_vdi(vid)) {
 		if (notify_vdi_add(vid, sw->entry.nr_copies,
@@ -413,6 +424,7 @@ static void do_load_object(struct work *work)
 	if (is_vdi_obj(sw->entry.oid))
 		add_active_vdi(buffer);
 
+success:
 	farm_show_progress(uatomic_add_return(&loaded, 1), trunk_get_count());
 	free(buffer);
 	return;
@@ -437,12 +449,13 @@ static int queue_load_snapshot_work(struct trunk_entry *entry, void *data)
 	memcpy(&sw->entry, entry, sizeof(struct trunk_entry));
 	sw->work.fn = do_load_object;
 	sw->work.done = load_object_done;
+	sw->specified_vdi = *(bool *)data;
 	queue_work(wq, &sw->work);
 
 	return 0;
 }
 
-int farm_load_snapshot(uint32_t idx, const char *tag)
+int farm_load_snapshot(uint32_t idx, const char *tag, bool specified_vdi)
 {
 	int ret = -1;
 	unsigned char trunk_sha1[SHA1_DIGEST_SIZE];
@@ -452,7 +465,7 @@ int farm_load_snapshot(uint32_t idx, const char *tag)
 
 	wq = create_work_queue("load snapshot", WQ_DYNAMIC);
 	if (for_each_entry_in_trunk(trunk_sha1, queue_load_snapshot_work,
-				    NULL) < 0)
+				    &specified_vdi) < 0)
 		goto out;
 
 	work_queue_wait(wq);
diff --git a/dog/farm/farm.h b/dog/farm/farm.h
index 95dcfca..2fd8cbe 100644
--- a/dog/farm/farm.h
+++ b/dog/farm/farm.h
@@ -17,6 +17,7 @@
 #include "sheep.h"
 #include "strbuf.h"
 #include "sha1.h"
+#include "rbtree.h"
 
 struct trunk_entry {
 	uint64_t oid;
@@ -49,11 +50,27 @@ struct snap_log {
 	unsigned char trunk_sha1[SHA1_DIGEST_SIZE];
 };
 
+struct snap_vdi_entry {
+	struct rb_node rb;
+	char *vdiname;
+};
+
+extern struct rb_root snap_vdi_tree;
+
+static inline int snap_vdi_entry_cmp(
+			const struct snap_vdi_entry *entry1,
+			const struct snap_vdi_entry *entry2)
+{
+	assert(entry1 != NULL);
+	assert(entry2 != NULL);
+	return strcmp(entry1->vdiname, entry2->vdiname);
+}
+
 /* farm.c */
 int farm_init(const char *path);
 bool farm_contain_snapshot(uint32_t idx, const char *tag);
 int farm_save_snapshot(const char *tag);
-int farm_load_snapshot(uint32_t idx, const char *tag);
+int farm_load_snapshot(uint32_t idx, const char *tag, bool specified_vdi);
 char *get_object_directory(void);
 
 /* trunk.c */
-- 
1.8.3.2





More information about the sheepdog mailing list