1 /******************************************************************************
4 * Lock-based red-black trees, based on Hanke's relaxed balancing operations.
6 * For more details on the local tree restructuring operations used here:
7 * S. Hanke, T. Ottmann, and E. Soisalon-Soininen.
8 * "Relaxed balanced red-black trees".
9 * 3rd Italian Conference on Algorithms and Complexity, pages 193-204.
11 * Rather than issuing up-in and up-out requests to a balancing process,
12 * each operation is directly responsible for local rebalancing. However,
13 * this process can be split into a number of individual restructuring
14 * operations, and locks can be released between each operation. Between
15 * operations, we mark the node concerned as UNBALANCED -- contending
16 * updates will then wait for this mark to be removed before continuing.
18 * Copyright (c) 2002-2003, K A Fraser
20 Redistribution and use in source and binary forms, with or without
21 modification, are permitted provided that the following conditions are
24 * Redistributions of source code must retain the above copyright
25 * notice, this list of conditions and the following disclaimer.
26 * Redistributions in binary form must reproduce the above
27 * copyright notice, this list of conditions and the following
28 * disclaimer in the documentation and/or other materials provided
29 * with the distribution. Neither the name of the Keir Fraser
30 * nor the names of its contributors may be used to endorse or
31 * promote products derived from this software without specific
32 * prior written permission.
34 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
35 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
36 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
37 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
38 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
39 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
40 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
41 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
42 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
43 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
44 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47 #define __SET_IMPLEMENTATION__
53 #include "portable_defns.h"
59 #define UNBALANCED_MARK 2
61 #define SET_VALUE(_v,_n) \
62 ((_v) = ((setval_t)(((unsigned long)(_v)&3)|((unsigned long)(_n)))))
63 #define GET_VALUE(_v) ((setval_t)((int_addr_t)(_v) & ~3UL))
64 #define GET_COLOUR(_v) ((int_addr_t)(_v) & 1)
65 #define SET_COLOUR(_v,_c) \
66 ((setval_t)(((unsigned long)(_v)&~1UL)|(unsigned long)(_c)))
68 #define IS_BLACK(_v) (GET_COLOUR(_v) == 0)
69 #define IS_RED(_v) (GET_COLOUR(_v) == 1)
70 #define IS_UNBALANCED(_v) (((int_addr_t)(_v) & 2) == 2)
72 #define MK_BLACK(_v) ((setval_t)(((int_addr_t)(_v)&~1UL) | 0))
73 #define MK_RED(_v) ((setval_t)(((int_addr_t)(_v)&~1UL) | 1))
74 #define MK_BALANCED(_v) ((setval_t)(((int_addr_t)(_v)&~2UL) | 0))
75 #define MK_UNBALANCED(_v) ((setval_t)(((int_addr_t)(_v)&~2UL) | 2))
77 #define GARBAGE_VALUE ((setval_t)4)
78 #define IS_GARBAGE(_n) (GET_VALUE((_n)->v) == GARBAGE_VALUE)
79 #define MK_GARBAGE(_n) (SET_VALUE((_n)->v, GARBAGE_VALUE))
81 #define INTERNAL_VALUE ((void *)0xdeadbee0)
83 #define IS_ROOT(_n) ((_n)->p->k == 0)
84 #define IS_LEAF(_n) ((_n)->l == NULL)
86 /* TRUE if node X is a child of P. */
87 #define ADJACENT(_p,_x) (((_p)->l==(_x))||((_p)->r==(_x)))
89 typedef struct node_st node_t
;
90 typedef struct set_st set_t
;
104 node_t dummy_g
, dummy_gg
;
109 /* Nodes p, x, y must be locked. */
110 static void left_rotate(ptst_t
*ptst
, node_t
*x
)
112 node_t
*y
= x
->r
, *p
= x
->p
, *nx
;
114 nx
= gc_alloc(ptst
, gc_id
);
128 if ( x
== p
->l
) p
->l
= y
; else p
->r
= y
;
131 gc_free(ptst
, x
, gc_id
);
135 /* Nodes p, x, y must be locked. */
136 static void right_rotate(ptst_t
*ptst
, node_t
*x
)
138 node_t
*y
= x
->l
, *p
= x
->p
, *nx
;
140 nx
= gc_alloc(ptst
, gc_id
);
154 if ( x
== p
->l
) p
->l
= y
; else p
->r
= y
;
157 gc_free(ptst
, x
, gc_id
);
161 static void fix_unbalance_up(ptst_t
*ptst
, node_t
*x
)
163 qnode_t x_qn
, g_qn
, p_qn
, w_qn
, gg_qn
;
164 node_t
*g
, *p
, *w
, *gg
;
168 assert(IS_UNBALANCED(x
->v
));
169 if ( IS_GARBAGE(x
) ) return;
175 mcs_lock(&gg
->lock
, &gg_qn
);
176 if ( !ADJACENT(gg
, g
) || IS_UNBALANCED(gg
->v
) || IS_GARBAGE(gg
) )
179 mcs_lock(&g
->lock
, &g_qn
);
180 if ( !ADJACENT(g
, p
) || IS_UNBALANCED(g
->v
) ) goto unlock_ggg
;
182 mcs_lock(&p
->lock
, &p_qn
);
183 if ( !ADJACENT(p
, x
) || IS_UNBALANCED(p
->v
) ) goto unlock_pggg
;
185 mcs_lock(&x
->lock
, &x_qn
);
187 assert(IS_RED(x
->v
));
188 assert(IS_UNBALANCED(x
->v
));
190 if ( IS_BLACK(p
->v
) )
192 /* Case 1. Nothing to do. */
193 x
->v
= MK_BALANCED(x
->v
);
201 x
->v
= MK_BLACK(MK_BALANCED(x
->v
));
209 p
->v
= MK_BLACK(p
->v
);
210 x
->v
= MK_BALANCED(x
->v
);
215 if ( g
->l
== p
) w
= g
->r
; else w
= g
->l
;
216 mcs_lock(&w
->lock
, &w_qn
);
221 /* In all other cases, doesn't change colour or subtrees. */
222 if ( IS_UNBALANCED(w
->v
) ) goto unlock_wxpggg
;
223 g
->v
= MK_UNBALANCED(MK_RED(g
->v
));
224 p
->v
= MK_BLACK(p
->v
);
225 w
->v
= MK_BLACK(w
->v
);
226 x
->v
= MK_BALANCED(x
->v
);
231 /* Cases 3 & 4. Both of these need the great-grandfather locked. */
236 /* Case 3. Single rotation. */
237 x
->v
= MK_BALANCED(x
->v
);
238 p
->v
= MK_BLACK(p
->v
);
240 right_rotate(ptst
, g
);
244 /* Case 4. Double rotation. */
245 x
->v
= MK_BALANCED(MK_BLACK(x
->v
));
247 left_rotate(ptst
, p
);
248 right_rotate(ptst
, g
);
251 else /* SYMMETRIC CASE */
255 /* Case 3. Single rotation. */
256 x
->v
= MK_BALANCED(x
->v
);
257 p
->v
= MK_BLACK(p
->v
);
259 left_rotate(ptst
, g
);
263 /* Case 4. Double rotation. */
264 x
->v
= MK_BALANCED(MK_BLACK(x
->v
));
266 right_rotate(ptst
, p
);
267 left_rotate(ptst
, g
);
274 mcs_unlock(&w
->lock
, &w_qn
);
276 mcs_unlock(&x
->lock
, &x_qn
);
278 mcs_unlock(&p
->lock
, &p_qn
);
280 mcs_unlock(&g
->lock
, &g_qn
);
282 mcs_unlock(&gg
->lock
, &gg_qn
);
294 static void fix_unbalance_down(ptst_t
*ptst
, node_t
*x
)
296 /* WN == W_NEAR, WF == W_FAR (W_FAR is further, in key space, from X). */
297 qnode_t x_qn
, w_qn
, p_qn
, g_qn
, wn_qn
, wf_qn
;
298 node_t
*w
, *p
, *g
, *wn
, *wf
;
302 if ( !IS_UNBALANCED(x
->v
) || IS_GARBAGE(x
) ) return;
307 mcs_lock(&g
->lock
, &g_qn
);
308 if ( !ADJACENT(g
, p
) || IS_UNBALANCED(g
->v
) || IS_GARBAGE(g
) )
311 mcs_lock(&p
->lock
, &p_qn
);
312 if ( !ADJACENT(p
, x
) || IS_UNBALANCED(p
->v
) ) goto unlock_pg
;
314 mcs_lock(&x
->lock
, &x_qn
);
316 if ( !IS_BLACK(x
->v
) || !IS_UNBALANCED(x
->v
) )
324 x
->v
= MK_BALANCED(x
->v
);
329 w
= (x
== p
->l
) ? p
->r
: p
->l
;
330 mcs_lock(&w
->lock
, &w_qn
);
331 if ( IS_UNBALANCED(w
->v
) )
333 if ( IS_BLACK(w
->v
) )
335 /* Funky relaxed rules to the rescue. */
336 x
->v
= MK_BALANCED(x
->v
);
337 w
->v
= MK_BALANCED(w
->v
);
338 if ( IS_BLACK(p
->v
) )
340 p
->v
= MK_UNBALANCED(p
->v
);
345 p
->v
= MK_BLACK(p
->v
);
365 mcs_lock(&wn
->lock
, &wn_qn
);
366 /* Hanke has an extra relaxed transform here. It's not needed. */
367 if ( IS_UNBALANCED(wn
->v
) ) goto unlock_wnwxpg
;
369 mcs_lock(&wf
->lock
, &wf_qn
);
370 if ( IS_UNBALANCED(wf
->v
) ) goto unlock_wfwnwxpg
;
374 /* Case 1. Rotate at parent. */
375 assert(IS_BLACK(p
->v
) && IS_BLACK(wn
->v
) && IS_BLACK(wf
->v
));
376 w
->v
= MK_BLACK(w
->v
);
378 if ( x
== p
->l
) left_rotate(ptst
, p
); else right_rotate(ptst
, p
);
379 goto unlock_wfwnwxpg
;
382 if ( IS_BLACK(wn
->v
) && IS_BLACK(wf
->v
) )
386 /* Case 2. Simple recolouring. */
387 p
->v
= MK_BLACK(p
->v
);
392 /* Case 5. Simple recolouring. */
393 p
->v
= MK_UNBALANCED(p
->v
);
397 x
->v
= MK_BALANCED(x
->v
);
398 goto unlock_wfwnwxpg
;
405 /* Case 3. Single rotation. */
406 wf
->v
= MK_BLACK(wf
->v
);
407 w
->v
= SET_COLOUR(w
->v
, GET_COLOUR(p
->v
));
408 p
->v
= MK_BLACK(p
->v
);
409 x
->v
= MK_BALANCED(x
->v
);
410 left_rotate(ptst
, p
);
414 /* Case 4. Double rotation. */
415 assert(IS_RED(wn
->v
));
416 wn
->v
= SET_COLOUR(wn
->v
, GET_COLOUR(p
->v
));
417 p
->v
= MK_BLACK(p
->v
);
418 x
->v
= MK_BALANCED(x
->v
);
419 right_rotate(ptst
, w
);
420 left_rotate(ptst
, p
);
423 else /* SYMMETRIC CASE: X == P->R */
427 /* Case 3. Single rotation. */
428 wf
->v
= MK_BLACK(wf
->v
);
429 w
->v
= SET_COLOUR(w
->v
, GET_COLOUR(p
->v
));
430 p
->v
= MK_BLACK(p
->v
);
431 x
->v
= MK_BALANCED(x
->v
);
432 right_rotate(ptst
, p
);
436 /* Case 4. Double rotation. */
437 assert(IS_RED(wn
->v
));
438 wn
->v
= SET_COLOUR(wn
->v
, GET_COLOUR(p
->v
));
439 p
->v
= MK_BLACK(p
->v
);
440 x
->v
= MK_BALANCED(x
->v
);
441 left_rotate(ptst
, w
);
442 right_rotate(ptst
, p
);
449 mcs_unlock(&wf
->lock
, &wf_qn
);
451 mcs_unlock(&wn
->lock
, &wn_qn
);
453 mcs_unlock(&w
->lock
, &w_qn
);
455 mcs_unlock(&x
->lock
, &x_qn
);
457 mcs_unlock(&p
->lock
, &p_qn
);
459 mcs_unlock(&g
->lock
, &g_qn
);
471 static void delete_finish(ptst_t
*ptst
, node_t
*x
)
473 qnode_t g_qn
, p_qn
, w_qn
, x_qn
;
478 if ( IS_GARBAGE(x
) ) return;
483 mcs_lock(&g
->lock
, &g_qn
);
484 if ( !ADJACENT(g
, p
) || IS_UNBALANCED(g
->v
) || IS_GARBAGE(g
) )
487 mcs_lock(&p
->lock
, &p_qn
);
488 /* Removing unbalanced red nodes is okay. */
489 if ( !ADJACENT(p
, x
) || (IS_UNBALANCED(p
->v
) && IS_BLACK(p
->v
)) )
492 mcs_lock(&x
->lock
, &x_qn
);
493 if ( IS_UNBALANCED(x
->v
) ) goto unlock_xpg
;
494 if ( GET_VALUE(x
->v
) != NULL
)
500 if ( p
->l
== x
) w
= p
->r
; else w
= p
->l
;
502 mcs_lock(&w
->lock
, &w_qn
);
503 if ( IS_UNBALANCED(w
->v
) ) goto unlock_wxpg
;
505 if ( g
->l
== p
) g
->l
= w
; else g
->r
= w
;
506 MK_GARBAGE(p
); gc_free(ptst
, p
, gc_id
);
507 MK_GARBAGE(x
); gc_free(ptst
, x
, gc_id
);
509 if ( IS_BLACK(p
->v
) && IS_BLACK(w
->v
) )
511 w
->v
= MK_UNBALANCED(w
->v
);
516 w
->v
= MK_BLACK(w
->v
);
521 mcs_unlock(&w
->lock
, &w_qn
);
523 mcs_unlock(&x
->lock
, &x_qn
);
525 mcs_unlock(&p
->lock
, &p_qn
);
527 mcs_unlock(&g
->lock
, &g_qn
);
531 if ( done
== 2 ) fix_unbalance_down(ptst
, w
);
535 set_t
*set_alloc(void)
541 ptst
= critical_enter();
543 set
= (set_t
*)malloc(sizeof(*set
));
544 memset(set
, 0, sizeof(*set
));
550 root
->v
= MK_RED(INTERNAL_VALUE
);
554 mcs_init(&root
->lock
);
556 null
->k
= SENTINEL_KEYMIN
;
557 null
->v
= MK_BLACK(INTERNAL_VALUE
);
561 mcs_init(&null
->lock
);
563 set
->dummy_gg
.l
= &set
->dummy_g
;
564 set
->dummy_g
.p
= &set
->dummy_gg
;
565 set
->dummy_g
.l
= &set
->root
;
566 set
->root
.p
= &set
->dummy_g
;
574 setval_t
set_update(set_t
*s
, setkey_t k
, setval_t v
, int overwrite
)
578 node_t
*y
, *z
, *new_internal
, *new_leaf
;
582 k
= CALLER_TO_INTERNAL_KEY(k
);
584 ptst
= critical_enter();
588 while ( (y
= (k
<= z
->k
) ? z
->l
: z
->r
) != NULL
)
592 mcs_lock(&y
->lock
, &y_qn
);
593 if ( (((k
<= y
->k
) ? y
->l
: y
->r
) != z
) || IS_GARBAGE(y
) )
595 mcs_unlock(&y
->lock
, &y_qn
);
599 mcs_lock(&z
->lock
, &z_qn
);
600 assert(!IS_GARBAGE(z
) && IS_LEAF(z
));
604 ov
= GET_VALUE(z
->v
);
605 if ( overwrite
|| (ov
== NULL
) )
610 new_leaf
= gc_alloc(ptst
, gc_id
);
611 new_internal
= gc_alloc(ptst
, gc_id
);
613 new_leaf
->v
= MK_BLACK(v
);
617 new_leaf
->p
= new_internal
;
618 mcs_init(&new_leaf
->lock
);
621 new_internal
->k
= z
->k
;
623 new_internal
->r
= new_leaf
;
628 new_internal
->l
= new_leaf
;
632 mcs_init(&new_internal
->lock
);
634 if ( IS_UNBALANCED(z
->v
) )
636 z
->v
= MK_BALANCED(z
->v
);
637 new_internal
->v
= MK_BLACK(INTERNAL_VALUE
);
639 else if ( IS_RED(y
->v
) )
641 new_internal
->v
= MK_UNBALANCED(MK_RED(INTERNAL_VALUE
));
646 new_internal
->v
= MK_RED(INTERNAL_VALUE
);
652 if ( y
->l
== z
) y
->l
= new_internal
; else y
->r
= new_internal
;
655 mcs_unlock(&y
->lock
, &y_qn
);
656 mcs_unlock(&z
->lock
, &z_qn
);
659 fix_unbalance_up(ptst
, new_internal
);
668 setval_t
set_remove(set_t
*s
, setkey_t k
)
675 k
= CALLER_TO_INTERNAL_KEY(k
);
677 ptst
= critical_enter();
680 while ( (y
= (k
<= z
->k
) ? z
->l
: z
->r
) != NULL
)
685 mcs_lock(&z
->lock
, &z_qn
);
686 if ( !IS_GARBAGE(z
) )
688 ov
= GET_VALUE(z
->v
);
690 SET_VALUE(z
->v
, NULL
);
692 mcs_unlock(&z
->lock
, &z_qn
);
696 delete_finish(ptst
, z
);
704 setval_t
set_lookup(set_t
*s
, setkey_t k
)
710 k
= CALLER_TO_INTERNAL_KEY(k
);
712 ptst
= critical_enter();
715 while ( (m
= (k
<= n
->k
) ? n
->l
: n
->r
) != NULL
)
718 v
= (k
== n
->k
) ? GET_VALUE(n
->v
) : NULL
;
719 if ( v
== GARBAGE_VALUE
) v
= NULL
;
727 void _init_set_subsystem(void)
729 gc_id
= gc_add_allocator(sizeof(node_t
));
733 static int valll
=0, bug
=0, nrb
=-1;
734 static void __traverse(node_t
*n
, int d
, int _nrb
)
739 if ( nrb
== -1 ) nrb
= _nrb
;
741 printf("Imbalance at depth %d (%d,%d)\n", d
, nrb
, _nrb
);
744 if ( IS_LEAF(n
) && (n
->k
!= 0) )
746 assert(n
->l
== NULL
);
747 assert(n
->r
== NULL
);
748 assert(IS_BLACK(n
->v
));
750 if ( !IS_LEAF(n
) && IS_RED(n
->v
) )
752 assert(IS_BLACK(n
->l
->v
));
753 assert(IS_BLACK(n
->r
->v
));
755 if ( IS_BLACK(n
->v
) ) _nrb
++;
756 __traverse(n
->l
, d
+1, _nrb
);
757 if ( valll
> n
->k
) bug
=1;
759 for ( i
= 0; i
< d
; i
++ ) printf(" ");
760 printf("%c%p K: %5d V: %p P: %p L: %p R: %p depth: %d\n",
761 IS_BLACK(n
->v
) ? 'B' : 'R', n
, n
->k
, n
->v
, n
->p
, n
->l
, n
->r
, d
);
764 __traverse(n
->r
, d
+1, _nrb
);
766 void check_tree(set_t
*s
)
768 __traverse(s
->root
.r
, 0, 0);
770 printf("***********************************************************************************************\n");