[sheepdog] [PATCH v2] dog/cluster: cluster-wide snapshot save or load specified vdi
Ruoyu
liangry at ucweb.com
Tue Jun 3 10:59:26 CEST 2014
It is useful for users who want to backup or restore only part of
all VDIs from cluster-wide snapshot.
To show which VDIs are snapshot, dog cluster snapshot show command
is added.
Usage and example:
1. save all vdi:
dog cluster snapshot save snapname /tmp/ss
2. save some specified vdi:
dog cluster snapshot save snapname /tmp/ss test0 test1 test2
3. load all vdi:
dog cluster snapshot load snapname /tmp/ss
4. load some specified vdi:
dog cluster snapshot load snapname /tmp/ss test6 test0 test3
5. show snapshot:
dog cluster snapshot show snapname /tmp/ss
Signed-off-by: Ruoyu <liangry at ucweb.com>
---
dog/cluster.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++-----
dog/farm/farm.c | 55 ++++++++++++++++++++++++++--
dog/farm/farm.h | 20 +++++++++-
3 files changed, 173 insertions(+), 14 deletions(-)
diff --git a/dog/cluster.c b/dog/cluster.c
index 69ec07c..ea37c4c 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,16 +478,57 @@ 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");
return ret;
}
+static int show_snapshot(int argc, char **argv)
+{
+ char *tag = argv[optind++];
+ char *path, *p;
+ uint32_t idx;
+ int ret = EXIT_SYSFAIL;
+
+ idx = strtol(tag, &p, 10);
+ if (tag == p)
+ idx = 0;
+
+ path = argv[optind++];
+ if (!path) {
+ sd_err("Please specify the path to show snapshot.");
+ return EXIT_USAGE;
+ }
+
+ if (farm_init(path) != SD_RES_SUCCESS)
+ goto out;
+
+ if (!farm_contain_snapshot(idx, tag)) {
+ sd_err("Snapshot index or tag does not exist.");
+ goto out;
+ }
+
+ if (farm_show_snapshot(idx, tag) != SD_RES_SUCCESS)
+ goto out;
+
+ ret = EXIT_SUCCESS;
+
+out:
+ if (ret)
+ sd_err("Fail to show snapshot");
+ return ret;
+}
+
#define RECOVER_PRINT \
"Caution! Please try starting all the cluster nodes normally before\n" \
"running this command.\n\n" \
@@ -530,6 +619,8 @@ static struct subcommand cluster_snapshot_cmd[] = {
NULL, CMD_NEED_ARG, list_snapshot, NULL},
{"load", NULL, "h", "load snapshot from localpath",
NULL, CMD_NEED_ARG | CMD_NEED_NODELIST, load_snapshot, NULL},
+ {"show", NULL, "h", "show vdi list from snapshot",
+ NULL, CMD_NEED_ARG | CMD_NEED_NODELIST, show_snapshot, NULL},
{NULL},
};
@@ -578,7 +669,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..597bbcf 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);
@@ -468,3 +481,39 @@ out:
rb_destroy(®istered_vdi_tree, struct registered_vdi_entry, rb);
return ret;
}
+
+static int print_entry(struct trunk_entry *entry, void *data)
+{
+ int ret = -1;
+ size_t size;
+ struct sd_inode *inode = slice_read(entry->sha1, &size);
+ if (!inode) {
+ sd_err("Fail to load object, oid %"PRIx64, entry->oid);
+ goto out;
+ }
+
+ printf("%s\n", inode->name);
+ ret = 0;
+out:
+ free(inode);
+ return ret;
+}
+
+int farm_show_snapshot(uint32_t idx, const char *tag)
+{
+ int ret = -1;
+ unsigned char trunk_sha1[SHA1_DIGEST_SIZE];
+
+ if (get_trunk_sha1(idx, tag, trunk_sha1) < 0)
+ goto out;
+
+ printf("The cluster-wide snapshot contains these VDIs:\n");
+ if (for_each_entry_in_trunk(trunk_sha1, print_entry, NULL) < 0)
+ goto out;
+
+ ret = 0;
+out:
+ if (ret)
+ sd_err("Fail to show snapshot.");
+ return ret;
+}
diff --git a/dog/farm/farm.h b/dog/farm/farm.h
index 95dcfca..1c9de47 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,28 @@ 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);
+int farm_show_snapshot(uint32_t idx, const char *tag);
char *get_object_directory(void);
/* trunk.c */
--
1.8.3.2
More information about the sheepdog
mailing list