@matheusbsbs / matheus-bagliano / commits / 00fbe63627
Fork 0

Notes API: prune_notes(): Prune notes that belong to non-existing objects

When an object is made unreachable by Git, any notes that annotate that object are not automagically made unreachable, since all notes are always trivially reachable from a notes ref. In order to remove notes for non-existing objects, we therefore need to add functionality for traversing the notes tree and explicitly removing references to notes that annotate non-reachable objects. Thus the notes objects themselves also become unreachable, and are removed by a later garbage collect. prune_notes() performs this traversal (by using for_each_note() internally), and removes the notes in question from the notes tree. Note that the effect of prune_notes() is not persistent unless a subsequent call to write_notes_tree() is made. 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 00fbe63627b72c807e558643f0634e435137122f
2 files changed +51
notes.c
+39
@@ -749,6 +749,29 @@ static int write_each_note(const unsigned char *object_sha1,
749 write_each_note_helper(d->root, note_path, mode, note_sha1);
750 }
751
752 +struct note_delete_list {
753 + struct note_delete_list *next;
754 + const unsigned char *sha1;
755 +};
756 +
757 +static int prune_notes_helper(const unsigned char *object_sha1,
758 + const unsigned char *note_sha1, char *note_path,
759 + void *cb_data)
760 +{
761 + struct note_delete_list **l = (struct note_delete_list **) cb_data;
762 + struct note_delete_list *n;
763 +
764 + if (has_sha1_file(object_sha1))
765 + return 0; /* nothing to do for this note */
766 +
767 + /* failed to find object => prune this note */
768 + n = (struct note_delete_list *) xmalloc(sizeof(*n));
769 + n->next = *l;
770 + n->sha1 = object_sha1;
771 + *l = n;
772 + return 0;
773 +}
774 +
775 int combine_notes_concatenate(unsigned char *cur_sha1,
776 const unsigned char *new_sha1)
777 {
@@ -922,6 +945,22 @@ int write_notes_tree(struct notes_tree *t, unsigned char *result)
945 return ret;
946 }
947
948 +void prune_notes(struct notes_tree *t)
949 +{
950 + struct note_delete_list *l = NULL;
951 +
952 + if (!t)
953 + t = &default_notes_tree;
954 + assert(t->initialized);
955 +
956 + for_each_note(t, 0, prune_notes_helper, &l);
957 +
958 + while (l) {
959 + remove_note(t, l->sha1);
960 + l = l->next;
961 + }
962 +}
963 +
964 void free_notes(struct notes_tree *t)
965 {
966 if (!t)
notes.h
+12
@@ -161,6 +161,18 @@ int for_each_note(struct notes_tree *t, int flags, each_note_fn fn,
161 */
162 int write_notes_tree(struct notes_tree *t, unsigned char *result);
163
164 +/*
165 + * Remove all notes annotating non-existing objects from the given notes tree
166 + *
167 + * All notes in the given notes_tree that are associated with objects that no
168 + * longer exist in the database, are removed from the notes tree.
169 + *
170 + * IMPORTANT: The changes made by prune_notes() to the given notes_tree
171 + * structure are not persistent until a subsequent call to write_notes_tree()
172 + * returns zero.
173 + */
174 +void prune_notes(struct notes_tree *t);
175 +
176 /*
177 * Free (and de-initialize) the given notes_tree structure
178 *