Esempio n. 1
0
/**
 * Schedules us to be notified with the given state within a particular amount
 * of time. This is used both for the timeout and for the interval
 */
void
lcbdur_switch_state(lcb_DURSET *dset, unsigned int state)
{
    lcb_U32 delay = 0;
    lcbio_TABLE* io = dset->instance->iotable;
    hrtime_t now = gethrtime();

    if (state == LCBDUR_STATE_TIMEOUT) {
        if (dset->ns_timeout && now < dset->ns_timeout) {
            delay = LCB_NS2US(dset->ns_timeout - now);
        } else {
            delay = 0;
        }
    } else if (state == LCBDUR_STATE_OBSPOLL) {
        if (now + LCB_US2NS(DSET_OPTFLD(dset, interval)) < dset->ns_timeout) {
            delay = DSET_OPTFLD(dset, interval);
        } else {
            delay = 0;
            state = LCBDUR_STATE_TIMEOUT;
        }
    } else if (state == LCBDUR_STATE_INIT) {
        delay = 0;
    }

    dset->next_state = state;
    io->timer.cancel(io->p, dset->timer);
    io->timer.schedule(io->p, dset->timer, delay, dset, timer_callback);
}
Esempio n. 2
0
lcb_error_t
lcb_bootstrap_common(lcb_t instance, int options)
{
    struct lcb_BOOTSTRAP *bs = instance->bootstrap;
    hrtime_t now = gethrtime();

    if (!bs) {
        bs = calloc(1, sizeof(*instance->bootstrap));
        if (!bs) {
            return LCB_CLIENT_ENOMEM;
        }

        bs->tm = lcbio_timer_new(instance->iotable, bs, initial_timeout);
        instance->bootstrap = bs;
        bs->parent = instance;
        lcb_confmon_add_listener(instance->confmon, &bs->listener);
    }

    if (lcb_confmon_is_refreshing(instance->confmon)) {
        return LCB_SUCCESS;
    }

    if (options & LCB_BS_REFRESH_THROTTLE) {
        /* Refresh throttle requested. This is not true if options == ALWAYS */
        hrtime_t next_ts;
        unsigned errthresh = LCBT_SETTING(instance, weird_things_threshold);

        if (options & LCB_BS_REFRESH_INCRERR) {
            bs->errcounter++;
        }
        next_ts = bs->last_refresh;
        next_ts += LCB_US2NS(LCBT_SETTING(instance, weird_things_delay));
        if (now < next_ts && bs->errcounter < errthresh) {
            lcb_log(LOGARGS(instance, INFO),
                "Not requesting a config refresh because of throttling parameters. Next refresh possible in %ums or %u errors. "
                "See LCB_CNTL_CONFDELAY_THRESH and LCB_CNTL_CONFERRTHRESH to modify the throttling settings",
                LCB_NS2US(next_ts-now)/1000, (unsigned)errthresh-bs->errcounter);
            return LCB_SUCCESS;
        }
    }

    if (options == LCB_BS_REFRESH_INITIAL) {
        lcb_confmon_prepare(instance->confmon);

        bs->listener.callback = config_callback;
        lcbio_timer_set_target(bs->tm, initial_timeout);
        lcbio_timer_rearm(bs->tm, LCBT_SETTING(instance, config_timeout));
        lcb_aspend_add(&instance->pendops, LCB_PENDTYPE_COUNTER, NULL);
    } else {
        /** No initial timer */
        bs->listener.callback = async_step_callback;
    }

    /* Reset the counters */
    bs->errcounter = 0;
    if (options != LCB_BS_REFRESH_INITIAL) {
        bs->last_refresh = now;
    }
    return lcb_confmon_start(instance->confmon);
}
Esempio n. 3
0
void lcb_bootstrap_errcount_incr(lcb_t instance)
{
    int should_refresh = 0;
    hrtime_t now = gethrtime();
    instance->weird_things++;

    if (now - instance->bootstrap->last_refresh >
            LCB_US2NS(instance->settings.weird_things_delay)) {

        lcb_log(LOGARGS(instance, INFO),
                "Max grace period for refresh exceeded");
        should_refresh = 1;
    }

    if (instance->weird_things == instance->settings.weird_things_threshold) {
        should_refresh = 1;
    }

    if (!should_refresh) {
        return;
    }

    instance->weird_things = 0;
    lcb_bootstrap_refresh(instance);
}
Esempio n. 4
0
void lcb_record_metrics(lcb_t instance,
                        hrtime_t delta,
                        uint8_t opcode)
{
    lcb_U32 num;
    struct lcb_histogram_st *hg = instance->histogram;
    if (hg == NULL) {
        return;
    }

    if (delta < 1000) {
        /* nsec */
        if (++hg->nsec > hg->max) {
            hg->max = hg->nsec;
        }
    } else if (delta < LCB_US2NS(1000)) {
        /* micros */
        delta /= LCB_US2NS(1);
        if ((num = ++hg->usec[delta/10]) > hg->max) {
            hg->max = num;
        }
    } else if (delta < LCB_US2NS(10000)) {
        /* 1-10ms */
        delta /= LCB_US2NS(1);
        assert(delta <= 10000);
        if ((num = ++hg->lt10msec[delta/100]) > hg->max) {
            hg->max = num;
        }
    } else if (delta < LCB_S2NS(1)) {
        delta /= LCB_US2NS(1000);
        if ((num = ++hg->msec[delta/10]) > hg->max) {
            hg->max = num;
        }
    } else {
        delta /= LCB_S2NS(1);
        if (delta > 9) {
            delta = 0;
        }
        if ((num = ++hg->sec[delta]) > hg->max) {
            hg->max = num;
        }
    }
    (void)opcode;
}
Esempio n. 5
0
static lcb_error_t
dset_ctx_schedule(lcb_MULTICMD_CTX *mctx, const void *cookie)
{
    size_t ii;
    lcb_error_t err;
    lcb_DURSET *dset = CTX_FROM_MULTI(mctx);
    char *kptr = dset->kvbufs.base;

    if (!DSET_COUNT(dset)) {
        lcbdur_destroy(dset);
        return LCB_EINVAL;
    }

    for (ii = 0; ii < DSET_COUNT(dset); ii++) {
        lcb_DURITEM *ent = DSET_ENTRIES(dset) + ii;
        RESFLD(ent, key) = kptr;
        kptr += RESFLD(ent, nkey);
    }

    if (DSET_PROCS(dset)->schedule) {
        err = DSET_PROCS(dset)->schedule(dset);
        if (err != LCB_SUCCESS) {
            lcbdur_destroy(dset);
            return err;
        }
    }

    lcbdur_ref(dset);
    dset->cookie = cookie;
    dset->nremaining = DSET_COUNT(dset);
    dset->ns_timeout = gethrtime() + LCB_US2NS(DSET_OPTFLD(dset, timeout));

    lcb_aspend_add(&dset->instance->pendops, LCB_PENDTYPE_DURABILITY, dset);
    lcbdur_switch_state(dset, LCBDUR_STATE_INIT);
    return LCB_SUCCESS;
}