static void fix_unbalance_down(ptst_t *ptst, node_t *x) { /* WN == W_NEAR, WF == W_FAR (W_FAR is further, in key space, from X). */ qnode_t x_qn, w_qn, p_qn, g_qn, wn_qn, wf_qn; node_t *w, *p, *g, *wn, *wf; int done = 0; do { if ( !IS_UNBALANCED(x->v) || IS_GARBAGE(x) ) return; p = x->p; g = p->p; mcs_lock(&g->lock, &g_qn); if ( !ADJACENT(g, p) || IS_UNBALANCED(g->v) || IS_GARBAGE(g) ) goto unlock_g; mcs_lock(&p->lock, &p_qn); if ( !ADJACENT(p, x) || IS_UNBALANCED(p->v) ) goto unlock_pg; mcs_lock(&x->lock, &x_qn); if ( !IS_BLACK(x->v) || !IS_UNBALANCED(x->v) ) { done = 1; goto unlock_xpg; } if ( IS_ROOT(x) ) { x->v = MK_BALANCED(x->v); done = 1; goto unlock_xpg; } w = (x == p->l) ? p->r : p->l; mcs_lock(&w->lock, &w_qn); if ( IS_UNBALANCED(w->v) ) { if ( IS_BLACK(w->v) ) { /* Funky relaxed rules to the rescue. */ x->v = MK_BALANCED(x->v); w->v = MK_BALANCED(w->v); if ( IS_BLACK(p->v) ) { p->v = MK_UNBALANCED(p->v); done = 2; } else { p->v = MK_BLACK(p->v); done = 1; } } goto unlock_wxpg; } assert(!IS_LEAF(w)); if ( x == p->l ) { wn = w->l; wf = w->r; } else { wn = w->r; wf = w->l; } mcs_lock(&wn->lock, &wn_qn); /* Hanke has an extra relaxed transform here. It's not needed. */ if ( IS_UNBALANCED(wn->v) ) goto unlock_wnwxpg; mcs_lock(&wf->lock, &wf_qn); if ( IS_UNBALANCED(wf->v) ) goto unlock_wfwnwxpg; if ( IS_RED(w->v) ) { /* Case 1. Rotate at parent. */ assert(IS_BLACK(p->v) && IS_BLACK(wn->v) && IS_BLACK(wf->v)); w->v = MK_BLACK(w->v); p->v = MK_RED(p->v); if ( x == p->l ) left_rotate(ptst, p); else right_rotate(ptst, p); goto unlock_wfwnwxpg; } if ( IS_BLACK(wn->v) && IS_BLACK(wf->v) ) { if ( IS_RED(p->v) ) { /* Case 2. Simple recolouring. */ p->v = MK_BLACK(p->v); done = 1; } else { /* Case 5. Simple recolouring. */ p->v = MK_UNBALANCED(p->v); done = 2; } w->v = MK_RED(w->v); x->v = MK_BALANCED(x->v); goto unlock_wfwnwxpg; } if ( x == p->l ) { if ( IS_RED(wf->v) ) { /* Case 3. Single rotation. */ wf->v = MK_BLACK(wf->v); w->v = SET_COLOUR(w->v, GET_COLOUR(p->v)); p->v = MK_BLACK(p->v); x->v = MK_BALANCED(x->v); left_rotate(ptst, p); } else { /* Case 4. Double rotation. */ assert(IS_RED(wn->v)); wn->v = SET_COLOUR(wn->v, GET_COLOUR(p->v)); p->v = MK_BLACK(p->v); x->v = MK_BALANCED(x->v); right_rotate(ptst, w); left_rotate(ptst, p); } } else /* SYMMETRIC CASE: X == P->R */ { if ( IS_RED(wf->v) ) { /* Case 3. Single rotation. */ wf->v = MK_BLACK(wf->v); w->v = SET_COLOUR(w->v, GET_COLOUR(p->v)); p->v = MK_BLACK(p->v); x->v = MK_BALANCED(x->v); right_rotate(ptst, p); } else { /* Case 4. Double rotation. */ assert(IS_RED(wn->v)); wn->v = SET_COLOUR(wn->v, GET_COLOUR(p->v)); p->v = MK_BLACK(p->v); x->v = MK_BALANCED(x->v); left_rotate(ptst, w); right_rotate(ptst, p); } } done = 1; unlock_wfwnwxpg: mcs_unlock(&wf->lock, &wf_qn); unlock_wnwxpg: mcs_unlock(&wn->lock, &wn_qn); unlock_wxpg: mcs_unlock(&w->lock, &w_qn); unlock_xpg: mcs_unlock(&x->lock, &x_qn); unlock_pg: mcs_unlock(&p->lock, &p_qn); unlock_g: mcs_unlock(&g->lock, &g_qn); if ( done == 2 ) { x = p; done = 0; } } while ( !done ); }
static void _fix_after_deletion(ptst_t *ptst, stm_tx *tx, stm_blk *sb, stm_blk *xb, node_t *x) { stm_blk *pb, *plb, *sibb, *siblb, *sibrb; node_t *p, *sib, *sibl, *sibr; set_t *s; while (GET_PARENT(x)!=NULL && IS_BLACK(x)) { pb = GET_PARENT(x); p = WRITE_OBJ(pb); plb = GET_LEFT(p); if ( xb == plb ) { sibb = GET_RIGHT(p); sib = WRITE_OBJ(sibb); if (IS_RED(sib)) { SET_COLOUR(sib, BLACK); SET_COLOUR(p, RED); _left_rotate(ptst, tx, sb, pb, p); pb = GET_PARENT(x); p=WRITE_OBJ(pb); sibb = GET_RIGHT(p); sib = WRITE_OBJ(sibb); } siblb = GET_LEFT(sib); sibl = READ_OBJ(siblb); sibrb = GET_RIGHT(sib); sibr = READ_OBJ(sibrb); if (IS_BLACK(sibl) && IS_BLACK(sibr)) { SET_COLOUR(sib, RED); xb = GET_PARENT(x); x = WRITE_OBJ(xb); } else { if (IS_BLACK(sibr)) { sibl = WRITE_OBJ(siblb); SET_COLOUR(sibl, BLACK); SET_COLOUR(sib,RED); _right_rotate(ptst, tx, sb, sibb, sib); pb = GET_PARENT(x); p = WRITE_OBJ(pb); sibb = GET_RIGHT(p); } sib = WRITE_OBJ(sibb); SET_COLOUR(sib, GET_COLOUR(p)); p = WRITE_OBJ(pb); SET_COLOUR(p, BLACK); sibrb = GET_RIGHT(sib); sibr = WRITE_OBJ(sibrb); SET_COLOUR(sibr, BLACK); _left_rotate(ptst, tx, sb, pb, p); s = (set_t*)READ_OBJ(sb); xb = GET_ROOT(s); x = WRITE_OBJ(xb); break; } } else { // inverse sibb = plb; sib = WRITE_OBJ(sibb); if (IS_RED(sib)) { SET_COLOUR(sib, BLACK); SET_COLOUR(p, RED); _right_rotate(ptst, tx, sb, pb, p); pb = GET_PARENT(x); p=WRITE_OBJ(pb); sibb = GET_LEFT(p); sib = WRITE_OBJ(sibb); } siblb = GET_LEFT(sib); sibl = READ_OBJ(siblb); sibrb = GET_RIGHT(sib); sibr = READ_OBJ(sibrb); if (IS_BLACK(sibl) && IS_BLACK(sibr)) { SET_COLOUR(sib, RED); xb = GET_PARENT(x); x = WRITE_OBJ(xb); } else { if (IS_BLACK(sibl)) { sibr = WRITE_OBJ(sibrb); SET_COLOUR(sibr, BLACK); SET_COLOUR(sib, RED); _left_rotate(ptst, tx, sb, sibb, sib); pb = GET_PARENT(x); p = WRITE_OBJ(pb); sibb = GET_LEFT(p); } sib = WRITE_OBJ(sibb); SET_COLOUR(sib, GET_COLOUR(p)); p = WRITE_OBJ(pb); SET_COLOUR(p, BLACK); siblb = GET_LEFT(sib); sibl = WRITE_OBJ(siblb); SET_COLOUR(sibl, BLACK); _right_rotate(ptst, tx, sb, pb, p); s = (set_t*)READ_OBJ(sb); xb = GET_ROOT(s); x = WRITE_OBJ(xb); break; } } } if(IS_RED(x)) { SET_COLOUR(x, BLACK); } }//fix_after_deletion