[Sheepdog] [PATCH v5 07/17] farm: add trunk object

Liu Yuan namei.unix at gmail.com
Fri Dec 30 14:07:02 CET 2011


From: Liu Yuan <tailai.ly at taobao.com>

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 <tailai.ly at taobao.com>
---
 sheep/farm.h       |   27 ++++++
 sheep/farm/trunk.c |  235 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 262 insertions(+), 0 deletions(-)
 create mode 100644 sheep/farm/trunk.c

diff --git a/sheep/farm.h b/sheep/farm.h
index a07928f..4f51ca6 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_incore {
+	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,11 @@ 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);
+extern void trunk_reset(void);
+
 #endif
diff --git a/sheep/farm/trunk.c b/sheep/farm/trunk.c
new file mode 100644
index 0000000..0506f3f
--- /dev/null
+++ b/sheep/farm/trunk.c
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2011 Taobao Inc.
+ *
+ * Liu Yuan <namei.unix at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Trunk object is meta data that describes the structure of the data objects
+ * at the time of snapshot being taken. It ties data objects together into a flat
+ * directory structure.
+ */
+#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 HASH_BITS	10
+#define HASH_SIZE	(1 << HASH_BITS)
+
+static LIST_HEAD(trunk_active_list);
+static pthread_mutex_t active_list_lock = PTHREAD_MUTEX_INITIALIZER;
+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_incore *entry)
+{
+	return entry->flags & TRUNK_ENTRY_DIRTY;
+}
+
+static inline void dirty_trunk_entry(struct trunk_entry_incore *entry)
+{
+	entry->flags |= TRUNK_ENTRY_DIRTY;
+}
+
+static inline void undirty_trunk_entry(struct trunk_entry_incore *entry)
+{
+	entry->flags &= ~TRUNK_ENTRY_DIRTY;
+}
+
+static inline int hash(uint64_t oid)
+{
+	return hash_64(oid, HASH_BITS);
+}
+
+static void inline get_entry(struct trunk_entry_incore *entry, struct hlist_head *head)
+{
+	hlist_add_head(&entry->hash, head);
+	pthread_mutex_lock(&active_list_lock);
+	list_add(&entry->active_list, &trunk_active_list);
+	trunk_entry_active_nr++;
+	pthread_mutex_unlock(&active_list_lock);
+}
+
+static struct trunk_entry_incore *lookup_trunk_entry(uint64_t oid, int create)
+{
+	int h = hash(oid);
+	struct hlist_head *head = trunk_hashtable + h;
+	struct trunk_entry_incore *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 = xzalloc(sizeof(*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 || oid == ULLONG_MAX)
+			continue;
+		lookup_trunk_entry(oid, 1);
+	}
+	closedir(dir);
+	return 0;
+}
+
+static int fill_entry_new_sha1(struct trunk_entry_incore *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("oid: %"PRIx64"\n", entry->raw.oid);
+out:
+	strbuf_release(&buf);
+	return ret;
+}
+
+static inline int trunk_entry_no_sha1(struct trunk_entry_incore *entry)
+{
+	return !strlen((char *)entry->raw.sha1);
+}
+
+static void inline put_entry(struct trunk_entry_incore *entry)
+{
+	hlist_del(&entry->hash);
+	pthread_mutex_lock(&active_list_lock);
+	list_del(&entry->active_list);
+	trunk_entry_active_nr--;
+	pthread_mutex_unlock(&active_list_lock);
+	free(entry);
+}
+
+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_incore *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));
+		undirty_trunk_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_incore *entry;
+
+	entry = lookup_trunk_entry(oid, 1);
+	if (!trunk_entry_is_dirty(entry))
+		dirty_trunk_entry(entry);
+
+	return 0;
+}
+
+void trunk_reset(void)
+{
+	struct trunk_entry_incore *entry, *t;
+	list_for_each_entry_safe(entry, t, &trunk_active_list, active_list) {
+	/* This is supposed to be called by format operation, so no lock needed */
+		put_entry(entry);
+	}
+	eprintf("%s\n", trunk_entry_active_nr ? "WARN: active_list not clean" :
+						"clean");
+}
-- 
1.7.8.rc3




More information about the sheepdog mailing list