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(&registered_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(&registered_obj_tree, new, rb, registered_obj_cmp)) {
> +             free(new);
> +             return;
> +     }
> +
> +     rb_insert(&registered_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(&registered_vdi_tree, struct registered_vdi_entry, rb);
> +     rb_destroy(&registered_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

Reply via email to