static PyObject *
Connection__thr_lockop(pycbc_Connection *self, PyObject *arg)
{
    int rv;
    int is_unlock = 0;
    rv = PyArg_ParseTuple(arg, "i:is_unlock", &is_unlock);

    if (!rv) {
        return NULL;
    }

    if (!self->lockmode) {
        PYCBC_EXC_WRAP(PYCBC_EXC_THREADING, 0, "lockmode is LOCKMODE_NONE");
        return NULL;
    }

    if (is_unlock) {
        PyThread_release_lock(self->lock);
    } else {
        if (!PyThread_acquire_lock(self->lock, WAIT_LOCK)) {
            PYCBC_EXC_WRAP(PYCBC_EXC_THREADING, 0, "Couldn't lock");
            return NULL;
        }
    }

    Py_RETURN_NONE;
}
PyObject *
pycbc_Bucket__fts_query(pycbc_Bucket *self, PyObject *args, PyObject *kwargs)
{
    int rv;
    PyObject *ret = NULL;
    pycbc_MultiResult *mres;
    pycbc_ViewResult *vres;
    lcb_error_t rc;
    lcb_CMDFTS cmd = { 0 };
    const char *params;
    pycbc_strlen_t nparams;

    static char *kwlist[] = { "params", NULL };
    rv = PyArg_ParseTupleAndKeywords(args, kwargs,
        "s#", kwlist, &params, &nparams);

    if (!rv) {
        PYCBC_EXCTHROW_ARGS();
        return NULL;
    }
    if (-1 == pycbc_oputil_conn_lock(self)) {
        return NULL;
    }
    if (self->pipeline_queue) {
        PYCBC_EXC_WRAP(PYCBC_EXC_PIPELINE, 0,
                       "FTS queries cannot be executed in pipeline context");
    }

    mres = (pycbc_MultiResult *)pycbc_multiresult_new(self);
    vres = (pycbc_ViewResult *)PYCBC_TYPE_CTOR(&pycbc_ViewResultType);
    pycbc_httpresult_init(&vres->base, mres);
    vres->rows = PyList_New(0);
    vres->base.format = PYCBC_FMT_JSON;
    vres->base.htype = PYCBC_HTTP_HN1QL;

    cmd.callback = fts_row_callback;
    cmd.query = params;
    cmd.nquery = nparams;
    cmd.handle = &vres->base.u.fts;
    rc = lcb_fts_query(self->instance, mres, &cmd);

    if (rc != LCB_SUCCESS) {
        PYCBC_EXC_WRAP(PYCBC_EXC_LCBERR, rc, "Couldn't schedule fts query");
        goto GT_DONE;
    }

    ret = (PyObject *)mres;
    mres = NULL;

    GT_DONE:
    Py_XDECREF(mres);
    pycbc_oputil_conn_unlock(self);
    return ret;
}
Exemple #3
0
/**
 * Fetches a bunch of results from the network. Returns False when
 * no more results remain.
 */
PyObject *
pycbc_HttpResult__fetch(pycbc_HttpResult *self)
{
    lcb_error_t err;
    PyObject *ret = NULL;

    if (-1 == pycbc_oputil_conn_lock(self->parent)) {
        return NULL;
    }

    if (!self->htreq) {
        ret = Py_None;
        Py_INCREF(ret);
        goto GT_RET;
    }

    if (self->parent->flags & PYCBC_CONN_F_ASYNC) {
        PYCBC_EXC_WRAP(PYCBC_EXC_ARGUMENTS, 0,
                       "_fetch() should not be called with an async "
                       "connection");
        goto GT_RET;
    } else if (self->parent->pipeline_queue) {
        PYCBC_EXC_WRAP(PYCBC_EXC_PIPELINE, 0,
                       "HTTP requests cannot be executed in pipeline context");
    }

    if (!self->rowsbuf) {
        self->rowsbuf = PyList_New(0);
    }

    err = pycbc_oputil_wait_common(self->parent);

    if (err != LCB_SUCCESS) {
        PYCBC_EXCTHROW_WAIT(err);
        goto GT_RET;

    } else {
        if (maybe_raise(self)) {
            goto GT_RET;
        }

        ret = self->rowsbuf;
        self->rowsbuf = NULL;
    }

    if (!pycbc_assert(self->parent->nremaining == 0)) {
        fprintf(stderr, "Remaining count unexpected. Adjusting");
        self->parent->nremaining = 0;
    }

    GT_RET:
    pycbc_oputil_conn_unlock(self->parent);
    return ret;
}
static int handle_replica_options(int *optype,
                                  struct getcmd_vars_st *gv,
                                  PyObject *replica_O)
{

#if LCB_VERSION >= 0x020007
    switch (*optype) {
    case PYCBC_CMD_GET:
        *optype = PYCBC_CMD_GETREPLICA;
        if (gv->u.ttl) {
            PYCBC_EXC_WRAP(PYCBC_EXC_ARGUMENTS,
                           0, "TTL specified along with replica");
            return -1;
        }
        gv->u.replica.strategy = LCB_REPLICA_FIRST;
        return 0;

    case PYCBC_CMD_GETREPLICA:
        gv->u.replica.strategy = LCB_REPLICA_FIRST;
        return 0;

    case PYCBC_CMD_GETREPLICA_INDEX:
        gv->u.replica.strategy = LCB_REPLICA_SELECT;
        if (replica_O == NULL || replica_O == Py_None) {
            PYCBC_EXC_WRAP(PYCBC_EXC_ARGUMENTS,
                           0, "rgetix must have a valid replica index");
            return -1;
        }
        gv->u.replica.index = pycbc_IntAsL(replica_O);
        if (PyErr_Occurred()) {
            return -1;
        }
        return 0;

    case PYCBC_CMD_GETREPLICA_ALL:
        gv->u.replica.strategy = LCB_REPLICA_ALL;
        return 0;

    default:
        PYCBC_EXC_WRAP(PYCBC_EXC_ARGUMENTS, 0,
                       "Replica option not supported for this operation");
        return -1;
    }
#else
    PYCBC_EXC_WRAP(PYCBC_EXC_ARGUMENTS, 0, "Need libcouchbase >= 2.0.7");
    (void)optype;
    (void)gv;
    (void)replica_O;
#endif
    return -1;
}
static PyObject *
convert_to_string(const char *buf, size_t nbuf, int mode)
{
    PyObject *ret = NULL;

    if (mode == CONVERT_MODE_BYTES_ONLY) {
        goto GT_BYTES;
    }

    ret = PyUnicode_DecodeUTF8(buf, nbuf, "strict");

    if (ret) {
        return ret;
    }

    if (mode == CONVERT_MODE_UTF8_ONLY) {
        PYCBC_EXC_WRAP(PYCBC_EXC_ENCODING, 0, "Couldn't decode as UTF-8");
        return NULL;
    }

    PyErr_Clear();
    GT_BYTES:

    return PyBytes_FromStringAndSize(buf, nbuf);
}
static PyObject *
Connection_server_nodes(pycbc_Connection *self, void *unused)
{
    const char * const *cnodes;
    const char **curnode;
    PyObject *ret_list;
    cnodes = lcb_get_server_list(self->instance);

    if (!cnodes) {
        PYCBC_EXC_WRAP(PYCBC_EXC_INTERNAL, 0, "Can't get server nodes");
        return NULL;
    }

    ret_list = PyList_New(0);
    if (!ret_list) {
        return NULL;
    }

    for (curnode = (const char**)cnodes; *curnode; curnode++) {
        PyObject *tmpstr = pycbc_SimpleStringZ(*curnode);
        PyList_Append(ret_list, tmpstr);
        Py_DECREF(tmpstr);
    }

    (void)unused;

    return ret_list;
}
Exemple #7
0
static PyObject *
handle_float_tmo(lcb_t instance,
                 int cmd, int mode, PyObject *val, lcb_error_t *err)
{
    lcb_uint32_t cval;

    if (val != NULL) {
        if (PyFloat_Check(val)) {
            double dv = PyFloat_AsDouble(val);
            if (dv < 0) {
                PYCBC_EXC_WRAP(PYCBC_EXC_ARGUMENTS, 0,
                               "Timeout cannot be < 0");
                return NULL;
            }
            cval = dv * 1000000;

        } else {
        cval = pycbc_IntAsL(val);
            if (cval == (lcb_uint32_t)-1 && PyErr_Occurred()) {
                PYCBC_EXCTHROW_ARGS();
                return NULL;
            }
        }
    }
    if ( (*err = lcb_cntl(instance, mode, cmd, &cval)) != LCB_SUCCESS) {
        return NULL;
    }

    return pycbc_IntFromUL(cval);
}
Exemple #8
0
PyObject *
pycbc_Connection__vbmap(pycbc_Connection *conn, PyObject *args)
{
    pycbc_strlen_t slen = 0;
    const char *s = NULL;
    PyObject *rtuple;
    struct vbinfo_st info;
    lcb_error_t err;

    if (!PyArg_ParseTuple(args, "s#", &s, &slen)) {
        PYCBC_EXCTHROW_ARGS();
    }

    memset(&info, 0, sizeof(info));
    info.v.v0.key = s;
    info.v.v0.nkey = slen;
    err = lcb_cntl(conn->instance, CNTL_GET, CNTL_VBMAP, &info);
    if (err != LCB_SUCCESS) {
        PYCBC_EXC_WRAP(PYCBC_EXC_ARGUMENTS, 0, "lcb_cntl failed");
        return NULL;
    }

    rtuple = PyTuple_New(2);
    PyTuple_SET_ITEM(rtuple, 0, pycbc_IntFromL(info.v.v0.vbucket));
    PyTuple_SET_ITEM(rtuple, 1, pycbc_IntFromL(info.v.v0.server_index));
    return rtuple;

}
static PyObject*
Bucket__connect(pycbc_Bucket *self)
{
    lcb_error_t err;

    if (self->flags & PYCBC_CONN_F_CONNECTED) {
        Py_RETURN_NONE;
    }

    err = lcb_connect(self->instance);

    if (err != LCB_SUCCESS) {
        PYCBC_EXC_WRAP(PYCBC_EXC_LCBERR, err,
                       "Couldn't schedule connection. This might be a result of "
                       "an invalid hostname.");
        return NULL;
    }

    pycbc_oputil_wait_common(self);
    if ((self->flags & PYCBC_CONN_F_ASYNC) == 0) {
        err = lcb_get_bootstrap_status(self->instance);
        if (err != LCB_SUCCESS) {
            PYCBC_EXCTHROW_WAIT(err);
            return NULL;
        }
    }
    Py_RETURN_NONE;
}
static PyObject *
Bucket__close(pycbc_Bucket *self)
{
    lcb_error_t err;

    if (self->flags & PYCBC_CONN_F_CLOSED) {
        Py_RETURN_NONE;
    }

    self->flags |= PYCBC_CONN_F_CLOSED;

    lcb_destroy(self->instance);

    if (self->iopswrap) {
        Py_XDECREF(self->iopswrap);
        self->iopswrap = NULL;
    }

    err = lcb_create(&self->instance, NULL);
    pycbc_assert(err == LCB_SUCCESS);
    if (err != LCB_SUCCESS) {
        PYCBC_EXC_WRAP(PYCBC_EXC_LCBERR,
                       err,
                       "Internal error while closing object");
        return NULL;
    }

    Py_RETURN_NONE;
}
static int
do_call_tc(pycbc_Bucket *conn,
          PyObject *obj,
          PyObject *flags,
          PyObject **result,
          int mode)
{
    PyObject *meth = NULL;
    PyObject *args = NULL;
    PyObject *strlookup = NULL;
    int ret = -1;

    switch (mode) {
    case ENCODE_KEY:
        strlookup = pycbc_helpers.tcname_encode_key;
        args = PyTuple_Pack(1, obj);
        break;
    case DECODE_KEY:
        strlookup = pycbc_helpers.tcname_decode_key;
        args = PyTuple_Pack(1, obj);
        break;

    case ENCODE_VALUE:
        strlookup = pycbc_helpers.tcname_encode_value;
        args = PyTuple_Pack(2, obj, flags);
        break;

    case DECODE_VALUE:
        strlookup = pycbc_helpers.tcname_decode_value;
        args = PyTuple_Pack(2, obj, flags);
        break;
    }
    if (args == NULL) {
        PYCBC_EXC_WRAP(PYCBC_EXC_INTERNAL, 0, "Couldn't build arguments");
        goto GT_DONE;
    }

    meth = PyObject_GetAttr(conn->tc, strlookup);
    if (!meth) {
        PYCBC_EXC_WRAP_OBJ(PYCBC_EXC_ENCODING, 0,
                           "Couldn't find transcoder method",
                           conn->tc);
        goto GT_DONE;
    }
    *result = PyObject_Call(meth, args, NULL);
    if (*result) {
        ret = 0;
    } else {
        PYCBC_EXC_WRAP_OBJ(PYCBC_EXC_ENCODING, 0,
                           "User-Defined transcoder failed",
                           obj);
    }

    GT_DONE:
    Py_XDECREF(meth);
    Py_XDECREF(args);
    return ret;
}
PyObject *
pycbc_Bucket__start_pipeline(pycbc_Bucket *self)
{
    if (self->pipeline_queue) {
        PYCBC_EXC_WRAP(PYCBC_EXC_PIPELINE, 0,
                       "A pipeline is already in progress");
        return NULL;
    }

    if (self->flags & PYCBC_CONN_F_ASYNC) {
        PYCBC_EXC_WRAP(PYCBC_EXC_PIPELINE, 0,
                       "Pipeline mode not valid in async handle");
        return NULL;
    }

    self->pipeline_queue = PyList_New(0);
    Py_INCREF(self->pipeline_queue);
    return self->pipeline_queue;
}
static int
modify_event_python(pycbc_IOPSWrapper *pio, pycbc_Event *ev,
                    pycbc_evaction_t action, lcb_socket_t newsock, void *arg)
{
    int ret;
    PyObject *result;
    PyObject *o_arg;
    PyObject *meth = NULL;
    PyObject *argtuple;

    short flags = 0;
    unsigned long usecs = 0;

    argtuple = PyTuple_New(3);
    Py_INCREF((PyObject *)ev);
    PyTuple_SET_ITEM(argtuple, 0, (PyObject *)ev);
    PyTuple_SET_ITEM(argtuple, 1, pycbc_IntFromL(action));

    if (ev->type == PYCBC_EVTYPE_IO) {
        flags = *(short*)arg;
        o_arg = pycbc_IntFromL(flags);
        ((pycbc_IOEvent *)ev)->fd = newsock;
        meth = pio->modevent;

    } else {
        usecs = *(lcb_uint32_t*)arg;
        o_arg = pycbc_IntFromL(usecs);
        meth = pio->modtimer;
    }
    PyTuple_SET_ITEM(argtuple, 2, o_arg);

    result = PyObject_CallObject(meth, argtuple);
    Py_DECREF(argtuple);
    Py_XDECREF(result);

    if (ev->type == PYCBC_EVTYPE_IO) {
        pycbc_IOEvent *evio = (pycbc_IOEvent*)ev;
        evio->flags = flags;
    }

    if (action == PYCBC_EVACTION_WATCH) {
        ev->state = PYCBC_EVSTATE_ACTIVE;
    } else {
        ev->state = PYCBC_EVSTATE_SUSPENDED;
    }

    if (!result) {
        ret = -1;
        PYCBC_EXC_WRAP(PYCBC_EXC_INTERNAL, 0, "Couldn't invoke IO Function");
    } else {
        ret = 0;
    }

    return ret;
}
lcb_io_opt_t
pycbc_iops_new(pycbc_Connection *conn, PyObject *pyio)
{
    lcb_io_opt_t ret = NULL;
    lcb_io_opt_t dfl = NULL;

    lcb_error_t err;
    struct lcb_create_io_ops_st options = { 0 };
    pycbc_iops_t *pio;

    pio = calloc(1, sizeof(*pio));
    ret = &pio->iops;
    pio->conn = conn;
    pio->pyio = pyio;

    Py_INCREF(pyio);

    /**
     * We create the select 'iops' handle and copy over its functionality
     * from there. Now that libcouchbase has the 'select' iops build in, we use
     * that instead.
     *
     * We discard the default iops loop data at the expense of leaking a
     * dlhandle.
     */
    options.v.v0.type = LCB_IO_OPS_SELECT;
    err = lcb_create_io_ops(&dfl, &options);
    if (err != LCB_SUCCESS) {
        PYCBC_EXC_WRAP(PYCBC_EXC_LCBERR, err, "Couldn't create IOPS");
        return NULL;
    }

    memcpy(&pio->iops, dfl, sizeof(*dfl));
    /* hide the dlsym */
    dfl->dlhandle = NULL;

    lcb_destroy_io_ops(dfl);
    dfl = NULL;

    ret->v.v0.create_event = create_event;
    ret->v.v0.create_timer = create_timer;
    ret->v.v0.destroy_event = destroy_event_common;
    ret->v.v0.destroy_timer = destroy_event_common;
    ret->v.v0.update_event = update_event;
    ret->v.v0.delete_event = delete_event;
    ret->v.v0.delete_timer = delete_timer;
    ret->v.v0.update_timer = update_timer;
    ret->v.v0.run_event_loop = run_event_loop;
    ret->v.v0.stop_event_loop = stop_event_loop;
    ret->destructor = iops_destructor;

    return ret;
}
static int
modify_event_python(pycbc_iops_t *pio,
                    pycbc_Event *ev,
                    pycbc_evaction_t action,
                    lcb_socket_t newsock,
                    void *arg)
{
    int ret;
    PyObject *argtuple = NULL;
    PyObject *result = NULL;
    PyObject *meth = NULL;
    short flags = 0;
    unsigned long usecs = 0;

    if (ev->type == PYCBC_EVTYPE_IO) {
        flags = *(short*)arg;
        argtuple = Py_BuildValue("(O,i,i)", ev, action, flags);
        ((pycbc_IOEvent *)ev)->fd = newsock;
        meth = PyObject_GetAttr(pio->pyio, pycbc_helpers.ioname_modevent);

    } else {
        usecs = *(lcb_uint32_t*)arg;
        argtuple = Py_BuildValue("(O,i,k)", ev, action, usecs);
        meth = PyObject_GetAttr(pio->pyio, pycbc_helpers.ioname_modtimer);
    }

    assert(meth);

    result = PyObject_CallObject(meth, argtuple);
    Py_XDECREF(meth);
    Py_XDECREF(result);
    Py_XDECREF(argtuple);

    if (ev->type == PYCBC_EVTYPE_IO) {
        pycbc_IOEvent *evio = (pycbc_IOEvent*)ev;
        evio->flags = flags;
    }

    if (action == PYCBC_EVACTION_WATCH) {
        ev->state = PYCBC_EVSTATE_ACTIVE;
    } else {
        ev->state = PYCBC_EVSTATE_SUSPENDED;
    }

    if (!result) {
        ret = -1;
        PYCBC_EXC_WRAP(PYCBC_EXC_INTERNAL, 0, "Couldn't invoke IO Function");
    } else {
        ret = 0;
    }

    return ret;
}
PyObject *
pycbc_Bucket__end_pipeline(pycbc_Bucket *self)
{
    PyObject *rv;
    int ii;

    if (!self->pipeline_queue) {
        PYCBC_EXC_WRAP(PYCBC_EXC_PIPELINE, 0,
                       "No pipeline in progress");
        return NULL;
    }

    rv = self->pipeline_queue;

    if (!self->nremaining) {
        goto GT_DONE;
    }

    pycbc_oputil_wait_common(self);

    pycbc_assert(self->nremaining == 0);

    for (ii = 0; ii < PyList_GET_SIZE(self->pipeline_queue); ii++) {
        PyObject *retitem;
        pycbc_MultiResult *mres =
                (pycbc_MultiResult *)PyList_GET_ITEM(self->pipeline_queue, ii);

        if (pycbc_multiresult_maybe_raise(mres)) {
            rv = NULL;
            break;
        }

        /** Returns new reference to something */
        retitem = pycbc_multiresult_get_result(mres);
        if (retitem != (PyObject *)mres) {
            PyList_SetItem(self->pipeline_queue, ii, retitem);
        } else {
            Py_DECREF(mres);
        }
    }


    GT_DONE:
    if (rv) {
        Py_INCREF(rv);
        pycbc_assert(rv == self->pipeline_queue);
    }

    Py_XDECREF(self->pipeline_queue);
    self->pipeline_queue = NULL;

    return rv;
}
int
pycbc_tc_decode_value(pycbc_Bucket *conn,
                       const void *value,
                       size_t nvalue,
                       lcb_uint32_t flags,
                       PyObject **pobj)
{
    PyObject *result = NULL;
    PyObject *pint = NULL;
    PyObject *pbuf = NULL;
    int rv;

    if (conn->data_passthrough == 0 && conn->tc == NULL) {
        return decode_common(pobj, value, nvalue, flags);
    }

    if (conn->data_passthrough) {
        *pobj = PyBytes_FromStringAndSize(value, nvalue);
        if (*pobj) {
            return 0;
        }
        return -1;
    }

    pbuf = PyBytes_FromStringAndSize(value, nvalue);
    if (!pbuf) {
        pbuf = PyBytes_FromString("");
    }

    pint = pycbc_IntFromUL(flags);
    if (!pint) {
        PYCBC_EXC_WRAP(PYCBC_EXC_INTERNAL, 0, "Couldn't create flags object");
        rv = -1;
        goto GT_DONE;
    }

    rv = do_call_tc(conn, pbuf, pint, &result, DECODE_VALUE);

    GT_DONE:
    Py_XDECREF(pint);
    Py_XDECREF(pbuf);

    if (rv < 0) {
        return -1;
    }

    *pobj = result;
    return 0;
}
Exemple #18
0
static void
maybe_invoke_async_callback(pycbc_HttpResult *htres)
{
    PyObject *args, *ret;

    if (!(htres->parent->flags & PYCBC_CONN_F_ASYNC)) {
        return;
    }

    if ((htres->htflags & PYCBC_HTRES_F_COMPLETE) == 0 &&
            (unsigned long)PyList_GET_SIZE(htres->rowsbuf) <
            (unsigned long)htres->rows_per_call) {
        return;
    }

    if (htres->htflags & PYCBC_HTRES_F_CHUNKED) {
        args = Py_BuildValue("(OO)", (PyObject *)htres, htres->rowsbuf);

    } else {
        args = Py_BuildValue("(OO)", Py_None, Py_None);
    }

    if (!htres->callback) {
        PYCBC_EXC_WRAP(PYCBC_EXC_ARGUMENTS, 0, "Missing callback for HTTP");

    } else {
        ret = PyObject_CallObject(htres->callback, args);

        if (ret) {
            Py_XDECREF(ret);

        } else {
            PyErr_PrintEx(0);
        }
    }

    Py_DECREF(args);

    if (htres->htflags & PYCBC_HTRES_F_COMPLETE) {
        Py_XDECREF(htres->callback);
        htres->callback = NULL;

        Py_XDECREF(htres);

    } else if (htres->htflags & PYCBC_HTRES_F_CHUNKED) {
        Py_XDECREF(htres->rowsbuf);
        htres->rowsbuf = PyList_New(0);
    }
}
static int
Connection_set_format(pycbc_Connection *self, PyObject *value, void *unused)
{
    if (value != pycbc_helpers.fmt_auto) {
        if (!PyNumber_Check(value)) {
            PYCBC_EXC_WRAP(PYCBC_EXC_ARGUMENTS, 0,
                           "Format must be a number");
            return -1;
        }

        if (Py_TYPE(value) == &PyBool_Type) {
            PYCBC_EXC_WRAP(PYCBC_EXC_ARGUMENTS, 0,
                           "Format must not be a boolean");
            return -1;
        }
    }

    Py_XDECREF(self->dfl_fmt);
    Py_INCREF(value);
    self->dfl_fmt = value;

    (void)unused;
    return 0;
}
static int
handle_single_observe(pycbc_Connection *self,
                      PyObject *curkey,
                      int ii,
                      int master_only,
                      struct pycbc_common_vars *cv)
{
    int rv;
    char *key;
    size_t nkey;
    lcb_observe_cmd_t *ocmd = cv->cmds.obs + ii;

    rv = pycbc_tc_encode_key(self, &curkey, (void**)&key, &nkey);
    if (rv < 0) {
        return -1;
    }


    cv->enckeys[ii] = curkey;

    if (!nkey) {
        PYCBC_EXCTHROW_EMPTYKEY();
        return -1;
    }

    if (master_only) {
        /** New 'MASTER_ONLY' was added in 2.3.0 */
#if LCB_VERSION < 0x020300
        PYCBC_EXC_WRAP(PYCBC_EXC_ARGUMENTS, 0,
                       "master_only requires libcouchbase >= 2.3.0");
        return -1;
#else
        ocmd->version = 1;
        ocmd->v.v1.options = LCB_OBSERVE_MASTER_ONLY;
#endif
    }

    ocmd->v.v0.key = key;
    ocmd->v.v0.nkey = nkey;

    cv->cmdlist.obs[ii] = ocmd;
    return 0;
}
static PyObject *
ViewResult_fetch(pycbc_ViewResult *self, PyObject *args)
{
    PyObject *ret = NULL;
    pycbc_MultiResult *mres = NULL;
    pycbc_Bucket *bucket;
    int rv;

    rv = PyArg_ParseTuple(args, "O", &mres);
    if (!rv) {
        PYCBC_EXCTHROW_ARGS();
        return NULL;
    }

    bucket = mres->parent;

    if (bucket->flags & PYCBC_CONN_F_ASYNC) {
        PYCBC_EXC_WRAP(PYCBC_EXC_INTERNAL, 0, "Cannot use fetch with async");
        return NULL;
    }

    if (-1 == pycbc_oputil_conn_lock(bucket)) {
        return NULL;
    }

    if (!self->base.done) {
        pycbc_oputil_wait_common(bucket);
    }

    if (pycbc_multiresult_maybe_raise(mres)) {
        goto GT_DONE;
    }

    ret = self->rows ? self->rows : PyList_New(0);
    self->rows = PyList_New(0);

    GT_DONE:
    pycbc_oputil_conn_unlock(bucket);
    return ret;
}
static PyObject *
Bucket__mutinfo(pycbc_Bucket *self)
{
    PyObject *ll = PyList_New(0);
    size_t ii, vbmax;
    lcbvb_CONFIG *cfg = NULL;
    lcb_error_t rc;

    rc = lcb_cntl(self->instance, LCB_CNTL_GET, LCB_CNTL_VBCONFIG, &cfg);
    if (rc != LCB_SUCCESS) {
        PYCBC_EXC_WRAP(PYCBC_EXC_LCBERR, rc, "Couldn't get vBucket config");
        return NULL;
    }

    vbmax = vbucket_config_get_num_vbuckets(cfg);
    for (ii = 0; ii < vbmax; ++ii) {
        lcb_KEYBUF kb = { 0 };
        const lcb_MUTATION_TOKEN *mt;
        lcb_error_t rc = LCB_SUCCESS;
        PyObject *cur;

        kb.type = LCB_KV_VBID;
        kb.contig.nbytes = (size_t)ii;

        mt = lcb_get_mutation_token(self->instance, &kb, &rc);
        if (mt == NULL) {
            continue;
        }
        cur = Py_BuildValue("HKK", LCB_MUTATION_TOKEN_VB(mt),
            LCB_MUTATION_TOKEN_ID(mt), LCB_MUTATION_TOKEN_SEQ(mt));
        PyList_Append(ll, cur);
        Py_DECREF(cur);
    }

    return ll;
}
PyObject *
pycbc_Bucket__view_request(pycbc_Bucket *self, PyObject *args, PyObject *kwargs)
{
    int rv;
    PyObject *ret = NULL;
    pycbc_MultiResult *mres = NULL;
    pycbc_ViewResult *vres = NULL;
    lcb_CMDVIEWQUERY vcmd = { 0 };
    viewpath_st vp = { NULL };
    lcb_error_t rc;
    const char *view = NULL, *design = NULL;
    PyObject *options = NULL;
    int flags;

    static char *kwlist[] = { "design", "view", "options", "_flags", NULL };

    rv = PyArg_ParseTupleAndKeywords(args, kwargs, "ss|Oi", kwlist,
                                     &design, &view, &options, &flags);
    if (!rv) {
        PYCBC_EXCTHROW_ARGS();
        return NULL;
    }
    if (-1 == pycbc_oputil_conn_lock(self)) {
        return NULL;
    }

    if (self->pipeline_queue) {
        PYCBC_EXC_WRAP(PYCBC_EXC_PIPELINE, 0,
                       "HTTP/View Requests cannot be executed in "
                       "pipeline context");
        goto GT_DONE;
    }

    mres = (pycbc_MultiResult *)pycbc_multiresult_new(self);
    vres = (pycbc_ViewResult *)PYCBC_TYPE_CTOR(&pycbc_ViewResultType);
    vres->base.htype = PYCBC_HTTP_HVIEW;

    pycbc_httpresult_init(&vres->base, mres);

    rv = get_viewpath_str(self, &vp, options);
    if (rv != 0) {
        goto GT_DONE;
    }

    vcmd.ddoc = design;
    vcmd.nddoc = strlen(design);
    vcmd.view = view;
    vcmd.nview = strlen(view);
    vcmd.optstr = vp.optstr;
    vcmd.noptstr = vp.noptstr;
    vcmd.postdata = vp.body;
    vcmd.npostdata = vp.nbody;
    vcmd.handle = &vres->base.u.vh;
    vcmd.callback = row_callback;
    vcmd.cmdflags = flags;

    vres->rows = PyList_New(0);
    vres->base.format = PYCBC_FMT_JSON;

    rc = lcb_view_query(self->instance, mres, &vcmd);

    if (rc != LCB_SUCCESS) {
        PYCBC_EXC_WRAP(PYCBC_EXC_LCBERR, rc, "Couldn't schedule view");
        goto GT_DONE;
    }

    ret = (PyObject*)mres;
    mres = NULL; /* Avoid GT_DONE decref */

    GT_DONE:
    Py_XDECREF(mres);
    Py_XDECREF(vp.bk);
    pycbc_oputil_conn_unlock(self);
    return ret;
}
static PyObject *
keyop_common(pycbc_Bucket *self, PyObject *args, PyObject *kwargs, int optype,
    int argopts)
{
    int rv;
    Py_ssize_t ncmds = 0;
    pycbc_seqtype_t seqtype;
    PyObject *casobj = NULL;
    PyObject *is_quiet = NULL;
    PyObject *kobj = NULL;
    char persist_to = 0, replicate_to = 0;
    struct pycbc_common_vars cv = PYCBC_COMMON_VARS_STATIC_INIT;

    static char *kwlist[] = {
            "keys", "cas", "quiet", "persist_to", "replicate_to", NULL
    };

    rv = PyArg_ParseTupleAndKeywords(args,
                                     kwargs,
                                     "O|OOBB",
                                     kwlist,
                                     &kobj,
                                     &casobj,
                                     &is_quiet,
                                     &persist_to, &replicate_to);

    if (!rv) {
        PYCBC_EXCTHROW_ARGS();
        return NULL;
    }

    if (argopts & PYCBC_ARGOPT_MULTI) {
        rv = pycbc_oputil_check_sequence(kobj, 1, &ncmds, &seqtype);
        if (rv < 0) {
            return NULL;
        }

        if (casobj && PyObject_IsTrue(casobj)) {
            PYCBC_EXC_WRAP(PYCBC_EXC_ARGUMENTS, 0, "Can't pass CAS for multiple keys");
        }

    } else {
        ncmds = 1;
    }

    rv = pycbc_common_vars_init(&cv, self, argopts, ncmds, 0);
    if (rv < 0) {
        return NULL;
    }

    if (argopts & PYCBC_ARGOPT_MULTI) {
        rv = pycbc_oputil_iter_multi(self, seqtype, kobj, &cv, optype,
                                     handle_single_keyop, NULL);
    } else {
        rv = handle_single_keyop(self, &cv, optype, kobj, casobj, NULL, NULL, NULL);
    }

    if (rv < 0) {
        goto GT_DONE;
    }

    if (optype == PYCBC_CMD_DELETE) {
        rv = pycbc_handle_durability_args(self, &cv.mres->dur,
                                          persist_to, replicate_to);
        if (rv == 1) {
            cv.mres->mropts |= PYCBC_MRES_F_DURABILITY;

        } else if (rv == -1) {
            goto GT_DONE;
        }
        if (pycbc_maybe_set_quiet(cv.mres, is_quiet) == -1) {
            goto GT_DONE;
        }
    }

    if (-1 == pycbc_common_vars_wait(&cv, self)) {
        goto GT_DONE;
    }

    GT_DONE:
    pycbc_common_vars_finalize(&cv, self);
    return cv.ret;
}
static int
Connection__init__(pycbc_Connection *self,
                       PyObject *args, PyObject *kwargs)
{
    int rv;
    int conntype = LCB_TYPE_BUCKET;
    lcb_error_t err;
    char *conncache = NULL;
    PyObject *unlock_gil_O = NULL;
    PyObject *iops_O = NULL;
    PyObject *timeout = NULL;
    PyObject *dfl_fmt = NULL;
    PyObject *tc = NULL;

    struct lcb_create_st create_opts = { 0 };
    struct lcb_cached_config_st cached_config = { { 0 } };


    /**
     * This xmacro enumerates the constructor keywords, targets, and types.
     * This was converted into an xmacro to ease the process of adding or
     * removing various parameters.
     */
#define XCTOR_ARGS(X) \
    X("_errors", &self->errors, "O") \
    X("_flags", &self->flags, "I") \
    X("bucket", &create_opts.v.v1.bucket, "z") \
    X("username", &create_opts.v.v1.user, "z") \
    X("password", &create_opts.v.v1.passwd, "z") \
    X("host", &create_opts.v.v1.host, "z") \
    X("conncache", &conncache, "z") \
    X("quiet", &self->quiet, "I") \
    X("unlock_gil", &unlock_gil_O, "O") \
    X("transcoder", &tc, "O") \
    X("timeout", &timeout, "O") \
    X("default_format", &dfl_fmt, "O") \
    X("lockmode", &self->lockmode, "i") \
    X("_conntype", &conntype, "i") \
    X("_iops", &iops_O, "O")

    static char *kwlist[] = {
        #define X(s, target, type) s,
            XCTOR_ARGS(X)
        #undef X

            NULL
    };

    #define X(s, target, type) type
    static char *argspec = "|" XCTOR_ARGS(X);
    #undef X

    if (self->init_called) {
        PyErr_SetString(PyExc_RuntimeError, "__init__ was already called");
        return -1;
    }

    self->init_called = 1;
    self->flags = 0;
    self->unlock_gil = 1;
    self->lockmode = PYCBC_LOCKMODE_EXC;

    #define X(s, target, type) target,
    rv = PyArg_ParseTupleAndKeywords(args,
                                     kwargs,
                                     argspec,
                                     kwlist,
                                     XCTOR_ARGS(X) NULL);
    #undef X

    if (!rv) {
        PYCBC_EXCTHROW_ARGS();
        return -1;
    }

    if (unlock_gil_O && PyObject_IsTrue(unlock_gil_O) == 0) {
        self->unlock_gil = 0;
    }

    if (create_opts.v.v1.bucket) {
        self->bucket = pycbc_SimpleStringZ(create_opts.v.v1.bucket);
    }

    create_opts.version = 1;
    create_opts.v.v1.type = conntype;

    if (iops_O && iops_O != Py_None) {
        self->iops = pycbc_iops_new(self, iops_O);
        create_opts.v.v1.io = self->iops;
        self->unlock_gil = 0;
    }

    Py_INCREF(self->errors);


    if (dfl_fmt == Py_None || dfl_fmt == NULL) {
        /** Set to 0 if None or NULL */
        dfl_fmt = pycbc_IntFromL(0);

    } else {
        Py_INCREF(dfl_fmt); /* later decref */
    }

    rv = Connection_set_format(self, dfl_fmt, NULL);
    Py_XDECREF(dfl_fmt);
    if (rv == -1) {
        return rv;
    }

    /** Set the transcoder */
    if (tc && Connection_set_transcoder(self, tc, NULL) == -1) {
        return -1;
    }

#ifdef WITH_THREAD
    if (!self->unlock_gil) {
        self->lockmode = PYCBC_LOCKMODE_NONE;
    }

    if (self->lockmode != PYCBC_LOCKMODE_NONE) {
        self->lock = PyThread_allocate_lock();
    }
#endif

    if (conncache) {
        if (conntype != LCB_TYPE_BUCKET) {
            PYCBC_EXC_WRAP(PYCBC_EXC_ARGUMENTS, 0,
                           "Cannot use connection cache with "
                           "management connection");
            return -1;
        }
        cached_config.cachefile = conncache;
        memcpy(&cached_config.createopt, &create_opts, sizeof(create_opts));
        err = lcb_create_compat(LCB_CACHED_CONFIG,
                                &cached_config,
                                &self->instance,
                                NULL);
    } else {
        err = lcb_create(&self->instance, &create_opts);
    }

    if (err != LCB_SUCCESS) {
        self->instance = NULL;
        PYCBC_EXC_WRAP(PYCBC_EXC_LCBERR, err,
                       "Couldn't create instance. Either bad "
                       "credentials/hosts/bucket names were "
                       "passed, or there was an internal error in creating the "
                       "object");
        return -1;
    }

    pycbc_callbacks_init(self->instance);
    lcb_set_cookie(self->instance, self);

    if (timeout && timeout != Py_None) {
        if (Connection_set_timeout(self, timeout, NULL) == -1) {
            return -1;
        }
    }

    PYCBC_CONN_THR_BEGIN(self);
    err = lcb_connect(self->instance);
    PYCBC_CONN_THR_END(self);

    if (err != LCB_SUCCESS) {
        PYCBC_EXC_WRAP(PYCBC_EXC_LCBERR, err,
                       "Couldn't schedule connection. This might be a result of "
                       "an invalid hostname.");
        return -1;
    }


    err = pycbc_oputil_wait_common(self);

    if (err != LCB_SUCCESS) {
        PYCBC_EXCTHROW_WAIT(err);
        return -1;
    }

    return 0;
}
PyObject *
pycbc_Bucket__stats(pycbc_Bucket *self, PyObject *args, PyObject *kwargs)
{
    int rv;
    int ii;
    Py_ssize_t ncmds;
    lcb_error_t err = LCB_ERROR;
    PyObject *keys = NULL, *is_keystats = NULL;
    struct pycbc_common_vars cv = PYCBC_COMMON_VARS_STATIC_INIT;
    static char *kwlist[] = {  "keys", "keystats", NULL };
    lcb_CMDSTATS cmd = { 0 };

    rv = PyArg_ParseTupleAndKeywords(args, kwargs, "|OO", kwlist,
        &keys, &is_keystats);

    if (!rv) {
        PYCBC_EXCTHROW_ARGS();
        return NULL;
    }

    if (keys == NULL || PyObject_IsTrue(keys) == 0) {
        keys = NULL;
        ncmds = 1;

    } else {
        if (!PySequence_Check(keys)) {
            PYCBC_EXC_WRAP(PYCBC_EXC_ARGUMENTS, 0, "keys argument must be sequence");
            return NULL;
        }
        ncmds = PySequence_Size(keys);
    }

    rv = pycbc_common_vars_init(&cv, self, PYCBC_ARGOPT_MULTI, ncmds, 0);
    if (rv < 0) {
        return NULL;
    }

    if (keys) {
        for (ii =0; ii < ncmds; ii++) {
            char *key;
            Py_ssize_t nkey;
            PyObject *newkey = NULL;

            PyObject *curkey = PySequence_GetItem(keys, ii);
            rv = pycbc_BufFromString(curkey, &key, &nkey, &newkey);
            if (rv < 0) {
                PYCBC_EXC_WRAP_KEY(PYCBC_EXC_ARGUMENTS, 0, "bad key type in stats", curkey);
                goto GT_DONE;
            }

            LCB_CMD_SET_KEY(&cmd, key, nkey);
            if (is_keystats && PyObject_IsTrue(is_keystats)) {
                cmd.cmdflags |= LCB_CMDSTATS_F_KV;
            }
            err = lcb_stats3(self->instance, cv.mres, &cmd);
            Py_XDECREF(newkey);
        }

    } else {
        err = lcb_stats3(self->instance, cv.mres, &cmd);
    }

    if (err != LCB_SUCCESS) {
        PYCBC_EXCTHROW_SCHED(err);
        goto GT_DONE;
    }

    if (-1 == pycbc_common_vars_wait(&cv, self)) {
        goto GT_DONE;
    }

    GT_DONE:
    pycbc_common_vars_finalize(&cv, self);
    return cv.ret;
}
static int
handle_item_kv(pycbc_Item *itm, PyObject *options, const struct storecmd_vars *scv,
    struct single_key_context *skc)
{
    int rv;
    PyObject *ttl_O = NULL, *flagsobj_Oalt = NULL, *igncas_O = NULL;
    PyObject *frag_O = NULL;
    static char *itm_optlist[] = {
            "ttl", "format", "ignore_cas", "fragment", NULL };

    lcb_cas_t itmcas = itm->cas;
    skc->value = itm->value;

    if (options) {
        rv = PyArg_ParseTupleAndKeywords(pycbc_DummyTuple, options, "|OOOO",
            itm_optlist, &ttl_O, &flagsobj_Oalt, &igncas_O, &frag_O);
        if (!rv) {
            PYCBC_EXC_WRAP(PYCBC_EXC_ARGUMENTS, 0,
                           "Couldn't parse item options");
            return -1;
        }

        if (ttl_O) {
            if (-1 == pycbc_get_ttl(ttl_O, &skc->ttl, 1)) {
                return -1;
            }

            if (!skc->ttl) {
                skc->ttl = scv->ttl;
            }
        }

        if (flagsobj_Oalt && flagsobj_Oalt != Py_None) {
            skc->flagsobj = flagsobj_Oalt;
        }

        if (igncas_O && PyObject_IsTrue(igncas_O)) {
            itmcas = 0;
        }

        if (frag_O == NULL) {
            if (scv->operation == LCB_APPEND || scv->operation == LCB_PREPEND) {
                PYCBC_EXC_WRAP(PYCBC_EXC_ARGUMENTS, 0, "append/prepend must provide options with 'fragment' specifier");
                return -1;
            }

        } else {
            if (scv->operation != LCB_APPEND && scv->operation != LCB_PREPEND) {
                PYCBC_EXC_WRAP(PYCBC_EXC_ARGUMENTS, 0, "'fragment' only valid for append/prepend");
                return -1;
            }

            skc->value = frag_O;
        }

    } else {
        if (scv->operation == LCB_APPEND || scv->operation == LCB_PREPEND) {
            PYCBC_EXC_WRAP(PYCBC_EXC_ARGUMENTS, 0, "append/prepend must provide options with 'fragment' specifier");
            return -1;
        }
    }

    if (!skc->value) {
        PYCBC_EXC_WRAP_OBJ(PYCBC_EXC_ARGUMENTS, 0, "Value is empty", skc->value);
        return -1;
    }

    skc->cas = itmcas;
    return 0;
}
static PyObject *
set_common(pycbc_Bucket *self, PyObject *args, PyObject *kwargs,
    const lcb_storage_t operation, int argopts)
{
    int rv;
    Py_ssize_t ncmds = 0;
    PyObject *ttl_O = NULL;
    PyObject *dict = NULL;
    PyObject *key;
    PyObject *value;
    pycbc_seqtype_t seqtype;
    struct pycbc_common_vars cv = PYCBC_COMMON_VARS_STATIC_INIT;
    struct storecmd_vars scv = { 0 };
    char persist_to = 0, replicate_to = 0;


    static char *kwlist_multi[] = {
            "kv", "ttl", "format",
            "persist_to", "replicate_to",
            NULL
    };

    static char *kwlist_single[] = {
            "key", "value", "cas", "ttl", "format",
            "persist_to", "replicate_to",
            NULL
    };

    scv.operation = operation;

    if (argopts & PYCBC_ARGOPT_MULTI) {
        rv = PyArg_ParseTupleAndKeywords(args, kwargs, "O|OOBB", kwlist_multi,
                                         &dict,
                                         &ttl_O, &scv.flagsobj,
                                         &persist_to, &replicate_to);

    } else {
        rv = PyArg_ParseTupleAndKeywords(args, kwargs, "OO|KOOBB", kwlist_single,
                                         &key, &value,
                                         &scv.single_cas, &ttl_O, &scv.flagsobj,
                                         &persist_to, &replicate_to);
    }

    if (!rv) {
        PYCBC_EXC_WRAP(PYCBC_EXC_ARGUMENTS, 0, "couldn't parse arguments");
        return NULL;
    }

    rv = pycbc_get_ttl(ttl_O, &scv.ttl, 1);
    if (rv < 0) {
        return NULL;
    }

    if (argopts & PYCBC_ARGOPT_MULTI) {
        rv = pycbc_oputil_check_sequence(dict, 0, &ncmds, &seqtype);
        if (rv < 0) {
            return NULL;
        }

    } else {
        ncmds = 1;
    }

    if (operation == LCB_APPEND || operation == LCB_PREPEND) {
        rv = handle_append_flags(self, &scv.flagsobj);
        if (rv < 0) {
            return NULL;
        }

    } else if (scv.flagsobj == NULL || scv.flagsobj == Py_None) {
        scv.flagsobj = self->dfl_fmt;
    }

    rv = pycbc_common_vars_init(&cv, self, argopts, ncmds, 1);
    if (rv < 0) {
        return NULL;
    }

    rv = pycbc_handle_durability_args(self, &cv.mres->dur,
                                      persist_to, replicate_to);

    if (rv == 1) {
        cv.mres->mropts |= PYCBC_MRES_F_DURABILITY;

    } else if (rv == -1) {
        goto GT_DONE;
    }

    if (argopts & PYCBC_ARGOPT_MULTI) {
        rv = pycbc_oputil_iter_multi(self, seqtype, dict, &cv, 0, handle_single_kv, &scv);

    } else {
        rv = handle_single_kv(self, &cv, 0, key, value, NULL, NULL, &scv);
    }

    if (rv < 0) {
        goto GT_DONE;
    }

    if (-1 == pycbc_common_vars_wait(&cv, self)) {
        goto GT_DONE;
    }

GT_DONE:
    pycbc_common_vars_finalize(&cv, self);
    return cv.ret;
}
Exemple #29
0
PyObject *
pycbc_Bucket__n1ql_query(pycbc_Bucket *self, PyObject *args, PyObject *kwargs)
{
    int rv;
    PyObject *ret = NULL;
    pycbc_MultiResult *mres;
    pycbc_ViewResult *vres;
    lcb_error_t rc;
    lcb_CMDN1QL cmd = { 0 };
    const char *params;
    pycbc_strlen_t nparams;
    int prepared = 0, cross_bucket = 0;

    static char *kwlist[] = { "params", "prepare", "cross_bucket", NULL };
    rv = PyArg_ParseTupleAndKeywords(
        args, kwargs, "s#|ii", kwlist, &params, &nparams, &prepared, &cross_bucket);

    if (!rv) {
        PYCBC_EXCTHROW_ARGS();
        return NULL;
    }
    if (-1 == pycbc_oputil_conn_lock(self)) {
        return NULL;
    }
    if (self->pipeline_queue) {
        PYCBC_EXC_WRAP(PYCBC_EXC_PIPELINE, 0,
                       "N1QL queries cannot be executed in "
                       "pipeline context");
    }

    mres = (pycbc_MultiResult *)pycbc_multiresult_new(self);
    vres = (pycbc_ViewResult *)PYCBC_TYPE_CTOR(&pycbc_ViewResultType);
    pycbc_httpresult_init(&vres->base, mres);
    vres->rows = PyList_New(0);
    vres->base.format = PYCBC_FMT_JSON;
    vres->base.htype = PYCBC_HTTP_HN1QL;

    cmd.content_type = "application/json";
    cmd.callback = n1ql_row_callback;
    cmd.query = params;
    cmd.nquery = nparams;
    cmd.handle = &vres->base.u.nq;
    if (prepared) {
        cmd.cmdflags |= LCB_CMDN1QL_F_PREPCACHE;
    }
    if (cross_bucket) {
        cmd.cmdflags |= LCB_CMD_F_MULTIAUTH;
    }
    rc = lcb_n1ql_query(self->instance, mres, &cmd);

    if (rc != LCB_SUCCESS) {
        PYCBC_EXC_WRAP(PYCBC_EXC_LCBERR, rc, "Couldn't schedule n1ql query");
        goto GT_DONE;
    }

    ret = (PyObject *)mres;
    mres = NULL;

    GT_DONE:
    Py_XDECREF(mres);
    pycbc_oputil_conn_unlock(self);
    return ret;
}
/**
 * This is called during each iteration of delete/unlock
 */
static int
handle_single_keyop(pycbc_Bucket *self, struct pycbc_common_vars *cv, int optype,
    PyObject *curkey, PyObject *curval, PyObject *options, pycbc_Item *item,
    void *arg)
{
    int rv;
    char *key;
    size_t nkey;
    lcb_U64 cas = 0;
    lcb_error_t err;

    union {
        lcb_CMDBASE base;
        lcb_CMDREMOVE rm;
        lcb_CMDUNLOCK unl;
        lcb_CMDENDURE endure;
    } ucmd;

    (void)options; (void)arg;

    memset(&ucmd, 0, sizeof ucmd);

    if ( (optype == PYCBC_CMD_UNLOCK || optype == PYCBC_CMD_ENDURE)
            && PYCBC_OPRES_CHECK(curkey)) {
        curval = curkey;
        curkey = ((pycbc_OperationResult*)curkey)->key;
    }

    rv = pycbc_tc_encode_key(self, &curkey, (void**)&key, &nkey);
    if (rv == -1) {
        return -1;
    }

    if (!nkey) {
        PYCBC_EXCTHROW_EMPTYKEY();
        rv = -1;
        goto GT_DONE;
    }

    if (item) {
        cas = item->cas;

    } else if (curval) {
        if (PyDict_Check(curval)) {
            PyObject *cas_o = PyDict_GetItemString(curval, "cas");
            if (!cas_o) {
                PyErr_Clear();
            }
            cas = pycbc_IntAsULL(cas_o);

        } else if (PYCBC_OPRES_CHECK(curval)) {
            /* If we're passed a Result object, just extract its CAS */
            cas = ((pycbc_OperationResult*)curval)->cas;

        } else if (PyNumber_Check(curval)) {
            cas = pycbc_IntAsULL(curval);

        }

        if (cas == (lcb_uint64_t)-1 && PyErr_Occurred()) {
            PyErr_Clear();
            PYCBC_EXC_WRAP(PYCBC_EXC_ARGUMENTS, 0, "Invalid CAS specified");
            return -1;
        }
    }

    LCB_CMD_SET_KEY(&ucmd.base, key, nkey);
    ucmd.base.cas = cas;

    if (optype == PYCBC_CMD_UNLOCK) {
        if (!cas) {
            PYCBC_EXC_WRAP(PYCBC_EXC_ARGUMENTS, 0, "CAS must be specified for unlock");
            return -1;
        }
        err = lcb_unlock3(self->instance, cv->mres, &ucmd.unl);

    } else if (optype == PYCBC_CMD_ENDURE) {
        err = cv->mctx->addcmd(cv->mctx, &ucmd.base);

    } else {
        err = lcb_remove3(self->instance, cv->mres, &ucmd.rm);
    }
    if (err == LCB_SUCCESS) {
        rv = 0;
    } else {
        rv = -1;
        PYCBC_EXCTHROW_SCHED(err);
    }

    GT_DONE:
    Py_XDECREF(curkey);
    return rv;
}