1 /******************************************************************************
2 * rb_lock_concurrentwriters.c
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 for writing. */
110 static void left_rotate(node_t *x)
112 node_t *y = x->r, *p = x->p;
118 if ( x == p->l ) p->l = y; else p->r = y;
122 /* Nodes p, x, y must be locked for writing. */
123 static void right_rotate(node_t *x)
125 node_t *y = x->l, *p = x->p;
131 if ( x == p->l ) p->l = y; else p->r = y;
135 static void fix_unbalance_up(node_t *x)
137 mrsw_qnode_t x_qn, g_qn, p_qn, w_qn, gg_qn;
138 node_t *g, *p, *w, *gg;
142 assert(IS_UNBALANCED(x->v));
143 if ( IS_GARBAGE(x) ) return;
149 wr_lock(&gg->lock, &gg_qn);
150 if ( !ADJACENT(gg, g) || IS_UNBALANCED(gg->v) || IS_GARBAGE(gg) )
153 wr_lock(&g->lock, &g_qn);
154 if ( !ADJACENT(g, p) || IS_UNBALANCED(g->v) ) goto unlock_ggg;
156 wr_lock(&p->lock, &p_qn);
157 if ( !ADJACENT(p, x) || IS_UNBALANCED(p->v) ) goto unlock_pggg;
159 wr_lock(&x->lock, &x_qn);
161 assert(IS_RED(x->v));
162 assert(IS_UNBALANCED(x->v));
164 if ( IS_BLACK(p->v) )
166 /* Case 1. Nothing to do. */
167 x->v = MK_BALANCED(x->v);
175 x->v = MK_BLACK(MK_BALANCED(x->v));
183 p->v = MK_BLACK(p->v);
184 x->v = MK_BALANCED(x->v);
189 if ( g->l == p ) w = g->r; else w = g->l;
190 wr_lock(&w->lock, &w_qn);
195 /* In all other cases, doesn't change colour or subtrees. */
196 if ( IS_UNBALANCED(w->v) ) goto unlock_wxpggg;
197 g->v = MK_UNBALANCED(MK_RED(g->v));
198 p->v = MK_BLACK(p->v);
199 w->v = MK_BLACK(w->v);
200 x->v = MK_BALANCED(x->v);
205 /* Cases 3 & 4. Both of these need the great-grandfather locked. */
210 /* Case 3. Single rotation. */
211 x->v = MK_BALANCED(x->v);
212 p->v = MK_BLACK(p->v);
218 /* Case 4. Double rotation. */
219 x->v = MK_BALANCED(MK_BLACK(x->v));
225 else /* SYMMETRIC CASE */
229 /* Case 3. Single rotation. */
230 x->v = MK_BALANCED(x->v);
231 p->v = MK_BLACK(p->v);
237 /* Case 4. Double rotation. */
238 x->v = MK_BALANCED(MK_BLACK(x->v));
248 wr_unlock(&w->lock, &w_qn);
250 wr_unlock(&x->lock, &x_qn);
252 wr_unlock(&p->lock, &p_qn);
254 wr_unlock(&g->lock, &g_qn);
256 wr_unlock(&gg->lock, &gg_qn);
268 static void fix_unbalance_down(node_t *x)
270 /* WN == W_NEAR, WF == W_FAR (W_FAR is further, in key space, from X). */
271 mrsw_qnode_t x_qn, w_qn, p_qn, g_qn, wn_qn, wf_qn;
272 node_t *w, *p, *g, *wn, *wf;
276 if ( !IS_UNBALANCED(x->v) || IS_GARBAGE(x) ) return;
281 wr_lock(&g->lock, &g_qn);
282 if ( !ADJACENT(g, p) || IS_UNBALANCED(g->v) || IS_GARBAGE(g) )
285 wr_lock(&p->lock, &p_qn);
286 if ( !ADJACENT(p, x) || IS_UNBALANCED(p->v) ) goto unlock_pg;
288 wr_lock(&x->lock, &x_qn);
290 if ( !IS_BLACK(x->v) || !IS_UNBALANCED(x->v) )
298 x->v = MK_BALANCED(x->v);
303 w = (x == p->l) ? p->r : p->l;
304 wr_lock(&w->lock, &w_qn);
305 if ( IS_UNBALANCED(w->v) )
307 if ( IS_BLACK(w->v) )
309 /* Funky relaxed rules to the rescue. */
310 x->v = MK_BALANCED(x->v);
311 w->v = MK_BALANCED(w->v);
312 if ( IS_BLACK(p->v) )
314 p->v = MK_UNBALANCED(p->v);
319 p->v = MK_BLACK(p->v);
339 wr_lock(&wn->lock, &wn_qn);
340 /* Hanke has an extra relaxed transform here. It's not needed. */
341 if ( IS_UNBALANCED(wn->v) ) goto unlock_wnwxpg;
343 wr_lock(&wf->lock, &wf_qn);
344 if ( IS_UNBALANCED(wf->v) ) goto unlock_wfwnwxpg;
348 /* Case 1. Rotate at parent. */
349 assert(IS_BLACK(p->v) && IS_BLACK(wn->v) && IS_BLACK(wf->v));
350 w->v = MK_BLACK(w->v);
352 if ( x == p->l ) left_rotate(p); else right_rotate(p);
353 goto unlock_wfwnwxpg;
356 if ( IS_BLACK(wn->v) && IS_BLACK(wf->v) )
360 /* Case 2. Simple recolouring. */
361 p->v = MK_BLACK(p->v);
366 /* Case 5. Simple recolouring. */
367 p->v = MK_UNBALANCED(p->v);
371 x->v = MK_BALANCED(x->v);
372 goto unlock_wfwnwxpg;
379 /* Case 3. Single rotation. */
380 wf->v = MK_BLACK(wf->v);
381 w->v = SET_COLOUR(w->v, GET_COLOUR(p->v));
382 p->v = MK_BLACK(p->v);
383 x->v = MK_BALANCED(x->v);
388 /* Case 4. Double rotation. */
389 assert(IS_RED(wn->v));
390 wn->v = SET_COLOUR(wn->v, GET_COLOUR(p->v));
391 p->v = MK_BLACK(p->v);
392 x->v = MK_BALANCED(x->v);
397 else /* SYMMETRIC CASE: X == P->R */
401 /* Case 3. Single rotation. */
402 wf->v = MK_BLACK(wf->v);
403 w->v = SET_COLOUR(w->v, GET_COLOUR(p->v));
404 p->v = MK_BLACK(p->v);
405 x->v = MK_BALANCED(x->v);
410 /* Case 4. Double rotation. */
411 assert(IS_RED(wn->v));
412 wn->v = SET_COLOUR(wn->v, GET_COLOUR(p->v));
413 p->v = MK_BLACK(p->v);
414 x->v = MK_BALANCED(x->v);
423 wr_unlock(&wf->lock, &wf_qn);
425 wr_unlock(&wn->lock, &wn_qn);
427 wr_unlock(&w->lock, &w_qn);
429 wr_unlock(&x->lock, &x_qn);
431 wr_unlock(&p->lock, &p_qn);
433 wr_unlock(&g->lock, &g_qn);
445 static void delete_finish(ptst_t *ptst, node_t *x)
447 mrsw_qnode_t g_qn, p_qn, w_qn, x_qn;
452 if ( IS_GARBAGE(x) ) return;
457 wr_lock(&g->lock, &g_qn);
458 if ( !ADJACENT(g, p) || IS_UNBALANCED(g->v) || IS_GARBAGE(g) )
461 wr_lock(&p->lock, &p_qn);
462 /* Removing unbalanced red nodes is okay. */
463 if ( !ADJACENT(p, x) || (IS_UNBALANCED(p->v) && IS_BLACK(p->v)) )
466 wr_lock(&x->lock, &x_qn);
467 if ( IS_UNBALANCED(x->v) ) goto unlock_xpg;
468 if ( GET_VALUE(x->v) != NULL )
474 if ( p->l == x ) w = p->r; else w = p->l;
476 wr_lock(&w->lock, &w_qn);
477 if ( IS_UNBALANCED(w->v) ) goto unlock_wxpg;
479 if ( g->l == p ) g->l = w; else g->r = w;
480 MK_GARBAGE(p); gc_free(ptst, p, gc_id);
481 MK_GARBAGE(x); gc_free(ptst, x, gc_id);
483 if ( IS_BLACK(p->v) && IS_BLACK(w->v) )
485 w->v = MK_UNBALANCED(w->v);
490 w->v = MK_BLACK(w->v);
495 wr_unlock(&w->lock, &w_qn);
497 wr_unlock(&x->lock, &x_qn);
499 wr_unlock(&p->lock, &p_qn);
501 wr_unlock(&g->lock, &g_qn);
505 if ( done == 2 ) fix_unbalance_down(w);
509 set_t *set_alloc(void)
515 ptst = critical_enter();
517 set = (set_t *)malloc(sizeof(*set));
518 memset(set, 0, sizeof(*set));
524 root->v = MK_RED(INTERNAL_VALUE);
528 mrsw_init(&root->lock);
530 null->k = SENTINEL_KEYMIN;
531 null->v = MK_BLACK(INTERNAL_VALUE);
535 mrsw_init(&null->lock);
537 set->dummy_gg.l = &set->dummy_g;
538 set->dummy_g.p = &set->dummy_gg;
539 set->dummy_g.l = &set->root;
540 set->root.p = &set->dummy_g;
548 setval_t set_update(set_t *s, setkey_t k, setval_t v, int overwrite)
551 node_t *x, *y, *z, *new_internal, *new_leaf;
552 mrsw_qnode_t qn[2], *y_pqn=qn+0, *z_pqn=qn+1, *t_pqn, x_qn;
556 k = CALLER_TO_INTERNAL_KEY(k);
558 ptst = critical_enter();
561 * We start our search by read-lock-coupling from the root.
562 * There is a special case, when there is only one node in the tree.
563 * In this case, we take a write lock on the root.
567 rd_lock(&z->lock, z_pqn);
570 * We read-couple down the tree until we get within two nodes of the
571 * required leaf. We then speculatively take write locks.
574 while ( (y = (k <= z->k) ? z->l : z->r) != NULL )
579 rd_unlock(&z->lock, z_pqn);
580 wr_lock(&y->lock, y_pqn);
581 x = (k <= z->k) ? z->l : z->r;
582 if ( IS_GARBAGE(y) || !IS_LEAF(x) )
584 wr_unlock(&y->lock, y_pqn);
585 goto retry_from_root;
587 wr_lock(&x->lock, &x_qn);
588 assert(!IS_GARBAGE(x));
589 goto found_and_locked;
592 x = (k <= y->k) ? y->l : y->r;
593 if ( IS_LEAF(x) ) goto found;
594 rd_lock(&y->lock, y_pqn);
595 rd_unlock(&z->lock, z_pqn);
603 * At this point Z is read locked, and next two nodes on search path
604 * are probably the last. Certainly there is more than one on the path.
607 wr_lock(&y->lock, y_pqn);
608 x = (k <= y->k) ? y->l : y->r;
611 wr_unlock(&y->lock, y_pqn);
614 wr_lock(&x->lock, &x_qn);
615 rd_unlock(&z->lock, z_pqn);
619 * At this point, node X is write locked and may be correct node.
620 * Y is X's parent, and is also write locked. No other node is locked.
622 assert(!IS_GARBAGE(x));
625 ov = GET_VALUE(x->v);
626 if ( overwrite || (ov == NULL) )
633 new_leaf = gc_alloc(ptst, gc_id);
634 new_internal = gc_alloc(ptst, gc_id);
636 new_leaf->v = MK_BLACK(v);
639 new_leaf->p = new_internal;
640 mrsw_init(&new_leaf->lock);
643 new_internal->k = x->k;
645 new_internal->r = new_leaf;
650 new_internal->l = new_leaf;
654 mrsw_init(&new_internal->lock);
656 if ( y->l == x ) y->l = new_internal; else y->r = new_internal;
657 if ( IS_UNBALANCED(x->v) )
659 x->v = MK_BALANCED(x->v);
660 new_internal->v = MK_BLACK(INTERNAL_VALUE);
662 else if ( IS_RED(y->v) )
664 new_internal->v = MK_UNBALANCED(MK_RED(INTERNAL_VALUE));
669 new_internal->v = MK_RED(INTERNAL_VALUE);
673 wr_unlock(&y->lock, y_pqn);
674 wr_unlock(&x->lock, &x_qn);
676 if ( fix_up ) fix_unbalance_up(new_internal);
684 setval_t set_remove(set_t *s, setkey_t k)
688 mrsw_qnode_t qn[2], *y_pqn=qn+0, *z_pqn=qn+1, *t_pqn;
691 k = CALLER_TO_INTERNAL_KEY(k);
693 ptst = critical_enter();
696 rd_lock(&z->lock, z_pqn);
698 while ( (y = (k <= z->k) ? z->l : z->r) != NULL )
701 wr_lock(&y->lock, y_pqn);
703 rd_lock(&y->lock, y_pqn);
704 rd_unlock(&z->lock, z_pqn);
713 ov = GET_VALUE(z->v);
714 SET_VALUE(z->v, NULL);
717 wr_unlock(&z->lock, z_pqn);
719 if ( ov != NULL ) delete_finish(ptst, z);
726 setval_t set_lookup(set_t *s, setkey_t k)
730 mrsw_qnode_t qn[2], *m_pqn=&qn[0], *n_pqn=&qn[1], *t_pqn;
733 k = CALLER_TO_INTERNAL_KEY(k);
735 ptst = critical_enter();
738 rd_lock(&n->lock, n_pqn);
740 while ( (m = (k <= n->k) ? n->l : n->r) != NULL )
742 rd_lock(&m->lock, m_pqn);
743 rd_unlock(&n->lock, n_pqn);
750 if ( k == n->k ) v = GET_VALUE(n->v);
752 rd_unlock(&n->lock, n_pqn);
760 void _init_set_subsystem(void)
762 gc_id = gc_add_allocator(sizeof(node_t));