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 <[email protected]> --- 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 -- sheepdog mailing list [email protected] http://lists.wpkg.org/mailman/listinfo/sheepdog
