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

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

From
Johan Herland <johan@herland.net>
Date
Feb 13, 2010, 21:28 UTC
Message-ID
<1266096518-2104-7-git-send-email-johan@herland.net>
In-Reply-To
<1266096518-2104-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.7.0.rc1.141.gd3fd
Previous: Johan HerlandNext: Johan Herland
Message 7 of 35 in “[PATCHv13 00/30] git notes”
  1. Johan HerlandFeb 13, 2010
  2. 01/30 Minor cosmetic fixes to notes.cJohan Herland, Feb 13, 2010
  3. 02/30 Notes API: get_commit_notes() -> format_note() + remove the commit restrictionJohan Herland, Feb 13, 2010
  4. 03/30 Add tests for checking correct handling of $GIT_NOTES_REF and core.notesRefJohan Herland, Feb 13, 2010
  5. 04/30 Notes API: init_notes(): Initialize the notes tree from the given notes refJohan Herland, Feb 13, 2010
  6. 05/30 Notes API: add_note(): Add note objects to the internal notes tree structureJohan Herland, Feb 13, 2010
  7. 06/30 Notes API: remove_note(): Remove note objects from the notes tree structureJohan Herland, Feb 13, 2010
  8. 07/30 Notes API: get_note(): Return the note annotating the given objectJohan Herland, Feb 13, 2010
  9. 08/30 Notes API: for_each_note(): Traverse the entire notes tree with a callbackJohan Herland, Feb 13, 2010
  10. 09/30 Notes API: write_notes_tree(): Store the notes tree in the databaseJohan Herland, Feb 13, 2010
  11. 10/30 Notes API: Allow multiple concurrent notes trees with new struct notes_treeJohan Herland, Feb 13, 2010
  12. 11/30 Refactor notes concatenation into a flexible interface for combining notesJohan Herland, Feb 13, 2010
  13. 12/30 Builtin-ify git-notesJohan Herland, Feb 13, 2010
  14. 13/30 t3301: Verify successful annotation of non-commitsJohan Herland, Feb 13, 2010
  15. 14/30 t3305: Verify that adding many notes with git-notes triggers increased fanoutJohan Herland, Feb 13, 2010
  16. 15/30 Teach notes code to properly preserve non-notes in the notes treeJohan Herland, Feb 13, 2010
  17. 16/30 Teach builtin-notes to remove empty notesJohan Herland, Feb 13, 2010
  18. 17/30 builtin-notes: Add "remove" subcommand for removing existing notesJohan Herland, Feb 13, 2010
  19. 18/30 t3305: Verify that removing notes triggers automatic fanout consolidationJohan Herland, Feb 13, 2010
  20. 19/30 Notes API: prune_notes(): Prune notes that belong to non-existing objectsJohan Herland, Feb 13, 2010
  21. 20/30 builtin-notes: Add "prune" subcommand for removing notes for missing objectsJohan Herland, Feb 13, 2010
  22. 21/30 Documentation: Generalize git-notes docs to 'objects' instead of 'commits'Johan Herland, Feb 13, 2010
  23. 22/30 builtin-notes: Add "list" subcommand for listing note objectsJohan Herland, Feb 13, 2010
  24. 23/30 builtin-notes: Add --message/--file aliases for -m/-F optionsJohan Herland, Feb 13, 2010
  25. 24/30 builtin-notes: Add "add" subcommand for adding notes to objectsJohan Herland, Feb 13, 2010
  26. 25/30 builtin-notes: Add "append" subcommand for appending to note objectsJohan Herland, Feb 13, 2010
  27. 26/30 builtin-notes: Deprecate the -m/-F options for "git notes edit"Johan Herland, Feb 13, 2010
  28. 27/30 builtin-notes: Refactor handling of -F option to allow combining -m and -FJohan Herland, Feb 13, 2010
  29. 28/30 builtin-notes: Add -c/-C options for reusing notesJohan Herland, Feb 13, 2010
  30. Stephen BoydFeb 15, 2010
  31. Johan HerlandFeb 16, 2010
  32. builtin-notes: Minor (mostly parse_options-related) fixesJohan Herland, Feb 25, 2010
  33. Stephen BoydFeb 25, 2010
  34. 29/30 builtin-notes: Misc. refactoring of argc and exit value handlingJohan Herland, Feb 13, 2010
  35. 30/30 builtin-notes: Add "copy" subcommand for copying notes between objectsJohan Herland, Feb 13, 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.