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 26bd84c..727aa26 100644 --- a/sheep/ops.c +++ b/sheep/ops.c @@ -760,6 +760,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) { @@ -1246,6 +1258,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 8281149..1610601 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 |