Пример #1
0
static void redundancy_removal(ptst_t *ptst, void *x)
{
    node_t *d, *e, *r;
    qnode_t d_qn, e_qn;
    setkey_t k;

    if ( x == NULL ) return;

    e = x;
    k = e->k;

    if ( e->copy )
    {
        r = weak_search(e->l, k);
        assert((r == NULL) || !IS_REDUNDANT(r) || (r->r == e));
        assert(r != e);
        redundancy_removal(ptst, r);
    }

    do {
        if ( IS_GARBAGE(e) ) return;
        d = e->p;
        LOCK(d, &d_qn);
        if ( IS_GARBAGE(d) ) UNLOCK(d, &d_qn);
    }
    while ( IS_GARBAGE(d) );

    LOCK(e, &e_qn);

    if ( IS_GARBAGE(e) || !IS_REDUNDANT(e) ) goto out_de;

    if ( d->l == e )
    {
        d->l = e->l;
    }
    else
    {
        assert(d->r == e);
        d->r = e->l;
    }

    assert(e->r != NULL);
    assert(e->r->k == k);
    assert(e->r->copy);
    assert(!IS_GARBAGE(e->r));
    assert(!e->copy);

    MK_GARBAGE(e);

    if ( e->l != NULL ) e->l->p = d;

    e->r->copy = 0;

    gc_free(ptst, e, gc_id);

 out_de:
    UNLOCK(d, &d_qn);
    UNLOCK(e, &e_qn);
}
Пример #2
0
/* Nodes p, x, y must be locked. */
static void right_rotate(ptst_t *ptst, node_t *x)
{
    node_t *y = x->l, *p = x->p, *nx;

    nx    = gc_alloc(ptst, gc_id);
    nx->p = y;
    nx->l = y->r;
    nx->r = x->r;
    nx->k = x->k;
    nx->v = x->v;
    mcs_init(&nx->lock);

    WMB();

    y->p    = p;
    x->r->p = nx;
    y->r->p = nx;
    y->r    = nx;
    if ( x == p->l ) p->l = y; else p->r = y;

    MK_GARBAGE(x);
    gc_free(ptst, x, gc_id);
}
Пример #3
0
/* NB. Node X is not locked on entry. */
static void predecessor_substitution(ptst_t *ptst, set_t *s, node_t *x)
{
    node_t *a, *b, *e, *f, **pac;
    qnode_t a_qn, b_qn, e_qn, f_qn;
    setkey_t k;

    b = x;
    k = x->k;

    do {
        if ( (b == NULL) || (b->v != NULL) ) return;
        a = b->p;
        LOCK(a, &a_qn);
        if ( IS_GARBAGE(a) ) UNLOCK(a, &a_qn);
    }
    while ( IS_GARBAGE(a) );

 regain_lock:
    LOCK(b, &b_qn);

    /*
     * We do nothing if:
     *  1. The node is already deleted (and is thus garbage); or
     *  2. The node is redundant (redundancy removal will do it); or
     *  3. The node has been reused.
     * These can all be checked by looking at the value field.
     */
    if ( b->v != NULL ) goto out_ab;

    /*
     * If this node is a copy, then we can do redundancy removal right now.
     * This is an improvement over Manber and Ladner's work.
     */
    if ( b->copy )
    {
        e = weak_search(b->l, k);
        UNLOCK(b, &b_qn);
        assert((e == NULL) || !IS_REDUNDANT(e) || (e->r == b));
        assert(e != b);
        redundancy_removal(ptst, e);
        goto regain_lock;
    }

    pac = (a->k < k) ? &a->r : &a->l;
    assert(*pac == b);
    assert(b->p == a);

    if ( (b->l == NULL) || (b->r == NULL) )
    {
        if ( b->r == NULL ) *pac = b->l; else *pac = b->r;
        MK_GARBAGE(b);
        if ( *pac != NULL ) (*pac)->p = a;
        gc_free(ptst, b, gc_id);
        goto out_ab;
    }
    else
    {
        e = strong_search(b->l, b->k, &e_qn);
        assert(!IS_REDUNDANT(e) && !IS_GARBAGE(e) && (b != e));
        assert(e->k < b->k);
        f = gc_alloc(ptst, gc_id);
        f->k = e->k;
        f->v = GET_VALUE(e);
        f->copy = 1;
        f->r = b->r;
        f->l = b->l;
        mcs_init(&f->lock);
        LOCK(f, &f_qn);

        e->r = f;
        MK_REDUNDANT(e);
        *pac = f;
        f->p = a;
        f->r->p = f;
        f->l->p = f;

        MK_GARBAGE(b);
        gc_free(ptst, b, gc_id);
        gc_add_ptr_to_hook_list(ptst, e, hook_id);
        UNLOCK(e, &e_qn);
        UNLOCK(f, &f_qn);
    }

 out_ab:
    UNLOCK(a, &a_qn);
    UNLOCK(b, &b_qn);
}
Пример #4
0
static void delete_finish(ptst_t *ptst, node_t *x)
{
    qnode_t g_qn, p_qn, w_qn, x_qn;
    node_t *g, *p, *w;
    int done = 0;

    do {
        if ( 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);
        /* Removing unbalanced red nodes is okay. */
        if ( !ADJACENT(p, x) || (IS_UNBALANCED(p->v) && IS_BLACK(p->v)) )
            goto unlock_pg;

        mcs_lock(&x->lock, &x_qn);
        if ( IS_UNBALANCED(x->v) ) goto unlock_xpg;        
        if ( GET_VALUE(x->v) != NULL )
        {
            done = 1;
            goto unlock_xpg;
        }

        if ( p->l == x ) w = p->r; else w = p->l;
        assert(w != x);
        mcs_lock(&w->lock, &w_qn);
        if ( IS_UNBALANCED(w->v) ) goto unlock_wxpg;

        if ( g->l == p ) g->l = w; else g->r = w; 
        MK_GARBAGE(p); gc_free(ptst, p, gc_id);
        MK_GARBAGE(x); gc_free(ptst, x, gc_id);
        w->p = g;
        if ( IS_BLACK(p->v) && IS_BLACK(w->v) )
        {
            w->v = MK_UNBALANCED(w->v);
            done = 2;
        }
        else
        {
            w->v = MK_BLACK(w->v);
            done = 1;
        }

    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);
    }
    while ( !done );

    if ( done == 2 ) fix_unbalance_down(ptst, w);
}