@matheusbsbs / matheus-bagliano / commits / 1ec666b092
Fork 0

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>

Johan Herland committed Feb 13, 2010 at 22:28 UTC 1ec666b092d1df5691cd4d38f20aaeadd5049aa2
2 files changed +87 -1
notes.c
+84 -1
@@ -44,7 +44,7 @@ struct leaf_node {
44 #define CLR_PTR_TYPE(ptr) ((void *) ((uintptr_t) (ptr) & ~3))
45 #define SET_PTR_TYPE(ptr, type) ((void *) ((uintptr_t) (ptr) | (type)))
46
47 -#define GET_NIBBLE(n, sha1) (((sha1[n >> 1]) >> ((~n & 0x01) << 2)) & 0x0f)
47 +#define GET_NIBBLE(n, sha1) (((sha1[(n) >> 1]) >> ((~(n) & 0x01) << 2)) & 0x0f)
48
49 #define SUBTREE_SHA1_PREFIXCMP(key_sha1, subtree_sha1) \
50 (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 note_tree_insert(new_node, n + 1, entry, type);
250 }
251
252 +/*
253 + * How to consolidate an int_node:
254 + * If there are > 1 non-NULL entries, give up and return non-zero.
255 + * Otherwise replace the int_node at the given index in the given parent node
256 + * with the only entry (or a NULL entry if no entries) from the given tree,
257 + * and return 0.
258 + */
259 +static int note_tree_consolidate(struct int_node *tree,
260 + struct int_node *parent, unsigned char index)
261 +{
262 + unsigned int i;
263 + void *p = NULL;
264 +
265 + assert(tree && parent);
266 + assert(CLR_PTR_TYPE(parent->a[index]) == tree);
267 +
268 + for (i = 0; i < 16; i++) {
269 + if (GET_PTR_TYPE(tree->a[i]) != PTR_TYPE_NULL) {
270 + if (p) /* more than one entry */
271 + return -2;
272 + p = tree->a[i];
273 + }
274 + }
275 +
276 + /* replace tree with p in parent[index] */
277 + parent->a[index] = p;
278 + free(tree);
279 + return 0;
280 +}
281 +
282 +/*
283 + * To remove a leaf_node:
284 + * Search to the tree location appropriate for the given leaf_node's key:
285 + * - If location does not hold a matching entry, abort and do nothing.
286 + * - Replace the matching leaf_node with a NULL entry (and free the leaf_node).
287 + * - Consolidate int_nodes repeatedly, while walking up the tree towards root.
288 + */
289 +static void note_tree_remove(struct int_node *tree, unsigned char n,
290 + struct leaf_node *entry)
291 +{
292 + struct leaf_node *l;
293 + struct int_node *parent_stack[20];
294 + unsigned char i, j;
295 + void **p = note_tree_search(&tree, &n, entry->key_sha1);
296 +
297 + assert(GET_PTR_TYPE(entry) == 0); /* no type bits set */
298 + if (GET_PTR_TYPE(*p) != PTR_TYPE_NOTE)
299 + return; /* type mismatch, nothing to remove */
300 + l = (struct leaf_node *) CLR_PTR_TYPE(*p);
301 + if (hashcmp(l->key_sha1, entry->key_sha1))
302 + return; /* key mismatch, nothing to remove */
303 +
304 + /* we have found a matching entry */
305 + free(l);
306 + *p = SET_PTR_TYPE(NULL, PTR_TYPE_NULL);
307 +
308 + /* consolidate this tree level, and parent levels, if possible */
309 + if (!n)
310 + return; /* cannot consolidate top level */
311 + /* first, build stack of ancestors between root and current node */
312 + parent_stack[0] = &root_node;
313 + for (i = 0; i < n; i++) {
314 + j = GET_NIBBLE(i, entry->key_sha1);
315 + parent_stack[i + 1] = CLR_PTR_TYPE(parent_stack[i]->a[j]);
316 + }
317 + assert(i == n && parent_stack[i] == tree);
318 + /* next, unwind stack until note_tree_consolidate() is done */
319 + while (i > 0 &&
320 + !note_tree_consolidate(parent_stack[i], parent_stack[i - 1],
321 + GET_NIBBLE(i - 1, entry->key_sha1)))
322 + i--;
323 +}
324 +
325 /* Free the entire notes data contained in the given tree */
326 static void note_tree_free(struct int_node *tree)
327 {
@@ -379,6 +452,16 @@ void add_note(const unsigned char *object_sha1, const unsigned char *note_sha1)
452 note_tree_insert(&root_node, 0, l, PTR_TYPE_NOTE);
453 }
454
455 +void remove_note(const unsigned char *object_sha1)
456 +{
457 + struct leaf_node l;
458 +
459 + assert(initialized);
460 + hashcpy(l.key_sha1, object_sha1);
461 + hashclr(l.val_sha1);
462 + return note_tree_remove(&root_node, 0, &l);
463 +}
464 +
465 static unsigned char *lookup_notes(const unsigned char *object_sha1)
466 {
467 struct leaf_node *found = note_tree_find(&root_node, 0, object_sha1);
notes.h
+3
@@ -25,6 +25,9 @@ void init_notes(const char *notes_ref, int flags);
25 void add_note(const unsigned char *object_sha1,
26 const unsigned char *note_sha1);
27
28 +/* Remove the given note object from the internal notes tree structure */
29 +void remove_note(const unsigned char *object_sha1);
30 +
31 /* Free (and de-initialize) the internal notes tree structure */
32 void free_notes(void);
33