[PATCHv13 09/30] Notes API: write_notes_tree(): Store the notes tree in the database

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Uses for_each_note() to traverse the notes tree, and produces tree
objects on the fly representing the "on-disk" version of the notes
tree with appropriate fanout.

Signed-off-by: Johan Herland <johan@xxxxxxxxxxx>
---
 notes.c |  145 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 notes.h |   38 +++++++++++++++-
 2 files changed, 180 insertions(+), 3 deletions(-)

diff --git a/notes.c b/notes.c
index eabd6f3..b576f7e 100644
--- a/notes.c
+++ b/notes.c
@@ -1,5 +1,6 @@
 #include "cache.h"
 #include "notes.h"
+#include "tree.h"
 #include "utf8.h"
 #include "strbuf.h"
 #include "tree-walk.h"
@@ -540,6 +541,126 @@ redo:
 	return 0;
 }
 
+struct tree_write_stack {
+	struct tree_write_stack *next;
+	struct strbuf buf;
+	char path[2]; /* path to subtree in next, if any */
+};
+
+static inline int matches_tree_write_stack(struct tree_write_stack *tws,
+		const char *full_path)
+{
+	return  full_path[0] == tws->path[0] &&
+		full_path[1] == tws->path[1] &&
+		full_path[2] == '/';
+}
+
+static void write_tree_entry(struct strbuf *buf, unsigned int mode,
+		const char *path, unsigned int path_len, const
+		unsigned char *sha1)
+{
+		strbuf_addf(buf, "%06o %.*s%c", mode, path_len, path, '\0');
+		strbuf_add(buf, sha1, 20);
+}
+
+static void tree_write_stack_init_subtree(struct tree_write_stack *tws,
+		const char *path)
+{
+	struct tree_write_stack *n;
+	assert(!tws->next);
+	assert(tws->path[0] == '\0' && tws->path[1] == '\0');
+	n = (struct tree_write_stack *)
+		xmalloc(sizeof(struct tree_write_stack));
+	n->next = NULL;
+	strbuf_init(&n->buf, 256 * (32 + 40)); /* assume 256 entries per tree */
+	n->path[0] = n->path[1] = '\0';
+	tws->next = n;
+	tws->path[0] = path[0];
+	tws->path[1] = path[1];
+}
+
+static int tree_write_stack_finish_subtree(struct tree_write_stack *tws)
+{
+	int ret;
+	struct tree_write_stack *n = tws->next;
+	unsigned char s[20];
+	if (n) {
+		ret = tree_write_stack_finish_subtree(n);
+		if (ret)
+			return ret;
+		ret = write_sha1_file(n->buf.buf, n->buf.len, tree_type, s);
+		if (ret)
+			return ret;
+		strbuf_release(&n->buf);
+		free(n);
+		tws->next = NULL;
+		write_tree_entry(&tws->buf, 040000, tws->path, 2, s);
+		tws->path[0] = tws->path[1] = '\0';
+	}
+	return 0;
+}
+
+static int write_each_note_helper(struct tree_write_stack *tws,
+		const char *path, unsigned int mode,
+		const unsigned char *sha1)
+{
+	size_t path_len = strlen(path);
+	unsigned int n = 0;
+	int ret;
+
+	/* Determine common part of tree write stack */
+	while (tws && 3 * n < path_len &&
+	       matches_tree_write_stack(tws, path + 3 * n)) {
+		n++;
+		tws = tws->next;
+	}
+
+	/* tws point to last matching tree_write_stack entry */
+	ret = tree_write_stack_finish_subtree(tws);
+	if (ret)
+		return ret;
+
+	/* Start subtrees needed to satisfy path */
+	while (3 * n + 2 < path_len && path[3 * n + 2] == '/') {
+		tree_write_stack_init_subtree(tws, path + 3 * n);
+		n++;
+		tws = tws->next;
+	}
+
+	/* There should be no more directory components in the given path */
+	assert(memchr(path + 3 * n, '/', path_len - (3 * n)) == NULL);
+
+	/* Finally add given entry to the current tree object */
+	write_tree_entry(&tws->buf, mode, path + 3 * n, path_len - (3 * n),
+			 sha1);
+
+	return 0;
+}
+
+struct write_each_note_data {
+	struct tree_write_stack *root;
+};
+
+static int write_each_note(const unsigned char *object_sha1,
+		const unsigned char *note_sha1, char *note_path,
+		void *cb_data)
+{
+	struct write_each_note_data *d =
+		(struct write_each_note_data *) cb_data;
+	size_t note_path_len = strlen(note_path);
+	unsigned int mode = 0100644;
+
+	if (note_path[note_path_len - 1] == '/') {
+		/* subtree entry */
+		note_path_len--;
+		note_path[note_path_len] = '\0';
+		mode = 040000;
+	}
+	assert(note_path_len <= 40 + 19);
+
+	return write_each_note_helper(d->root, note_path, mode, note_sha1);
+}
+
 void init_notes(const char *notes_ref, int flags)
 {
 	unsigned char sha1[20], object_sha1[20];
@@ -604,6 +725,30 @@ int for_each_note(int flags, each_note_fn fn, void *cb_data)
 	return for_each_note_helper(&root_node, 0, 0, flags, fn, cb_data);
 }
 
+int write_notes_tree(unsigned char *result)
+{
+	struct tree_write_stack root;
+	struct write_each_note_data cb_data;
+	int ret;
+
+	assert(initialized);
+
+	/* Prepare for traversal of current notes tree */
+	root.next = NULL; /* last forward entry in list is grounded */
+	strbuf_init(&root.buf, 256 * (32 + 40)); /* assume 256 entries */
+	root.path[0] = root.path[1] = '\0';
+	cb_data.root = &root;
+
+	/* Write tree objects representing current notes tree */
+	ret = for_each_note(FOR_EACH_NOTE_DONT_UNPACK_SUBTREES |
+				FOR_EACH_NOTE_YIELD_SUBTREES,
+			write_each_note, &cb_data) ||
+		tree_write_stack_finish_subtree(&root) ||
+		write_sha1_file(root.buf.buf, root.buf.len, tree_type, result);
+	strbuf_release(&root.buf);
+	return ret;
+}
+
 void free_notes(void)
 {
 	note_tree_free(&root_node);
diff --git a/notes.h b/notes.h
index 2131912..c49b7a5 100644
--- a/notes.h
+++ b/notes.h
@@ -21,11 +21,23 @@
  */
 void init_notes(const char *notes_ref, int flags);
 
-/* Add the given note object to the internal notes tree structure */
+/*
+ * Add the given note object to the internal notes tree structure
+ *
+ * IMPORTANT: The changes made by add_note() to the internal notes tree structure
+ * are not persistent until a subsequent call to write_notes_tree() returns
+ * zero.
+ */
 void add_note(const unsigned char *object_sha1,
 		const unsigned char *note_sha1);
 
-/* Remove the given note object from the internal notes tree structure */
+/*
+ * Remove the given note object from the internal notes tree structure
+ *
+ * IMPORTANT: The changes made by remove_note() to the internal notes tree
+ * structure are not persistent until a subsequent call to write_notes_tree()
+ * returns zero.
+ */
 void remove_note(const unsigned char *object_sha1);
 
 /*
@@ -82,7 +94,27 @@ typedef int each_note_fn(const unsigned char *object_sha1,
 		void *cb_data);
 int for_each_note(int flags, each_note_fn fn, void *cb_data);
 
-/* Free (and de-initialize) the internal notes tree structure */
+/*
+ * Write the internal notes tree structure to the object database
+ *
+ * Creates a new tree object encapsulating the current state of the
+ * internal notes tree, and stores its SHA1 into the 'result' argument.
+ *
+ * Returns zero on success, non-zero on failure.
+ *
+ * IMPORTANT: Changes made to the internal notes tree structure are not
+ * persistent until this function has returned zero. Please also remember
+ * to create a corresponding commit object, and update the appropriate
+ * notes ref.
+ */
+int write_notes_tree(unsigned char *result);
+
+/*
+ * Free (and de-initialize) the internal notes tree structure
+ *
+ * IMPORTANT: Changes made to the notes tree since the last, successful
+ * call to write_notes_tree() will be lost.
+ */
 void free_notes(void);
 
 /* Flags controlling how notes are formatted */
-- 
1.7.0.rc1.141.gd3fd

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]