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

Yunkai Zhang yunkai.me at gmail.com
Tue Aug 21 16:09:43 CEST 2012


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

V2:
- just do rebase
----------------- >8

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    | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 4 files changed, 133 insertions(+), 7 deletions(-)

diff --git a/collie/collie.c b/collie/collie.c
index c1b1854..a3fb31c 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_opts[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_opts[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 7f93ded..947cd22 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 83a2c3d..712a439 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 b479efd..015733c 100644
--- a/collie/vdi.c
+++ b/collie/vdi.c
@@ -24,10 +24,19 @@ static struct sd_option vdi_options[] = {
 	{'d', "delete", 0, "delete a key"},
 	{'C', "cache", 0, "enable object cache"},
 	{'R', "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;
@@ -37,6 +46,8 @@ struct vdi_cmd_data {
 	int prealloc;
 	int cache;
 	int repair;
+	struct oid_arg *oid_args;
+	int nr_oid_args;
 } vdi_cmd_data = { ~0, };
 
 struct get_vdi_info {
@@ -1096,6 +1107,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++];
@@ -1104,6 +1134,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]) {
@@ -1136,7 +1167,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;
@@ -1158,7 +1196,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;
@@ -1585,7 +1629,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>]]", "apCh", "write data to an image",
@@ -1599,7 +1643,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':
@@ -1628,6 +1674,42 @@ static int vdi_parser(int ch, char *opt)
 		break;
 	case 'C':
 		vdi_cmd_data.cache = 1;
+	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;
 	case 'R':
 		vdi_cmd_data.repair = 1;
-- 
1.7.11.2




More information about the sheepdog mailing list