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