Command example:
*Usage*
Save all readonly objects to local path.
"tag" is used to describe a snapshot.
$collie cluster snapshot save tag /localpath

List all cluster snapshot saved in local path.
$collie cluster snapshot list /localpath

Load a snapshot to a cluster.
This will format cluster firstly.
User can use tag or index to select a snapshot.
$collie cluster snapshot load tag|idx /localpath

Signed-off-by: Kai Zhang <[email protected]>
---
 collie/cluster.c |  163 ++++++++++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 146 insertions(+), 17 deletions(-)

diff --git a/collie/cluster.c b/collie/cluster.c
index fa2e131..956243d 100644
--- a/collie/cluster.c
+++ b/collie/cluster.c
@@ -15,20 +15,18 @@
 #include <sys/time.h>
 
 #include "collie.h"
+#include "farm/farm.h"
 
 static struct sd_option cluster_options[] = {
        {'b', "store", true, "specify backend store"},
        {'c', "copies", true, "specify the default data redundancy (number of 
copies)"},
        {'m', "mode", true, "mode (safe, quorum, unsafe)"},
        {'f', "force", false, "do not prompt for confirmation"},
-       {'R', "restore", true, "restore the cluster"},
-       {'l', "list", false, "list the user epoch information"},
 
        { 0, NULL, false, NULL },
 };
 
 static struct cluster_cmd_data {
-       uint32_t epoch;
        bool list;
        int copies;
        bool nohalt;
@@ -223,6 +221,133 @@ static int cluster_shutdown(int argc, char **argv)
        return EXIT_SUCCESS;
 }
 
+static void print_list(void *buf, unsigned len)
+{
+       struct snap_log *log_buf = (struct snap_log *)buf;
+       unsigned nr = len / sizeof(struct snap_log), i;
+
+       printf("Index\t\tTag\t\tSnapshot Time\n");
+       for (i = 0; i < nr; i++, log_buf++) {
+               time_t *t = (time_t *)&log_buf->time;
+               printf("%d\t\t", log_buf->idx);
+               printf("%s\t\t", log_buf->tag);
+               printf("%s", ctime(t));
+       }
+}
+
+static int list_snapshot(int argc, char **argv)
+{
+       char *path = argv[optind++];
+       void *buf = NULL;
+       int log_nr;
+       int ret = EXIT_SYSFAIL;
+
+       if (farm_init(path) != SD_RES_SUCCESS)
+               goto out;
+
+       buf = snap_log_read(&log_nr);
+       if (!buf)
+               goto out;
+
+       print_list(buf, log_nr * sizeof(struct snap_log));
+       ret = EXIT_SUCCESS;
+out:
+       if (ret)
+               sd_eprintf("fail to list snapshot");
+       free(buf);
+       return ret;
+}
+
+static void fill_obj_tree(uint32_t vid, const char *name, const char *tag,
+                         uint32_t snapid, uint32_t flags,
+                         const struct sd_inode *i, void *data)
+{
+       uint64_t vdi_oid = vid_to_vdi_oid(vid);
+
+       /* ignore active vdi */
+       if (!i->snap_ctime)
+               return;
+
+       obj_tree_insert(vdi_oid, VDI, i->nr_copies);
+
+       for (int idx = 0; idx < MAX_DATA_OBJS; idx++) {
+               if (i->data_vdi_id[idx]) {
+                       uint64_t oid = vid_to_data_oid(i->data_vdi_id[idx],
+                                                      idx);
+                       obj_tree_insert(oid, OBJECT, i->nr_copies);
+               }
+       }
+}
+
+static int save_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) {
+               fprintf(stderr, "Tag should not start with number\n");
+               return EXIT_USAGE;
+       }
+
+       if (!argv[optind]) {
+               fprintf(stderr, "Please specify the path to save snapshot\n");
+               return EXIT_USAGE;
+       }
+       path = argv[optind];
+
+       if (parse_vdi(fill_obj_tree, SD_INODE_SIZE, NULL) != SD_RES_SUCCESS)
+               goto out;
+
+       if (farm_init(path) != SD_RES_SUCCESS)
+               goto out;
+
+       if (farm_save_snapshot(tag) != SD_RES_SUCCESS)
+               goto out;
+
+       ret = EXIT_SUCCESS;
+out:
+       if (ret)
+               fprintf(stderr, "fail to save snapshot to path: %s\n", path);
+       free_obj_tree();
+       return ret;
+}
+
+static int load_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;
+
+       if (!argv[optind]) {
+               fprintf(stderr, "Please specify the path to save snapshot\n");
+               return EXIT_USAGE;
+       }
+       path = argv[optind];
+
+       if (farm_init(path) != SD_RES_SUCCESS)
+               goto out;
+
+       if (cluster_format(0, NULL) != SD_RES_SUCCESS)
+               goto out;
+
+       if (farm_load_snapshot(idx, tag) != SD_RES_SUCCESS)
+               goto out;
+
+       ret = EXIT_SUCCESS;
+out:
+       if (ret)
+               fprintf(stderr, "fail to load snapshot\n");
+       return ret;
+}
+
 #define RECOVER_PRINT \
        "Caution! Please try starting all the cluster nodes normally before\n" \
        "running this command.\n\n" \
@@ -315,6 +440,21 @@ static int cluster_recover(int argc, char **argv)
        return do_generic_subcommand(cluster_recover_cmd, argc, argv);
 }
 
+/* Subcommand list of snapshot */
+static struct subcommand cluster_snapshot_cmd[] = {
+       {"save", NULL, "h", "save snapshot to localpath",
+        NULL, SUBCMD_FLAG_NEED_ARG, save_snapshot, NULL},
+       {"list", NULL, "h", "list snapshot of localpath",
+        NULL, SUBCMD_FLAG_NEED_ARG, list_snapshot, NULL},
+       {"load", NULL, "h", "list snapshot of localpath",
+        NULL, SUBCMD_FLAG_NEED_ARG, load_snapshot, NULL}
+};
+
+static int cluster_snapshot(int argc, char **argv)
+{
+       return do_generic_subcommand(cluster_snapshot_cmd, argc, argv);
+}
+
 static struct subcommand cluster_cmd[] = {
        {"info", NULL, "aprh", "show cluster information",
         NULL, SUBCMD_FLAG_NEED_NODELIST, cluster_info, cluster_options},
@@ -322,6 +462,9 @@ static struct subcommand cluster_cmd[] = {
         NULL, 0, cluster_format, cluster_options},
        {"shutdown", NULL, "aph", "stop Sheepdog",
         NULL, 0, cluster_shutdown, cluster_options},
+       {"snapshot", "<tag|idx> <path>", "aph", "snapshot/restore the cluster",
+        cluster_snapshot_cmd, SUBCMD_FLAG_NEED_ARG,
+        cluster_snapshot, cluster_options},
        {"recover", NULL, "afph",
         "See 'collie cluster recover' for more information\n",
         cluster_recover_cmd, SUBCMD_FLAG_NEED_ARG,
@@ -369,20 +512,6 @@ static int cluster_parser(int ch, char *opt)
        case 'f':
                cluster_cmd_data.force = true;
                break;
-       case 'R':
-               cluster_cmd_data.epoch = strtol(opt, &p, 10);
-               if (opt == p) {
-                       fprintf(stderr, "The epoch must be an integer\n");
-                       exit(EXIT_FAILURE);
-               }
-               if (cluster_cmd_data.epoch < 1) {
-                       fprintf(stderr, "The epoch must be greater than 0\n");
-                       exit(EXIT_FAILURE);
-               }
-               break;
-       case 'l':
-               cluster_cmd_data.list = true;
-               break;
        }
 
        return 0;
-- 
1.7.1

-- 
sheepdog mailing list
[email protected]
http://lists.wpkg.org/mailman/listinfo/sheepdog

Reply via email to