2 Bacula® - The Network Backup Solution
4 Copyright (C) 2005-2014 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from many
7 others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 Bacula® is a registered trademark of Kern Sibbald.
17 * Bacula red-black binary tree routines.
19 * rblist is a binary tree with the links being in the data item.
21 * Developped in part from ideas obtained from several online University
24 * Kern Sibbald, November MMV
30 /* ===================================================================
35 * Insert an item in the tree, but only if it is unique
36 * otherwise, the item is returned non inserted
37 * The big trick is keeping the tree balanced after the
38 * insert. We use a parent pointer to make it simpler and
41 * Returns: item if item inserted
42 * other_item if same value already exists (item not inserted)
44 void *rblist::insert(void *item, int compare(void *item1, void *item2))
47 void *last = NULL; /* last leaf if not found */
55 comp = compare(item, x);
58 } else if (comp > 0) {
65 if (found) { /* found? */
66 return found; /* yes, return item found */
69 set_right(item, NULL);
70 set_parent(item, NULL);
72 /* Handle empty tree */
79 /* Not found, so insert it on appropriate side of tree */
83 set_right(last, item);
86 set_parent(item, last);
89 /* Now we must walk up the tree balancing it */
91 while (x != head && red(parent(x))) {
92 if (parent(x) == left(parent(parent(x)))) {
93 /* Look at the right side of our grandparent */
94 y = right(parent(parent(x)));
96 /* our parent must be black */
97 set_red(parent(x), false);
99 set_red(parent(parent(x)), true);
100 x = parent(parent(x)); /* move up to grandpa */
102 if (x == right(parent(x))) { /* right side of parent? */
106 /* make parent black too */
107 set_red(parent(x), false);
108 set_red(parent(parent(x)), true);
109 right_rotate(parent(parent(x)));
112 /* Look at left side of our grandparent */
113 y = left(parent(parent(x)));
115 set_red(parent(x), false);
117 set_red(parent(parent(x)), true);
118 x = parent(parent(x)); /* move up to grandpa */
120 if (x == left(parent(x))) {
124 /* make parent black too */
125 set_red(parent(x), false);
126 set_red(parent(parent(x)), true);
127 left_rotate(parent(parent(x)));
131 /* Make sure the head is always black */
132 set_red(head, false);
139 void *rblist::search(void *item, int compare(void *item1, void *item2))
147 comp = compare(item, x);
150 } else if (comp > 0) {
161 * Get first item (i.e. lowest value)
163 void *rblist::first(void)
181 * This is a non-recursive btree walk routine that returns
182 * the items one at a time in order. I've never seen a
183 * non-recursive tree walk routine published that returns
184 * one item at a time rather than doing a callback.
186 * Return the next item in sorted order. We assume first()
187 * was called once before calling this routine.
188 * We always go down as far as we can to the left, then up, and
189 * down one to the right, and again down as far as we can to the
192 * Returns: pointer to next larger item
193 * NULL when no more items in tree
195 void *rblist::next(void *item)
204 if ((down && !left(x) && right(x)) || (!down && right(x))) {
205 /* Move down to right one */
208 /* Then all the way down left */
215 /* We have gone down all we can, so now go up */
217 /* If at head, we are done */
221 /* Move up in tree */
223 /* if coming from right, continue up */
224 if (right(parent(x)) == x) {
228 /* Coming from left, go up one -- ie. return parent */
234 * Similer to next(), but visits all right nodes when
235 * coming up the tree.
237 void *rblist::any(void *item)
246 if ((down && !left(x) && right(x)) || (!down && right(x))) {
247 /* Move down to right one */
250 /* Then all the way down left */
257 /* We have gone down all we can, so now go up */
259 /* If at head, we are done */
264 /* Go up one and return parent */
270 /* x is item, y is below and to right, then rotated to below left */
271 void rblist::left_rotate(void *item)
278 set_right(x, left(y));
280 set_parent(left(y), x);
282 set_parent(y, parent(x));
283 /* if no parent then we have a new head */
286 } else if (x == left(parent(x))) {
287 set_left(parent(x), y);
289 set_right(parent(x), y);
295 void rblist::right_rotate(void *item)
301 set_left(y, right(x));
303 set_parent(right(x), y);
305 set_parent(x, parent(y));
306 /* if no parent then we have a new head */
309 } else if (y == left(parent(y))) {
310 set_left(parent(y), x);
312 set_right(parent(y), x);
319 void rblist::remove(void *item)
323 /* Destroy the tree contents. Not totally working */
324 void rblist::destroy()
329 // printf("head=%p first=%p left=%p right=%p\n", head, x, left(x), right(x));
330 for ( ; (y=any(x)); ) {
331 /* Prune the last item */
333 if (x == left(parent(x))) {
334 set_left(parent(x), NULL);
335 } else if (x == right(parent(x))) {
336 set_right(parent(x), NULL);
339 if (!left(x) && !right(x)) {
343 // if (num_items<30) {
344 // printf("free nitems=%d item=%p left=%p right=%p\n", num_items, x, left(x), right(x));
346 free((void *)x); /* free previous node */
349 x = y; /* save last node */
355 // printf("free nitems=%d item=%p left=%p right=%p\n", num_items, x, left(x), right(x));
360 // printf("Free head\n");
363 // printf("free nitems=%d\n", num_items);
377 static int my_compare(void *item1, void *item2)
381 jcr1 = (MYJCR *)item1;
382 jcr2 = (MYJCR *)item2;
383 comp = strcmp(jcr1->buf, jcr2->buf);
384 //Dmsg3(000, "compare=%d: %s to %s\n", comp, jcr1->buf, jcr2->buf);
396 /* Now do a binary insert for the tree */
397 jcr_chain = New(rblist());
399 printf("append %d items\n", CNT*CNT*CNT);
402 for (int i=0; i<CNT; i++) {
403 for (int j=0; j<CNT; j++) {
404 for (int k=0; k<CNT; k++) {
406 if ((count & 0x3FF) == 0) {
407 Dmsg1(000, "At %d\n", count);
409 jcr = (MYJCR *)malloc(sizeof(MYJCR));
410 memset(jcr, 0, sizeof(MYJCR));
411 jcr->buf = bstrdup(buf);
412 // printf("buf=%p %s\n", jcr, jcr->buf);
413 jcr1 = (MYJCR *)jcr_chain->insert((void *)jcr, my_compare);
415 Dmsg2(000, "Insert of %s vs %s failed.\n", jcr->buf, jcr1->buf);
425 printf("%d items appended\n", CNT*CNT*CNT);
426 printf("num_items=%d\n", jcr_chain->size());
428 jcr = (MYJCR *)malloc(sizeof(MYJCR));
429 memset(jcr, 0, sizeof(MYJCR));
431 jcr->buf = bstrdup("a");
432 if ((jcr1=(MYJCR *)jcr_chain->search((void *)jcr, my_compare))) {
433 printf("One less failed!!!! Got: %s\n", jcr1->buf);
435 printf("One less: OK\n");
439 jcr->buf = bstrdup("ZZZZZZZZZZZZZZZZ");
440 if ((jcr1=(MYJCR *)jcr_chain->search((void *)jcr, my_compare))) {
441 printf("One greater failed!!!! Got:%s\n", jcr1->buf);
443 printf("One greater: OK\n");
447 jcr->buf = bstrdup("AAA");
448 if ((jcr1=(MYJCR *)jcr_chain->search((void *)jcr, my_compare))) {
449 printf("Search for AAA got %s\n", jcr1->buf);
451 printf("Search for AAA not found\n");
455 jcr->buf = bstrdup("ZZZ");
456 if ((jcr1 = (MYJCR *)jcr_chain->search((void *)jcr, my_compare))) {
457 printf("Search for ZZZ got %s\n", jcr1->buf);
459 printf("Search for ZZZ not found\n");
465 printf("Find each of %d items in tree.\n", count);
466 for (jcr=(MYJCR *)jcr_chain->first(); jcr; (jcr=(MYJCR *)jcr_chain->next((void *)jcr)) ) {
467 // printf("Got: %s\n", jcr->buf);
468 if (!jcr_chain->search((void *)jcr, my_compare)) {
469 printf("rblist binary_search item not found = %s\n", jcr->buf);
472 printf("Free each of %d items in tree.\n", count);
473 for (jcr=(MYJCR *)jcr_chain->first(); jcr; (jcr=(MYJCR *)jcr_chain->next((void *)jcr)) ) {
474 // printf("Free: %p %s\n", jcr, jcr->buf);
478 printf("num_items=%d\n", jcr_chain->size());
482 sm_dump(true); /* unit test */