Browse Source

Notes API: remove_note(): Remove note objects from the notes tree structure

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

Signed-off-by: Johan Herland <johan@herland.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
maint
Johan Herland 15 years ago committed by Junio C Hamano
parent
commit
1ec666b092
  1. 85
      notes.c
  2. 3
      notes.h

85
notes.c

@ -44,7 +44,7 @@ struct leaf_node { @@ -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, @@ -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) @@ -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);

3
notes.h

@ -25,6 +25,9 @@ void init_notes(const char *notes_ref, int flags); @@ -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);


Loading…
Cancel
Save