[sheepdog] [PATCH 2/2] sheep: add support for upgrading sheep store
MORITA Kazutaka
morita.kazutaka at lab.ntt.co.jp
Fri Sep 28 19:37:04 CEST 2012
This adds a '-u' option to sheep usage. If we start a sheep daemon
with the option, it will upgrade the underlying store layout if
necessary.
Signed-off-by: MORITA Kazutaka <morita.kazutaka at lab.ntt.co.jp>
---
sheep/Makefile.am | 2 +-
sheep/config.c | 9 +++-
sheep/migrate.c | 177 ++++++++++++++++++++++++++++++++++++++++++++++++++++
sheep/sheep.c | 7 ++-
sheep/sheep_priv.h | 5 ++
5 files changed, 197 insertions(+), 3 deletions(-)
create mode 100644 sheep/migrate.c
diff --git a/sheep/Makefile.am b/sheep/Makefile.am
index 875542c..e7b4f53 100644
--- a/sheep/Makefile.am
+++ b/sheep/Makefile.am
@@ -27,7 +27,7 @@ sbin_PROGRAMS = sheep
sheep_SOURCES = sheep.c group.c request.c gateway.c store.c vdi.c work.c \
journal.c ops.c recovery.c cluster/local.c \
object_cache.c object_list_cache.c sockfd_cache.c \
- plain_store.c config.c
+ plain_store.c config.c migrate.c
if BUILD_COROSYNC
sheep_SOURCES += cluster/corosync.c
diff --git a/sheep/config.c b/sheep/config.c
index 8a9115c..04a934c 100644
--- a/sheep/config.c
+++ b/sheep/config.c
@@ -29,7 +29,7 @@ static struct sheepdog_config {
uint64_t space;
} config;
-static char *config_path;
+char *config_path;
#define CONFIG_PATH "/config"
@@ -94,6 +94,13 @@ int init_config_path(const char *base_path)
if (config.version != SD_FORMAT_VERSION) {
eprintf("This sheep version is not compatible with the existing "
"data layout, %d\n", config.version);
+ if (sys->upgrade) {
+ /* upgrade sheep store */
+ ret = sd_migrate_store(config.version, SD_FORMAT_VERSION);
+ goto out;
+ }
+
+ eprintf("use '-u' option to upgrade sheep store\n");
ret = -1;
goto out;
}
diff --git a/sheep/migrate.c b/sheep/migrate.c
new file mode 100644
index 0000000..bbad644
--- /dev/null
+++ b/sheep/migrate.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2012 Nippon Telegraph and Telephone Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "sheep_priv.h"
+
+extern char *config_path;
+
+/* sheepdog 0.4.0 */
+struct node_id_v0 {
+ uint8_t addr[16];
+ uint16_t port;
+};
+
+struct sd_node_v0 {
+ struct node_id_v0 nid;
+ uint16_t nr_vnodes;
+ uint32_t zone;
+};
+
+struct sheepdog_config_v0 {
+ uint64_t ctime;
+ uint16_t flags;
+ uint8_t copies;
+ uint8_t store[STORE_LEN];
+};
+
+/* sheepdog 0.5.1 */
+struct node_id_v1 {
+ uint8_t addr[16];
+ uint16_t port;
+};
+
+struct sd_node_v1 {
+ struct node_id_v1 nid;
+ uint16_t nr_vnodes;
+ uint32_t zone;
+ uint64_t space;
+};
+
+struct sheepdog_config_v1 {
+ uint64_t ctime;
+ uint16_t flags;
+ uint8_t copies;
+ uint8_t store[STORE_LEN];
+ uint8_t __pad[3];
+ uint16_t version;
+ uint64_t space;
+};
+
+
+static int migrate_from_v0_to_v1(void)
+{
+ int fd, ret, epoch, le, i;
+ char path[PATH_MAX];
+ struct sheepdog_config_v1 config;
+
+ fd = open(config_path, O_RDWR);
+ if (fd < 0) {
+ eprintf("failed to open config file, %m\n");
+ return -1;
+ }
+
+ memset(&config, 0, sizeof(config));
+ ret = xread(fd, &config, sizeof(config));
+ if (ret < 0) {
+ eprintf("failed to read config file, %m\n");
+ close(fd);
+ return ret;
+ }
+
+ /* If the config file contains a space field, the store layout
+ * is compatible with v1. In this case, what we need to do is
+ * only adding version number to the config file. */
+ if (config.space > 0) {
+ config.version = 1;
+ ret = xwrite(fd, &config, sizeof(config));
+ if (ret != sizeof(config)) {
+ eprintf("failed to write config data, %m\n");
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+ return 0;
+ }
+
+ /* upgrade epoch log */
+ le = get_latest_epoch();
+ for (epoch = 1; epoch <= le; epoch++) {
+ struct sd_node_v0 nodes_v0[SD_MAX_NODES];
+ struct sd_node_v1 nodes_v1[SD_MAX_NODES];
+ size_t nr_nodes;
+ time_t *t;
+ int len;
+
+ snprintf(path, sizeof(path), "%s%08u", epoch_path, epoch);
+ fd = open(path, O_RDWR | O_DSYNC);
+ if (fd < 0) {
+ if (errno == ENOENT)
+ continue;
+
+ eprintf("failed to open epoch %"PRIu32" log\n", epoch);
+ return -1;
+ }
+
+ ret = xread(fd, nodes_v0, sizeof(nodes_v0));
+ if (ret < 0) {
+ eprintf("failed to read epoch %"PRIu32" log\n", epoch);
+ close(fd);
+ return ret;
+ }
+
+ nr_nodes = ret / sizeof(nodes_v0[0]);
+ for (i = 0; i < nr_nodes; i++) {
+ memcpy(&nodes_v1[i].nid, &nodes_v0[i].nid,
+ sizeof(struct node_id_v1));
+ nodes_v1[i].nr_vnodes = nodes_v0[i].nr_vnodes;
+ nodes_v1[i].zone = nodes_v0[i].zone;
+ nodes_v1[i].space = 0;
+ }
+
+ len = sizeof(nodes_v1[0]) * nr_nodes;
+ ret = xpwrite(fd, nodes_v1, len, 0);
+ if (ret != len) {
+ eprintf("failed to write epoch %"PRIu32" log\n", epoch);
+ close(fd);
+ return -1;
+ }
+
+ t = (time_t *)&nodes_v0[nr_nodes];
+
+ ret = xpwrite(fd, t, sizeof(*t), len);
+ if (ret != sizeof(*t)) {
+ eprintf("failed to write time to epoch %"PRIu32" log\n",
+ epoch);
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+ }
+
+ return ret;
+}
+
+static int (*migrate[])(void) = {
+ migrate_from_v0_to_v1, /* from 0.4.0 or 0.5.0 to 0.5.1 */
+};
+
+int sd_migrate_store(int from, int to)
+{
+ int ver, ret;
+
+ assert(to <= sizeof(migrate));
+
+ for (ver = from; ver < to; ver++) {
+ ret = migrate[ver]();
+ if (ret < 0)
+ return ret;
+ }
+
+ /* success */
+ return 0;
+}
diff --git a/sheep/sheep.c b/sheep/sheep.c
index cf42205..d4405ab 100644
--- a/sheep/sheep.c
+++ b/sheep/sheep.c
@@ -51,13 +51,14 @@ static struct option const long_options[] = {
{"stdout", no_argument, NULL, 'o'},
{"port", required_argument, NULL, 'p'},
{"disk-space", required_argument, NULL, 's'},
+ {"upgrade", no_argument, NULL, 'u'},
{"zone", required_argument, NULL, 'z'},
{"pidfile", required_argument, NULL, 'P'},
{"write-cache", required_argument, NULL, 'w'},
{NULL, 0, NULL, 0},
};
-static const char *short_options = "b:c:dDfghjl:op:P:s:w:y:z:";
+static const char *short_options = "b:c:dDfghjl:op:P:s:uw:y:z:";
static void usage(int status)
{
@@ -81,6 +82,7 @@ Options:\n\
-p, --port specify the TCP port on which to listen\n\
-P, --pidfile create a pid file\n\
-s, --disk-space specify the free disk space in megabytes\n\
+ -u, --upgrade upgrade to the latest data layout\n\
-y, --myaddr specify the address advertised to other sheep\n\
-z, --zone specify the zone id\n\
-w, --write-cache specify the cache type\n\
@@ -402,6 +404,9 @@ int main(int argc, char **argv)
}
sys->disk_space = free_space * 1024 * 1024;
break;
+ case 'u':
+ sys->upgrade = true;
+ break;
case 'c':
sys->cdrv = find_cdrv(optarg);
if (!sys->cdrv) {
diff --git a/sheep/sheep_priv.h b/sheep/sheep_priv.h
index f80c5f8..ecfeb5f 100644
--- a/sheep/sheep_priv.h
+++ b/sheep/sheep_priv.h
@@ -124,6 +124,8 @@ struct cluster_info {
bool object_cache_directio;
bool use_journal;
+ bool upgrade; /* upgrade data layout before starting service
+ * if necessary*/
};
struct siocb {
@@ -386,6 +388,9 @@ void object_cache_delete(uint32_t vid);
int object_cache_init(const char *p);
void object_cache_remove(uint64_t oid);
+/* store layout migration */
+int sd_migrate_store(int from, int to);
+
/* sockfd_cache */
struct sockfd {
int fd;
--
1.7.2.5
More information about the sheepdog
mailing list