[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