[sheepdog] [PATCH 2/2] collie: introduce '-o, --oid' option to 'collie vdi read' command

Yunkai Zhang yunkai.me at gmail.com
Mon Aug 20 16:28:10 CEST 2012


From: Yunkai Zhang <qiushu.zyk at taobao.com>

This option is useful when we known the replicas of one object are different
(for example: we have checked it by executing 'collie vdi check' command), and
we want to export the specify replica of that object. It can help us to test
wich replica is correct.

The format of this option is:
$ collie vdi read --oid oid at host:port[,oid2 at host2:port2]... <vdiname>

For example:

# Specify one replica of 7c2b2500000001 object to be exported:
$ collie vdi read --oid 7c2b2500000001 at 127.0.0.1:7000 linux.img

# Specify replicas of 7c2b2500000001 and 7c2b2500000002 objects:
$ collie vdi read --oid 7c2b2500000001 at 127.0.0.1:7000,7c2b2500000002:127.0.0.1:7003 linux.img

Signed-off-by: Yunkai Zhang <qiushu.zyk at taobao.com>
---
 collie/collie.c |  9 ++++--
 collie/collie.h |  3 ++
 collie/common.c | 38 ++++++++++++++++++++++++
 collie/vdi.c    | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 4 files changed, 134 insertions(+), 7 deletions(-)

diff --git a/collie/collie.c b/collie/collie.c
index 442f3fe..86dfc8c 100644
--- a/collie/collie.c
+++ b/collie/collie.c
@@ -321,7 +321,9 @@ void subcommand_usage(char *cmd, char *subcmd, int status)
 	for (i = 0; i < len; i++) {
 		sd_opt = find_opt(command_options[i]);
 		if (sd_opt->has_arg)
-			printf(" [-%c %s]", sd_opt->val, sd_opt->name);
+			printf(" [-%c %s]", sd_opt->val,
+			       sd_opt->arg_desc ?
+			       sd_opt->arg_desc : sd_opt->name);
 		else
 			printf(" [-%c]", sd_opt->val);
 	}
@@ -339,8 +341,9 @@ void subcommand_usage(char *cmd, char *subcmd, int status)
 	printf("Options:\n");
 	for (i = 0; i < len; i++) {
 		sd_opt = find_opt(command_options[i]);
-		sprintf(name, "-%c, --%s", sd_opt->val, sd_opt->name);
-		printf("  %-24s%s\n", name, sd_opt->desc);
+		sprintf(name, "-%c, --%s %s", sd_opt->val, sd_opt->name,
+			sd_opt->arg_desc ? sd_opt->arg_desc : "");
+		printf("  %-26s%s\n", name, sd_opt->desc);
 	}
 
 	exit(status);
diff --git a/collie/collie.h b/collie/collie.h
index c02fc76..4de44dd 100644
--- a/collie/collie.h
+++ b/collie/collie.h
@@ -33,6 +33,7 @@ struct sd_option {
 	const char *name;
 	int has_arg;
 	const char *desc;
+	const char *arg_desc;
 };
 
 struct command {
@@ -72,6 +73,8 @@ typedef void (*vdi_parser_func_t)(uint32_t vid, char *name, char *tag,
 int parse_vdi(vdi_parser_func_t func, size_t size, void *data);
 int sd_read_object(uint64_t oid, void *data, unsigned int datalen,
 		   uint64_t offset);
+int sd_read_object_directly(uint64_t oid, void *data, unsigned int datalen,
+		   uint64_t offset, const char *host, int port);
 int sd_write_object(uint64_t oid, uint64_t cow_oid, void *data, unsigned int datalen,
 		    uint64_t offset, uint32_t flags, int copies, int create);
 int send_light_req(struct sd_req *hdr, const char *host, int port);
diff --git a/collie/common.c b/collie/common.c
index f885c8c..164271a 100644
--- a/collie/common.c
+++ b/collie/common.c
@@ -42,6 +42,44 @@ char *size_to_str(uint64_t _size, char *str, int str_size)
 	return str;
 }
 
+int sd_read_object_directly(uint64_t oid, void *data, unsigned int datalen,
+		   uint64_t offset, const char *host, int port)
+{
+	struct sd_req hdr;
+	struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
+	int fd, ret;
+	unsigned wlen = 0, rlen = datalen;
+
+	fd = connect_to(host, port);
+	if (fd < 0) {
+		fprintf(stderr, "Failed to connect\n");
+		return SD_RES_EIO;
+	}
+
+	sd_init_req(&hdr, SD_OP_READ_PEER);
+	hdr.epoch = sd_epoch;
+	hdr.data_length = rlen;
+
+	hdr.obj.oid = oid;
+	hdr.obj.offset = offset;
+
+	ret = exec_req(fd, &hdr, data, &wlen, &rlen);
+	close(fd);
+
+	if (ret) {
+		fprintf(stderr, "Failed to read object %" PRIx64 "\n", oid);
+		return SD_RES_EIO;
+	}
+
+	if (rsp->result != SD_RES_SUCCESS) {
+		fprintf(stderr, "Failed to read object %" PRIx64 " %s\n", oid,
+			sd_strerror(rsp->result));
+		return rsp->result;
+	}
+
+	return SD_RES_SUCCESS;
+}
+
 int sd_read_object(uint64_t oid, void *data, unsigned int datalen,
 		   uint64_t offset)
 {
diff --git a/collie/vdi.c b/collie/vdi.c
index 4d686a5..2e37fdb 100644
--- a/collie/vdi.c
+++ b/collie/vdi.c
@@ -23,10 +23,19 @@ static struct sd_option vdi_options[] = {
 	{'x', "exclusive", 0, "write in an exclusive mode"},
 	{'d', "delete", 0, "delete a key"},
 	{'F', "force_repair", 0, "force repair object's copies (dangerous)"},
+	{'o', "oid", 1, "specify oid[s] to be exported, format: "
+			"oid at host:port[,oid2 at host2:port2]...",
+			"oid at host:port"},
 
 	{ 0, NULL, 0, NULL },
 };
 
+struct oid_arg {
+	uint64_t oid;
+	char host[128];
+	int port;
+};
+
 struct vdi_cmd_data {
 	unsigned int index;
 	int snapshot_id;
@@ -35,6 +44,8 @@ struct vdi_cmd_data {
 	int delete;
 	int prealloc;
 	int force_repair;
+	struct oid_arg *oid_args;
+	int nr_oid_args;
 } vdi_cmd_data = { ~0, };
 
 struct get_vdi_info {
@@ -1094,6 +1105,25 @@ static int vdi_getattr(int argc, char **argv)
 	return EXIT_SUCCESS;
 }
 
+static int cmp_oid_args(const void *a, const void *b)
+{
+	const struct oid_arg *oa1 = a;
+	const struct oid_arg *oa2 = b;
+
+	if (oa1->oid > oa2->oid)
+		return 1;
+	else if (oa1->oid == oa2->oid)
+		return 0;
+	else
+		return -1;
+}
+
+static struct oid_arg *find_oid(uint64_t oid)
+{
+	return bsearch(&oid, vdi_cmd_data.oid_args, vdi_cmd_data.nr_oid_args,
+		     sizeof(struct oid_arg), cmp_oid_args);
+}
+
 static int vdi_read(int argc, char **argv)
 {
 	char *vdiname = argv[optind++];
@@ -1102,6 +1132,7 @@ static int vdi_read(int argc, char **argv)
 	struct sheepdog_inode *inode = NULL;
 	uint64_t offset = 0, oid, done = 0, total = (uint64_t) -1;
 	unsigned int len, remain;
+	struct oid_arg *oa;
 	char *buf = NULL;
 
 	if (argv[optind]) {
@@ -1134,7 +1165,14 @@ static int vdi_read(int argc, char **argv)
 		ret = EXIT_FAILURE;
 		goto out;
 	}
-	ret = sd_read_object(vid_to_vdi_oid(vid), inode, SD_INODE_SIZE, 0);
+
+	oid = vid_to_vdi_oid(vid);
+	oa = find_oid(oid);
+	if (oa)
+		ret = sd_read_object_directly(oid, inode, SD_INODE_SIZE, 0,
+					      oa->host, oa->port);
+	else
+		ret = sd_read_object(oid, inode, SD_INODE_SIZE, 0);
 	if (ret != SD_RES_SUCCESS) {
 		fprintf(stderr, "Failed to read an inode\n");
 		ret = EXIT_FAILURE;
@@ -1156,7 +1194,13 @@ static int vdi_read(int argc, char **argv)
 
 		if (inode->data_vdi_id[idx]) {
 			oid = vid_to_data_oid(inode->data_vdi_id[idx], idx);
-			ret = sd_read_object(oid, buf, len, offset);
+			oa = find_oid(oid);
+			if (oa)
+				ret = sd_read_object_directly(oid, buf, len,
+							      offset, oa->host,
+							      oa->port);
+			else
+				ret = sd_read_object(oid, buf, len, offset);
 			if (ret != SD_RES_SUCCESS) {
 				fprintf(stderr, "Failed to read VDI\n");
 				ret = EXIT_FAILURE;
@@ -1536,7 +1580,7 @@ static struct subcommand vdi_cmd[] = {
 	{"resize", "<vdiname> <new size>", "aph", "resize an image",
 	 NULL, SUBCMD_FLAG_NEED_NODELIST|SUBCMD_FLAG_NEED_THIRD_ARG,
 	 vdi_resize, vdi_options},
-	{"read", "<vdiname> [<offset> [<len>]]", "saph", "read data from an image",
+	{"read", "<vdiname> [<offset> [<len>]]", "osaph", "read data from an image",
 	 NULL, SUBCMD_FLAG_NEED_NODELIST|SUBCMD_FLAG_NEED_THIRD_ARG,
 	 vdi_read, vdi_options},
 	{"write", "<vdiname> [<offset> [<len>]]", "aph", "write data to an image",
@@ -1547,7 +1591,9 @@ static struct subcommand vdi_cmd[] = {
 
 static int vdi_parser(int ch, char *opt)
 {
-	char *p;
+	int n;
+	char *p, *q;
+	struct oid_arg *oa;
 
 	switch (ch) {
 	case 'P':
@@ -1577,6 +1623,43 @@ static int vdi_parser(int ch, char *opt)
 	case 'd':
 		vdi_cmd_data.delete = 1;
 		break;
+	case 'o':
+		n = 1;
+		p = opt;
+		while ((q = strchr(p, ','))) {
+			p = ++q;
+			n++;
+		}
+
+		oa = xmalloc(n * sizeof(struct oid_arg));
+		vdi_cmd_data.oid_args = oa;
+		vdi_cmd_data.nr_oid_args = 0;
+		q = opt;
+		do {
+			/* oid */
+			sscanf(q, "%"PRIx64"@", &oa->oid);
+
+			/* host */
+			p = strchr(q, '@');
+			p++;
+			q = strchr(p, ':');
+			strncpy(oa->host, p, q - p);
+			oa->host[q - p] = 0;
+
+			/* port */
+			sscanf(++q, "%d", &oa->port);
+
+			oa++;
+			vdi_cmd_data.nr_oid_args++;
+			q = strchr(p, ',');
+		} while (q && *(++q));
+
+		/* sort oid_args */
+		qsort(vdi_cmd_data.oid_args,
+		      vdi_cmd_data.nr_oid_args,
+		      sizeof(struct oid_arg),
+		      cmp_oid_args);
+		break;
 	}
 
 	return 0;
-- 
1.7.11.2




More information about the sheepdog mailing list