PHP_COUCHBASE_LOCAL void php_couchbase_store_impl(INTERNAL_FUNCTION_PARAMETERS, lcb_storage_t op, int multi) { lcb_error_t retval; php_couchbase_res *couchbase_res; php_couchbase_ctx *ctx; time_t exp = {0}; unsigned int flags = 0; char *payload, *cas = NULL; size_t payload_len = 0; unsigned long long cas_v = 0; long expire = 0, cas_len = 0; char *key = NULL; if (!multi) { char *key = NULL; zval *value; long klen = 0; PHP_COUCHBASE_GET_PARAMS(couchbase_res, PHP_COUCHBASE_ARG_F_FUNCTIONAL, "sz|ls", &key, &klen, &value, &expire, &cas, &cas_len); if (pcbc_check_expiry(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, expire, &exp) == -1) { /* Incorrect expiry time */ return; } if (!klen) { couchbase_report_error(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, cb_illegal_key_exception, "No key specified: Empty key"); return; } if (cas) { char *e; cas_v = (lcb_cas_t)strtoull(cas, &e, 10); if (*e != '\0') { couchbase_report_error(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, cb_illegal_key_exception, "Invalid CAS specified"); return; } } payload = php_couchbase_zval_to_payload(value, &payload_len, &flags, couchbase_res->serializer, couchbase_res->compressor TSRMLS_CC); if (payload == NULL) { RETURN_FALSE; } if (couchbase_res->prefix_key_len) { klen = spprintf(&key, 0, "%s_%s", couchbase_res->prefix_key, key); } ctx = ecalloc(1, sizeof(php_couchbase_ctx)); ctx->res = couchbase_res; ctx->rv = return_value; couchbase_res->seqno += 1; { lcb_store_cmd_t cmd; lcb_store_cmd_t *commands[] = { &cmd }; memset(&cmd, 0, sizeof(cmd)); cmd.v.v0.operation = op; cmd.v.v0.key = key; cmd.v.v0.nkey = klen; cmd.v.v0.bytes = payload; cmd.v.v0.nbytes = payload_len; cmd.v.v0.flags = flags; cmd.v.v0.exptime = exp; cmd.v.v0.cas = (uint64_t)cas_v; retval = lcb_store(couchbase_res->handle, ctx, 1, (const lcb_store_cmd_t * const *)commands); } efree(payload); if (couchbase_res->prefix_key_len) { efree(key); } if (LCB_SUCCESS != retval) { efree(ctx); couchbase_report_error(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, cb_lcb_exception, "Failed to schedule set request: %s", lcb_strerror(couchbase_res->handle, retval)); return; } } else { /* multi */ zval *akeys, **ppzval; char *key = NULL; uint klen = 0; ulong idx; int key_type, nkey = 0; PHP_COUCHBASE_GET_PARAMS(couchbase_res, PHP_COUCHBASE_ARG_F_FUNCTIONAL, "a|l", &akeys, &expire); if (pcbc_check_expiry(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, expire, &exp) == -1) { /* Incorrect expiry time */ return; } ctx = ecalloc(1, sizeof(php_couchbase_ctx)); ctx->res = couchbase_res; ctx->rv = return_value; array_init(ctx->rv); for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(akeys)); zend_hash_has_more_elements(Z_ARRVAL_P(akeys)) == SUCCESS; zend_hash_move_forward(Z_ARRVAL_P(akeys))) { if (zend_hash_get_current_data(Z_ARRVAL_P(akeys), (void **)&ppzval) == FAILURE) { continue; } switch ((key_type = zend_hash_get_current_key(Z_ARRVAL_P(akeys), &key, &idx, 0))) { case HASH_KEY_IS_LONG: spprintf(&key, 0, "%ld", idx); break; case HASH_KEY_IS_STRING: break; default: continue; } if (!(klen = strlen(key))) { continue; } payload = php_couchbase_zval_to_payload(*ppzval, &payload_len, &flags, couchbase_res->serializer, couchbase_res->compressor TSRMLS_CC); if (payload == NULL) { RETURN_FALSE; } if (couchbase_res->prefix_key_len) { char *new_key; klen = spprintf(&new_key, 0, "%s_%s", couchbase_res->prefix_key, key); if (key_type == HASH_KEY_IS_LONG) { efree(key); } key = new_key; } { lcb_store_cmd_t cmd; lcb_store_cmd_t *commands[] = { &cmd }; memset(&cmd, 0, sizeof(cmd)); cmd.v.v0.operation = op; cmd.v.v0.key = key; cmd.v.v0.nkey = klen; cmd.v.v0.bytes = payload; cmd.v.v0.nbytes = payload_len; cmd.v.v0.flags = flags; cmd.v.v0.exptime = exp; retval = lcb_store(couchbase_res->handle, ctx, 1, (const lcb_store_cmd_t * const *)commands); } efree(payload); if (couchbase_res->prefix_key_len || HASH_KEY_IS_LONG == key_type) { efree(key); } if (LCB_SUCCESS != retval) { efree(ctx); couchbase_report_error(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, cb_lcb_exception, "Failed to schedule set request: %s", lcb_strerror(couchbase_res->handle, retval)); return; } nkey++; } if (!nkey) { efree(ctx); return; } couchbase_res->seqno += nkey; } { pcbc_start_loop(couchbase_res); if (IS_ARRAY != Z_TYPE_P(return_value)) { if (LCB_SUCCESS != ctx->res->rc) { RETVAL_FALSE; switch (op) { case LCB_ADD: if (LCB_KEY_EEXISTS == ctx->res->rc) { break; } case LCB_APPEND: case LCB_PREPEND: if (LCB_NOT_STORED == ctx->res->rc) { break; } case LCB_REPLACE: case LCB_SET: if (LCB_KEY_ENOENT == ctx->res->rc) { break; } if (cas && LCB_KEY_EEXISTS == ctx->res->rc) { break; } default: couchbase_report_error(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, cb_lcb_exception, "Failed to store a value to server: %s", lcb_strerror(couchbase_res->handle, ctx->res->rc)); break; } } } efree(ctx); } }
PHP_COUCHBASE_LOCAL void php_couchbase_store_multi_impl_oo(INTERNAL_FUNCTION_PARAMETERS) { lcb_error_t retval; php_couchbase_res *couchbase_res; php_couchbase_ctx *ctx; time_t exp = {0}; long expire = 0; zval *akeys; long persist_to = 0; long replicate_to = 0; struct observe_entry *entries; int numkeys; lcb_store_cmd_t *cmds; lcb_store_cmd_t **commands; int ii; PHP_COUCHBASE_GET_PARAMS(couchbase_res, PHP_COUCHBASE_ARG_F_OO, "a|lll", &akeys, &expire, &persist_to, &replicate_to); if (pcbc_check_expiry(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1, expire, &exp) == -1) { /* Incorrect expiry time */ return; } if (validate_simple_observe_clause(couchbase_res->handle, persist_to, replicate_to TSRMLS_CC) == -1) { /* Exception already thrown */ return; } numkeys = zend_hash_num_elements(Z_ARRVAL_P(akeys)); if (numkeys == 0) { zend_throw_exception(cb_illegal_key_exception, "No items specified", 0 TSRMLS_CC); return ; } entries = ecalloc(numkeys, sizeof(struct observe_entry)); commands = ecalloc(numkeys, sizeof(lcb_store_cmd_t *)); cmds = ecalloc(numkeys, sizeof(lcb_store_cmd_t)); /* link the command pointers */ for (ii = 0; ii < numkeys; ++ii) { commands[ii] = cmds + ii; } ctx = ecalloc(1, sizeof(php_couchbase_ctx)); ctx->res = couchbase_res; ctx->rv = return_value; array_init(ctx->rv); for (ii = 0, zend_hash_internal_pointer_reset(Z_ARRVAL_P(akeys)); zend_hash_has_more_elements(Z_ARRVAL_P(akeys)) == SUCCESS; zend_hash_move_forward(Z_ARRVAL_P(akeys)), ++ii) { char *key = NULL; uint klen; size_t payload_len = 0; char *payload; unsigned int flags = 0; zval **ppzval; if (zend_hash_get_current_key_type(Z_ARRVAL_P(akeys)) != HASH_KEY_IS_STRING) { int xx; for (xx = 0; xx < ii; ++xx) { efree((void *)cmds[xx].v.v0.bytes); } efree(commands); efree(cmds); efree(ctx); release_entry_array(entries, xx); zend_throw_exception(cb_illegal_key_exception, "Invalid key specified (not a string)", 0 TSRMLS_CC); return ; } zend_hash_get_current_key(Z_ARRVAL_P(akeys), &key, NULL, 0); if ((klen = strlen(key)) == 0) { int xx; for (xx = 0; xx < ii; ++xx) { efree((void *)cmds[xx].v.v0.bytes); } efree(commands); efree(cmds); efree(ctx); release_entry_array(entries, xx); zend_throw_exception(cb_illegal_key_exception, "Invalid key specified (empty string)", 0 TSRMLS_CC); return ; } if (zend_hash_get_current_data(Z_ARRVAL_P(akeys), (void **)&ppzval) == FAILURE) { int xx; for (xx = 0; xx < ii; ++xx) { efree((void *)cmds[xx].v.v0.bytes); } efree(commands); efree(cmds); efree(ctx); release_entry_array(entries, xx); zend_throw_exception(cb_exception, "Failed to get data for key", 0 TSRMLS_CC); return ; } payload = php_couchbase_zval_to_payload(*ppzval, &payload_len, &flags, couchbase_res->serializer, couchbase_res->compressor TSRMLS_CC); if (payload == NULL) { /* Shouldn't we call an exception? */ RETURN_FALSE; } if (couchbase_res->prefix_key_len) { char *new_key; klen = spprintf(&new_key, 0, "%s_%s", couchbase_res->prefix_key, key); key = new_key; } entries[ii].nkey = klen; entries[ii].key = emalloc(klen); memcpy(entries[ii].key, key, klen); cmds[ii].v.v0.operation = LCB_SET; cmds[ii].v.v0.key = entries[ii].key; cmds[ii].v.v0.nkey = klen; cmds[ii].v.v0.bytes = payload; cmds[ii].v.v0.nbytes = payload_len; cmds[ii].v.v0.flags = flags; cmds[ii].v.v0.exptime = exp; if (couchbase_res->prefix_key_len) { efree(key); } } retval = lcb_store(couchbase_res->handle, ctx, numkeys, (const lcb_store_cmd_t * const *)commands); couchbase_res->seqno += numkeys; pcbc_start_loop(couchbase_res); /* * Time to release the payloads... */ for (ii = 0; ii < numkeys; ++ii) { efree((void *)cmds[ii].v.v0.bytes); } efree(cmds); efree(commands); if (LCB_SUCCESS != retval) { efree(ctx); couchbase_report_error(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1, cb_lcb_exception, "Failed to schedule set request: %s", lcb_strerror(couchbase_res->handle, retval)); release_entry_array(entries, numkeys); RETURN_FALSE; } /* * The item was stored successfully. Did the user want to wait until * it was persisted/replicated? */ if (persist_to != 0 || replicate_to != 0) { int ii = 0; for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(return_value)); zend_hash_has_more_elements(Z_ARRVAL_P(return_value)) == SUCCESS; zend_hash_move_forward(Z_ARRVAL_P(return_value)), ++ii) { zval **curr_cas; zend_hash_get_current_data(Z_ARRVAL_P(return_value), (void **)&curr_cas); if (Z_STRLEN_PP(curr_cas)) { entries[ii].cas = strtoull(Z_STRVAL_PP(curr_cas), 0, 10); } else { /* @todo what to do here? */ fprintf(stderr, "wtf!\n"); } } retval = simple_observe(couchbase_res->handle, entries, numkeys, persist_to, replicate_to); couchbase_res->rc = retval; if (retval != LCB_SUCCESS) { if (retval == LCB_ETIMEDOUT) { zend_throw_exception(cb_timeout_exception, "Timed out waiting for the objects to persist", 0 TSRMLS_CC); } else { char errmsg[256]; snprintf(errmsg, sizeof(errmsg), "An error occured while waiting for the objects to persist: %s", lcb_strerror(couchbase_res->handle, retval)); zend_throw_exception(cb_lcb_exception, errmsg, 0 TSRMLS_CC); } } else { int currsize = 4096; char *errmsg = malloc(currsize); int offset = sprintf(errmsg, "The following documents was mutated:"); int errors = 0; for (ii = 0; ii < numkeys; ++ii) { if (entries[ii].mutated) { if ((offset + entries[ii].nkey + 3) > currsize) { char *p = realloc(errmsg, currsize * 2); if (p) { currsize *= 2; errmsg = p; } } if ((offset + entries[ii].nkey + 3) < currsize) { offset += sprintf(errmsg + offset, " \""); memcpy(errmsg + offset, entries[ii].key, entries[ii].nkey); offset += entries[ii].nkey; offset += sprintf(errmsg + offset, "\""); } errors = 1; } } if (errors) { zend_throw_exception(cb_key_mutated_exception, errmsg, 0 TSRMLS_CC); } free(errmsg); } } release_entry_array(entries, numkeys); efree(ctx); }
PHP_COUCHBASE_LOCAL void php_couchbase_cas_impl(INTERNAL_FUNCTION_PARAMETERS, int oo) { zval *value; time_t exp = {0}; unsigned int flags = 0; size_t payload_len = 0; unsigned long long cas_v = 0; char *key, *payload, *cas = NULL; long klen = 0, expire = 0, cas_len = 0; php_couchbase_res *couchbase_res; long replicate_to = 0; long persist_to = 0; lcb_error_t retval; php_couchbase_ctx *ctx; lcb_store_cmd_t cmd; const lcb_store_cmd_t *const commands[] = { &cmd }; int argf = oo ? PHP_COUCHBASE_ARG_F_OO : PHP_COUCHBASE_ARG_F_FUNCTIONAL; PHP_COUCHBASE_GET_PARAMS(couchbase_res, argf, "ssz|lll", &cas, &cas_len, &key, &klen, &value, &expire, &persist_to, &replicate_to); if (pcbc_check_expiry(INTERNAL_FUNCTION_PARAM_PASSTHRU, oo, expire, &exp) == -1) { /* Incorrect expiry time */ return; } if (validate_simple_observe_clause(couchbase_res->handle, persist_to, replicate_to TSRMLS_CC) == -1) { /* Exception already thrown */ return; } if (klen == 0) { couchbase_report_error(INTERNAL_FUNCTION_PARAM_PASSTHRU, oo, cb_illegal_key_exception, "Failed to schedule set request: Empty key"); return; } if (cas_len == 0) { couchbase_report_error(INTERNAL_FUNCTION_PARAM_PASSTHRU, oo, cb_exception, "Illegal CAS specified"); return; } if (cas) { char *end; cas_v = strtoull(cas, &end, 10); if (*end != '\0') { couchbase_report_error(INTERNAL_FUNCTION_PARAM_PASSTHRU, oo, cb_exception, "Illegal CAS specified"); return; } } ctx = ecalloc(1, sizeof(php_couchbase_ctx)); ctx->res = couchbase_res; ctx->rv = return_value; payload = php_couchbase_zval_to_payload(value, &payload_len, &flags, couchbase_res->serializer, couchbase_res->compressor TSRMLS_CC); if (payload == NULL) { RETURN_FALSE; } if (couchbase_res->prefix_key_len) { klen = spprintf(&key, 0, "%s_%s", couchbase_res->prefix_key, key); } memset(&cmd, 0, sizeof(cmd)); cmd.v.v0.operation = LCB_SET; cmd.v.v0.key = key; cmd.v.v0.nkey = klen; cmd.v.v0.bytes = payload; cmd.v.v0.nbytes = payload_len; cmd.v.v0.flags = flags; cmd.v.v0.exptime = exp; cmd.v.v0.cas = (uint64_t)cas_v; retval = lcb_store(couchbase_res->handle, ctx, 1, commands); efree(payload); if (couchbase_res->prefix_key_len) { efree(key); } if (retval != LCB_SUCCESS) { efree(ctx); couchbase_report_error(INTERNAL_FUNCTION_PARAM_PASSTHRU, oo, cb_lcb_exception, "Failed to schedule cas request: %s", lcb_strerror(couchbase_res->handle, retval)); return; } ++couchbase_res->seqno; pcbc_start_loop(couchbase_res); zval_dtor(return_value); if (LCB_SUCCESS == ctx->res->rc) { ZVAL_TRUE(return_value); } else if (LCB_KEY_EEXISTS == ctx->res->rc) { ZVAL_FALSE(return_value); } else { couchbase_report_error(INTERNAL_FUNCTION_PARAM_PASSTHRU, oo, cb_lcb_exception, "Failed to store a value to server: %s", lcb_strerror(couchbase_res->handle, ctx->res->rc)); } efree(ctx); }
PHP_COUCHBASE_LOCAL void php_couchbase_store_impl_oo(INTERNAL_FUNCTION_PARAMETERS, lcb_storage_t op) { lcb_error_t retval; php_couchbase_res *couchbase_res; php_couchbase_ctx *ctx; time_t exp = {0}; unsigned int flags = 0; char *cas = NULL; char *payload; size_t payload_len = 0; unsigned long long cas_v = 0; long expire = 0; long replicate_to = 0; long persist_to = 0; long cas_len = 0; char *key = NULL; zval *value; long klen = 0; lcb_store_cmd_t cmd; const lcb_store_cmd_t *const commands[] = { &cmd }; if (op == LCB_ADD) { PHP_COUCHBASE_GET_PARAMS(couchbase_res, PHP_COUCHBASE_ARG_F_OO, "sz|lll", &key, &klen, &value, &expire, &persist_to, &replicate_to); } else { PHP_COUCHBASE_GET_PARAMS(couchbase_res, PHP_COUCHBASE_ARG_F_OO, "sz|lsll", &key, &klen, &value, &expire, &cas, &cas_len, &persist_to, &replicate_to); } if (pcbc_check_expiry(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1, expire, &exp) == -1) { /* Incorrect expiry time */ return; } if (validate_simple_observe_clause(couchbase_res->handle, persist_to, replicate_to TSRMLS_CC) == -1) { /* Exception already thrown */ return; } if (!klen) { zend_throw_exception(cb_illegal_key_exception, "Failed to schedule set request: Empty key", 0 TSRMLS_CC); return ; } if (cas) { char *e; cas_v = (lcb_cas_t)strtoull(cas, &e, 10); if (*e != '\0') { couchbase_report_error(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1, cb_illegal_key_exception, "Invalid CAS specified"); return; } } payload = php_couchbase_zval_to_payload(value, &payload_len, &flags, couchbase_res->serializer, couchbase_res->compressor TSRMLS_CC); if (payload == NULL) { /* ?? I guess we should throw an exception here? */ RETURN_FALSE; } if (couchbase_res->prefix_key_len) { klen = spprintf(&key, 0, "%s_%s", couchbase_res->prefix_key, key); } ctx = ecalloc(1, sizeof(php_couchbase_ctx)); ctx->res = couchbase_res; ctx->rv = return_value; couchbase_res->seqno += 1; memset(&cmd, 0, sizeof(cmd)); cmd.v.v0.operation = op; cmd.v.v0.key = key; cmd.v.v0.nkey = klen; cmd.v.v0.bytes = payload; cmd.v.v0.nbytes = payload_len; cmd.v.v0.flags = flags; cmd.v.v0.exptime = exp; cmd.v.v0.cas = (uint64_t)cas_v; retval = lcb_store(couchbase_res->handle, ctx, 1, commands); efree(payload); if (couchbase_res->prefix_key_len) { efree(key); } if (retval != LCB_SUCCESS) { char errmsg[256]; efree(ctx); sprintf(errmsg, "Failed to schedule set request: %s", lcb_strerror(couchbase_res->handle, retval)); zend_throw_exception(cb_lcb_exception, errmsg, 0 TSRMLS_CC); return ; } pcbc_start_loop(couchbase_res); if (LCB_SUCCESS != ctx->res->rc) { RETVAL_FALSE; switch (op) { case LCB_ADD: if (LCB_KEY_EEXISTS == ctx->res->rc) { break; } case LCB_APPEND: case LCB_PREPEND: if (LCB_NOT_STORED == ctx->res->rc) { break; } case LCB_REPLACE: case LCB_SET: if (LCB_KEY_ENOENT == ctx->res->rc) { break; } if (cas && LCB_KEY_EEXISTS == ctx->res->rc) { break; } default: { char errmsg[256]; sprintf(errmsg, "Failed to store value to server: %s", lcb_strerror(couchbase_res->handle, ctx->res->rc)); zend_throw_exception(cb_lcb_exception, errmsg, 0 TSRMLS_CC); } break; } } else { /* * The item was stored successfully. Did the user want to wait until * it was persisted/replicated? */ if (persist_to != 0 || replicate_to != 0) { struct observe_entry entry; memset(&entry, 0, sizeof(entry)); entry.key = key; entry.nkey = klen; entry.cas = strtoull(Z_STRVAL_P(return_value), 0, 10); retval = simple_observe(couchbase_res->handle, &entry, 1, persist_to, replicate_to); couchbase_res->rc = retval; if (retval != LCB_SUCCESS) { if (retval == LCB_ETIMEDOUT) { zend_throw_exception(cb_timeout_exception, "Timed out waiting for the objects to persist", 0 TSRMLS_CC); } else { char errmsg[512]; snprintf(errmsg, sizeof(errmsg), "observe failed for: %s", klen, key, lcb_strerror(couchbase_res->handle, retval)); zend_throw_exception(cb_lcb_exception, errmsg, 0 TSRMLS_CC); } } else { /* @todo checkfor timeout!!! */ if (entry.mutated) { zend_throw_exception(cb_key_mutated_exception, "The document was mutated", 0 TSRMLS_CC); } } } } efree(ctx); }
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_fetch_impl(INTERNAL_FUNCTION_PARAMETERS, int multi, int oo) /* {{{ */ { php_couchbase_res *couchbase_res; int argflags; if (oo) { argflags = PHP_COUCHBASE_ARG_F_OO; } else { argflags = PHP_COUCHBASE_ARG_F_FUNCTIONAL; } argflags |= PHP_COUCHBASE_ARG_F_ASYNC; PHP_COUCHBASE_GET_PARAMS(couchbase_res, argflags, ""); { php_couchbase_ctx *ctx; if (!couchbase_res->async) { RETURN_FALSE; } ctx = couchbase_res->async_ctx; if (couchbase_res->async == 2) { fetch_one: { char *key; uint key_len; ulong index = 0; zval **ppzval; zval *stash = (zval *)ctx->extended_value; if (zend_hash_num_elements(Z_ARRVAL_P(stash)) == 0) { couchbase_res->async = 0; zval_ptr_dtor(&stash); efree(ctx); couchbase_res->async_ctx = NULL; RETURN_NULL(); } zend_hash_internal_pointer_reset(Z_ARRVAL_P(stash)); zend_hash_get_current_data(Z_ARRVAL_P(stash), (void **)&ppzval); RETVAL_ZVAL(*ppzval, 1, 0); zend_hash_get_current_key_ex(Z_ARRVAL_P(stash), &key, &key_len, &index, 0, NULL); zend_hash_index_del(Z_ARRVAL_P(stash), index); return; } } array_init(return_value); ctx->rv = return_value; pcbc_start_loop(couchbase_res); if (!multi) { zval *stash; MAKE_STD_ZVAL(stash); ZVAL_ZVAL(stash, return_value, 1, 0); ctx->extended_value = (void *)stash; zval_dtor(return_value); couchbase_res->async = 2; goto fetch_one; } else { efree(ctx); couchbase_res->async = 0; couchbase_res->async_ctx = NULL; } } }
PHP_COUCHBASE_LOCAL void php_couchbase_get_delayed_impl(INTERNAL_FUNCTION_PARAMETERS, int oo) /* {{{ */ { zval *res, *akeys; long with_cas = 0; lcb_time_t exp = {0}; long expiry = 0; zend_bool lock = 0; int argflags = PHP_COUCHBASE_ARG_F_ASYNC; php_couchbase_res *couchbase_res; #if PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 2 zend_fcall_info fci = {0}; zend_fcall_info_cache fci_cache = {0}; if (oo) { argflags |= PHP_COUCHBASE_ARG_F_OO; } else { argflags |= PHP_COUCHBASE_ARG_F_FUNCTIONAL; } PHP_COUCHBASE_GET_PARAMS_WITH_ZV(res, couchbase_res, argflags, "a|lf!lb", &akeys, &with_cas, &fci, &fci_cache, &expiry, &lock); #else if (oo) { argflags |= PHP_COUCHBASE_ARG_F_OO; } else { argflags |= PHP_COUCHBASE_ARG_F_FUNCTIONAL; } zval *callback = NULL; PHP_COUCHBASE_GET_PARAMS_WITH_ZV(res, couchbase_res, argflags, "a|lzlb", &akeys, &with_cas, &callback, &expiry, &lock); if (callback && Z_TYPE_P(callback) != IS_NULL && !zend_is_callable(callback, 0, NULL)) { couchbase_report_error(INTERNAL_FUNCTION_PARAM_PASSTHRU, oo, cb_exception, "third argument is expected to be a valid callback"); return; } #endif { zval **ppzval; lcb_error_t retval; php_couchbase_ctx *ctx; char **keys; long nkey, *klens, i; nkey = zend_hash_num_elements(Z_ARRVAL_P(akeys)); keys = ecalloc(nkey, sizeof(char *)); klens = ecalloc(nkey, sizeof(long)); for (i = 0, zend_hash_internal_pointer_reset(Z_ARRVAL_P(akeys)); zend_hash_has_more_elements(Z_ARRVAL_P(akeys)) == SUCCESS; zend_hash_move_forward(Z_ARRVAL_P(akeys)), i++) { if (zend_hash_get_current_data(Z_ARRVAL_P(akeys), (void **)&ppzval) == FAILURE) { nkey--; continue; } if (IS_ARRAY != Z_TYPE_PP(ppzval)) { convert_to_string_ex(ppzval); } if (!Z_STRLEN_PP(ppzval)) { nkey--; continue; } if (couchbase_res->prefix_key_len) { klens[i] = spprintf(&(keys[i]), 0, "%s_%s", couchbase_res->prefix_key, Z_STRVAL_PP(ppzval)); } else { keys[i] = Z_STRVAL_PP(ppzval); klens[i] = Z_STRLEN_PP(ppzval); } } if (!nkey) { efree(keys); efree(klens); return; } couchbase_res->seqno += nkey; ctx = ecalloc(1, sizeof(php_couchbase_ctx)); ctx->res = couchbase_res; ctx->flags = with_cas; { lcb_get_cmd_t **commands = ecalloc(nkey, sizeof(lcb_get_cmd_t *)); int ii; if (expiry) { exp = pcbc_check_expiry(expiry); } for (ii = 0; ii < nkey; ++ii) { lcb_get_cmd_t *cmd = ecalloc(1, sizeof(lcb_get_cmd_t)); commands[ii] = cmd; cmd->v.v0.key = keys[ii]; cmd->v.v0.nkey = klens[ii]; cmd->v.v0.lock = (int)lock; cmd->v.v0.exptime = exp; /* NB: this assumes that sizeof(lcb_time_t) == sizeof(long) */ } retval = lcb_get(couchbase_res->handle, ctx, nkey, (const lcb_get_cmd_t * const *)commands); for (ii = 0; ii < nkey; ++ii) { efree(commands[ii]); } efree(commands); } if (LCB_SUCCESS != retval) { if (couchbase_res->prefix_key_len) { int i; for (i = 0; i < nkey; i++) { efree(keys[i]); } } efree(keys); efree(klens); efree(ctx); couchbase_report_error(INTERNAL_FUNCTION_PARAM_PASSTHRU, oo, cb_lcb_exception, "Failed to schedule delayed get request: %s", lcb_strerror(couchbase_res->handle, retval)); return; } couchbase_res->async = 1; couchbase_res->async_ctx = ctx; if (couchbase_res->prefix_key_len) { int i; for (i = 0; i < nkey; i++) { efree(keys[i]); } } efree(keys); efree(klens); if ( #if PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 2 fci.size #else callback #endif ) { zval *result, **ppzval, *retval_ptr = NULL; zval **params[2]; MAKE_STD_ZVAL(result); array_init(result); ctx->rv = result; pcbc_start_loop(couchbase_res); couchbase_res->async = 0; for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(result)); zend_hash_has_more_elements(Z_ARRVAL_P(result)) == SUCCESS; zend_hash_move_forward(Z_ARRVAL_P(result))) { if (zend_hash_get_current_data(Z_ARRVAL_P(result), (void **)&ppzval) == FAILURE) { continue; } params[0] = &res; params[1] = ppzval; #if PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 2 fci.retval_ptr_ptr = &retval_ptr; fci.param_count = 2; fci.params = params; zend_call_function(&fci, &fci_cache TSRMLS_CC); #else call_user_function_ex(EG(function_table), NULL, callback, &retval_ptr, 2, params, 0, NULL TSRMLS_CC); #endif if (retval_ptr != NULL) { zval_ptr_dtor(&retval_ptr); } } zval_ptr_dtor(&result); efree(ctx); } } RETURN_TRUE; }
PHP_COUCHBASE_LOCAL void php_couchbase_get_impl(INTERNAL_FUNCTION_PARAMETERS, int multi, int oo, int lock, int touch) { char *key, **keys; long *klens, klen = 0; int nkey = 0; long flag = 0; lcb_time_t exp = {0}; long expiry = 0; zval *res, *cas_token = NULL; int argflags; lcb_error_t retval; php_couchbase_res *couchbase_res; php_couchbase_ctx *ctx; argflags = oo ? PHP_COUCHBASE_ARG_F_OO : PHP_COUCHBASE_ARG_F_FUNCTIONAL; if (multi) { zval *akeys; zval **ppzval; zend_bool preserve_order; int i; if (lock) { PHP_COUCHBASE_GET_PARAMS_WITH_ZV(res, couchbase_res, argflags, "az|ll", &akeys, &cas_token, &flag, &expiry); } else if (touch) { PHP_COUCHBASE_GET_PARAMS_WITH_ZV(res, couchbase_res, argflags, "al|z", &akeys, &expiry, &cas_token); } else { PHP_COUCHBASE_GET_PARAMS_WITH_ZV(res, couchbase_res, argflags, "a|zl", &akeys, &cas_token, &flag); } nkey = zend_hash_num_elements(Z_ARRVAL_P(akeys)); keys = ecalloc(nkey, sizeof(char *)); klens = ecalloc(nkey, sizeof(long)); preserve_order = (flag & COUCHBASE_GET_PRESERVE_ORDER); array_init(return_value); for (i = 0, zend_hash_internal_pointer_reset(Z_ARRVAL_P(akeys)); zend_hash_has_more_elements(Z_ARRVAL_P(akeys)) == SUCCESS; zend_hash_move_forward(Z_ARRVAL_P(akeys)), i++) { if (zend_hash_get_current_data(Z_ARRVAL_P(akeys), (void **)&ppzval) == FAILURE) { nkey--; continue; } if (IS_ARRAY != Z_TYPE_PP(ppzval)) { convert_to_string_ex(ppzval); } if (!Z_STRLEN_PP(ppzval)) { nkey--; continue; } if (couchbase_res->prefix_key_len) { klens[i] = spprintf(&(keys[i]), 0, "%s_%s", couchbase_res->prefix_key, Z_STRVAL_PP(ppzval)); } else { keys[i] = Z_STRVAL_PP(ppzval); klens[i] = Z_STRLEN_PP(ppzval); } if (preserve_order) { add_assoc_null_ex(return_value, keys[i], klens[i] + 1); } } if (!nkey) { efree(keys); efree(klens); return; } if (cas_token && IS_ARRAY != Z_TYPE_P(cas_token)) { zval_dtor(cas_token); array_init(cas_token); } } else { if (lock) { PHP_COUCHBASE_GET_PARAMS_WITH_ZV(res, couchbase_res, argflags, "sz|l", &key, &klen, &cas_token, &expiry); } else if (touch) { PHP_COUCHBASE_GET_PARAMS_WITH_ZV(res, couchbase_res, argflags, "sl|z", &key, &klen, &expiry, &cas_token); } else { PHP_COUCHBASE_GET_PARAMS_WITH_ZV(res, couchbase_res, argflags, "s|z", &key, &klen, &cas_token); } if (!klen) { return; } nkey = 1; if (couchbase_res->prefix_key_len) { klen = spprintf(&key, 0, "%s_%s", couchbase_res->prefix_key, key); } keys = &key; klens = &klen; if (cas_token) { zval_dtor(cas_token); ZVAL_NULL(cas_token); } } { lcb_get_cmd_t **commands = ecalloc(nkey, sizeof(lcb_get_cmd_t *)); int ii; if (expiry) { exp = pcbc_check_expiry(expiry); } for (ii = 0; ii < nkey; ++ii) { lcb_get_cmd_t *cmd = ecalloc(1, sizeof(lcb_get_cmd_t)); commands[ii] = cmd; cmd->v.v0.key = keys[ii]; cmd->v.v0.nkey = klens[ii]; cmd->v.v0.lock = (int)lock; cmd->v.v0.exptime = exp; /* NB: this assumes sizeof(lcb_time_t) == sizeof(long) */ } ctx = ecalloc(1, sizeof(php_couchbase_ctx)); ctx->res = couchbase_res; ctx->rv = return_value; ctx->cas = cas_token; retval = lcb_get(couchbase_res->handle, ctx, nkey, (const lcb_get_cmd_t * const *)commands); for (ii = 0; ii < nkey; ++ii) { efree(commands[ii]); } efree(commands); if (LCB_SUCCESS != retval) { if (couchbase_res->prefix_key_len) { int i; for (i = 0; i < nkey; i++) { efree(keys[i]); } } if (multi) { efree(keys); efree(klens); zval_dtor(return_value); } efree(ctx); couchbase_report_error(INTERNAL_FUNCTION_PARAM_PASSTHRU, oo, cb_lcb_exception, "Failed to schedule get request: %s", lcb_strerror(couchbase_res->handle, retval)); return; } couchbase_res->seqno += nkey; pcbc_start_loop(couchbase_res); if (LCB_SUCCESS != ctx->res->rc) { if (LCB_KEY_ENOENT != ctx->res->rc) { couchbase_report_error(INTERNAL_FUNCTION_PARAM_PASSTHRU, oo, cb_lcb_exception, "Failed to get a value from server: %s", lcb_strerror(couchbase_res->handle, ctx->res->rc)); } } efree(ctx); if (couchbase_res->prefix_key_len) { int i; for (i = 0; i < nkey; i++) { efree(keys[i]); } } if (multi) { efree(keys); efree(klens); } } }
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; }