From: MORITA Kazutaka <[email protected]>

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 <[email protected]>
---
 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

-- 
sheepdog mailing list
[email protected]
http://lists.wpkg.org/mailman/listinfo/sheepdog

Reply via email to