Exemplo n.º 1
0
/**
 * Purge all non-complete (i.e. not 'resdone') entries and invoke their
 * callback, setting the result's error code with the specified error
 */
static void purge_entries(lcb_durability_set_t *dset, lcb_error_t err)
{
    lcb_size_t ii;
    dset->us_timeout = 0;
    dset->next_state = STATE_IGNORE;

    /**
     * Each time we call 'ent_set_resdone' we might cause the refcount to drop
     * to zero, making 'dset' point to freed memory. To avoid this, we bump
     * up the refcount before the loop and defer the possible free operation
     * until the end.
     */
    dset_ref(dset);

    for (ii = 0; ii < dset->nentries; ii++) {
        lcb_durability_entry_t *ent = dset->entries + ii;
        if (ent->done) {
            continue;
        }
        RESFLD(ent, err) = err;
        ent_set_resdone(ent);
    }

    dset_unref(dset);
}
Exemplo n.º 2
0
/**
 * Called when the last (primitive) OBSERVE response is received for the entry.
 */
static void dset_done_waiting(lcb_durability_set_t *dset)
{
    lcb_assert(dset->waiting || ("Got NULL callback twice!" && 0));

    dset->waiting = 0;

    if (dset->nremaining > 0) {
        timer_schedule(dset, DSET_OPTFLD(dset, interval), STATE_OBSPOLL);
    }
    dset_unref(dset);
}
Exemplo n.º 3
0
/**
 * Set the logical state of the entry to done, and invoke the callback.
 * It is safe to call this multiple times
 */
static void ent_set_resdone(lcb_DURITEM *ent)
{
    lcb_RESPCALLBACK callback;
    if (ent->done) {
        return;
    }

    ent->done = 1;
    ent->parent->nremaining--;

    /** Invoke the callback now :) */
    ent->result.cookie = (void *)ent->parent->cookie;
    callback = lcb_find_callback(ent->parent->instance, LCB_CALLBACK_ENDURE);
    callback(ent->parent->instance, LCB_CALLBACK_ENDURE, (lcb_RESPBASE*)&ent->result);
    if (ent->parent->nremaining == 0) {
        dset_unref(ent->parent);
    }
}
Exemplo n.º 4
0
/**
 * Set the logical state of the entry to done, and invoke the callback.
 * It is safe to call this multiple times
 */
static void ent_set_resdone(lcb_durability_entry_t *ent)
{
    if (ent->done) {
        return;
    }

    ent->done = 1;
    ent->parent->nremaining--;

    /**
     * Invoke the callback now :)
     */
    ent->parent->instance->callbacks.durability(ent->parent->instance,
                                                ent->parent->cookie,
                                                LCB_SUCCESS,
                                                &ent->result);

    if (ent->parent->nremaining == 0) {
        dset_unref(ent->parent);
    }
}
Exemplo n.º 5
0
/**
 * Schedules a single sweep of observe requests.
 */
static void poll_once(lcb_durability_set_t *dset)
{
    lcb_size_t ii, oix;
    lcb_error_t err;

    /**
     * We should never be called while an 'iter' operation is still
     * in progress
     */
    lcb_assert(dset->waiting == 0);
    dset_ref(dset);

    for (ii = 0, oix = 0; ii < dset->nentries; ii++) {
        struct lcb_durability_entry_st *ent = dset->entries + ii;

        if (ent->done) {
            continue;
        }

        /* reset all the per-iteration fields */
        RESFLD(ent, persisted_master) = 0;
        RESFLD(ent, exists_master) = 0;
        RESFLD(ent, npersisted) = 0;
        RESFLD(ent, nreplicated) = 0;
        RESFLD(ent, cas) = 0;
        RESFLD(ent, err) = LCB_SUCCESS;

        dset->valid_entries[oix++] = ent;
    }

    lcb_assert(oix == dset->nremaining);

    err = lcb_observe_ex(dset->instance,
                         dset,
                         dset->nremaining,
                         (const void * const *)dset->valid_entries,
                         LCB_OBSERVE_TYPE_DURABILITY);

    if (err != LCB_SUCCESS) {
        for (ii = 0; ii < dset->nentries; ii++) {
            lcb_durability_entry_t *ent = dset->entries + ii;
            if (ent->done) {
                continue;
            }
            RESFLD(ent, err) = err;
            ent_set_resdone(ent);
        }

    } else {
        dset->waiting = 1;
        dset_ref(dset);
    }

    if (dset->waiting && oix) {
        lcb_uint32_t us_now = (lcb_uint32_t)(gethrtime() / 1000);
        lcb_uint32_t us_tmo;

        if (dset->us_timeout > us_now) {
            us_tmo = dset->us_timeout - us_now;
        } else {
            us_tmo = 1;
        }

        timer_schedule(dset,
                       us_tmo,
                       STATE_TIMEOUT);

    } else {
        purge_entries(dset, LCB_ERROR);
    }

    dset_unref(dset);
}
Exemplo n.º 6
0
/**
 * Schedules a single sweep of observe requests.
 */
static void poll_once(lcb_DURSET *dset)
{
    unsigned ii, n_added = 0;
    lcb_error_t err;
    lcb_MULTICMD_CTX *mctx = NULL;

    /**
     * We should never be called while an 'iter' operation is still
     * in progress
     */
    lcb_assert(dset->waiting == 0);
    dset_ref(dset);
    mctx = lcb_observe_ctx_dur_new(dset->instance);
    if (!mctx) {
        err = LCB_CLIENT_ENOMEM;
        goto GT_ERR;
    }

    for (ii = 0; ii < dset->nentries; ii++) {
        lcb_CMDOBSERVE cmd = { 0 };
        struct lcb_durability_entry_st *ent = dset->entries + ii;
        if (ent->done) {
            continue;
        }

        /* reset all the per-iteration fields */
        RESFLD(ent, persisted_master) = 0;
        RESFLD(ent, exists_master) = 0;
        RESFLD(ent, npersisted) = 0;
        RESFLD(ent, nreplicated) = 0;
        RESFLD(ent, cas) = 0;
        RESFLD(ent, rc) = LCB_SUCCESS;

        LCB_KREQ_SIMPLE(&cmd.key, RESFLD(ent, key), RESFLD(ent, nkey));
        cmd.hashkey = ent->hashkey;

        err = mctx->addcmd(mctx, (lcb_CMDBASE *)&cmd);
        if (err != LCB_SUCCESS) {
            goto GT_ERR;
        }
        n_added ++;
    }

    lcb_assert(n_added == dset->nremaining);

    if (n_added) {
        lcb_sched_enter(dset->instance);
        mctx->done(mctx, dset);
        lcb_sched_leave(dset->instance);
    }

    GT_ERR:
    if (err != LCB_SUCCESS) {
        if (mctx) {
            mctx->fail(mctx);
        }

        for (ii = 0; ii < dset->nentries; ii++) {
            lcb_DURITEM *ent = dset->entries + ii;
            if (ent->done) {
                continue;
            }
            RESFLD(ent, rc) = err;
            ent_set_resdone(ent);
        }

    } else {
        dset->waiting = 1;
        dset_ref(dset);
    }

    if (dset->waiting && n_added) {
        lcb_uint32_t us_now = (lcb_uint32_t)(gethrtime() / 1000);
        lcb_uint32_t us_tmo;
        if (dset->us_timeout > us_now) {
            us_tmo = dset->us_timeout - us_now;
        } else {
            us_tmo = 1;
        }
        timer_schedule(dset, us_tmo, STATE_TIMEOUT);
    } else {
        purge_entries(dset, LCB_ERROR);
    }

    dset_unref(dset);
}