/** * 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); }
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); }
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); }
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; }
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; }