[sheepdog] [PATCH v4 07/10] sheep: add operation to get object sha1 digest

MORITA Kazutaka morita.kazutaka at gmail.com
Tue May 14 09:00:16 CEST 2013


From: MORITA Kazutaka <morita.kazutaka at lab.ntt.co.jp>

Currently, we compare entire object contents to check whether there is
no difference among them.  However, this wastes a lot of network
bandwidth and some operations like vdi check or object recovery take
too long time to complete.

This adds an operation SD_OP_GET_HASH to get the sha1 digest of the
object, and enables us to do faster vdi check and recovery.

Signed-off-by: MORITA Kazutaka <morita.kazutaka at lab.ntt.co.jp>
---
 include/internal_proto.h |    1 +
 include/sha1.h           |    1 +
 include/sheepdog_proto.h |    5 +++++
 lib/sha1.c               |   15 +++++++++++++++
 sheep/farm/farm.c        |    1 +
 sheep/farm/farm.h        |    1 -
 sheep/farm/sha1_file.c   |   15 ---------------
 sheep/ops.c              |   18 ++++++++++++++++++
 sheep/plain_store.c      |   41 +++++++++++++++++++++++++++++++++++++++++
 sheep/sheep_priv.h       |    2 ++
 10 files changed, 84 insertions(+), 16 deletions(-)

diff --git a/include/internal_proto.h b/include/internal_proto.h
index 995e213..a04af88 100644
--- a/include/internal_proto.h
+++ b/include/internal_proto.h
@@ -72,6 +72,7 @@
 #define SD_OP_MD_INFO   0xB1
 #define SD_OP_MD_PLUG   0xB2
 #define SD_OP_MD_UNPLUG 0xB3
+#define SD_OP_GET_HASH       0xB4
 
 /* internal flags for hdr.flags, must be above 0x80 */
 #define SD_FLAG_CMD_RECOVERY 0x0080
diff --git a/include/sha1.h b/include/sha1.h
index 1043b30..332f5c1 100644
--- a/include/sha1.h
+++ b/include/sha1.h
@@ -23,5 +23,6 @@ struct sha1_ctx {
 void sha1_init(void *ctx);
 void sha1_update(void *ctx, const uint8_t *data, unsigned int len);
 void sha1_final(void *ctx, uint8_t *out);
+const char *sha1_to_hex(const unsigned char *sha1);
 
 #endif
diff --git a/include/sheepdog_proto.h b/include/sheepdog_proto.h
index 0916948..e211ce3 100644
--- a/include/sheepdog_proto.h
+++ b/include/sheepdog_proto.h
@@ -180,6 +180,11 @@ struct sd_rsp {
 			uint64_t	store_size;
 			uint64_t	store_free;
 		} node;
+		struct {
+			uint32_t	__pad1;
+			uint32_t	__pad2;
+			uint8_t		digest[20];
+		} hash;
 
 		uint32_t		__pad[8];
 	};
diff --git a/lib/sha1.c b/lib/sha1.c
index 8d3399a..c1ada09 100644
--- a/lib/sha1.c
+++ b/lib/sha1.c
@@ -197,3 +197,18 @@ void sha1_final(void *ctx, uint8_t *out)
 	/* Wipe context */
 	memset(sctx, 0, sizeof *sctx);
 }
+
+const char *sha1_to_hex(const unsigned char *sha1)
+{
+	static __thread char buffer[50];
+	static const char hex[] = "0123456789abcdef";
+	char *buf = buffer;
+	int i;
+
+	for (i = 0; i < SHA1_DIGEST_SIZE; i++) {
+		unsigned int val = *sha1++;
+		*buf++ = hex[val >> 4];
+		*buf++ = hex[val & 0xf];
+	}
+	return buffer;
+}
diff --git a/sheep/farm/farm.c b/sheep/farm/farm.c
index cca8bbd..c31c501 100644
--- a/sheep/farm/farm.c
+++ b/sheep/farm/farm.c
@@ -266,6 +266,7 @@ static struct store_driver farm = {
 	.format = default_format,
 	.purge_obj = default_purge_obj,
 	.remove_object = default_remove_object,
+	.get_hash = default_get_hash,
 };
 
 add_store_driver(farm);
diff --git a/sheep/farm/farm.h b/sheep/farm/farm.h
index 0fbdf12..41208e7 100644
--- a/sheep/farm/farm.h
+++ b/sheep/farm/farm.h
@@ -47,7 +47,6 @@ extern char farm_obj_dir[PATH_MAX];
 char *sha1_to_path(const unsigned char *sha1);
 int sha1_file_write(unsigned char *buf, unsigned len, unsigned char *);
 void *sha1_file_read(const unsigned char *sha1, struct sha1_file_hdr *);
-char *sha1_to_hex(const unsigned char *sha1);
 int get_sha1_hex(const char *hex, unsigned char *sha1);
 int sha1_file_try_delete(const unsigned char *sha1);
 
diff --git a/sheep/farm/sha1_file.c b/sheep/farm/sha1_file.c
index 3883d95..dd29e23 100644
--- a/sheep/farm/sha1_file.c
+++ b/sheep/farm/sha1_file.c
@@ -256,18 +256,3 @@ int get_sha1_hex(const char *hex, unsigned char *sha1)
 	}
 	return 0;
 }
-
-char *sha1_to_hex(const unsigned char *sha1)
-{
-	static char buffer[50];
-	static const char hex[] = "0123456789abcdef";
-	char *buf = buffer;
-	int i;
-
-	for (i = 0; i < SHA1_LEN; i++) {
-		unsigned int val = *sha1++;
-		*buf++ = hex[val >> 4];
-		*buf++ = hex[val & 0xf];
-	}
-	return buffer;
-}
diff --git a/sheep/ops.c b/sheep/ops.c
index e40fc65..8ab9ac3 100644
--- a/sheep/ops.c
+++ b/sheep/ops.c
@@ -761,6 +761,18 @@ static int local_md_unplug(const struct sd_req *req, struct sd_rsp *rsp,
 	return md_unplug_disks(disks);
 }
 
+static int local_get_hash(struct request *request)
+{
+	struct sd_req *req = &request->rq;
+	struct sd_rsp *rsp = &request->rp;
+
+	if (!sd_store->get_hash)
+		return SD_RES_NO_SUPPORT;
+
+	return sd_store->get_hash(req->obj.oid, req->obj.tgt_epoch,
+				  rsp->hash.digest);
+}
+
 static int cluster_restore(const struct sd_req *req, struct sd_rsp *rsp,
 			   void *data)
 {
@@ -1247,6 +1259,12 @@ static struct sd_op_template sd_ops[] = {
 		.process_main = local_md_unplug,
 	},
 
+	[SD_OP_GET_HASH] = {
+		.name = "GET_HASH",
+		.type = SD_OP_TYPE_LOCAL,
+		.process_work = local_get_hash,
+	},
+
 	/* gateway I/O operations */
 	[SD_OP_CREATE_AND_WRITE_OBJ] = {
 		.name = "CREATE_AND_WRITE_OBJ",
diff --git a/sheep/plain_store.c b/sheep/plain_store.c
index c44a42f..3b71467 100644
--- a/sheep/plain_store.c
+++ b/sheep/plain_store.c
@@ -17,6 +17,7 @@
 
 #include "sheep_priv.h"
 #include "config.h"
+#include "sha1.h"
 
 static int get_open_flags(uint64_t oid, bool create)
 {
@@ -475,6 +476,45 @@ int default_remove_object(uint64_t oid)
 	return SD_RES_SUCCESS;
 }
 
+int default_get_hash(uint64_t oid, uint32_t epoch, uint8_t *sha1)
+{
+	int ret;
+	void *buf;
+	struct siocb iocb = {};
+	struct sha1_ctx c;
+	uint64_t offset = 0;
+	uint32_t length;
+
+	length = get_objsize(oid);
+	buf = malloc(length);
+	if (buf == NULL)
+		return SD_RES_NO_MEM;
+
+	iocb.epoch = epoch;
+	iocb.buf = buf;
+	iocb.length = length;
+
+	ret = default_read(oid, &iocb);
+	if (ret != SD_RES_SUCCESS) {
+		free(buf);
+		return ret;
+	}
+
+	trim_zero_sectors(buf, &offset, &length);
+
+	sha1_init(&c);
+	sha1_update(&c, (uint8_t *)&offset, sizeof(offset));
+	sha1_update(&c, (uint8_t *)&length, sizeof(length));
+	sha1_update(&c, buf, length);
+	sha1_final(&c, sha1);
+	free(buf);
+
+	sd_dprintf("the message digest of %"PRIx64" at epoch %d is %s", oid,
+		   epoch, sha1_to_hex(sha1));
+
+	return ret;
+}
+
 int default_purge_obj(void)
 {
 	uint32_t tgt_epoch = get_latest_epoch();
@@ -494,6 +534,7 @@ static struct store_driver plain_store = {
 	.cleanup = default_cleanup,
 	.format = default_format,
 	.remove_object = default_remove_object,
+	.get_hash = default_get_hash,
 	.purge_obj = default_purge_obj,
 };
 
diff --git a/sheep/sheep_priv.h b/sheep/sheep_priv.h
index 27aec3f..56c512a 100644
--- a/sheep/sheep_priv.h
+++ b/sheep/sheep_priv.h
@@ -166,6 +166,7 @@ struct store_driver {
 	int (*read)(uint64_t oid, const struct siocb *);
 	int (*format)(void);
 	int (*remove_object)(uint64_t oid);
+	int (*get_hash)(uint64_t oid, uint32_t epoch, uint8_t *sha1);
 	/* Operations in recovery */
 	int (*link)(uint64_t oid, uint32_t tgt_epoch);
 	int (*update_epoch)(uint32_t epoch);
@@ -187,6 +188,7 @@ int default_update_epoch(uint32_t epoch);
 int default_cleanup(void);
 int default_format(void);
 int default_remove_object(uint64_t oid);
+int default_get_hash(uint64_t oid, uint32_t epoch, uint8_t *sha1);
 int default_purge_obj(void);
 int for_each_object_in_wd(int (*func)(uint64_t, char *, void *), bool, void *);
 int for_each_obj_path(int (*func)(char *path));
-- 
1.7.9.5




More information about the sheepdog mailing list