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; }
static PyObject * make_error_tuple(void) { PyObject *type, *value, *traceback; PyObject *ret; pycbc_assert(PyErr_Occurred()); PyErr_Fetch(&type, &value, &traceback); PyErr_Clear(); if (value == NULL) { value = Py_None; Py_INCREF(value); } if (traceback == NULL) { traceback = Py_None; Py_INCREF(traceback); } ret = PyTuple_New(3); /** Steal references from PyErr_Fetch() */ PyTuple_SET_ITEM(ret, 0, type); PyTuple_SET_ITEM(ret, 1, value); PyTuple_SET_ITEM(ret, 2, traceback); return ret; }
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; }
void pycbc_schedule_dtor_event(pycbc_Bucket *self) { struct dtor_info_st *dti; if ((self->flags & PYCBC_CONN_F_ASYNC_DTOR) == 0) { return; } pycbc_assert(self->instance); dti = malloc(sizeof(*dti)); if (!dti) { fprintf(stderr, "[PYCBC] Couldn't allocate memory for libcouchbase async " "destruction. Instance will leak\n"); } else { dti->iowrap = self->iopswrap; dti->dtorcb = self->dtorcb; dti->conncb = self->conncb; } lcb_set_destroy_callback(self->instance, dtor_callback); lcb_destroy_async(self->instance, dti); self->instance = NULL; self->iopswrap = NULL; self->dtorcb = NULL; self->conncb = NULL; }
void pycbc_viewresult_step(pycbc_ViewResult *vres, pycbc_MultiResult *mres, pycbc_Bucket *bucket, int force_callback) { if ((bucket->flags & PYCBC_CONN_F_ASYNC) && should_call_async(vres, force_callback)) { pycbc_AsyncResult *ares = (pycbc_AsyncResult*)mres; PyObject *args = PyTuple_Pack(1, mres); PyObject *result; pycbc_assert(ares->callback); result = PyObject_CallObject(ares->callback, args); Py_XDECREF(result); if (!result) { PyErr_Print(); } Py_DECREF(args); Py_DECREF(vres->rows); vres->rows = PyList_New(0); } if (!bucket->nremaining) { lcb_breakout(bucket->instance); } }
static void maybe_breakout(pycbc_Connection *self) { pycbc_assert(self->nremaining); if (!--self->nremaining) { lcb_breakout(self->instance); } }
static void error_callback(lcb_t instance, lcb_error_t err, const char *msg) { PyObject *errtuple; PyObject *result; pycbc_Connection *self = (pycbc_Connection*) lcb_get_cookie(instance); CB_THR_END(self); pycbc_assert(self->errors); errtuple = Py_BuildValue("(i,s)", err, msg); pycbc_assert(errtuple); result = PyObject_CallMethod(self->errors, "append", "(O)", errtuple); pycbc_assert(result); Py_DECREF(errtuple); Py_DECREF(result); CB_THR_BEGIN(self); }
/** * 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 void invoke_endure_test_notification(pycbc_Bucket *self, pycbc_Result *resp) { PyObject *ret; PyObject *argtuple = Py_BuildValue("(O)", resp); ret = PyObject_CallObject(self->dur_testhook, argtuple); pycbc_assert(ret); Py_XDECREF(ret); Py_XDECREF(argtuple); }
static void cb_thr_begin(pycbc_Bucket *self) { if (Py_REFCNT(self) > 1) { Py_DECREF(self); PYCBC_CONN_THR_BEGIN(self); return; } pycbc_assert(self->unlock_gil == 0); Py_DECREF(self); }
int pycbc_tc_encode_key(pycbc_Bucket *conn, PyObject **key, void **buf, size_t *nbuf) { int rv; Py_ssize_t plen; PyObject *orig_key; PyObject *new_key = NULL; if (!conn->tc) { return encode_common(key, buf, nbuf, PYCBC_FMT_UTF8); } orig_key = *key; pycbc_assert(orig_key); rv = do_call_tc(conn, orig_key, NULL, &new_key, ENCODE_KEY); if (new_key == NULL || rv < 0) { return -1; } rv = PyBytes_AsStringAndSize(new_key, (char**)buf, &plen); if (rv == -1) { PYCBC_EXC_WRAP_KEY(PYCBC_EXC_ENCODING, 0, "Couldn't convert encoded key to bytes. It is " "possible that the Transcoder.encode_key method " "returned an unexpected value", new_key); Py_XDECREF(new_key); return -1; } if (plen == 0) { PYCBC_EXC_WRAP_KEY(PYCBC_EXC_ENCODING, 0, "Transcoder.encode_key returned an empty string", new_key); Py_XDECREF(new_key); return -1; } *nbuf = plen; *key = new_key; return 0; }
static void destroy_event_common(lcb_io_opt_t io, void *arg) { pycbc_Event *ev = arg; lcb_U32 dummy = 0; pycbc_assert(ev->state != PYCBC_EVSTATE_ACTIVE); modify_event_python(PYCBC_IOW_FROM_IOPS(io), ev, PYCBC_EVACTION_CLEANUP, 0, &dummy); ev->state = PYCBC_EVSTATE_FREED; Py_DECREF(ev); }
static void add_data(pycbc_HttpResult *htres, const void *data, size_t ndata) { PyObject *o; if (!ndata) { return; } if (htres->format == PYCBC_FMT_JSON) { o = PyUnicode_FromStringAndSize(data, ndata); } else { o = PyBytes_FromStringAndSize(data, ndata); } pycbc_assert(htres->http_data); pycbc_assert(o); PyList_Append(htres->http_data, o); Py_XDECREF(o); }
/** * This is only called if 'o' is not bytes */ static PyObject* convert_to_bytesobj(PyObject *o) { PyObject *bytesobj = NULL; pycbc_assert(!PyBytes_Check(o)); if (PyUnicode_Check(o)) { bytesobj = PyUnicode_AsUTF8String(o); } if (!bytesobj) { PYCBC_EXC_WRAP_OBJ(PYCBC_EXC_ENCODING, 0, "Couldn't convert object to bytes", o); } return bytesobj; }
/** * 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->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; }
/** * This callback does things a bit differently. * Instead of using a MultiResult, we use a single HttpResult object. * We won't ever have "multiple" http objects. */ static void http_complete_callback(lcb_http_request_t req, lcb_t instance, const void *cookie, lcb_error_t err, const lcb_http_resp_t *resp) { pycbc_HttpResult *htres = (pycbc_HttpResult*)cookie; htres->htreq = NULL; if (!htres->parent) { return; } htres->rc = err; htres->htcode = resp->v.v0.status; if (htres->htflags & PYCBC_HTRES_F_CHUNKED) { /** No data here */ if (!pycbc_assert(resp->v.v0.nbytes == 0)) { fprintf(stderr, "Unexpected payload in HTTP response callback\n"); } if (!htres->parent->nremaining) { lcb_breakout(instance); } return; } PYCBC_CONN_THR_END(htres->parent); if (!--htres->parent->nremaining) { lcb_breakout(instance); } get_data(htres, resp->v.v0.bytes, resp->v.v0.nbytes); get_headers(htres, resp); PYCBC_CONN_THR_BEGIN(htres->parent); (void)instance; (void)req; }
static void finalize_data(pycbc_HttpResult *htres) { PyObject *sep; PyObject *res; if (htres->format != PYCBC_FMT_JSON && htres->format != PYCBC_FMT_UTF8) { return; } if (!PyObject_IsTrue(htres->http_data)) { return; } sep = pycbc_SimpleStringZ(""); res = PyUnicode_Join(sep, htres->http_data); Py_DECREF(sep); /* Set the bytes */ Py_DECREF(htres->http_data); htres->http_data = res; if (htres->format == PYCBC_FMT_JSON) { PyObject *args = Py_BuildValue("(O)", htres->http_data); pycbc_assert(PyErr_Occurred() == NULL); res = PyObject_CallObject(pycbc_helpers.json_decode, args); if (res) { Py_XDECREF(htres->http_data); htres->http_data = res; } else { PyErr_Clear(); } Py_XDECREF(args); } }
static void operation_completed(pycbc_Bucket *self, pycbc_MultiResult *mres) { pycbc_assert(self->nremaining); --self->nremaining; if ((self->flags & PYCBC_CONN_F_ASYNC) == 0) { if (!self->nremaining) { lcb_breakout(self->instance); } return; } if (mres) { pycbc_AsyncResult *ares; ares = (pycbc_AsyncResult *)mres; if (--ares->nops) { return; } pycbc_asyncresult_invoke(ares); } }
/** * Call this function for each callback. Note that even if this function * returns nonzero, CB_THR_BEGIN() must still be called, and the `conn` * and `mres` out parameters are considered valid * @param resp base response object * @param[out] conn the bucket object * @param[out] res the result object for the individual operation * @param restype What type should `res` be if it needs to be created * @param[out] mres the context for the current operation * @return 0 if operation processing may proceed, nonzero if operation * processing has completed. In both cases the `conn` and `mres` paramters * are valid, however. */ static int get_common_objects(const lcb_RESPBASE *resp, pycbc_Bucket **conn, pycbc_Result **res, int restype, pycbc_MultiResult **mres) { PyObject *hkey; PyObject *mrdict; int rv; pycbc_assert(pycbc_multiresult_check(resp->cookie)); *mres = (pycbc_MultiResult*)resp->cookie; *conn = (*mres)->parent; CB_THR_END(*conn); rv = pycbc_tc_decode_key(*conn, resp->key, resp->nkey, &hkey); if (rv < 0) { pycbc_multiresult_adderr(*mres); return -1; } mrdict = pycbc_multiresult_dict(*mres); *res = (pycbc_Result*)PyDict_GetItem(mrdict, hkey); if (*res) { int exists_ok = (restype & RESTYPE_EXISTS_OK) || ( (*mres)->mropts & PYCBC_MRES_F_UALLOCED); if (!exists_ok) { if ((*conn)->flags & PYCBC_CONN_F_WARNEXPLICIT) { PyErr_WarnExplicit(PyExc_RuntimeWarning, "Found duplicate key", __FILE__, __LINE__, "couchbase._libcouchbase", NULL); } else { PyErr_WarnEx(PyExc_RuntimeWarning, "Found duplicate key", 1); } /** * We need to destroy the existing object and re-create it. */ PyDict_DelItem(mrdict, hkey); *res = NULL; } else { Py_XDECREF(hkey); } } if (*res == NULL) { /* Now, get/set the result object */ if ( (*mres)->mropts & PYCBC_MRES_F_ITEMS) { *res = (pycbc_Result*)pycbc_item_new(*conn); } else if (restype & RESTYPE_BASE) { *res = (pycbc_Result*)pycbc_result_new(*conn); } else if (restype & RESTYPE_OPERATION) { *res = (pycbc_Result*)pycbc_opresult_new(*conn); } else if (restype & RESTYPE_VALUE) { *res = (pycbc_Result*)pycbc_valresult_new(*conn); } else { abort(); } PyDict_SetItem(mrdict, hkey, (PyObject*)*res); (*res)->key = hkey; Py_DECREF(*res); } if (resp->rc) { (*res)->rc = resp->rc; } if (resp->rc != LCB_SUCCESS) { (*mres)->all_ok = 0; } return 0; }
static int encode_common(PyObject **o, void **buf, size_t *nbuf, lcb_uint32_t flags) { PyObject *bytesobj; Py_ssize_t plen; int rv; if (flags == PYCBC_FMT_UTF8) { #if PY_MAJOR_VERSION == 2 if (PyString_Check(*o)) { #else if (0) { #endif bytesobj = *o; Py_INCREF(*o); } else { if (!PyUnicode_Check(*o)) { PYCBC_EXC_WRAP_OBJ(PYCBC_EXC_ENCODING, 0, "Must be unicode or string", *o); return -1; } bytesobj = PyUnicode_AsUTF8String(*o); } } else if (flags == PYCBC_FMT_BYTES) { if (PyBytes_Check(*o) || PyByteArray_Check(*o)) { bytesobj = *o; Py_INCREF(*o); } else { PYCBC_EXC_WRAP_OBJ(PYCBC_EXC_ENCODING, 0, "Must be bytes or bytearray", *o); return -1; } } else { PyObject *args = NULL; PyObject *helper; if (flags == PYCBC_FMT_PICKLE) { helper = pycbc_helpers.pickle_encode; } else if (flags == PYCBC_FMT_JSON) { helper = pycbc_helpers.json_encode; } else { PYCBC_EXC_WRAP(PYCBC_EXC_ARGUMENTS, 0, "Unrecognized format"); return -1; } args = PyTuple_Pack(1, *o); bytesobj = PyObject_CallObject(helper, args); Py_DECREF(args); if (!bytesobj) { PYCBC_EXC_WRAP_OBJ(PYCBC_EXC_ENCODING, 0, "Couldn't encode value", *o); return -1; } if (!PyBytes_Check(bytesobj)) { PyObject *old = bytesobj; bytesobj = convert_to_bytesobj(old); Py_DECREF(old); if (!bytesobj) { return -1; } } } if (PyByteArray_Check(bytesobj)) { *buf = PyByteArray_AS_STRING(bytesobj); plen = PyByteArray_GET_SIZE(bytesobj); rv = 0; } else { rv = PyBytes_AsStringAndSize(bytesobj, (char**)buf, &plen); } if (rv < 0) { Py_DECREF(bytesobj); PYCBC_EXC_WRAP(PYCBC_EXC_ENCODING, 0, "Couldn't encode value"); return -1; } *nbuf = plen; *o = bytesobj; return 0; } static int decode_common(PyObject **vp, const char *buf, size_t nbuf, lcb_uint32_t flags) { PyObject *decoded = NULL; lcb_U32 c_flags, l_flags; c_flags = flags & PYCBC_FMT_COMMON_MASK; l_flags = flags & PYCBC_FMT_LEGACY_MASK; #define FMT_MATCHES(fmtbase) \ (c_flags == PYCBC_FMT_COMMON_##fmtbase || l_flags == PYCBC_FMT_LEGACY_##fmtbase) if (FMT_MATCHES(UTF8)) { decoded = convert_to_string(buf, nbuf, CONVERT_MODE_UTF8_ONLY); if (!decoded) { return -1; } } else if (FMT_MATCHES(BYTES)) { GT_BYTES: decoded = convert_to_string(buf, nbuf, CONVERT_MODE_BYTES_ONLY); pycbc_assert(decoded); } else { PyObject *converter = NULL; PyObject *args = NULL; PyObject *first_arg = NULL; if (FMT_MATCHES(PICKLE)) { converter = pycbc_helpers.pickle_decode; first_arg = convert_to_string(buf, nbuf, CONVERT_MODE_BYTES_ONLY); pycbc_assert(first_arg); } else if (FMT_MATCHES(JSON)) { converter = pycbc_helpers.json_decode; first_arg = convert_to_string(buf, nbuf, CONVERT_MODE_UTF8_ONLY); if (!first_arg) { return -1; } } else { PyErr_Warn(PyExc_UserWarning, "Unrecognized flags. Forcing bytes"); goto GT_BYTES; } pycbc_assert(first_arg); args = PyTuple_Pack(1, first_arg); decoded = PyObject_CallObject(converter, args); Py_DECREF(args); Py_DECREF(first_arg); } if (!decoded) { PyObject *bytes_tmp = PyBytes_FromStringAndSize(buf, nbuf); PYCBC_EXC_WRAP_OBJ(PYCBC_EXC_ENCODING, 0, "Failed to decode bytes", bytes_tmp); Py_XDECREF(bytes_tmp); return -1; } *vp = decoded; return 0; #undef FMT_MATCHES }
static int get_common_objects(PyObject *cookie, const void *key, size_t nkey, lcb_error_t err, pycbc_Connection **conn, pycbc_Result **res, int restype, pycbc_MultiResult **mres) { PyObject *hkey; int rv; pycbc_assert(Py_TYPE(cookie) == &pycbc_MultiResultType); *mres = (pycbc_MultiResult*)cookie; *conn = (*mres)->parent; if (!(restype & RESTYPE_VARCOUNT)) { maybe_breakout(*conn); } CB_THR_END(*conn); rv = pycbc_tc_decode_key(*conn, key, nkey, &hkey); if (rv < 0) { push_fatal_error(*mres); return -1; } *res = (pycbc_Result*)PyDict_GetItem((PyObject*)*mres, hkey); if (*res) { int exists_ok = (restype & RESTYPE_EXISTS_OK) || ( (*mres)->mropts & PYCBC_MRES_F_UALLOCED); if (!exists_ok) { if ((*conn)->flags & PYCBC_CONN_F_WARNEXPLICIT) { PyErr_WarnExplicit(PyExc_RuntimeWarning, "Found duplicate key", __FILE__, __LINE__, "couchbase._libcouchbase", NULL); } else { PyErr_WarnEx(PyExc_RuntimeWarning, "Found duplicate key", 1); } /** * We need to destroy the existing object and re-create it. */ PyDict_DelItem((PyObject*)*mres, hkey); *res = NULL; } else { Py_XDECREF(hkey); } } if (*res == NULL) { /** * Now, get/set the result object */ if ( (*mres)->mropts & PYCBC_MRES_F_ITEMS) { *res = (pycbc_Result*)pycbc_item_new(*conn); } else if (restype & RESTYPE_BASE) { *res = (pycbc_Result*)pycbc_result_new(*conn); } else if (restype & RESTYPE_OPERATION) { *res = (pycbc_Result*)pycbc_opresult_new(*conn); } else if (restype & RESTYPE_VALUE) { *res = (pycbc_Result*)pycbc_valresult_new(*conn); } else { abort(); } PyDict_SetItem((PyObject*)*mres, hkey, (PyObject*)*res); (*res)->key = hkey; Py_DECREF(*res); } if (err) { (*res)->rc = err; } if (err != LCB_SUCCESS) { (*mres)->all_ok = 0; } return 0; }