Beispiel #1
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);
}
Beispiel #2
0
LIBCOUCHBASE_API
lcb_destroy_callback
lcb_set_destroy_callback(lcb_t instance, lcb_destroy_callback cb)
{
    lcb_destroy_callback ret = LCBT_SETTING(instance, dtorcb);
    if (cb) {
        LCBT_SETTING(instance, dtorcb) = cb;
    }
    return ret;
}
Beispiel #3
0
/**
 * Optionally decompress an incoming payload.
 * @param o The instance
 * @param resp The response received
 * @param[out] bytes pointer to the final payload
 * @param[out] nbytes pointer to the size of the final payload
 * @param[out] freeptr pointer to free. This should be initialized to `NULL`.
 * If temporary dynamic storage is required this will be set to the allocated
 * pointer upon return. Otherwise it will be set to NULL. In any case it must
 */
static void
maybe_decompress(lcb_t o,
    const packet_info *respkt, lcb_RESPGET *rescmd, void **freeptr)
{
    lcb_U8 dtype = 0;
    if (!PACKET_NVALUE(respkt)) {
        return;
    }

    if (PACKET_DATATYPE(respkt) & PROTOCOL_BINARY_DATATYPE_JSON) {
        dtype = LCB_VALUE_F_JSON;
    }

    if (PACKET_DATATYPE(respkt) & PROTOCOL_BINARY_DATATYPE_COMPRESSED) {
        if (LCBT_SETTING(o, compressopts) & LCB_COMPRESS_IN) {
            /* if we inflate, we don't set the flag */
            mcreq_inflate_value(
                PACKET_VALUE(respkt), PACKET_NVALUE(respkt),
                &rescmd->value, &rescmd->nvalue, freeptr);

        } else {
            /* user doesn't want inflation. signal it's compressed */
            dtype |= LCB_VALUE_F_SNAPPYCOMP;
        }
    }
    rescmd->datatype = dtype;
}
Beispiel #4
0
/**
 * Handles the propagation and population of the 'synctoken' information.
 * @param mc_resp The response packet
 * @param req The request packet (used to get the vBucket)
 * @param tgt Pointer to synctoken which should be populated.
 */
static void
handle_synctoken(lcb_t instance, const packet_info *mc_resp,
    const mc_PACKET *req, lcb_SYNCTOKEN *stok)
{
    const char *sbuf;
    uint16_t vbid;

    if (PACKET_EXTLEN(mc_resp) == 0) {
        return; /* No extras */
    }

    if (!instance->dcpinfo && LCBT_SETTING(instance, dur_synctokens)) {
        size_t nvb = LCBT_VBCONFIG(instance)->nvb;
        if (nvb) {
            instance->dcpinfo = calloc(nvb, sizeof(*instance->dcpinfo));
        }
    }

    sbuf = PACKET_BODY(mc_resp);
    vbid = mcreq_get_vbucket(req);
    stok->vbid_ = vbid;
    memcpy(&stok->uuid_, sbuf, 8);
    memcpy(&stok->seqno_, sbuf + 8, 8);

    stok->uuid_ = lcb_ntohll(stok->uuid_);
    stok->seqno_ = lcb_ntohll(stok->seqno_);

    if (instance->dcpinfo) {
        instance->dcpinfo[vbid] = *stok;
    }
}
Beispiel #5
0
static int
can_compress(lcb_t instance, const mc_PIPELINE *pipeline,
    const lcb_VALBUF *vbuf, lcb_datatype_t datatype)
{
    mc_SERVER *server = (mc_SERVER *)pipeline;
    int compressopts = LCBT_SETTING(instance, compressopts);

    if (mcreq_compression_supported() == 0) {
        return 0;
    }

    if (vbuf->vtype != LCB_KV_COPY) {
        return 0;
    }
    if ((compressopts & LCB_COMPRESS_OUT) == 0) {
        return 0;
    }
    if (server->compsupport == 0 && (compressopts & LCB_COMPRESS_FORCE) == 0) {
        return 0;
    }
    if (datatype & LCB_VALUE_F_SNAPPYCOMP) {
        return 0;
    }
    return 1;
}
Beispiel #6
0
LIBCOUCHBASE_API
lcb_error_t
lcb_cbflush3(lcb_t instance, const void *cookie, const lcb_CMDBASE *cmd)
{
    lcb_http_request_t htr;
    lcb_CMDHTTP htcmd = { 0 };
    lcb_string urlpath;
    lcb_error_t rc;

    (void)cmd;

    lcb_string_init(&urlpath);
    lcb_string_appendz(&urlpath, "/pools/default/buckets/");
    lcb_string_appendz(&urlpath, LCBT_SETTING(instance, bucket));
    lcb_string_appendz(&urlpath, "/controller/doFlush");


    htcmd.type = LCB_HTTP_TYPE_MANAGEMENT;
    htcmd.method = LCB_HTTP_METHOD_POST;
    htcmd.reqhandle = &htr;
    LCB_CMD_SET_KEY(&htcmd, urlpath.base, urlpath.nused);

    rc = lcb_http3(instance, cookie, &htcmd);
    lcb_string_release(&urlpath);

    if (rc != LCB_SUCCESS) {
        return rc;
    }
    lcb_htreq_setcb(htr, flush_cb);
    return LCB_SUCCESS;
}
Beispiel #7
0
static void
on_flush_done(lcbio_CTX *ctx, unsigned expected, unsigned actual)
{
    mc_SERVER *server = lcbio_ctx_data(ctx);
    lcb_U64 now = 0;

    if (LCBT_SETTING(server->instance, readj_ts_wait)) {
        now = gethrtime();
    }

    mcreq_flush_done_ex(&server->pipeline, actual, expected, now);
    check_closed(server);
}
Beispiel #8
0
LIBCOUCHBASE_API
lcb_MULTICMD_CTX *
lcb_endure3_ctxnew(lcb_t instance, const lcb_durability_opts_t *options,
    lcb_error_t *errp)
{
    lcb_DURSET *dset;
    lcb_error_t err_s;
    hrtime_t now;
    lcbio_pTABLE io = instance->iotable;

    if (!errp) {
        errp = &err_s;
    }

    if (!LCBT_VBCONFIG(instance)) {
        *errp = LCB_CLIENT_ETMPFAIL;
        return NULL;
    }

    now = gethrtime();
    dset = calloc(1, sizeof(*dset));

    if (!dset) {
        *errp = LCB_CLIENT_ENOMEM;
        return NULL;
    }

    dset->opts = *options;
    dset->instance = instance;
    dset->mctx.addcmd = dset_ctx_add;
    dset->mctx.done = dset_ctx_schedule;
    dset->mctx.fail = dset_ctx_fail;

    if (!DSET_OPTFLD(dset, timeout)) {
        DSET_OPTFLD(dset, timeout) = LCBT_SETTING(instance, durability_timeout);
    }
    if (!DSET_OPTFLD(dset, interval)) {
        DSET_OPTFLD(dset, interval) = LCB_DEFAULT_DURABILITY_INTERVAL;
    }

    if (-1 == verify_critera(instance, dset)) {
        free(dset);
        *errp = LCB_DURABILITY_ETOOMANY;
        return NULL;
    }

    dset->us_timeout = (lcb_U32)(now / 1000) + DSET_OPTFLD(dset, timeout);
    dset->timer = io->timer.create(io->p);
    lcb_string_init(&dset->kvbufs);
    return &dset->mctx;
}
Beispiel #9
0
static lcb_U8
get_poll_meth(lcb_t instance, const lcb_DURABILITYOPTSv0 *options)
{
    /* Need to call this first, so we can actually allocate the appropriate
     * data for this.. */
    lcb_U8 meth = options->pollopts;
    if (meth == LCB_DURABILITY_MODE_DEFAULT) {
        meth = LCB_DURABILITY_MODE_CAS;

        if (LCBT_SETTING(instance, fetch_mutation_tokens) &&
                LCBT_SETTING(instance, dur_mutation_tokens)) {
            size_t ii;
            for (ii = 0; ii < LCBT_NSERVERS(instance); ii++) {
                mc_SERVER *s = LCBT_GET_SERVER(instance, ii);
                if (s->mutation_tokens) {
                    meth = LCB_DURABILITY_MODE_SEQNO;
                    break;
                }
            }
        }
    }
    return meth;
}
Beispiel #10
0
static void
maybe_reset_timeouts(lcb_t instance)
{
    size_t ii;
    lcb_U64 now;

    if (!LCBT_SETTING(instance, readj_ts_wait)) {
        return;
    }

    now = lcb_nstime();
    for (ii = 0; ii < LCBT_NSERVERS(instance); ++ii) {
        mc_SERVER *ss = LCBT_GET_SERVER(instance, ii);
        mcreq_reset_timeouts(&ss->pipeline, now);
    }
    lcb_retryq_reset_timeouts(instance->retryq, now);
}
Beispiel #11
0
static lcb_error_t
wrap_return(lcb_t instance, lcb_error_t retval)
{
    if (retval == LCB_SUCCESS) {
        return retval;
    }
    if (instance && LCBT_SETTING(instance, detailed_neterr) == 0) {
        switch (retval) {
        case LCB_ECTL_UNKNOWN:
            return LCB_NOT_SUPPORTED;
        case LCB_ECTL_UNSUPPMODE:
            return LCB_NOT_SUPPORTED;
        case LCB_ECTL_BADARG:
            return LCB_EINVAL;
        default:
            return retval;
        }
    } else {
        return retval;
    }
}
Beispiel #12
0
LIBCOUCHBASE_API
lcb_MULTICMD_CTX *
lcb_endure3_ctxnew(lcb_t instance, const lcb_durability_opts_t *options,
    lcb_error_t *errp)
{
    lcb_DURSET *dset;
    lcb_error_t err_s;
    lcbio_pTABLE io = instance->iotable;
    const lcb_DURABILITYOPTSv0 *opts_in = &options->v.v0;

    if (!errp) {
        errp = &err_s;
    }

    *errp = LCB_SUCCESS;

    if (!LCBT_VBCONFIG(instance)) {
        *errp = LCB_CLIENT_ETMPFAIL;
        return NULL;
    }

    dset = calloc(1, sizeof(*dset));
    if (!dset) {
        *errp = LCB_CLIENT_ENOMEM;
        return NULL;
    }

    /* Ensure we don't clobber options from older versions */
    dset->opts.cap_max = opts_in->cap_max;
    dset->opts.check_delete = opts_in->check_delete;
    dset->opts.interval = opts_in->interval;
    dset->opts.persist_to = opts_in->persist_to;
    dset->opts.replicate_to = opts_in->replicate_to;
    dset->opts.timeout = opts_in->timeout;

    if (options->version > 0) {
        dset->opts.pollopts = opts_in->pollopts;
    }

    dset->opts.pollopts = get_poll_meth(instance, &dset->opts);

    dset->instance = instance;
    dset->mctx.addcmd = dset_ctx_add;
    dset->mctx.done = dset_ctx_schedule;
    dset->mctx.fail = dset_ctx_fail;

    if (!DSET_OPTFLD(dset, timeout)) {
        DSET_OPTFLD(dset, timeout) = LCBT_SETTING(instance, durability_timeout);
    }
    if (!DSET_OPTFLD(dset, interval)) {
        DSET_OPTFLD(dset, interval) = LCBT_SETTING(instance, durability_interval);
    }

    *errp = lcb_durability_validate(instance,
        &dset->opts.persist_to, &dset->opts.replicate_to,
        dset->opts.cap_max ? LCB_DURABILITY_VALIDATE_CAPMAX : 0);

    if (*errp != LCB_SUCCESS) {
        free(dset);
        return NULL;
    }

    dset->timer = io->timer.create(io->p);
    lcb_string_init(&dset->kvbufs);
    return &dset->mctx;
}
Beispiel #13
0
LIBCOUCHBASE_API
const char *
lcb_get_node(lcb_t instance, lcb_GETNODETYPE type, unsigned ix)
{
    if (type & LCB_NODE_HTCONFIG) {
        if (type & LCB_NODE_CONNECTED) {
            const lcb_host_t *host = lcb_confmon_get_rest_host(instance->confmon);
            if (host) {
                return mk_scratch_host(instance, host);
            } else {
                return return_badhost(type);
            }

        } else {
            /* Retrieve one from the vbucket configuration */
            lcbvb_CONFIG *vbc = LCBT_VBCONFIG(instance);
            lcbvb_SVCMODE mode;
            const char *hp = NULL;
            if (LCBT_SETTING(instance, sslopts) & LCB_SSL_ENABLED) {
                mode = LCBVB_SVCMODE_SSL;
            } else {
                mode = LCBVB_SVCMODE_PLAIN;
            }

            if (instance->type == LCB_TYPE_BUCKET) {
                if (vbc) {
                    ix %= LCBVB_NSERVERS(vbc);
                    hp = lcbvb_get_hostport(vbc, ix, LCBVB_SVCTYPE_MGMT, mode);

                } else if ((type & LCB_NODE_NEVERNULL) == 0) {
                    return NULL;
                }
            }
            if (hp == NULL && instance->ht_nodes && instance->ht_nodes->nentries) {
                ix %= instance->ht_nodes->nentries;
                hostlist_ensure_strlist(instance->ht_nodes);
                hp = instance->ht_nodes->slentries[ix];
            }
            if (!hp) {
                if ((hp = return_badhost(type)) == NULL) {
                    return NULL;
                }
            }
            if (!ensure_scratch(instance, strlen(hp)+1)) {
                return NULL;
            }
            lcb_string_appendz(instance->scratch, hp);
            return instance->scratch->base;
        }
    } else if (type & (LCB_NODE_DATA|LCB_NODE_VIEWS)) {
        const mc_SERVER *server;
        ix %= LCBT_NSERVERS(instance);
        server = LCBT_GET_SERVER(instance, ix);

        if ((type & LCB_NODE_CONNECTED) && server->connctx == NULL) {
            return return_badhost(type);
        }
        if (server->curhost == NULL) {
            return return_badhost(type);
        }

        /* otherwise, return the actual host:port of the server */
        if (type & LCB_NODE_DATA) {
            return mk_scratch_host(instance, server->curhost);
        } else {
            return server->viewshost;
        }
    } else {
        return NULL; /* don't know the type */
    }
}
Beispiel #14
0
LIBCOUCHBASE_API
lcb_error_t
lcb_n1ql_query(lcb_t instance, const void *cookie, const lcb_CMDN1QL *cmd)
{
    lcb_CMDHTTP htcmd = { 0 };
    lcb_error_t err;
    N1QLREQ *req = NULL;

    if (cmd->query == NULL || cmd->nquery == 0 ||
            cmd->callback == NULL || cmd->content_type == NULL) {
        return LCB_EINVAL;
    }
    htcmd.body = cmd->query;
    htcmd.nbody = cmd->nquery;
    htcmd.content_type = cmd->content_type;
    htcmd.method = LCB_HTTP_METHOD_POST;
    if (cmd->host) {
        htcmd.type = LCB_HTTP_TYPE_RAW;
        LCB_CMD_SET_KEY(&htcmd, QUERY_PATH, strlen(QUERY_PATH));
        htcmd.host = cmd->host;
        htcmd.username = LCBT_SETTING(instance, bucket);
        htcmd.password = LCBT_SETTING(instance, password);
    } else {
        htcmd.type = LCB_HTTP_TYPE_N1QL;
    }

    htcmd.cmdflags = LCB_CMDHTTP_F_STREAM;
    req = calloc(1, sizeof(*req));
    if (!req) {
        err = LCB_CLIENT_ENOMEM; goto GT_DESTROY;
    }

    req->callback = cmd->callback;
    req->cookie = cookie;
    req->instance = instance;
    req->parser = lcbjsp_create(LCBJSP_MODE_N1QL);

    if (!req->parser) {
        err = LCB_CLIENT_ENOMEM; goto GT_DESTROY;
    }
    req->parser->data = req;
    req->parser->callback = row_callback;

    htcmd.reqhandle = &req->htreq;
    err = lcb_http3(instance, req, &htcmd);
    if (err != LCB_SUCCESS) {
        goto GT_DESTROY;
    }

    lcb_htreq_setcb(req->htreq, chunk_callback);
    if (cmd->handle) {
        *cmd->handle = req;
    }
    return LCB_SUCCESS;

    GT_DESTROY:
    if (req) {
        req->callback = NULL;
        destroy_req(req);
    }
    return err;
}