@matheusbsbs / matheus-bagliano / commits / cd30539214
Fork 0

Notes API: Allow multiple concurrent notes trees with new struct notes_tree

The new struct notes_tree encapsulates access to a specific notes tree. It is provided to allow callers to make use of several different notes trees simultaneously. A struct notes_tree * parameter is added to every function in the notes API. In all cases, NULL can be passed, in which case the fallback "default" notes tree (default_notes_tree) is used. 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 cd30539214bb09881b84c796a50d30e409dee3fa
3 files changed +112 -66
notes.c
+56 -34
@@ -50,9 +50,7 @@ struct leaf_node {
50 #define SUBTREE_SHA1_PREFIXCMP(key_sha1, subtree_sha1) \
51 (memcmp(key_sha1, subtree_sha1, subtree_sha1[19]))
52
53 -static struct int_node root_node;
54 -
55 -static int initialized;
53 +struct notes_tree default_notes_tree;
54
55 static void load_subtree(struct leaf_node *subtree, struct int_node *node,
56 unsigned int n);
@@ -287,8 +285,8 @@ static int note_tree_consolidate(struct int_node *tree,
285 * - Replace the matching leaf_node with a NULL entry (and free the leaf_node).
286 * - Consolidate int_nodes repeatedly, while walking up the tree towards root.
287 */
290 -static void note_tree_remove(struct int_node *tree, unsigned char n,
291 - struct leaf_node *entry)
288 +static void note_tree_remove(struct notes_tree *t, struct int_node *tree,
289 + unsigned char n, struct leaf_node *entry)
290 {
291 struct leaf_node *l;
292 struct int_node *parent_stack[20];
@@ -310,7 +308,7 @@ static void note_tree_remove(struct int_node *tree, unsigned char n,
308 if (!n)
309 return; /* cannot consolidate top level */
310 /* first, build stack of ancestors between root and current node */
313 - parent_stack[0] = &root_node;
311 + parent_stack[0] = t->root;
312 for (i = 0; i < n; i++) {
313 j = GET_NIBBLE(i, entry->key_sha1);
314 parent_stack[i + 1] = CLR_PTR_TYPE(parent_stack[i]->a[j]);
@@ -661,14 +659,15 @@ static int write_each_note(const unsigned char *object_sha1,
659 return write_each_note_helper(d->root, note_path, mode, note_sha1);
660 }
661
664 -void init_notes(const char *notes_ref, int flags)
662 +void init_notes(struct notes_tree *t, const char *notes_ref, int flags)
663 {
664 unsigned char sha1[20], object_sha1[20];
665 unsigned mode;
666 struct leaf_node root_tree;
667
670 - assert(!initialized);
671 - initialized = 1;
668 + if (!t)
669 + t = &default_notes_tree;
670 + assert(!t->initialized);
671
672 if (!notes_ref)
673 notes_ref = getenv(GIT_NOTES_REF_ENVIRONMENT);
@@ -677,6 +676,10 @@ void init_notes(const char *notes_ref, int flags)
676 if (!notes_ref)
677 notes_ref = GIT_NOTES_DEFAULT_REF;
678
679 + t->root = (struct int_node *) xcalloc(sizeof(struct int_node), 1);
680 + t->ref = notes_ref ? xstrdup(notes_ref) : NULL;
681 + t->initialized = 1;
682 +
683 if (flags & NOTES_INIT_EMPTY || !notes_ref ||
684 read_ref(notes_ref, object_sha1))
685 return;
@@ -686,52 +689,65 @@ void init_notes(const char *notes_ref, int flags)
689
690 hashclr(root_tree.key_sha1);
691 hashcpy(root_tree.val_sha1, sha1);
689 - load_subtree(&root_tree, &root_node, 0);
692 + load_subtree(&root_tree, t->root, 0);
693 }
694
692 -void add_note(const unsigned char *object_sha1, const unsigned char *note_sha1)
695 +void add_note(struct notes_tree *t, const unsigned char *object_sha1,
696 + const unsigned char *note_sha1)
697 {
698 struct leaf_node *l;
699
696 - assert(initialized);
700 + if (!t)
701 + t = &default_notes_tree;
702 + assert(t->initialized);
703 l = (struct leaf_node *) xmalloc(sizeof(struct leaf_node));
704 hashcpy(l->key_sha1, object_sha1);
705 hashcpy(l->val_sha1, note_sha1);
700 - note_tree_insert(&root_node, 0, l, PTR_TYPE_NOTE);
706 + note_tree_insert(t->root, 0, l, PTR_TYPE_NOTE);
707 }
708
703 -void remove_note(const unsigned char *object_sha1)
709 +void remove_note(struct notes_tree *t, const unsigned char *object_sha1)
710 {
711 struct leaf_node l;
712
707 - assert(initialized);
713 + if (!t)
714 + t = &default_notes_tree;
715 + assert(t->initialized);
716 hashcpy(l.key_sha1, object_sha1);
717 hashclr(l.val_sha1);
710 - return note_tree_remove(&root_node, 0, &l);
718 + return note_tree_remove(t, t->root, 0, &l);
719 }
720
713 -const unsigned char *get_note(const unsigned char *object_sha1)
721 +const unsigned char *get_note(struct notes_tree *t,
722 + const unsigned char *object_sha1)
723 {
724 struct leaf_node *found;
725
717 - assert(initialized);
718 - found = note_tree_find(&root_node, 0, object_sha1);
726 + if (!t)
727 + t = &default_notes_tree;
728 + assert(t->initialized);
729 + found = note_tree_find(t->root, 0, object_sha1);
730 return found ? found->val_sha1 : NULL;
731 }
732
722 -int for_each_note(int flags, each_note_fn fn, void *cb_data)
733 +int for_each_note(struct notes_tree *t, int flags, each_note_fn fn,
734 + void *cb_data)
735 {
724 - assert(initialized);
725 - return for_each_note_helper(&root_node, 0, 0, flags, fn, cb_data);
736 + if (!t)
737 + t = &default_notes_tree;
738 + assert(t->initialized);
739 + return for_each_note_helper(t->root, 0, 0, flags, fn, cb_data);
740 }
741
728 -int write_notes_tree(unsigned char *result)
742 +int write_notes_tree(struct notes_tree *t, unsigned char *result)
743 {
744 struct tree_write_stack root;
745 struct write_each_note_data cb_data;
746 int ret;
747
734 - assert(initialized);
748 + if (!t)
749 + t = &default_notes_tree;
750 + assert(t->initialized);
751
752 /* Prepare for traversal of current notes tree */
753 root.next = NULL; /* last forward entry in list is grounded */
@@ -740,7 +756,7 @@ int write_notes_tree(unsigned char *result)
756 cb_data.root = &root;
757
758 /* Write tree objects representing current notes tree */
743 - ret = for_each_note(FOR_EACH_NOTE_DONT_UNPACK_SUBTREES |
759 + ret = for_each_note(t, FOR_EACH_NOTE_DONT_UNPACK_SUBTREES |
760 FOR_EACH_NOTE_YIELD_SUBTREES,
761 write_each_note, &cb_data) ||
762 tree_write_stack_finish_subtree(&root) ||
@@ -749,15 +765,19 @@ int write_notes_tree(unsigned char *result)
765 return ret;
766 }
767
752 -void free_notes(void)
768 +void free_notes(struct notes_tree *t)
769 {
754 - note_tree_free(&root_node);
755 - memset(&root_node, 0, sizeof(struct int_node));
756 - initialized = 0;
770 + if (!t)
771 + t = &default_notes_tree;
772 + if (t->root)
773 + note_tree_free(t->root);
774 + free(t->root);
775 + free(t->ref);
776 + memset(t, 0, sizeof(struct notes_tree));
777 }
778
759 -void format_note(const unsigned char *object_sha1, struct strbuf *sb,
760 - const char *output_encoding, int flags)
779 +void format_note(struct notes_tree *t, const unsigned char *object_sha1,
780 + struct strbuf *sb, const char *output_encoding, int flags)
781 {
782 static const char utf8[] = "utf-8";
783 const unsigned char *sha1;
@@ -765,10 +785,12 @@ void format_note(const unsigned char *object_sha1, struct strbuf *sb,
785 unsigned long linelen, msglen;
786 enum object_type type;
787
768 - if (!initialized)
769 - init_notes(NULL, 0);
788 + if (!t)
789 + t = &default_notes_tree;
790 + if (!t->initialized)
791 + init_notes(t, NULL, 0);
792
771 - sha1 = get_note(object_sha1);
793 + sha1 = get_note(t, object_sha1);
794 if (!sha1)
795 return;
796
notes.h
+52 -29
@@ -1,6 +1,21 @@
1 #ifndef NOTES_H
2 #define NOTES_H
3
4 +/*
5 + * Notes tree object
6 + *
7 + * Encapsulates the internal notes tree structure associated with a notes ref.
8 + * Whenever a struct notes_tree pointer is required below, you may pass NULL in
9 + * order to use the default/internal notes tree. E.g. you only need to pass a
10 + * non-NULL value if you need to refer to several different notes trees
11 + * simultaneously.
12 + */
13 +extern struct notes_tree {
14 + struct int_node *root;
15 + char *ref;
16 + int initialized;
17 +} default_notes_tree;
18 +
19 /*
20 * Flags controlling behaviour of notes tree initialization
21 *
@@ -10,48 +25,54 @@
25 #define NOTES_INIT_EMPTY 1
26
27 /*
13 - * Initialize internal notes tree structure with the notes tree at the given
28 + * Initialize the given notes_tree with the notes tree structure at the given
29 * ref. If given ref is NULL, the value of the $GIT_NOTES_REF environment
30 * variable is used, and if that is missing, the default notes ref is used
31 * ("refs/notes/commits").
32 *
18 - * If you need to re-intialize the internal notes tree structure (e.g. loading
19 - * from a different notes ref), please first de-initialize the current notes
20 - * tree by calling free_notes().
33 + * If you need to re-intialize a notes_tree structure (e.g. when switching from
34 + * one notes ref to another), you must first de-initialize the notes_tree
35 + * structure by calling free_notes(struct notes_tree *).
36 + *
37 + * If you pass t == NULL, the default internal notes_tree will be initialized.
38 + *
39 + * Precondition: The notes_tree structure is zeroed (this can be achieved with
40 + * memset(t, 0, sizeof(struct notes_tree)))
41 */
22 -void init_notes(const char *notes_ref, int flags);
42 +void init_notes(struct notes_tree *t, const char *notes_ref, int flags);
43
44 /*
25 - * Add the given note object to the internal notes tree structure
45 + * Add the given note object to the given notes_tree structure
46 *
27 - * IMPORTANT: The changes made by add_note() to the internal notes tree structure
47 + * IMPORTANT: The changes made by add_note() to the given notes_tree structure
48 * are not persistent until a subsequent call to write_notes_tree() returns
49 * zero.
50 */
31 -void add_note(const unsigned char *object_sha1,
51 +void add_note(struct notes_tree *t, const unsigned char *object_sha1,
52 const unsigned char *note_sha1);
53
54 /*
35 - * Remove the given note object from the internal notes tree structure
55 + * Remove the given note object from the given notes_tree structure
56 *
37 - * IMPORTANT: The changes made by remove_note() to the internal notes tree
57 + * IMPORTANT: The changes made by remove_note() to the given notes_tree
58 * structure are not persistent until a subsequent call to write_notes_tree()
59 * returns zero.
60 */
41 -void remove_note(const unsigned char *object_sha1);
61 +void remove_note(struct notes_tree *t, const unsigned char *object_sha1);
62
63 /*
64 * Get the note object SHA1 containing the note data for the given object
65 *
66 * Return NULL if the given object has no notes.
67 */
48 -const unsigned char *get_note(const unsigned char *object_sha1);
68 +const unsigned char *get_note(struct notes_tree *t,
69 + const unsigned char *object_sha1);
70
71 /*
72 * Flags controlling behaviour of for_each_note()
73 *
74 * Default behaviour of for_each_note() is to traverse every single note object
54 - * in the notes tree, unpacking subtree entries along the way.
75 + * in the given notes tree, unpacking subtree entries along the way.
76 * The following flags can be used to alter the default behaviour:
77 *
78 * - DONT_UNPACK_SUBTREES causes for_each_note() NOT to unpack and recurse into
@@ -75,7 +96,7 @@ const unsigned char *get_note(const unsigned char *object_sha1);
96 #define FOR_EACH_NOTE_YIELD_SUBTREES 2
97
98 /*
78 - * Invoke the specified callback function for each note
99 + * Invoke the specified callback function for each note in the given notes_tree
100 *
101 * If the callback returns nonzero, the note walk is aborted, and the return
102 * value from the callback is returned from for_each_note(). Hence, a zero
@@ -92,30 +113,30 @@ const unsigned char *get_note(const unsigned char *object_sha1);
113 typedef int each_note_fn(const unsigned char *object_sha1,
114 const unsigned char *note_sha1, char *note_path,
115 void *cb_data);
95 -int for_each_note(int flags, each_note_fn fn, void *cb_data);
116 +int for_each_note(struct notes_tree *t, int flags, each_note_fn fn,
117 + void *cb_data);
118
119 /*
98 - * Write the internal notes tree structure to the object database
120 + * Write the given notes_tree structure to the object database
121 *
100 - * Creates a new tree object encapsulating the current state of the
101 - * internal notes tree, and stores its SHA1 into the 'result' argument.
122 + * Creates a new tree object encapsulating the current state of the given
123 + * notes_tree, and stores its SHA1 into the 'result' argument.
124 *
125 * Returns zero on success, non-zero on failure.
126 *
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.
127 + * IMPORTANT: Changes made to the given notes_tree are not persistent until
128 + * this function has returned zero. Please also remember to create a
129 + * corresponding commit object, and update the appropriate notes ref.
130 */
110 -int write_notes_tree(unsigned char *result);
131 +int write_notes_tree(struct notes_tree *t, unsigned char *result);
132
133 /*
113 - * Free (and de-initialize) the internal notes tree structure
134 + * Free (and de-initialize) the given notes_tree structure
135 *
115 - * IMPORTANT: Changes made to the notes tree since the last, successful
136 + * IMPORTANT: Changes made to the given notes_tree since the last, successful
137 * call to write_notes_tree() will be lost.
138 */
118 -void free_notes(void);
139 +void free_notes(struct notes_tree *t);
140
141 /* Flags controlling how notes are formatted */
142 #define NOTES_SHOW_HEADER 1
@@ -124,12 +145,14 @@ void free_notes(void);
145 /*
146 * Fill the given strbuf with the notes associated with the given object.
147 *
127 - * If the internal notes structure is not initialized, it will be auto-
148 + * If the given notes_tree structure is not initialized, it will be auto-
149 * initialized to the default value (see documentation for init_notes() above).
150 + * If the given notes_tree is NULL, the internal/default notes_tree will be
151 + * used instead.
152 *
153 * 'flags' is a bitwise combination of the above formatting flags.
154 */
132 -void format_note(const unsigned char *object_sha1, struct strbuf *sb,
133 - const char *output_encoding, int flags);
155 +void format_note(struct notes_tree *t, const unsigned char *object_sha1,
156 + struct strbuf *sb, const char *output_encoding, int flags);
157
158 #endif
pretty.c
+4 -3
@@ -775,8 +775,9 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
775 }
776 return 0; /* unknown %g placeholder */
777 case 'N':
778 - format_note(commit->object.sha1, sb, git_log_output_encoding ?
779 - git_log_output_encoding : git_commit_encoding, 0);
778 + format_note(NULL, commit->object.sha1, sb,
779 + git_log_output_encoding ? git_log_output_encoding
780 + : git_commit_encoding, 0);
781 return 1;
782 }
783
@@ -1095,7 +1096,7 @@ void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit,
1096 strbuf_addch(sb, '\n');
1097
1098 if (context->show_notes)
1098 - format_note(commit->object.sha1, sb, encoding,
1099 + format_note(NULL, commit->object.sha1, sb, encoding,
1100 NOTES_SHOW_HEADER | NOTES_INDENT);
1101
1102 free(reencoded);