Code

notes.h/c: Allow combine_notes functions to remove notes
authorJohan Herland <johan@herland.net>
Tue, 9 Nov 2010 21:49:41 +0000 (22:49 +0100)
committerJunio C Hamano <gitster@pobox.com>
Wed, 10 Nov 2010 18:25:52 +0000 (10:25 -0800)
Allow combine_notes functions to request that a note be removed, by setting
the resulting note SHA1 to null_sha1 (0000000...).

For consistency, also teach note_tree_insert() to skip insertion of an empty
note (a note with entry->val_sha1 equal to null_sha1) when there is no note
to combine it with.

In general, an empty note (null_sha1) is treated identically to no note at
all, but when adding an empty note where there already exists a non-empty
note, we allow the combine_notes function to potentially record a new/changed
note. Document this behaviour, and clearly specify how combine_notes functions
are expected to handle null_sha1 in input.

Before this patch, storing null_sha1s in the notes tree were silently allowed,
causing an invalid notes tree (referring to blobs with null_sha1) to be
produced by write_notes_tree().

Signed-off-by: Johan Herland <johan@herland.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
notes.c
notes.h

diff --git a/notes.c b/notes.c
index bfb3ea5b53a67978112217b99b48f29f6937d5d1..0c13a36eb7d39be92743c2906412412b73ccf8f1 100644 (file)
--- a/notes.c
+++ b/notes.c
@@ -248,7 +248,10 @@ static void note_tree_insert(struct notes_tree *t, struct int_node *tree,
        switch (GET_PTR_TYPE(*p)) {
        case PTR_TYPE_NULL:
                assert(!*p);
-               *p = SET_PTR_TYPE(entry, type);
+               if (is_null_sha1(entry->val_sha1))
+                       free(entry);
+               else
+                       *p = SET_PTR_TYPE(entry, type);
                return;
        case PTR_TYPE_NOTE:
                switch (type) {
@@ -264,6 +267,9 @@ static void note_tree_insert(struct notes_tree *t, struct int_node *tree,
                                            sha1_to_hex(l->val_sha1),
                                            sha1_to_hex(entry->val_sha1),
                                            sha1_to_hex(l->key_sha1));
+
+                               if (is_null_sha1(l->val_sha1))
+                                       note_tree_remove(t, tree, n, entry);
                                free(entry);
                                return;
                        }
@@ -295,6 +301,10 @@ static void note_tree_insert(struct notes_tree *t, struct int_node *tree,
        /* non-matching leaf_node */
        assert(GET_PTR_TYPE(*p) == PTR_TYPE_NOTE ||
               GET_PTR_TYPE(*p) == PTR_TYPE_SUBTREE);
+       if (is_null_sha1(entry->val_sha1)) { /* skip insertion of empty note */
+               free(entry);
+               return;
+       }
        new_node = (struct int_node *) xcalloc(sizeof(struct int_node), 1);
        note_tree_insert(t, new_node, n + 1, l, GET_PTR_TYPE(*p),
                         combine_notes);
diff --git a/notes.h b/notes.h
index 20db42fe952ed330c831563085236cd3a082e435..79ea7976abacd12c2e870d0502de60607c7d14ca 100644 (file)
--- a/notes.h
+++ b/notes.h
  * resulting SHA1 into the first SHA1 argument (cur_sha1). A non-zero return
  * value indicates failure.
  *
- * The two given SHA1s must both be non-NULL and different from each other.
+ * The two given SHA1s shall both be non-NULL and different from each other.
+ * Either of them (but not both) may be == null_sha1, which indicates an
+ * empty/non-existent note. If the resulting SHA1 (cur_sha1) is == null_sha1,
+ * the note will be removed from the notes tree.
  *
  * The default combine_notes function (you get this when passing NULL) is
  * combine_notes_concatenate(), which appends the contents of the new note to
@@ -90,6 +93,17 @@ void init_notes(struct notes_tree *t, const char *notes_ref,
 /*
  * Add the given note object to the given notes_tree structure
  *
+ * If there already exists a note for the given object_sha1, the given
+ * combine_notes function is invoked to break the tie. If not given (i.e.
+ * combine_notes == NULL), the default combine_notes function for the given
+ * notes_tree is used.
+ *
+ * Passing note_sha1 == null_sha1 indicates the addition of an
+ * empty/non-existent note. This is a (potentially expensive) no-op unless
+ * there already exists a note for the given object_sha1, AND combining that
+ * note with the empty note (using the given combine_notes function) results
+ * in a new/changed note.
+ *
  * IMPORTANT: The changes made by add_note() to the given notes_tree structure
  * are not persistent until a subsequent call to write_notes_tree() returns
  * zero.