1 /*
2    BAREOS® - Backup Archiving REcovery Open Sourced
3 
4    Copyright (C) 2005-2011 Free Software Foundation Europe e.V.
5 
6    This program is Free Software; you can redistribute it and/or
7    modify it under the terms of version three of the GNU Affero General Public
8    License as published by the Free Software Foundation and included
9    in the file LICENSE.
10 
11    This program is distributed in the hope that it will be useful, but
12    WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14    Affero General Public License for more details.
15 
16    You should have received a copy of the GNU Affero General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19    02110-1301, USA.
20 */
21 /*
22  * BAREOS red-black binary tree routines.
23  *
24  * rblist is a binary tree with the links being in the data item.
25  *
26  * Developed in part from ideas obtained from several online University courses.
27  *
28  * Kern Sibbald, November MMV
29  */
30 
31 #include "include/bareos.h"
32 #include "lib/rblist.h"
33 
34 /*
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
39  *   to avoid recursion.
40  *
41  * Returns: item         if item inserted
42  *          other_item   if same value already exists (item not inserted)
43  */
insert(void * item,int compare (void * item1,void * item2))44 void* rblist::insert(void* item, int compare(void* item1, void* item2))
45 {
46   void *x, *y;
47   void* last = NULL; /* last leaf if not found */
48   void* found = NULL;
49   int comp = 0;
50 
51   /* Search */
52   x = head;
53   while (x && !found) {
54     last = x;
55     comp = compare(item, x);
56     if (comp < 0) {
57       x = left(x);
58     } else if (comp > 0) {
59       x = right(x);
60     } else {
61       found = x;
62     }
63   }
64 
65   if (found) {    /* found? */
66     return found; /* yes, return item found */
67   }
68   SetLeft(item, NULL);
69   SetRight(item, NULL);
70   SetParent(item, NULL);
71   SetRed(item, false);
72   /* Handle empty tree */
73   if (num_items == 0) {
74     head = item;
75     num_items++;
76     return item;
77   }
78   x = last;
79   /* Not found, so insert it on appropriate side of tree */
80   if (comp < 0) {
81     SetLeft(last, item);
82   } else {
83     SetRight(last, item);
84   }
85   SetRed(last, true);
86   SetParent(item, last);
87   num_items++;
88 
89   /* Now we must walk up the tree balancing it */
90   x = last;
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)));
95       if (y && red(y)) {
96         /* our parent must be black */
97         SetRed(parent(x), false);
98         SetRed(y, false);
99         SetRed(parent(parent(x)), true);
100         x = parent(parent(x)); /* move up to grandpa */
101       } else {
102         if (x == right(parent(x))) { /* right side of parent? */
103           x = parent(x);
104           LeftRotate(x);
105         }
106         /* make parent black too */
107         SetRed(parent(x), false);
108         SetRed(parent(parent(x)), true);
109         RightRotate(parent(parent(x)));
110       }
111     } else {
112       /* Look at left side of our grandparent */
113       y = left(parent(parent(x)));
114       if (y && red(y)) {
115         SetRed(parent(x), false);
116         SetRed(y, false);
117         SetRed(parent(parent(x)), true);
118         x = parent(parent(x)); /* move up to grandpa */
119       } else {
120         if (x == left(parent(x))) {
121           x = parent(x);
122           RightRotate(x);
123         }
124         /* make parent black too */
125         SetRed(parent(x), false);
126         SetRed(parent(parent(x)), true);
127         LeftRotate(parent(parent(x)));
128       }
129     }
130   }
131   /* Make sure the head is always black */
132   SetRed(head, false);
133   return item;
134 }
135 
136 /*
137  * Search for item
138  */
search(void * item,int compare (void * item1,void * item2))139 void* rblist::search(void* item, int compare(void* item1, void* item2))
140 {
141   void* found = NULL;
142   void* x;
143   int comp;
144 
145   x = head;
146   while (x) {
147     comp = compare(item, x);
148     if (comp < 0) {
149       x = left(x);
150     } else if (comp > 0) {
151       x = right(x);
152     } else {
153       found = x;
154       break;
155     }
156   }
157   return found;
158 }
159 
160 /*
161  * Get first item (i.e. lowest value)
162  */
first(void)163 void* rblist::first(void)
164 {
165   void* x;
166 
167   x = head;
168   down = true;
169   while (x) {
170     if (left(x)) {
171       x = left(x);
172       continue;
173     }
174     return x;
175   }
176   /* Tree is empty */
177   return NULL;
178 }
179 
180 /*
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.
185  *
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
190  *  left.  etc.
191  *
192  * Returns: pointer to next larger item
193  *          NULL when no more items in tree
194  */
next(void * item)195 void* rblist::next(void* item)
196 {
197   void* x;
198 
199   if (!item) { return first(); }
200 
201   x = item;
202   if ((down && !left(x) && right(x)) || (!down && right(x))) {
203     /* Move down to right one */
204     down = true;
205     x = right(x);
206     /* Then all the way down left */
207     while (left(x)) { x = left(x); }
208     return x;
209   }
210 
211   /* We have gone down all we can, so now go up */
212   for (;;) {
213     /* If at head, we are done */
214     if (!parent(x)) { return NULL; }
215     /* Move up in tree */
216     down = false;
217     /* if coming from right, continue up */
218     if (right(parent(x)) == x) {
219       x = parent(x);
220       continue;
221     }
222     /* Coming from left, go up one -- ie. return parent */
223     return parent(x);
224   }
225 }
226 
227 /*
228  * Similer to next(), but visits all right nodes when
229  *  coming up the tree.
230  */
any(void * item)231 void* rblist::any(void* item)
232 {
233   void* x;
234 
235   if (!item) { return NULL; }
236 
237   x = item;
238   if ((down && !left(x) && right(x)) || (!down && right(x))) {
239     /* Move down to right one */
240     down = true;
241     x = right(x);
242     /* Then all the way down left */
243     while (left(x)) { x = left(x); }
244     return x;
245   }
246 
247   /* We have gone down all we can, so now go up */
248   for (;;) {
249     /* If at head, we are done */
250     if (!parent(x)) { return NULL; }
251     down = false;
252     /* Go up one and return parent */
253     return parent(x);
254   }
255 }
256 
257 
258 /* x is item, y is below and to right, then rotated to below left */
LeftRotate(void * item)259 void rblist::LeftRotate(void* item)
260 {
261   void* y;
262   void* x;
263 
264   x = item;
265   y = right(x);
266   SetRight(x, left(y));
267   if (left(y)) { SetParent(left(y), x); }
268   SetParent(y, parent(x));
269   /* if no parent then we have a new head */
270   if (!parent(x)) {
271     head = y;
272   } else if (x == left(parent(x))) {
273     SetLeft(parent(x), y);
274   } else {
275     SetRight(parent(x), y);
276   }
277   SetLeft(y, x);
278   SetParent(x, y);
279 }
280 
RightRotate(void * item)281 void rblist::RightRotate(void* item)
282 {
283   void *x, *y;
284 
285   y = item;
286   x = left(y);
287   SetLeft(y, right(x));
288   if (right(x)) { SetParent(right(x), y); }
289   SetParent(x, parent(y));
290   /* if no parent then we have a new head */
291   if (!parent(y)) {
292     head = x;
293   } else if (y == left(parent(y))) {
294     SetLeft(parent(y), x);
295   } else {
296     SetRight(parent(y), x);
297   }
298   SetRight(x, y);
299   SetParent(y, x);
300 }
301 
302 
remove(void * item)303 void rblist::remove(void* item) {}
304 
305 /* Destroy the tree contents.  Not totally working */
destroy()306 void rblist::destroy()
307 {
308   void *x, *y = NULL;
309 
310   x = first();
311   // printf("head=%p first=%p left=%p right=%p\n", head, x, left(x), right(x));
312   for (; (y = any(x));) {
313     /* Prune the last item */
314     if (parent(x)) {
315       if (x == left(parent(x))) {
316         SetLeft(parent(x), NULL);
317       } else if (x == right(parent(x))) {
318         SetRight(parent(x), NULL);
319       }
320     }
321     if (!left(x) && !right(x)) {
322       if (head == x) { head = NULL; }
323       //          if (num_items<30) {
324       //             printf("free nitems=%d item=%p left=%p right=%p\n",
325       //             num_items, x, left(x), right(x));
326       //          }
327       free((void*)x); /* free previous node */
328       num_items--;
329     }
330     x = y; /* save last node */
331   }
332   if (x) {
333     if (x == head) { head = NULL; }
334     //    printf("free nitems=%d item=%p left=%p right=%p\n", num_items, x,
335     //    left(x), right(x));
336     free((void*)x);
337     num_items--;
338   }
339   if (head) {
340     //    printf("Free head\n");
341     free((void*)head);
342   }
343   // printf("free nitems=%d\n", num_items);
344 
345   head = NULL;
346 }
347