From: Liu Yuan <tailai.ly at taobao.com> For storing one object into backend store, either a) no content change, then point to the same old sha1_file (no stale object) or b) content updated, then will point to a new object with a new sha1. So we need to remove stale object in case b), only in the assumption it is the object generated by recovery code. [*] When we try store new snapshot object into the backend store, it is safe and good timing for us to remove the old object with the same object ID. [*] Here I assume we don't need to restore to 'sys epoch' state. Signed-off-by: Liu Yuan <tailai.ly at taobao.com> --- sheep/farm/trunk.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 133 insertions(+), 3 deletions(-) diff --git a/sheep/farm/trunk.c b/sheep/farm/trunk.c index ec36081..fd0a525 100644 --- a/sheep/farm/trunk.c +++ b/sheep/farm/trunk.c @@ -1,5 +1,7 @@ #include <pthread.h> #include <dirent.h> +#include <sys/stat.h> +#include <unistd.h> #include "farm.h" #include "strbuf.h" @@ -19,6 +21,11 @@ static struct hlist_head trunk_hashtable[HASH_SIZE]; static pthread_mutex_t hashtable_lock[HASH_SIZE] = { [0 ... HASH_SIZE - 1] = PTHREAD_MUTEX_INITIALIZER }; static unsigned int trunk_entry_active_nr; +struct omap_entry { + uint64_t oid; + unsigned char sha1[SHA1_LEN]; +}; + static inline int trunk_entry_is_dirty(struct __trunk_entry *entry) { return entry->flags & TRUNK_ENTRY_DIRTY; @@ -78,6 +85,27 @@ out: return entry; } +static int create_files(void) +{ + int fd, ret = 0; + struct strbuf buf = STRBUF_INIT; + + strbuf_addstr(&buf, farm_dir); + strbuf_addf(&buf, "/%s", "obj_map"); + + fd = open(buf.buf, O_CREAT | O_EXCL, 0666); + if (fd < 0) { + if (errno != EEXIST) { + ret = -1; + goto out; + } + } + close(fd); +out: + strbuf_release(&buf); + return ret; +} + int trunk_init(void) { DIR *dir; @@ -96,6 +124,10 @@ int trunk_init(void) continue; lookup_trunk_entry(oid, 1); } + + if (create_files() < 0) + return -1; + closedir(dir); return 0; } @@ -148,9 +180,92 @@ static void put_entry(struct __trunk_entry *entry) trunk_entry_active_nr--; } + +static int omap_file_init(struct strbuf *outbuf) +{ + int fd; + int len = -1; + void *buffer = NULL; + struct strbuf buf = STRBUF_INIT; + struct stat st; + + strbuf_addf(&buf, "%s/%s", farm_dir, "obj_map"); + fd = open(buf.buf, O_RDONLY); + if (fd < 0) + goto out; + + if (fstat(fd, &st) < 0) { + dprintf("%m\n"); + goto out_close; + } + + len = st.st_size; + if (len == 0) + goto out_close; + + buffer = xmalloc(len); + len = xread(fd, buffer, len); + if (len != st.st_size) { + len = -1; + goto out_close; + } + strbuf_add(outbuf, buffer, len); +out_close: + close(fd); +out: + strbuf_release(&buf); + free(buffer); + return len; +} + +static int omap_file_final(struct strbuf *omap_buf) +{ + int fd, ret = -1; + struct strbuf buf = STRBUF_INIT; + + if (omap_buf->len == 0) + return 0; + + strbuf_addf(&buf, "%s/%s", farm_dir, "obj_map"); + fd = open(buf.buf, O_WRONLY); + if (fd < 0) { + dprintf("%m\n"); + goto out; + } + + ret = xwrite(fd, omap_buf->buf, omap_buf->len); + if (ret != omap_buf->len) + ret = -1; + + close(fd); +out: + strbuf_release(&buf); + return ret; +} + +static struct omap_entry *omap_file_insert(struct strbuf *buf, struct omap_entry *new) +{ + unsigned i, nr = buf->len / sizeof(struct omap_entry); + struct omap_entry *omap_buf = (struct omap_entry *)buf->buf; + for (i = 0; i < nr; i++, omap_buf++) + if (omap_buf->oid == new->oid) { + if (memcmp(omap_buf->sha1, new->sha1, SHA1_LEN) == 0) + return NULL; + else { + struct omap_entry *old = xmalloc(sizeof(*old)); + memcpy(old, omap_buf, sizeof(*old)); + memcpy(omap_buf->sha1, new->sha1, SHA1_LEN); + return old; + } + } + dprintf("oid, %"PRIx64"\n", new->oid); + strbuf_add(buf, new, sizeof(*new)); + return NULL; +} + int trunk_file_write(unsigned char *outsha1, int user) { - struct strbuf buf; + struct strbuf buf, omap_buf = STRBUF_INIT; uint64_t data_size = sizeof(struct trunk_entry) * trunk_entry_active_nr; struct sha1_file_hdr hdr = { .size = data_size, .priv = trunk_entry_active_nr }; @@ -159,18 +274,32 @@ int trunk_file_write(unsigned char *outsha1, int user) memcpy(hdr.tag, TAG_TRUNK, TAG_LEN); strbuf_init(&buf, sizeof(hdr) + data_size); + omap_file_init(&omap_buf); strbuf_add(&buf, &hdr, sizeof(hdr)); list_for_each_entry_safe(entry, t, &trunk_active_list, active_list) { - if (trunk_entry_no_sha1(entry) || trunk_entry_is_dirty(entry)) { + if (trunk_entry_no_sha1(entry) || trunk_entry_is_dirty(entry)) if (fill_entry_new_sha1(entry) < 0) { ret = -1; goto out; } - } strbuf_add(&buf, &entry->raw, sizeof(struct trunk_entry)); + if (!user) { + struct omap_entry new = { .oid = entry->raw.oid }, *old; + memcpy(new.sha1, entry->raw.sha1, SHA1_LEN); + old = omap_file_insert(&omap_buf, &new); + if (old) { + dprintf("try delete stale %s, oid %"PRIx64"\n", + sha1_to_hex(old->sha1), old->oid); + sha1_file_delete(old->sha1); + free(old); + } + } put_entry(entry); } + if (omap_file_final(&omap_buf) < 0) + eprintf("omap_file_final failed\n"); + if (sha1_file_write((void *)buf.buf, buf.len, outsha1) < 0) { ret = -1; goto out; @@ -178,6 +307,7 @@ int trunk_file_write(unsigned char *outsha1, int user) dprintf("trunk sha1: %s\n", sha1_to_hex(outsha1)); out: strbuf_release(&buf); + strbuf_release(&omap_buf); return ret; } -- 1.7.8.rc3 |