Beispiel #1
0
Datei: cb.c Projekt: muut/cberl
ERL_NIF_TERM cb_unlock(ErlNifEnv* env, handle_t* handle, void* obj)
{
    unlock_args_t* args = (unlock_args_t*)obj;

    struct libcouchbase_callback cb;

    lcb_error_t ret;

    lcb_unlock_cmd_t unlock;
    memset(&unlock, 0, sizeof(unlock));
    unlock.v.v0.key = args->key;
    unlock.v.v0.nkey = args->nkey;
    unlock.v.v0.cas = args->cas;
    const lcb_unlock_cmd_t* commands[] = { &unlock };
    ret = lcb_unlock(handle->instance, &cb, 1, commands);

    free(args->key);

    if (ret != LCB_SUCCESS) {
        return return_lcb_error(env, ret);
    }
    lcb_wait(handle->instance);
    if(cb.error != LCB_SUCCESS) {
        return return_lcb_error(env, cb.error);
    }
    return A_OK(env);
}
Beispiel #2
0
static lcb_error_t do_unlock(lcb_t instance, const void *key, uint16_t klen,
							 lcb_cas_t cas)
{
	lcb_error_t error;
	lcb_unlock_cmd_t cmd;
	const lcb_unlock_cmd_t *const commands[] = { &cmd };
	lcb_error_t retval;

	memset(&cmd, 0, sizeof(cmd));
	cmd.v.v0.key = key;
	cmd.v.v0.nkey = klen;
	cmd.v.v0.cas = cas;

	lcb_behavior_set_syncmode(instance, LCB_SYNCHRONOUS);
	retval = lcb_unlock(instance, &error, 1, commands);
	lcb_behavior_set_syncmode(instance, LCB_ASYNCHRONOUS);

	return (retval == LCB_SUCCESS) ? error : retval;
}
static PyObject *
keyop_common(pycbc_Connection *self,
             PyObject *args,
             PyObject *kwargs,
             int optype,
             int argopts)
{
    int rv;
    int ii;
    Py_ssize_t ncmds = 0;
    pycbc_seqtype_t seqtype;
    PyObject *casobj = NULL;

    PyObject *ret = NULL;
    PyObject *is_quiet = NULL;
    PyObject *kobj = NULL;
    pycbc_MultiResult *mres = NULL;
    lcb_error_t err;
    struct pycbc_common_vars cv = PYCBC_COMMON_VARS_STATIC_INIT;

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

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

    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, ncmds, sizeof(lcb_remove_cmd_t), 0);
    if (rv < 0) {
        return NULL;
    }

    if (argopts & PYCBC_ARGOPT_MULTI) {
        Py_ssize_t dictpos = 0;
        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_keyop(self, curkey, curvalue, ii, optype, &cv);

            Py_XDECREF(curkey);
            Py_XDECREF(curvalue);

            if (rv < 0) {
                goto GT_ITER_DONE;
            }
        }

        GT_ITER_DONE:
        Py_XDECREF(iter);

        if (rv < 0) {
            goto GT_DONE;
        }

    } else {
        rv = handle_single_keyop(self, kobj, casobj, 0, optype, &cv);
        if (rv < 0) {
            goto GT_DONE;
        }
    }

    mres = (pycbc_MultiResult*)pycbc_multiresult_new(self);


    if (optype == PYCBC_CMD_DELETE) {
        if (pycbc_maybe_set_quiet(mres, is_quiet) == -1) {
            goto GT_DONE;
        }
        err = lcb_remove(self->instance, mres, ncmds, cv.cmdlist.remove);

    } else {
        err = lcb_unlock(self->instance, mres, ncmds, cv.cmdlist.unlock);
    }

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

    err = pycbc_oputil_wait_common(self);

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

    if (!pycbc_multiresult_maybe_raise(mres)) {
        ret = (PyObject*)mres;
    }

    GT_DONE:
    pycbc_common_vars_free(&cv);
    ret = pycbc_make_retval(argopts, &ret, &mres);
    Py_XDECREF(mres);

    return ret;
}
Beispiel #4
0
/*
 * Unlock key
 *
 * @since 1.2.0
 *
 * The +unlock+ method allow you to unlock key once locked by {Bucket#get}
 * with +:lock+ option.
 *
 * @overload unlock(key, options = {})
 *   @param key [String, Symbol] Key used to reference the value.
 *   @param options [Hash] Options for operation.
 *   @option options [Fixnum] :cas The CAS value must match the current one
 *     from the storage.
 *   @option options [true, false] :quiet (self.quiet) If set to +true+, the
 *     operation won't raise error for missing key, it will return +nil+.
 *
 *   @return [true, false] +true+ if the operation was successful and +false+
 *     otherwise.
 *
 *   @raise [Couchbase::Error::Connect] if connection closed (see {Bucket#reconnect})
 *
 *   @raise [ArgumentError] when passing the block in synchronous mode
 *
 *   @raise [Couchbase::Error::NotFound] if key(s) not found in the storage
 *
 *   @raise [Couchbase::Error::TemporaryFail] if either the key wasn't
 *      locked or given CAS value doesn't match to actual in the storage
 *
 *   @example Unlock the single key
 *     val, _, cas = c.get("foo", :lock => true, :extended => true)
 *     c.unlock("foo", :cas => cas)
 *
 * @overload unlock(keys)
 *   @param keys [Hash] The Hash where keys represent the keys in the
 *     database, values -- the CAS for corresponding key.
 *
 *   @yieldparam ret [Result] the result of operation for each key in
 *     asynchronous mode (valid attributes: +error+, +operation+, +key+).
 *
 *   @return [Hash] Mapping keys to result of unlock operation (+true+ if the
 *     operation was successful and +false+ otherwise)
 *
 *   @example Unlock several keys
 *     c.unlock("foo" => cas1, :bar => cas2) #=> {"foo" => true, "bar" => true}
 *
 *   @example Unlock several values in async mode
 *     c.run do
 *       c.unlock("foo" => 10, :bar => 20) do |ret|
 *          ret.operation   #=> :unlock
 *          ret.success?    #=> true
 *          ret.key         #=> "foo" and "bar" in separate calls
 *       end
 *     end
 *
 */
   VALUE
cb_bucket_unlock(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_unlock)) {
        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");
    }
    rb_funcall(params.args, cb_id_flatten_bang, 0);
    params.type = cb_cmd_unlock;
    params.bucket = bucket;
    cb_params_build(&params);
    ctx = cb_context_alloc_common(bucket, proc, params.cmd.unlock.num);
    ctx->quiet = params.cmd.unlock.quiet;
    err = lcb_unlock(bucket->handle, (const void *)ctx,
            params.cmd.unlock.num, params.cmd.unlock.ptr);
    cb_params_destroy(&params);
    exc = cb_check_error(err, "failed to schedule unlock 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.unlock.num > 1) {
            return rv;  /* return as a hash {key => true, ...} */
        } else {
            VALUE vv = Qnil;
            rb_hash_foreach(rv, cb_first_value_i, (VALUE)&vv);
            return vv;
        }
    }
}