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 <lian...@ucweb.com> --- dog/cluster.c | 86 ++++++++++++++++++++++++++++++++--- dog/farm/farm.c | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- dog/farm/farm.h | 10 +++- 3 files changed, 224 insertions(+), 11 deletions(-) diff --git a/dog/cluster.c b/dog/cluster.c index 69ec07c..13aef8b 100644 --- a/dog/cluster.c +++ b/dog/cluster.c @@ -326,11 +326,25 @@ 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; + struct vdi_option *opt = (struct vdi_option *)data; + bool matched; /* ignore active vdi */ if (!vdi_is_snapshot(i)) return; + /* iff vdi specified in command line */ + if (opt->count > 0) { + matched = false; + for (int n = 0; n < opt->count; n++) + if (strcmp(name, opt->name[n]) == 0) { + matched = true; + break; + } + if (!matched) + return; + } + /* fill vdi object id */ object_tree_insert(vdi_oid, i->nr_copies, i->copy_policy); @@ -360,6 +374,7 @@ static int save_snapshot(int argc, char **argv) const char *tag = argv[optind++]; char *path, *p; int ret = EXIT_SYSFAIL, uninitialized_var(unused); + struct vdi_option opt; unused = strtol(tag, &p, 10); if (tag != p) { @@ -367,11 +382,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,8 +397,23 @@ static int save_snapshot(int argc, char **argv) goto out; } - if (parse_vdi(fill_object_tree, SD_INODE_SIZE, NULL) != SD_RES_SUCCESS) + opt.count = argc - optind; + opt.name = argv + optind; + if (parse_vdi(fill_object_tree, SD_INODE_SIZE, &opt) != SD_RES_SUCCESS) + goto out; + + if (object_tree_size() == 0) { + sd_err("Object not found. It may be caused by:"); + if (opt.count > 0) { + 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 out; + } if (farm_save_snapshot(tag) != SD_RES_SUCCESS) goto out; @@ -408,11 +438,11 @@ static int load_snapshot(int argc, char **argv) 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 +460,55 @@ 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) + if (farm_load_snapshot(idx, tag, argc - optind, argv + optind) + != SD_RES_SUCCESS) goto out; ret = EXIT_SUCCESS; + 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, argc - optind, argv + optind) + != 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 +599,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 +649,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..e5d86b2 100644 --- a/dog/farm/farm.c +++ b/dog/farm/farm.c @@ -40,10 +40,18 @@ struct active_vdi_entry { uint8_t store_policy; }; +struct registered_obj_entry { + struct rb_node rb; + uint64_t oid; +}; + /* We use active_vdi_tree to create active vdi on top of the snapshot chain */ static struct rb_root active_vdi_tree = RB_ROOT; /* We have to register vdi information first before loading objects */ static struct rb_root registered_vdi_tree = RB_ROOT; +/* register object if vdi specified */ +static struct rb_root registered_obj_tree = RB_ROOT; +static uint64_t obj_to_load; struct snapshot_work { struct trunk_entry entry; @@ -413,7 +421,8 @@ static void do_load_object(struct work *work) if (is_vdi_obj(sw->entry.oid)) add_active_vdi(buffer); - farm_show_progress(uatomic_add_return(&loaded, 1), trunk_get_count()); + farm_show_progress(uatomic_add_return(&loaded, 1), + (obj_to_load > 0) ? obj_to_load : trunk_get_count()); free(buffer); return; error: @@ -430,9 +439,25 @@ static void load_object_done(struct work *work) free(sw); } +static int registered_obj_cmp(struct registered_obj_entry *a, + struct registered_obj_entry *b) +{ + return intcmp(a->oid, b->oid); +} + static int queue_load_snapshot_work(struct trunk_entry *entry, void *data) { - struct snapshot_work *sw = xzalloc(sizeof(struct snapshot_work)); + struct snapshot_work *sw; + struct registered_obj_entry key; + + if (obj_to_load > 0) { + key.oid = entry->oid; + if (!rb_search(®istered_obj_tree, &key, rb, + registered_obj_cmp)) + return 0; + } + + sw = xzalloc(sizeof(struct snapshot_work)); memcpy(&sw->entry, entry, sizeof(struct trunk_entry)); sw->work.fn = do_load_object; @@ -442,14 +467,89 @@ static int queue_load_snapshot_work(struct trunk_entry *entry, void *data) return 0; } -int farm_load_snapshot(uint32_t idx, const char *tag) +static int visit_vdi_obj_entry(struct trunk_entry *entry, void *data) +{ + int ret = -1; + size_t size; + struct sd_inode *inode; + struct vdi_option *opt = (struct vdi_option *)data; + + if (!is_vdi_obj(entry->oid)) + return 0; + + inode = slice_read(entry->sha1, &size); + if (!inode) { + sd_err("Fail to load vdi object, oid %"PRIx64, entry->oid); + goto out; + } + + if (opt->count == 0) { + if (opt->enable_if_blank) + opt->func(inode); + } else { + for (int i = 0; i < opt->count; i++) + if (!strcmp(inode->name, opt->name[i])) { + opt->func(inode); + break; + } + } + + ret = 0; +out: + free(inode); + return ret; +} + +static void do_register_obj(uint64_t oid) +{ + struct registered_obj_entry *new; + + new = xmalloc(sizeof(*new)); + new->oid = oid; + if (rb_search(®istered_obj_tree, new, rb, registered_obj_cmp)) { + free(new); + return; + } + + rb_insert(®istered_obj_tree, new, rb, registered_obj_cmp); + obj_to_load++; +} + +static void register_obj(struct sd_inode *inode) +{ + do_register_obj(vid_to_vdi_oid(inode->vdi_id)); + + for (int i = 0; i < SD_INODE_DATA_INDEX; i++) { + if (!inode->data_vdi_id[i]) + continue; + + do_register_obj(vid_to_data_oid(inode->data_vdi_id[i], i)); + } +} + +int farm_load_snapshot(uint32_t idx, const char *tag, int count, char **name) { int ret = -1; unsigned char trunk_sha1[SHA1_DIGEST_SIZE]; + struct vdi_option opt; if (get_trunk_sha1(idx, tag, trunk_sha1) < 0) goto out; + opt.count = count; + opt.name = name; + opt.func = register_obj; + opt.enable_if_blank = false; + + if (for_each_entry_in_trunk(trunk_sha1, visit_vdi_obj_entry, &opt) < 0) + goto out; + + if (count > 0 && obj_to_load == 0) { + sd_err("Objects of specified VDIs are not found " + "in local cluster snapshot storage."); + goto out; + } + wq = create_work_queue("load snapshot", WQ_DYNAMIC); if (for_each_entry_in_trunk(trunk_sha1, queue_load_snapshot_work, NULL) < 0) @@ -466,5 +566,38 @@ int farm_load_snapshot(uint32_t idx, const char *tag) out: rb_destroy(&active_vdi_tree, struct active_vdi_entry, rb); rb_destroy(®istered_vdi_tree, struct registered_vdi_entry, rb); + rb_destroy(®istered_obj_tree, struct registered_obj_entry, rb); + return ret; +} + +static void print_vdi(struct sd_inode *inode) +{ + static int seq; + + sd_info("%d. VDI id: %"PRIx32", name: %s, tag: %s", + ++seq, inode->vdi_id, inode->name, inode->tag); +} + +int farm_show_snapshot(uint32_t idx, const char *tag, int count, char **name) +{ + int ret = -1; + unsigned char trunk_sha1[SHA1_DIGEST_SIZE]; + struct vdi_option opt; + + if (get_trunk_sha1(idx, tag, trunk_sha1) < 0) + goto out; + + opt.count = count; + opt.name = name; + opt.func = print_vdi; + opt.enable_if_blank = true; + + if (for_each_entry_in_trunk(trunk_sha1, visit_vdi_obj_entry, &opt) < 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..b95006a 100644 --- a/dog/farm/farm.h +++ b/dog/farm/farm.h @@ -49,11 +49,19 @@ struct snap_log { unsigned char trunk_sha1[SHA1_DIGEST_SIZE]; }; +struct vdi_option { + int count; + char **name; + void (*func)(struct sd_inode *inode); + bool enable_if_blank; +}; + /* 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, int count, char **name); +int farm_show_snapshot(uint32_t idx, const char *tag, int count, char **name); char *get_object_directory(void); /* trunk.c */ -- 1.8.3.2 -- sheepdog mailing list sheepdog@lists.wpkg.org http://lists.wpkg.org/mailman/listinfo/sheepdog