@matheusbsbs / matheus-bagliano / commits / 61a7cca0c6
Fork 0

Notes API: write_notes_tree(): Store the notes tree in the database

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@herland.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Johan Herland committed Feb 13, 2010 at 22:28 UTC 61a7cca0c6504aee7bae7837582230561bdb81d4
2 files changed +180 -3
notes.c
+145
@@ -1,5 +1,6 @@
1 #include "cache.h"
2 #include "notes.h"
3 +#include "tree.h"
4 #include "utf8.h"
5 #include "strbuf.h"
6 #include "tree-walk.h"
@@ -540,6 +541,126 @@ redo:
541 return 0;
542 }
543
544 +struct tree_write_stack {
545 + struct tree_write_stack *next;
546 + struct strbuf buf;
547 + char path[2]; /* path to subtree in next, if any */
548 +};
549 +
550 +static inline int matches_tree_write_stack(struct tree_write_stack *tws,
551 + const char *full_path)
552 +{
553 + return full_path[0] == tws->path[0] &&
554 + full_path[1] == tws->path[1] &&
555 + full_path[2] == '/';
556 +}
557 +
558 +static void write_tree_entry(struct strbuf *buf, unsigned int mode,
559 + const char *path, unsigned int path_len, const
560 + unsigned char *sha1)
561 +{
562 + strbuf_addf(buf, "%06o %.*s%c", mode, path_len, path, '\0');
563 + strbuf_add(buf, sha1, 20);
564 +}
565 +
566 +static void tree_write_stack_init_subtree(struct tree_write_stack *tws,
567 + const char *path)
568 +{
569 + struct tree_write_stack *n;
570 + assert(!tws->next);
571 + assert(tws->path[0] == '\0' && tws->path[1] == '\0');
572 + n = (struct tree_write_stack *)
573 + xmalloc(sizeof(struct tree_write_stack));
574 + n->next = NULL;
575 + strbuf_init(&n->buf, 256 * (32 + 40)); /* assume 256 entries per tree */
576 + n->path[0] = n->path[1] = '\0';
577 + tws->next = n;
578 + tws->path[0] = path[0];
579 + tws->path[1] = path[1];
580 +}
581 +
582 +static int tree_write_stack_finish_subtree(struct tree_write_stack *tws)
583 +{
584 + int ret;
585 + struct tree_write_stack *n = tws->next;
586 + unsigned char s[20];
587 + if (n) {
588 + ret = tree_write_stack_finish_subtree(n);
589 + if (ret)
590 + return ret;
591 + ret = write_sha1_file(n->buf.buf, n->buf.len, tree_type, s);
592 + if (ret)
593 + return ret;
594 + strbuf_release(&n->buf);
595 + free(n);
596 + tws->next = NULL;
597 + write_tree_entry(&tws->buf, 040000, tws->path, 2, s);
598 + tws->path[0] = tws->path[1] = '\0';
599 + }
600 + return 0;
601 +}
602 +
603 +static int write_each_note_helper(struct tree_write_stack *tws,
604 + const char *path, unsigned int mode,
605 + const unsigned char *sha1)
606 +{
607 + size_t path_len = strlen(path);
608 + unsigned int n = 0;
609 + int ret;
610 +
611 + /* Determine common part of tree write stack */
612 + while (tws && 3 * n < path_len &&
613 + matches_tree_write_stack(tws, path + 3 * n)) {
614 + n++;
615 + tws = tws->next;
616 + }
617 +
618 + /* tws point to last matching tree_write_stack entry */
619 + ret = tree_write_stack_finish_subtree(tws);
620 + if (ret)
621 + return ret;
622 +
623 + /* Start subtrees needed to satisfy path */
624 + while (3 * n + 2 < path_len && path[3 * n + 2] == '/') {
625 + tree_write_stack_init_subtree(tws, path + 3 * n);
626 + n++;
627 + tws = tws->next;
628 + }
629 +
630 + /* There should be no more directory components in the given path */
631 + assert(memchr(path + 3 * n, '/', path_len - (3 * n)) == NULL);
632 +
633 + /* Finally add given entry to the current tree object */
634 + write_tree_entry(&tws->buf, mode, path + 3 * n, path_len - (3 * n),
635 + sha1);
636 +
637 + return 0;
638 +}
639 +
640 +struct write_each_note_data {
641 + struct tree_write_stack *root;
642 +};
643 +
644 +static int write_each_note(const unsigned char *object_sha1,
645 + const unsigned char *note_sha1, char *note_path,
646 + void *cb_data)
647 +{
648 + struct write_each_note_data *d =
649 + (struct write_each_note_data *) cb_data;
650 + size_t note_path_len = strlen(note_path);
651 + unsigned int mode = 0100644;
652 +
653 + if (note_path[note_path_len - 1] == '/') {
654 + /* subtree entry */
655 + note_path_len--;
656 + note_path[note_path_len] = '\0';
657 + mode = 040000;
658 + }
659 + assert(note_path_len <= 40 + 19);
660 +
661 + return write_each_note_helper(d->root, note_path, mode, note_sha1);
662 +}
663 +
664 void init_notes(const char *notes_ref, int flags)
665 {
666 unsigned char sha1[20], object_sha1[20];
@@ -604,6 +725,30 @@ int for_each_note(int flags, each_note_fn fn, void *cb_data)
725 return for_each_note_helper(&root_node, 0, 0, flags, fn, cb_data);
726 }
727
728 +int write_notes_tree(unsigned char *result)
729 +{
730 + struct tree_write_stack root;
731 + struct write_each_note_data cb_data;
732 + int ret;
733 +
734 + assert(initialized);
735 +
736 + /* Prepare for traversal of current notes tree */
737 + root.next = NULL; /* last forward entry in list is grounded */
738 + strbuf_init(&root.buf, 256 * (32 + 40)); /* assume 256 entries */
739 + root.path[0] = root.path[1] = '\0';
740 + cb_data.root = &root;
741 +
742 + /* Write tree objects representing current notes tree */
743 + ret = for_each_note(FOR_EACH_NOTE_DONT_UNPACK_SUBTREES |
744 + FOR_EACH_NOTE_YIELD_SUBTREES,
745 + write_each_note, &cb_data) ||
746 + tree_write_stack_finish_subtree(&root) ||
747 + write_sha1_file(root.buf.buf, root.buf.len, tree_type, result);
748 + strbuf_release(&root.buf);
749 + return ret;
750 +}
751 +
752 void free_notes(void)
753 {
754 note_tree_free(&root_node);
notes.h
+35 -3
@@ -21,11 +21,23 @@
21 */
22 void init_notes(const char *notes_ref, int flags);
23
24 -/* Add the given note object to the internal notes tree structure */
24 +/*
25 + * Add the given note object to the internal notes tree structure
26 + *
27 + * IMPORTANT: The changes made by add_note() to the internal notes tree structure
28 + * are not persistent until a subsequent call to write_notes_tree() returns
29 + * zero.
30 + */
31 void add_note(const unsigned char *object_sha1,
32 const unsigned char *note_sha1);
33
28 -/* Remove the given note object from the internal notes tree structure */
34 +/*
35 + * Remove the given note object from the internal notes tree structure
36 + *
37 + * IMPORTANT: The changes made by remove_note() to the internal notes tree
38 + * structure are not persistent until a subsequent call to write_notes_tree()
39 + * returns zero.
40 + */
41 void remove_note(const unsigned char *object_sha1);
42
43 /*
@@ -82,7 +94,27 @@ typedef int each_note_fn(const unsigned char *object_sha1,
94 void *cb_data);
95 int for_each_note(int flags, each_note_fn fn, void *cb_data);
96
85 -/* Free (and de-initialize) the internal notes tree structure */
97 +/*
98 + * Write the internal notes tree structure to the object database
99 + *
100 + * Creates a new tree object encapsulating the current state of the
101 + * internal notes tree, and stores its SHA1 into the 'result' argument.
102 + *
103 + * Returns zero on success, non-zero on failure.
104 + *
105 + * IMPORTANT: Changes made to the internal notes tree structure are not
106 + * persistent until this function has returned zero. Please also remember
107 + * to create a corresponding commit object, and update the appropriate
108 + * notes ref.
109 + */
110 +int write_notes_tree(unsigned char *result);
111 +
112 +/*
113 + * Free (and de-initialize) the internal notes tree structure
114 + *
115 + * IMPORTANT: Changes made to the notes tree since the last, successful
116 + * call to write_notes_tree() will be lost.
117 + */
118 void free_notes(void);
119
120 /* Flags controlling how notes are formatted */