VALUE cb_bucket_observe(int argc, VALUE *argv, VALUE self) { struct cb_bucket_st *bucket = DATA_PTR(self); struct cb_context_st *ctx; VALUE rv, proc, exc; lcb_error_t err; struct cb_params_st params; if (!cb_bucket_connected_bang(bucket, cb_sym_observe)) { return Qnil; } memset(¶ms, 0, sizeof(struct cb_params_st)); rb_scan_args(argc, argv, "0*&", ¶ms.args, &proc); if (!bucket->async && proc != Qnil) { rb_raise(rb_eArgError, "synchronous mode doesn't support callbacks"); } params.type = cb_cmd_observe; params.bucket = bucket; cb_params_build(¶ms); ctx = cb_context_alloc_common(bucket, proc, params.cmd.observe.num); err = lcb_observe(bucket->handle, (const void *)ctx, params.cmd.observe.num, params.cmd.observe.ptr); cb_params_destroy(¶ms); exc = cb_check_error(err, "failed to schedule observe request", Qnil); if (exc != Qnil) { cb_context_free(ctx); rb_exc_raise(exc); } bucket->nbytes += params.npayload; if (bucket->async) { cb_maybe_do_loop(bucket); return Qnil; } else { if (ctx->nqueries > 0) { /* we have some operations pending */ lcb_wait(bucket->handle); } exc = ctx->exception; rv = ctx->rv; cb_context_free(ctx); if (exc != Qnil) { rb_exc_raise(exc); } exc = bucket->exception; if (exc != Qnil) { bucket->exception = Qnil; rb_exc_raise(exc); } if (params.cmd.observe.num > 1 || params.cmd.observe.array) { return rv; /* return as a hash {key => {}, ...} */ } else { VALUE vv = Qnil; rb_hash_foreach(rv, cb_first_value_i, (VALUE)&vv); return vv; /* return first value */ } } }
static PyObject * observe_common(pycbc_Connection *self, PyObject *args, PyObject *kwargs, int argopts) { int rv; int ii; Py_ssize_t ncmds; PyObject *kobj = NULL; pycbc_seqtype_t seqtype; lcb_error_t err; int master_only = 0; PyObject *master_only_O = NULL; struct pycbc_common_vars cv = PYCBC_COMMON_VARS_STATIC_INIT; static char *kwlist[] = { "keys", "master_only", NULL }; rv = PyArg_ParseTupleAndKeywords(args, kwargs, "O|O", kwlist, &kobj, &master_only_O); 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; } } else { ncmds = 1; } master_only = master_only_O && PyObject_IsTrue(master_only_O); rv = pycbc_common_vars_init(&cv, self, argopts, ncmds, sizeof(lcb_observe_cmd_t), 0); if (rv < 0) { return NULL; } if (argopts & PYCBC_ARGOPT_MULTI) { Py_ssize_t dictpos; PyObject *curseq, *iter = NULL; curseq = pycbc_oputil_iter_prepare(seqtype, kobj, &iter, &dictpos); if (!curseq) { goto GT_DONE; } for (ii = 0; ii < ncmds; ii++) { PyObject *curkey = NULL, *curvalue = NULL; rv = pycbc_oputil_sequence_next(seqtype, curseq, &dictpos, ii, &curkey, &curvalue); if (rv < 0) { goto GT_ITER_DONE; } rv = handle_single_observe(self, curkey, ii, master_only, &cv); GT_ITER_DONE: Py_XDECREF(curkey); Py_XDECREF(curvalue); if (rv < 0) { goto GT_DONE; } } } else { rv = handle_single_observe(self, kobj, 0, master_only, &cv); if (rv < 0) { goto GT_DONE; } } err = lcb_observe(self->instance, cv.mres, ncmds, cv.cmdlist.obs); if (err != LCB_SUCCESS) { PYCBC_EXCTHROW_SCHED(err); goto GT_DONE; } cv.is_seqcmd = 1; if (-1 == pycbc_common_vars_wait(&cv, self)) { goto GT_DONE; } GT_DONE: pycbc_common_vars_finalize(&cv, self); return cv.ret; }
PHP_COUCHBASE_LOCAL lcb_error_t simple_observe(lcb_t instance, struct observe_entry *entries, int nentries, long persist_to, long replicate_to) { lcb_error_t err = LCB_SUCCESS; lcb_observe_cmd_t *cmds = ecalloc(nentries, sizeof(lcb_observe_cmd_t)); lcb_observe_cmd_t **commands = ecalloc(nentries, sizeof(lcb_observe_cmd_t *)); int ii; lcb_observe_callback org = lcb_set_observe_callback(instance, simple_observe_callback); struct observe_cookie cookie; int xx; int done = 0; int numtries = 0; int interval = INI_INT(PCBC_INIENT_OBS_INTERVAL); int maxretry = INI_INT(PCBC_INIENT_OBS_TIMEOUT) / interval; cookie.entries = entries; cookie.num = nentries; cookie.error = LCB_SUCCESS; lcb_behavior_set_syncmode(instance, LCB_SYNCHRONOUS); do { /* set up the commands */ for (xx = 0, ii = 0; ii < nentries; ++ii) { cmds[ii].v.v0.key = entries[ii].key; cmds[ii].v.v0.nkey = entries[ii].nkey; if (should_add(&entries[ii], persist_to, replicate_to)) { commands[xx++] = cmds + ii; } } if (xx > 0) { if (numtries > 0) { usleep(interval); } ++numtries; err = lcb_observe(instance, &cookie, xx, (const lcb_observe_cmd_t * const *)commands); } else { done = 1; } } while (!done && numtries < maxretry); efree(cmds); efree(commands); lcb_behavior_set_syncmode(instance, LCB_ASYNCHRONOUS); lcb_set_observe_callback(instance, org); if (!done) { return LCB_ETIMEDOUT; } return (err == LCB_SUCCESS) ? cookie.error : err; }
static int observe_iterate(php_couchbase_res *res, struct observe_collection *ocoll) { int ii, scheduled = 0; obs_debug("Have %d total requests\n", ocoll->nks); for (ii = 0; ii < ocoll->nks; ii++) { lcb_error_t err; struct observe_keystate *oks = ocoll->ks + ii; const lcb_observe_cmd_t *cmdp; if (oks->done) { continue; } /* reset the per-wait counters */ if (oks->got.errstr) { efree(oks->got.errstr); oks->got.errstr = NULL; } memset(&oks->got, 0, sizeof(oks->got)); cmdp = &oks->ocmd; err = lcb_observe(res->handle, oks, 1, &cmdp); if (err != LCB_SUCCESS) { oks_set_error(oks, lcb_strerror(res->handle, err), 1); oks_set_done(oks); } scheduled++; } if (!scheduled) { obs_debug("No commands scheduled..\n"); return 0; } obs_debug("Waiting for %d commands\n", scheduled); pcbc_start_loop(res); /** * Iterate again over the responses. */ for (ii = 0; ii < ocoll->nks; ii++) { struct observe_keystate *oks = ocoll->ks + ii; if (oks->done) { continue; } /** * We get responses from the nodes each time. If we don't have enough * total responses (NOT_FOUND or otherwise) it means there aren't * that many nodes online. */ if (oks->expected.persist > oks->got.resp || oks->expected.replicate > oks->got.resp) { oks_set_error(oks, "Not enough nodes for durability criteria", 1); oks_set_done(oks); } } return ocoll->remaining; }
VALUE cb_bucket_observe(int argc, VALUE *argv, VALUE self) { struct bucket_st *bucket = DATA_PTR(self); struct context_st *ctx; VALUE args, rv, proc, exc; lcb_error_t err; struct params_st params; if (bucket->handle == NULL) { rb_raise(eConnectError, "closed connection"); } rb_scan_args(argc, argv, "0*&", &args, &proc); if (!bucket->async && proc != Qnil) { rb_raise(rb_eArgError, "synchronous mode doesn't support callbacks"); } memset(¶ms, 0, sizeof(struct params_st)); params.type = cmd_observe; params.bucket = bucket; cb_params_build(¶ms, RARRAY_LEN(args), args); ctx = xcalloc(1, sizeof(struct context_st)); if (ctx == NULL) { rb_raise(eClientNoMemoryError, "failed to allocate memory for context"); } ctx->proc = cb_gc_protect(bucket, proc); ctx->bucket = bucket; rv = rb_hash_new(); ctx->rv = &rv; ctx->exception = Qnil; ctx->nqueries = params.cmd.observe.num; err = lcb_observe(bucket->handle, (const void *)ctx, params.cmd.observe.num, params.cmd.observe.ptr); cb_params_destroy(¶ms); exc = cb_check_error(err, "failed to schedule observe request", Qnil); if (exc != Qnil) { xfree(ctx); rb_exc_raise(exc); } bucket->nbytes += params.npayload; if (bucket->async) { maybe_do_loop(bucket); return Qnil; } else { if (ctx->nqueries > 0) { /* we have some operations pending */ lcb_wait(bucket->handle); } exc = ctx->exception; xfree(ctx); if (exc != Qnil) { cb_gc_unprotect(bucket, exc); rb_exc_raise(exc); } if (bucket->exception != Qnil) { rb_exc_raise(bucket->exception); } if (params.cmd.observe.num > 1 || params.cmd.observe.array) { return rv; /* return as a hash {key => {}, ...} */ } else { VALUE vv = Qnil; rb_hash_foreach(rv, cb_first_value_i, (VALUE)&vv); return vv; /* return first value */ } } }