Ejemplo n.º 1
0
    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(&params, 0, sizeof(struct cb_params_st));
    rb_scan_args(argc, argv, "0*&", &params.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(&params);
    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(&params);
    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;
}
Ejemplo n.º 4
0
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;
}
Ejemplo n.º 5
0
    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(&params, 0, sizeof(struct params_st));
    params.type = cmd_observe;
    params.bucket = bucket;
    cb_params_build(&params, 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(&params);
    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 */
        }
    }
}