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
