At Mon, 28 Jul 2014 14:21:37 +0800, 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 > > v4 is rebased on the latest master. > > 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(-)
Applied, thanks. Hitoshi > > diff --git a/dog/cluster.c b/dog/cluster.c > index ba44ad9..188d4f4 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}, > }; > > @@ -659,7 +730,8 @@ static struct subcommand cluster_cmd[] = { > NULL, CMD_NEED_NODELIST, cluster_format, cluster_options}, > {"shutdown", NULL, "apht", "stop Sheepdog", > NULL, 0, cluster_shutdown, cluster_options}, > - {"snapshot", "<tag|idx> <path>", "apht", "snapshot/restore the cluster", > + {"snapshot", "<tag|idx> <path> [vdi1] [vdi2] ...", > + "apht", "snapshot/restore the cluster", > cluster_snapshot_cmd, CMD_NEED_ARG, > cluster_snapshot, cluster_options}, > {"recover", NULL, "afpht", > diff --git a/dog/farm/farm.c b/dog/farm/farm.c > index fb2b08d..e4f532e 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 iff 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 -- sheepdog mailing list sheepdog@lists.wpkg.org http://lists.wpkg.org/mailman/listinfo/sheepdog