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); }
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; }
/* * 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(¶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"); } rb_funcall(params.args, cb_id_flatten_bang, 0); params.type = cb_cmd_unlock; params.bucket = bucket; cb_params_build(¶ms); 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(¶ms); 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; } } }