static void
dur_chain2(pycbc_Bucket *conn,
    pycbc_MultiResult *mres,
    pycbc_OperationResult *res, int cbtype, const lcb_RESPBASE *resp)
{
    lcb_error_t err;
    lcb_durability_opts_t dopts = { 0 };
    lcb_CMDENDURE cmd = { 0 };
    lcb_MULTICMD_CTX *mctx = NULL;
    int is_delete = cbtype == LCB_CALLBACK_REMOVE;

    res->rc = resp->rc;
    if (resp->rc == LCB_SUCCESS) {
        const lcb_MUTATION_TOKEN *mutinfo = lcb_resp_get_mutation_token(cbtype, resp);
        Py_XDECREF(res->mutinfo);

        if (mutinfo && LCB_MUTATION_TOKEN_ISVALID(mutinfo)) {
            /* Create the mutation token tuple: (vb,uuid,seqno) */
            res->mutinfo = Py_BuildValue("HKKO",
                LCB_MUTATION_TOKEN_VB(mutinfo),
                LCB_MUTATION_TOKEN_ID(mutinfo),
                LCB_MUTATION_TOKEN_SEQ(mutinfo),
                conn->bucket);
        } else {
            Py_INCREF(Py_None);
            res->mutinfo = Py_None;
        }
        res->cas = resp->cas;
    }

    /** For remove, we check quiet */
    maybe_push_operr(mres, (pycbc_Result*)res, resp->rc, is_delete ? 1 : 0);

    if ((mres->mropts & PYCBC_MRES_F_DURABILITY) == 0 || resp->rc != LCB_SUCCESS) {
        operation_completed(conn, mres);
        CB_THR_BEGIN(conn);
        return;
    }

    if (conn->dur_testhook && conn->dur_testhook != Py_None) {
        invoke_endure_test_notification(conn, (pycbc_Result *)res);
    }

    /** Setup global options */
    dopts.v.v0.persist_to = mres->dur.persist_to;
    dopts.v.v0.replicate_to = mres->dur.replicate_to;
    dopts.v.v0.timeout = conn->dur_timeout;
    dopts.v.v0.check_delete = is_delete;
    if (mres->dur.persist_to < 0 || mres->dur.replicate_to < 0) {
        dopts.v.v0.cap_max = 1;
    }

    lcb_sched_enter(conn->instance);
    mctx = lcb_endure3_ctxnew(conn->instance, &dopts, &err);
    if (mctx == NULL) {
        goto GT_DONE;
    }

    cmd.cas = resp->cas;
    LCB_CMD_SET_KEY(&cmd, resp->key, resp->nkey);
    err = mctx->addcmd(mctx, (lcb_CMDBASE*)&cmd);
    if (err != LCB_SUCCESS) {
        goto GT_DONE;
    }

    err = mctx->done(mctx, mres);
    if (err == LCB_SUCCESS) {
        mctx = NULL;
        lcb_sched_leave(conn->instance);
    }

    GT_DONE:
    if (mctx) {
        mctx->fail(mctx);
    }
    if (err != LCB_SUCCESS) {
        res->rc = err;
        maybe_push_operr(mres, (pycbc_Result*)res, err, 0);
        operation_completed(conn, mres);

    }

    CB_THR_BEGIN(conn);
}
Esempio n. 2
0
static void
compat_default_callback(lcb_t instance, int cbtype, const lcb_RESPBASE *r3base)
{
    const uRESP *r3 = (uRESP *)r3base;
    const void *cookie = r3base->cookie;
    lcb_error_t err = r3base->rc;

    #define FILL_KVC(dst) \
        (dst)->v.v0.key = r3base->key; \
        (dst)->v.v0.nkey = r3base->nkey; \
        (dst)->v.v0.cas = r3base->cas;

    switch (cbtype) {
    case LCB_CALLBACK_GET:
    case LCB_CALLBACK_GETREPLICA: {
        lcb_get_resp_t r2 = { 0 };
        FILL_KVC(&r2)
        r2.v.v0.bytes = r3->get.value;
        r2.v.v0.nbytes = r3->get.nvalue;
        r2.v.v0.flags = r3->get.itmflags;
        r2.v.v0.datatype = r3->get.datatype;
        instance->callbacks.get(instance, cookie, err, &r2);
        break;
    }
    case LCB_CALLBACK_STORE: {
        lcb_store_resp_t r2 = { 0 };
        FILL_KVC(&r2)
        r2.v.v0.mutation_token = lcb_resp_get_mutation_token(cbtype, r3base);
        instance->callbacks.store(instance, cookie, r3->store.op, err, &r2);
        break;
    }
    case LCB_CALLBACK_COUNTER: {
        lcb_arithmetic_resp_t r2 = { 0 };
        FILL_KVC(&r2);
        r2.v.v0.value = r3->arith.value;
        r2.v.v0.mutation_token = lcb_resp_get_mutation_token(cbtype, r3base);
        instance->callbacks.arithmetic(instance, cookie, err, &r2);
        break;
    }
    case LCB_CALLBACK_REMOVE: {
        lcb_remove_resp_t r2 = { 0 };
        FILL_KVC(&r2)
        r2.v.v0.mutation_token = lcb_resp_get_mutation_token(cbtype, r3base);
        instance->callbacks.remove(instance, cookie, err, &r2);
        break;
    }
    case LCB_CALLBACK_TOUCH: {
        lcb_touch_resp_t r2 = { 0 };
        FILL_KVC(&r2)
        instance->callbacks.touch(instance, cookie, err, &r2);
        break;
    }
    case LCB_CALLBACK_UNLOCK: {
        lcb_unlock_resp_t r2 = { 0 };
        r2.v.v0.key = r3->unl.key;
        r2.v.v0.nkey = r3->unl.nkey;
        instance->callbacks.unlock(instance, cookie, err, &r2);
        break;
    }
    case LCB_CALLBACK_FLUSH: {
        lcb_flush_resp_t r2 = { 0 };
        r2.v.v0.server_endpoint = r3->flush.server;
        instance->callbacks.flush(instance, cookie, err, &r2);
        break;
    }
    case LCB_CALLBACK_VERSIONS: {
        lcb_server_version_resp_t r2 = { 0 };
        r2.v.v0.server_endpoint = r3->mcversion.server;
        r2.v.v0.vstring = r3->mcversion.mcversion;
        r2.v.v0.nvstring = r3->mcversion.nversion;
        instance->callbacks.version(instance, cookie, err, &r2);
        break;
    }
    case LCB_CALLBACK_VERBOSITY: {
        lcb_verbosity_resp_t r2 = { 0 };
        r2.v.v0.server_endpoint = r3->verbosity.server;
        instance->callbacks.verbosity(instance, cookie, err, &r2);
        break;
    }
    case LCB_CALLBACK_STATS: {
        lcb_server_stat_resp_t r2 = { 0 };
        r2.v.v0.key = r3->stats.key;
        r2.v.v0.nkey = r3->stats.nkey;
        r2.v.v0.bytes = r3->stats.value;
        r2.v.v0.nbytes = r3->stats.nvalue;
        r2.v.v0.server_endpoint = r3->stats.server;
        instance->callbacks.stat(instance, cookie, err, &r2);
        break;
    }
    case LCB_CALLBACK_OBSERVE: {
        lcb_observe_resp_t r2 = { 0 };
        FILL_KVC(&r2);
        r2.v.v0.status = r3->observe.status;
        r2.v.v0.from_master = r3->observe.ismaster;
        r2.v.v0.ttp = r3->observe.ttp;
        r2.v.v0.ttr = r3->observe.ttr;
        instance->callbacks.observe(instance, cookie, err, &r2);
        break;
    }
    case LCB_CALLBACK_ENDURE: {
        lcb_durability_resp_t r2 = { 0 };
        FILL_KVC(&r2);
        r2.v.v0.err = r3->endure.rc;
        r2.v.v0.exists_master = r3->endure.exists_master;
        r2.v.v0.persisted_master = r3->endure.persisted_master;
        r2.v.v0.npersisted = r3->endure.npersisted;
        r2.v.v0.nreplicated = r3->endure.nreplicated;
        r2.v.v0.nresponses = r3->endure.nresponses;
        if (err == LCB_SUCCESS) {
            err = r3->endure.rc;
        }
        instance->callbacks.durability(instance, cookie, err, &r2);
        break;
    }
    case LCB_CALLBACK_HTTP: {
        lcb_http_res_callback target;
        lcb_http_resp_t r2 = { 0 };
        r2.v.v0.path = r3->http.key;
        r2.v.v0.npath = r3->http.nkey;
        r2.v.v0.bytes = r3->http.body;
        r2.v.v0.nbytes = r3->http.nbody;
        r2.v.v0.status = r3->http.htstatus;
        r2.v.v0.headers = r3->http.headers;
        if (!(r3base->rflags & LCB_RESP_F_FINAL)) {
            target = instance->callbacks.http_data;
        } else {
            target = instance->callbacks.http_complete;
        }
        target(r3->http._htreq, instance, cookie, err, &r2);
        break;
    }

    default:
        break;
    }
}