On Tue, Jul 1, 2014 at 11:23 AM, Ruoyu <[email protected]> wrote: > Any feedback for the patch?
Looks good to me. Could you rebase it on the latest master? Thanks, Hitoshi > > > On 2014年06月18日 17:08, Ruoyu wrote: >> >> 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 <[email protected]> >> --- >> 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 */ > > > > -- > sheepdog mailing list > [email protected] > http://lists.wpkg.org/mailman/listinfo/sheepdog -- sheepdog mailing list [email protected] http://lists.wpkg.org/mailman/listinfo/sheepdog
