git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCHv12 06/23] Notes API: remove_note(): Remove note objects from the notes tree structure

From
Johan Herland <johan@herland.net>
Date
Jan 27, 2010, 11:51 UTC
Message-ID
<1264593120-4428-7-git-send-email-johan@herland.net>
In-Reply-To
<1264593120-4428-1-git-send-email-johan@herland.net>

This includes adding internal functions for maintaining a healthy notes tree structure after removing individual notes.

Signed-off-by: Johan Herland <johan@herland.net>
---
 notes.c |   85 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 notes.h |    3 ++
 2 files changed, 87 insertions(+), 1 deletions(-)
diff --git a/notes.c b/notes.c
index 2c0d14e..2e82d71 100644
--- a/notes.c
+++ b/notes.c
@@ -44,7 +44,7 @@ struct leaf_node {
 #define CLR_PTR_TYPE(ptr)       ((void *) ((uintptr_t) (ptr) & ~3))
 #define SET_PTR_TYPE(ptr, type) ((void *) ((uintptr_t) (ptr) | (type)))
 
-#define GET_NIBBLE(n, sha1) (((sha1[n >> 1]) >> ((~n & 0x01) << 2)) & 0x0f)
+#define GET_NIBBLE(n, sha1) (((sha1[(n) >> 1]) >> ((~(n) & 0x01) << 2)) & 0x0f)
 
 #define SUBTREE_SHA1_PREFIXCMP(key_sha1, subtree_sha1) \
 	(memcmp(key_sha1, subtree_sha1, subtree_sha1[19]))
@@ -249,6 +249,79 @@ static void note_tree_insert(struct int_node *tree, unsigned char n,
 	note_tree_insert(new_node, n + 1, entry, type);
 }
 
+/*
+ * How to consolidate an int_node:
+ * If there are > 1 non-NULL entries, give up and return non-zero.
+ * Otherwise replace the int_node at the given index in the given parent node
+ * with the only entry (or a NULL entry if no entries) from the given tree,
+ * and return 0.
+ */
+static int note_tree_consolidate(struct int_node *tree,
+	struct int_node *parent, unsigned char index)
+{
+	unsigned int i;
+	void *p = NULL;
+
+	assert(tree && parent);
+	assert(CLR_PTR_TYPE(parent->a[index]) == tree);
+
+	for (i = 0; i < 16; i++) {
+		if (GET_PTR_TYPE(tree->a[i]) != PTR_TYPE_NULL) {
+			if (p) /* more than one entry */
+				return -2;
+			p = tree->a[i];
+		}
+	}
+
+	/* replace tree with p in parent[index] */
+	parent->a[index] = p;
+	free(tree);
+	return 0;
+}
+
+/*
+ * To remove a leaf_node:
+ * Search to the tree location appropriate for the given leaf_node's key:
+ * - If location does not hold a matching entry, abort and do nothing.
+ * - Replace the matching leaf_node with a NULL entry (and free the leaf_node).
+ * - Consolidate int_nodes repeatedly, while walking up the tree towards root.
+ */
+static void note_tree_remove(struct int_node *tree, unsigned char n,
+		struct leaf_node *entry)
+{
+	struct leaf_node *l;
+	struct int_node *parent_stack[20];
+	unsigned char i, j;
+	void **p = note_tree_search(&tree, &n, entry->key_sha1);
+
+	assert(GET_PTR_TYPE(entry) == 0); /* no type bits set */
+	if (GET_PTR_TYPE(*p) != PTR_TYPE_NOTE)
+		return; /* type mismatch, nothing to remove */
+	l = (struct leaf_node *) CLR_PTR_TYPE(*p);
+	if (hashcmp(l->key_sha1, entry->key_sha1))
+		return; /* key mismatch, nothing to remove */
+
+	/* we have found a matching entry */
+	free(l);
+	*p = SET_PTR_TYPE(NULL, PTR_TYPE_NULL);
+
+	/* consolidate this tree level, and parent levels, if possible */
+	if (!n)
+		return; /* cannot consolidate top level */
+	/* first, build stack of ancestors between root and current node */
+	parent_stack[0] = &root_node;
+	for (i = 0; i < n; i++) {
+		j = GET_NIBBLE(i, entry->key_sha1);
+		parent_stack[i + 1] = CLR_PTR_TYPE(parent_stack[i]->a[j]);
+	}
+	assert(i == n && parent_stack[i] == tree);
+	/* next, unwind stack until note_tree_consolidate() is done */
+	while (i > 0 &&
+	       !note_tree_consolidate(parent_stack[i], parent_stack[i - 1],
+				      GET_NIBBLE(i - 1, entry->key_sha1)))
+		i--;
+}
+
 /* Free the entire notes data contained in the given tree */
 static void note_tree_free(struct int_node *tree)
 {
@@ -379,6 +452,16 @@ void add_note(const unsigned char *object_sha1, const unsigned char *note_sha1)
 	note_tree_insert(&root_node, 0, l, PTR_TYPE_NOTE);
 }
 
+void remove_note(const unsigned char *object_sha1)
+{
+	struct leaf_node l;
+
+	assert(initialized);
+	hashcpy(l.key_sha1, object_sha1);
+	hashclr(l.val_sha1);
+	return note_tree_remove(&root_node, 0, &l);
+}
+
 static unsigned char *lookup_notes(const unsigned char *object_sha1)
 {
 	struct leaf_node *found = note_tree_find(&root_node, 0, object_sha1);
diff --git a/notes.h b/notes.h
index 5f22852..9e66855 100644
--- a/notes.h
+++ b/notes.h
@@ -25,6 +25,9 @@ void init_notes(const char *notes_ref, int flags);
 void add_note(const unsigned char *object_sha1,
 		const unsigned char *note_sha1);
 
+/* Remove the given note object from the internal notes tree structure */
+void remove_note(const unsigned char *object_sha1);
+
 /* Free (and de-initialize) the internal notes tree structure */
 void free_notes(void);
 
-- 
1.6.6.405.g80ed6
Previous: Johan HerlandNext: Johan Herland
Message 9 of 31 in “[PATCHv12 00/23] git notes”
  1. Johan HerlandJan 27, 2010
  2. 01/23 Minor non-functional fixes to notes.cJohan Herland, Jan 27, 2010
  3. Junio C HamanoJan 27, 2010
  4. Johan HerlandJan 27, 2010
  5. 02/23 Notes API: get_commit_notes() -> format_note() + remove the commit restrictionJohan Herland, Jan 27, 2010
  6. 03/23 Add tests for checking correct handling of $GIT_NOTES_REF and core.notesRefJohan Herland, Jan 27, 2010
  7. 04/23 Notes API: init_notes(): Initialize the notes tree from the given notes refJohan Herland, Jan 27, 2010
  8. 05/23 Notes API: add_note(): Add note objects to the internal notes tree structureJohan Herland, Jan 27, 2010
  9. 06/23 Notes API: remove_note(): Remove note objects from the notes tree structureJohan Herland, Jan 27, 2010
  10. 07/23 Notes API: get_note(): Return the note annotating the given objectJohan Herland, Jan 27, 2010
  11. 08/23 Notes API: for_each_note(): Traverse the entire notes tree with a callbackJohan Herland, Jan 27, 2010
  12. 09/23 Notes API: write_notes_tree(): Store the notes tree in the databaseJohan Herland, Jan 27, 2010
  13. 10/23 Notes API: Allow multiple concurrent notes trees with new struct notes_treeJohan Herland, Jan 27, 2010
  14. 11/23 Refactor notes concatenation into a flexible interface for combining notesJohan Herland, Jan 27, 2010
  15. 12/23 Builtin-ify git-notesJohan Herland, Jan 27, 2010
  16. 13/23 t3301: Verify successful annotation of non-commitsJohan Herland, Jan 27, 2010
  17. 14/23 t3305: Verify that adding many notes with git-notes triggers increased fanoutJohan Herland, Jan 27, 2010
  18. 15/23 Teach notes code to properly preserve non-notes in the notes treeJohan Herland, Jan 27, 2010
  19. 16/23 Teach builtin-notes to remove empty notesJohan Herland, Jan 27, 2010
  20. 17/23 builtin-notes: Add "remove" subcommand for removing existing notesJohan Herland, Jan 27, 2010
  21. 18/23 t3305: Verify that removing notes triggers automatic fanout consolidationJohan Herland, Jan 27, 2010
  22. 19/23 Notes API: prune_notes(): Prune notes that belong to non-existing objectsJohan Herland, Jan 27, 2010
  23. 20/23 builtin-notes: Add "prune" subcommand for removing notes for missing objectsJohan Herland, Jan 27, 2010
  24. 21/23 Documentation: Generalize git-notes docs to 'objects' instead of 'commits'Johan Herland, Jan 27, 2010
  25. 22/23 builtin-notes: Add "list" subcommand for listing note objectsJohan Herland, Jan 27, 2010
  26. 23/23 builtin-notes: Add "add" subcommand for appending to note objectsJohan Herland, Jan 27, 2010
  27. Junio C HamanoJan 27, 2010
  28. Sverre RabbelierJan 27, 2010
  29. Johan HerlandJan 27, 2010
  30. Junio C HamanoJan 28, 2010
  31. Johan HerlandJan 28, 2010

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.