From: Liu Yuan <[email protected]>

trunk object is meta data that describes the structure of the data objects
at the timeline of snapshot being taken.

Signed-off-by: Liu Yuan <[email protected]>
---
 sheep/farm.h       |   26 +++++++
 sheep/farm/trunk.c |  209 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 235 insertions(+), 0 deletions(-)
 create mode 100644 sheep/farm/trunk.c

diff --git a/sheep/farm.h b/sheep/farm.h
index a07928f..77b6c15 100644
--- a/sheep/farm.h
+++ b/sheep/farm.h
@@ -18,11 +18,17 @@
 #include "sheepdog_proto.h"
 #include "sheep.h"
 #include "logger.h"
+#include "strbuf.h"
 
 #define SHA1_LEN        20
 #define HEX_LEN         40
 #define NAME_LEN        HEX_LEN
 
+#define TAG_LEN         6
+#define TAG_DATA        "data\0\0"
+#define TAG_TRUNK       "trunk\0"
+#define TAG_SNAP        "snap\0\0"
+
 struct sha1_file_hdr {
        char tag[TAG_LEN];
        uint64_t size;
@@ -30,6 +36,20 @@ struct sha1_file_hdr {
        uint64_t reserved;
 };
 
+struct trunk_entry {
+       uint64_t oid;
+       unsigned char sha1[SHA1_LEN];
+};
+
+struct __trunk_entry {
+       struct trunk_entry raw;
+       int flags;
+       struct list_head active_list;
+       struct hlist_node hash;
+};
+
+extern char *epoch_path;
+
 /* sha1_file.c */
 extern char *sha1_to_path(const unsigned char *sha1);
 extern int sha1_file_write(unsigned char *buf, unsigned len, unsigned char 
*outsha1);
@@ -38,4 +58,10 @@ extern char * sha1_to_hex(const unsigned char *sha1);
 extern int get_sha1_hex(const char *hex, unsigned char *sha1);
 extern int sha1_file_delete(const unsigned char *sha1);
 
+/* trunk.c */
+extern int trunk_init(void);
+extern int trunk_file_write(unsigned char *outsha1, int user);
+extern void *trunk_file_read(unsigned char *sha1, struct sha1_file_hdr *);
+extern int trunk_update_entry(uint64_t oid);
+
 #endif
diff --git a/sheep/farm/trunk.c b/sheep/farm/trunk.c
new file mode 100644
index 0000000..ec36081
--- /dev/null
+++ b/sheep/farm/trunk.c
@@ -0,0 +1,209 @@
+#include <pthread.h>
+#include <dirent.h>
+
+#include "farm.h"
+#include "strbuf.h"
+#include "list.h"
+#include "util.h"
+#include "sheepdog_proto.h"
+
+#define TRUNK_ENTRY_DIRTY      0x00000001
+
+#define trunk_entry_size() sizeof(struct __trunk_entry)
+
+#define HASH_BITS      10
+#define HASH_SIZE      (1 << HASH_BITS)
+
+static LIST_HEAD(trunk_active_list); /* no lock protection */
+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;
+
+static inline int trunk_entry_is_dirty(struct __trunk_entry *entry)
+{
+       return entry->flags & TRUNK_ENTRY_DIRTY;
+}
+
+static inline void mark_trunk_entry_dirty(struct __trunk_entry *entry)
+{
+       entry->flags |= TRUNK_ENTRY_DIRTY;
+}
+
+static inline int hash(uint64_t oid)
+{
+       return hash_64(oid, HASH_BITS);
+}
+
+static inline struct __trunk_entry *alloc_trunk_entry(void)
+{
+       return (struct __trunk_entry *)malloc(trunk_entry_size());
+}
+
+static inline void free_trunk_entry(struct __trunk_entry *entry)
+{
+       free(entry);
+}
+
+
+static void get_entry(struct __trunk_entry *entry, struct hlist_head *head)
+{
+       hlist_add_head(&entry->hash, head);
+       list_add(&entry->active_list, &trunk_active_list);
+       trunk_entry_active_nr++;
+}
+
+static struct __trunk_entry *lookup_trunk_entry(uint64_t oid, int create)
+{
+       int h = hash(oid);
+       struct hlist_head *head = trunk_hashtable + h;
+       struct __trunk_entry *entry = NULL;
+       struct hlist_node *node;
+
+       pthread_mutex_lock(&hashtable_lock[h]);
+       if (hlist_empty(head))
+               goto not_found;
+
+       hlist_for_each_entry(entry, node, head, hash) {
+               if (entry->raw.oid == oid)
+                       goto out;
+       }
+not_found:
+       if (create) {
+               entry = alloc_trunk_entry();
+               entry->raw.oid = oid;
+               get_entry(entry, head);
+       }
+out:
+       pthread_mutex_unlock(&hashtable_lock[h]);
+       return entry;
+}
+
+int trunk_init(void)
+{
+       DIR *dir;
+       struct dirent *d;
+       uint64_t oid;
+
+       dir = opendir(obj_path);
+       if (!dir)
+               return -1;
+
+       while ((d = readdir(dir))) {
+               if (!strncmp(d->d_name, ".", 1))
+                       continue;
+               oid = strtoull(d->d_name, NULL, 16);
+               if (oid == 0)
+                       continue;
+               lookup_trunk_entry(oid, 1);
+       }
+       closedir(dir);
+       return 0;
+}
+
+static int fill_entry_new_sha1(struct __trunk_entry *entry)
+{
+       struct strbuf buf = STRBUF_INIT;
+       int fd, ret = 0;
+       struct sha1_file_hdr hdr = { .priv = 0 };
+
+       memcpy(hdr.tag, TAG_DATA, TAG_LEN);
+       strbuf_addstr(&buf, obj_path);
+       strbuf_addf(&buf, "%016" PRIx64, entry->raw.oid);
+       fd = open(buf.buf, O_RDONLY);
+       strbuf_reset(&buf);
+
+       if (fd < 0) {
+               ret = -1;
+               goto out;
+       }
+       if (!strbuf_read(&buf, fd, SD_DATA_OBJ_SIZE) == SD_DATA_OBJ_SIZE) {
+               ret = -1;
+               close(fd);
+               goto out;
+       }
+       hdr.size = buf.len;
+       strbuf_insert(&buf, 0, &hdr, sizeof(hdr));
+
+       if (sha1_file_write((void *)buf.buf, buf.len, entry->raw.sha1) < 0) {
+               ret = -1;
+               close(fd);
+               goto out;
+       }
+       dprintf("dirty data sha1: %s\n", sha1_to_hex(entry->raw.sha1));
+out:
+       strbuf_release(&buf);
+       return ret;
+}
+
+static inline int trunk_entry_no_sha1(struct __trunk_entry *entry)
+{
+       return !strlen((char *)entry->raw.sha1);
+}
+
+static void put_entry(struct __trunk_entry *entry)
+{
+       hlist_del(&entry->hash);
+       list_del(&entry->active_list);
+       free_trunk_entry(entry);
+       trunk_entry_active_nr--;
+}
+
+int trunk_file_write(unsigned char *outsha1, int user)
+{
+       struct strbuf buf;
+       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 };
+       struct __trunk_entry *entry, *t;
+       int ret = 0;
+
+       memcpy(hdr.tag, TAG_TRUNK, TAG_LEN);
+       strbuf_init(&buf, sizeof(hdr) + data_size);
+
+       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 (fill_entry_new_sha1(entry) < 0) {
+                               ret = -1;
+                               goto out;
+                       }
+               }
+               strbuf_add(&buf, &entry->raw, sizeof(struct trunk_entry));
+               put_entry(entry);
+       }
+       if (sha1_file_write((void *)buf.buf, buf.len, outsha1) < 0) {
+               ret = -1;
+               goto out;
+       }
+       dprintf("trunk sha1: %s\n", sha1_to_hex(outsha1));
+out:
+       strbuf_release(&buf);
+       return ret;
+}
+
+void *trunk_file_read(unsigned char *sha1, struct sha1_file_hdr *outhdr)
+{
+       void *buffer;
+
+       dprintf("%s\n", sha1_to_hex(sha1));
+       buffer = sha1_file_read(sha1, outhdr);
+       if (!buffer)
+               return NULL;
+       if (strcmp(outhdr->tag, TAG_TRUNK) != 0) {
+               free(buffer);
+               return NULL;
+       }
+
+       return buffer;
+}
+
+int trunk_update_entry(uint64_t oid)
+{
+       struct __trunk_entry *entry;
+
+       entry = lookup_trunk_entry(oid, 1);
+       if (!trunk_entry_is_dirty(entry))
+               mark_trunk_entry_dirty(entry);
+
+       return 0;
+}
-- 
1.7.8.rc3

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

Reply via email to