int couchbase_add(cachedb_con *connection,str *attr,int val,int expires,int *new_val) { lcb_t instance; lcb_error_t oprc; lcb_arithmetic_cmd_t cmd; const lcb_arithmetic_cmd_t *commands[1]; instance = COUCHBASE_CON(connection); commands[0] = &cmd; memset(&cmd, 0, sizeof(cmd)); cmd.v.v0.key = attr->s; cmd.v.v0.nkey = attr->len; cmd.v.v0.delta = val; cmd.v.v0.create = 1; cmd.v.v0.initial = val; cmd.v.v0.exptime = expires; oprc = lcb_arithmetic(instance, NULL, 1, commands); if (oprc != LCB_SUCCESS) { if (oprc == LCB_KEY_ENOENT) { return -1; } LM_ERR("Failed to send the arithmetic query - %s\n", lcb_strerror(instance, oprc)); //Attempt reconnect if (couchbase_conditional_reconnect(connection, oprc) != 1) { return -2; } //Try again instance = COUCHBASE_CON(connection); oprc = lcb_arithmetic(instance, NULL, 1, commands); if (oprc != LCB_SUCCESS) { if (oprc == LCB_KEY_ENOENT) { LM_ERR("Arithmetic command successfully retried\n"); return -1; } LM_ERR("Arithmetic command retry failed - %s\n", lcb_strerror(instance, oprc)); return -2; } LM_ERR("Arithmetic command successfully retried\n"); } if (new_val) *new_val = arithmetic_res; return 1; }
ERL_NIF_TERM cb_arithmetic(ErlNifEnv* env, handle_t* handle, void* obj) { arithmetic_args_t* args = (arithmetic_args_t*)obj; struct libcouchbase_callback cb; lcb_error_t ret; //for checking responses lcb_arithmetic_cmd_t arithmetic; const lcb_arithmetic_cmd_t* commands[1]; commands[0] = &arithmetic; memset(&arithmetic, 0, sizeof(arithmetic)); arithmetic.v.v0.key = args->key; arithmetic.v.v0.nkey = args->nkey; arithmetic.v.v0.initial = args->initial; arithmetic.v.v0.create = args->create; arithmetic.v.v0.delta = args->delta; arithmetic.v.v0.exptime = args->exp; ret = lcb_arithmetic(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 enif_make_tuple2(env, A_OK(env), return_value(env, &cb)); }
// Given an LCB instance and a key name, create an arithmetic, and // wait until it finishes, and if there is an error, display it. static void OrigrBlockingArithmeticCreate(lcb_t instance, char *keyName, int expTimeSeconds) { int keyLength = strlen(keyName); lcb_error_t arithmeticCreateErrorCode = 0; lcb_arithmetic_cmd_t *arithmeticCommand = calloc(1, sizeof(*arithmeticCommand)); arithmeticCommand->version = 0; arithmeticCommand->v.v0.key = keyName; arithmeticCommand->v.v0.nkey = keyLength; arithmeticCommand->v.v0.exptime = expTimeSeconds; arithmeticCommand->v.v0.create = 1; arithmeticCommand->v.v0.delta = 1; arithmeticCommand->v.v0.initial = 1234500; const lcb_arithmetic_cmd_t* arithCommands[] = { arithmeticCommand }; arithmeticCreateErrorCode = lcb_arithmetic(instance, NULL, 1, arithCommands); if (arithmeticCreateErrorCode != LCB_SUCCESS) { printf("Couldn't schedule arithmeetic create operation!\n"); printf("lcb_arithmetic errorCode is 0x%.8X \n", arithmeticCreateErrorCode); exit(1); } printf("Arithmetic CREATE: About to do lcb_wait()...\n"); lcb_wait(instance); printf("Arithmetic CREATE: Back from lcb_wait()...\n"); } // end of blockingArithmeticCreate()
// Given an LCB instance and a key name, increment an arithmetic, and // wait until it finishes, and if there is an error, display it. static void OrigBlockingArithmeticIncrement(lcb_t instance, char *keyName) { int keyLength = strlen(keyName); lcb_error_t arithmeticIncrementErrorCode = 0; lcb_arithmetic_cmd_t *arithmeticCommand = calloc(1, sizeof(*arithmeticCommand)); arithmeticCommand->version = 0; // Determine if this is factor arithmeticCommand->v.v0.key = keyName; arithmeticCommand->v.v0.nkey = keyLength; arithmeticCommand->v.v0.create = 0; // as opposed to 1 arithmeticCommand->v.v0.delta = 1; // increment by one const lcb_arithmetic_cmd_t* arithCommands[] = { arithmeticCommand }; arithmeticIncrementErrorCode = lcb_arithmetic(instance, NULL, 1, arithCommands); if (arithmeticIncrementErrorCode != LCB_SUCCESS) { printf("Couldn't schedule arithmetic increment operation!\n"); printf("lcb_arithmetic errorCode is 0x%.8X \n", arithmeticIncrementErrorCode); exit(1); } printf("Arithmetic CREATE: About to do lcb_wait()...\n"); lcb_wait(instance); printf("Arithmetic CREATE: Back from lcb_wait()...\n"); } // end of blockingArithmeticIncrement()
// Given an LCB instance and a key name, increment an arithmetic, and // wait until it finishes, and if there is an error, display it. static void blockingArithmeticIncrement2(lcb_t instance, char *keyName) { int keyLength = strlen(keyName); lcb_error_t arithmeticIncrementErrorCode = 0; lcb_arithmetic_cmd_t *arithmeticCommand = calloc(1, sizeof(*arithmeticCommand)); // These are the exact values arithmeticCommand->version = 0; arithmeticCommand->v.v0.key = keyName; arithmeticCommand->v.v0.nkey = strlen(keyName); arithmeticCommand->v.v0.exptime = 0; arithmeticCommand->v.v0.create = 1; arithmeticCommand->v.v0.delta = 1; // Unknown since not printed in logs arithmeticCommand->v.v0.initial = 1; // Equal to delta const lcb_arithmetic_cmd_t* arithCommands[] = { arithmeticCommand }; arithmeticIncrementErrorCode = lcb_arithmetic(instance, NULL, 1, arithCommands); if (arithmeticIncrementErrorCode != LCB_SUCCESS) { printf("Couldn't schedule increment operation!\n"); printf("lcb_arithmetic errorCode is 0x%.8X \n", arithmeticIncrementErrorCode); exit(1); } printf("INCREMENT: About to do lcb_wait()...\n"); lcb_wait(instance); printf("INCREMENT: Back from lcb_wait()...\n"); } // end of blockingArithmeticIncrement2()
int main(void) { struct lcb_create_st create_options; lcb_t instance; lcb_error_t err; memset(&create_options, 0, sizeof(create_options)); create_options.v.v0.host = "ec2-204-236-172-232.us-west-1.compute.amazonaws.com:8091"; create_options.v.v0.user = "******"; create_options.v.v0.passwd = "password"; create_options.v.v0.bucket = "default"; err = lcb_create(&instance, &create_options); if (err != LCB_SUCCESS) { fprintf(stderr, "Failed to create libcouchbase instance: %s\n", lcb_strerror(NULL, err)); return 1; } else { fprintf(stdout, "Successful in creating libCouchbase instance: %s\n"); } if ((err = lcb_connect(instance)) != LCB_SUCCESS) { fprintf(stderr, "Failed to initiate connect: %s\n", lcb_strerror(NULL, err)); return 1; } else { fprintf(stdout, "Successful in initializing libCouchbase instance: %s\n"); } /* Run the event loop and wait until we've connected */ lcb_wait(instance); lcb_arithmetic_cmd_t arithmetic; memset(&arithmetic, 0, sizeof(arithmetic)); arithmetic.version = 0; arithmetic.v.v0.key = "036"; arithmetic.v.v0.nkey = sizeof(arithmetic.v.v0.key); arithmetic.v.v0.create = 1; arithmetic.v.v0.delta = -10; arithmetic.v.v0.initial = 036; const lcb_arithmetic_cmd_t* const commands[1] = { &arithmetic }; err = lcb_arithmetic(instance, NULL, 1, commands); if (err != LCB_SUCCESS) { fprintf(stderr, "Failed to incr %s\n", lcb_strerror(NULL, err)); return 1; } else { fprintf(stdout, "Successful in incrementingthe keys and Values: %s\n"); } lcb_wait(instance); lcb_destroy(instance); exit(EXIT_SUCCESS); }
static inline VALUE cb_bucket_arithmetic(int sign, 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, sign > 0 ? cb_sym_increment : cb_sym_decrement)) { 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_arith; params.bucket = bucket; params.cmd.arith.sign = sign; cb_params_build(¶ms); ctx = cb_context_alloc_common(bucket, proc, params.cmd.arith.num); err = lcb_arithmetic(bucket->handle, (const void *)ctx, params.cmd.arith.num, params.cmd.arith.ptr); cb_params_destroy(¶ms); exc = cb_check_error(err, "failed to schedule arithmetic 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); } if (params.cmd.store.num > 1) { return rv; /* return as a hash {key => cas, ...} */ } else { VALUE vv = Qnil; rb_hash_foreach(rv, cb_first_value_i, (VALUE)&vv); return vv; } return rv; } }
int couchbase_add(cachedb_con *connection,str *attr,int val,int expires,int *new_val) { lcb_t instance; lcb_error_t oprc; lcb_arithmetic_cmd_t cmd; const lcb_arithmetic_cmd_t *commands[1]; last_error = LCB_SUCCESS; instance = COUCHBASE_CON(connection); commands[0] = &cmd; memset(&cmd, 0, sizeof(cmd)); cmd.v.v0.key = attr->s; cmd.v.v0.nkey = attr->len; cmd.v.v0.delta = val; cmd.v.v0.create = 1; cmd.v.v0.initial = val; cmd.v.v0.exptime = expires; oprc = lcb_arithmetic(instance, NULL, 1, commands); if (oprc != LCB_SUCCESS) { LM_ERR("Failed to send the arithmetic query - %s\n", lcb_strerror(instance, oprc)); couchbase_conditional_reconnect(connection, oprc); return -2; } lcb_wait(instance); if (last_error != LCB_SUCCESS) { couchbase_conditional_reconnect(connection, last_error); return -1; } if (new_val) *new_val = arithmetic_res; return 1; }
PHP_COUCHBASE_LOCAL void php_couchbase_arithmetic_impl(INTERNAL_FUNCTION_PARAMETERS, char op, int oo) /* {{{ */ { char *key; time_t exp = {0}; long klen = 0, offset = 1, expire = 0; long create = 0, initial = 0; php_couchbase_res *couchbase_res; int argflags = oo ? PHP_COUCHBASE_ARG_F_OO : PHP_COUCHBASE_ARG_F_FUNCTIONAL; PHP_COUCHBASE_GET_PARAMS(couchbase_res, argflags, "s|llll", &key, &klen, &offset, &create, &expire, &initial); { lcb_error_t retval; php_couchbase_ctx *ctx; long delta = (op == '+') ? offset : -offset; if (expire) { exp = pcbc_check_expiry(expire); } ctx = ecalloc(1, sizeof(php_couchbase_ctx)); ctx->res = couchbase_res; ctx->rv = return_value; { lcb_arithmetic_cmd_t cmd; lcb_arithmetic_cmd_t *commands[] = { &cmd }; memset(&cmd, 0, sizeof(cmd)); cmd.v.v0.key = key; cmd.v.v0.nkey = klen; cmd.v.v0.create = create; cmd.v.v0.delta = delta; cmd.v.v0.initial = initial; cmd.v.v0.exptime = exp; retval = lcb_arithmetic(couchbase_res->handle, ctx, 1, (const lcb_arithmetic_cmd_t * const *)commands); } if (LCB_SUCCESS != retval) { efree(ctx); php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to schedule rithmetic request: %s", lcb_strerror(couchbase_res->handle, retval)); RETURN_FALSE; } couchbase_res->seqno += 1; pcbc_start_loop(couchbase_res); if (LCB_SUCCESS != ctx->res->rc) { // Just return false and don't print a warning when no key is present and create is false if (!(LCB_KEY_ENOENT == ctx->res->rc && create == 0)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to %s value in server: %s", (op == '+') ? "increment" : "decrement", lcb_strerror(couchbase_res->handle, ctx->res->rc)); } efree(ctx); RETURN_FALSE; } efree(ctx); } }
PHP_COUCHBASE_LOCAL void php_couchbase_arithmetic_impl(INTERNAL_FUNCTION_PARAMETERS, char op, int oo) { char *key; time_t exp; long klen = 0; long offset = 1; long expire = 0; long create = 0; long initial = 0; php_couchbase_res *couchbase_res; lcb_arithmetic_cmd_t cmd; const lcb_arithmetic_cmd_t *const commands[] = { &cmd }; lcb_error_t retval; struct arithmetic_cookie cookie; int argflags; long delta; lcb_t instance; argflags = oo ? PHP_COUCHBASE_ARG_F_OO : PHP_COUCHBASE_ARG_F_FUNCTIONAL; PHP_COUCHBASE_GET_PARAMS(couchbase_res, argflags, "s|llll", &key, &klen, &offset, &create, &expire, &initial); if (pcbc_check_expiry(INTERNAL_FUNCTION_PARAM_PASSTHRU, oo, expire, &exp) == -1) { /* Incorrect expiry time */ return; } instance = couchbase_res->handle; memset(&cookie, 0, sizeof(cookie)); delta = (op == '+') ? offset : -offset; memset(&cmd, 0, sizeof(cmd)); cmd.v.v0.key = key; cmd.v.v0.nkey = klen; cmd.v.v0.create = create; cmd.v.v0.delta = delta; cmd.v.v0.initial = initial; cmd.v.v0.exptime = exp; lcb_behavior_set_syncmode(instance, LCB_SYNCHRONOUS); retval = lcb_arithmetic(instance, &cookie, 1, commands); lcb_behavior_set_syncmode(instance, LCB_ASYNCHRONOUS); if (retval == LCB_SUCCESS) { retval = cookie.error ; } couchbase_res->rc = retval; if (retval == LCB_SUCCESS) { ZVAL_LONG(return_value, cookie.value); } else { if (retval == LCB_KEY_ENOENT && create == 0) { /* The user told us to not create the key... */ RETURN_FALSE; } couchbase_report_error(INTERNAL_FUNCTION_PARAM_PASSTHRU, oo, cb_lcb_exception, "Failed to %s value in the server: %s", (op == '+') ? "increment" : "decrement", lcb_strerror(instance, retval)); } }
PyObject * arithmetic_common(pycbc_Bucket *self, PyObject *args, PyObject *kwargs, int optype, int argopts) { int rv; Py_ssize_t ncmds; struct arithmetic_common_vars global_params = { 0 }; pycbc_seqtype_t seqtype; PyObject *all_initial_O = NULL; PyObject *all_ttl_O = NULL; PyObject *collection; lcb_error_t err; struct pycbc_common_vars cv = PYCBC_COMMON_VARS_STATIC_INIT; static char *kwlist[] = { "keys", "delta", "initial", "ttl", NULL }; global_params.delta = 1; rv = PyArg_ParseTupleAndKeywords(args, kwargs, "O|LOO", kwlist, &collection, &global_params.delta, &all_initial_O, &all_ttl_O); if (!rv) { PYCBC_EXCTHROW_ARGS(); return NULL; } rv = pycbc_get_ttl(all_ttl_O, &global_params.ttl, 1); if (rv < 0) { return NULL; } if (argopts & PYCBC_ARGOPT_MULTI) { rv = pycbc_oputil_check_sequence(collection, 1, &ncmds, &seqtype); if (rv < 0) { return NULL; } } else { ncmds = 1; } if (all_initial_O && PyNumber_Check(all_initial_O)) { global_params.create = 1; global_params.initial = pycbc_IntAsULL(all_initial_O); } rv = pycbc_common_vars_init(&cv, self, argopts, ncmds, sizeof(lcb_arithmetic_cmd_t), 0); if (argopts & PYCBC_ARGOPT_MULTI) { rv = pycbc_oputil_iter_multi(self, seqtype, collection, &cv, optype, handle_single_arith, &global_params); } else { rv = handle_single_arith(self, &cv, optype, collection, NULL, NULL, NULL, 0, &global_params); } if (rv < 0) { goto GT_DONE; } err = lcb_arithmetic(self->instance, cv.mres, ncmds, cv.cmdlist.arith); if (err != LCB_SUCCESS) { PYCBC_EXCTHROW_SCHED(err); goto GT_DONE; } if (-1 == pycbc_common_vars_wait(&cv, self)) { goto GT_DONE; } GT_DONE: pycbc_common_vars_finalize(&cv, self); return cv.ret; }
static inline VALUE cb_bucket_arithmetic(int sign, 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_arith; params.bucket = bucket; params.cmd.arith.sign = sign; 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"); } rv = rb_hash_new(); ctx->rv = &rv; ctx->bucket = bucket; ctx->proc = cb_gc_protect(bucket, proc); ctx->exception = Qnil; ctx->nqueries = params.cmd.arith.num; err = lcb_arithmetic(bucket->handle, (const void *)ctx, params.cmd.arith.num, params.cmd.arith.ptr); cb_params_destroy(¶ms); exc = cb_check_error(err, "failed to schedule arithmetic 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 (params.cmd.store.num > 1) { return rv; /* return as a hash {key => cas, ...} */ } else { VALUE vv = Qnil; rb_hash_foreach(rv, cb_first_value_i, (VALUE)&vv); return vv; } return rv; } }