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; }
PHP_COUCHBASE_LOCAL void php_couchbase_flush_impl(INTERNAL_FUNCTION_PARAMETERS, int oo) { php_couchbase_res *res; lcb_t instance; int argflags = oo ? PHP_COUCHBASE_ARG_F_OO : PHP_COUCHBASE_ARG_F_FUNCTIONAL; PHP_COUCHBASE_GET_PARAMS(res, argflags, ""); instance = res->handle; lcb_behavior_set_syncmode(instance, LCB_SYNCHRONOUS); if (COUCHBASE_G(restflush)) { do_rest_flush(INTERNAL_FUNCTION_PARAM_PASSTHRU, oo, res); } else { do_memcached_flush(INTERNAL_FUNCTION_PARAM_PASSTHRU, oo, res); } lcb_behavior_set_syncmode(instance, LCB_ASYNCHRONOUS); }
PHP_COUCHBASE_LOCAL void php_couchbase_stats_impl(INTERNAL_FUNCTION_PARAMETERS, int oo) { php_couchbase_res *couchbase_res; lcb_error_t retval; php_couchbase_ctx *ctx; lcb_server_stats_cmd_t cmd; const lcb_server_stats_cmd_t *const commands[] = { &cmd }; lcb_t instance; int argflags = oo ? PHP_COUCHBASE_ARG_F_OO : PHP_COUCHBASE_ARG_F_FUNCTIONAL; PHP_COUCHBASE_GET_PARAMS(couchbase_res, argflags, ""); ctx = ecalloc(1, sizeof(php_couchbase_ctx)); ctx->res = couchbase_res; ctx->rv = return_value; couchbase_res->rc = LCB_SUCCESS; instance = couchbase_res->handle; memset(&cmd, 0, sizeof(cmd)); lcb_behavior_set_syncmode(instance, LCB_SYNCHRONOUS); retval = lcb_server_stats(instance, (const void *)ctx, 1, commands); lcb_behavior_set_syncmode(instance, LCB_ASYNCHRONOUS); if (retval == LCB_SUCCESS) { retval = couchbase_res->rc; } else { couchbase_res->rc = retval; } efree(ctx); if (retval != LCB_SUCCESS) { couchbase_report_error(INTERNAL_FUNCTION_PARAM_PASSTHRU, oo, cb_lcb_exception, "Failed to stat: %s", lcb_strerror(instance, retval)); } }
static lcb_error_t do_remove(lcb_t instance, const void *key, uint16_t klen, lcb_cas_t *cas) { lcb_remove_cmd_t cmd; const lcb_remove_cmd_t *const commands[] = { &cmd }; struct remove_cookie rmc; lcb_error_t retval; memset(&cmd, 0, sizeof(cmd)); memset(&rmc, 0, sizeof(rmc)); cmd.v.v0.key = key; cmd.v.v0.nkey = klen; cmd.v.v0.cas = *cas; lcb_behavior_set_syncmode(instance, LCB_SYNCHRONOUS); retval = lcb_remove(instance, &rmc, 1, commands); lcb_behavior_set_syncmode(instance, LCB_ASYNCHRONOUS); if (retval == LCB_SUCCESS && rmc.error == LCB_SUCCESS) { *cas = rmc.cas; } return (retval == LCB_SUCCESS) ? rmc.error : retval; }
PHP_COUCHBASE_LOCAL void php_couchbase_delget_design_doc_impl(INTERNAL_FUNCTION_PARAMETERS, int oo, int rem) { char *path; char *name = NULL; long nname = 0; php_couchbase_res *couchbase_res; int argflags; lcb_t instance; lcb_error_t rc; struct http_ctx ctx; lcb_http_cmd_t cmd; lcb_http_complete_callback old; int len; if (oo) { argflags = PHP_COUCHBASE_ARG_F_OO; } else { argflags = PHP_COUCHBASE_ARG_F_FUNCTIONAL; } PHP_COUCHBASE_GET_PARAMS(couchbase_res, argflags, "s", &name, &nname); if (!nname) { couchbase_report_error(INTERNAL_FUNCTION_PARAM_PASSTHRU, oo, cb_illegal_key_exception, "You have to specify the name of the design doc"); return; } memset(&ctx, 0, sizeof(ctx)); memset(&cmd, 0, sizeof(cmd)); instance = couchbase_res->handle; path = ecalloc(1, 80 + nname); len = sprintf(path, "/_design/%*s", (int)nname, name); cmd.v.v0.path = path; cmd.v.v0.npath = len; if (rem) { cmd.v.v0.method = LCB_HTTP_METHOD_DELETE; } else { cmd.v.v0.method = LCB_HTTP_METHOD_GET; } cmd.v.v0.content_type = "application/json"; old = lcb_set_http_complete_callback(instance, http_callback); lcb_behavior_set_syncmode(instance, LCB_SYNCHRONOUS); rc = lcb_make_http_request(instance, &ctx, LCB_HTTP_TYPE_VIEW, &cmd, NULL); lcb_behavior_set_syncmode(instance, LCB_ASYNCHRONOUS); old = lcb_set_http_complete_callback(instance, old); efree(path); if (rc == LCB_SUCCESS) { rc = ctx.error; } couchbase_res->rc = rc; if (rc != LCB_SUCCESS) { /* An error occured occurred on libcouchbase level */ efree(ctx.payload); couchbase_report_error(INTERNAL_FUNCTION_PARAM_PASSTHRU, oo, cb_lcb_exception, "Failed to retrieve design doc: %s", lcb_strerror(instance, rc)); return; } switch (ctx.status) { case LCB_HTTP_STATUS_OK: if (rem) { efree(ctx.payload); RETURN_TRUE; } else { RETURN_STRING(ctx.payload, 0); } /* not reached */ case LCB_HTTP_STATUS_NOT_FOUND: efree(ctx.payload); RETURN_FALSE; case LCB_HTTP_STATUS_UNAUTHORIZED: couchbase_report_error(INTERNAL_FUNCTION_PARAM_PASSTHRU, oo, cb_auth_exception, "Incorrect credentials"); break; default: if (ctx.payload == NULL) { couchbase_report_error(INTERNAL_FUNCTION_PARAM_PASSTHRU, oo, cb_server_exception, "{\"errors\":{\"http response\": %d }}", (int)ctx.status); } else { couchbase_report_error(INTERNAL_FUNCTION_PARAM_PASSTHRU, oo, cb_server_exception, ctx.payload); } } efree(ctx.payload); }
PHP_COUCHBASE_LOCAL void php_couchbase_list_design_docs_impl(INTERNAL_FUNCTION_PARAMETERS, int oo) { php_couchbase_res *couchbase_res; int argflags; lcb_t instance; lcb_error_t rc; struct http_ctx ctx; lcb_http_cmd_t cmd; lcb_http_complete_callback old; int len; char *path; if (oo) { argflags = PHP_COUCHBASE_ARG_F_OO; } else { argflags = PHP_COUCHBASE_ARG_F_FUNCTIONAL; } PHP_COUCHBASE_GET_PARAMS(couchbase_res, argflags, ""); instance = couchbase_res->handle; memset(&ctx, 0, sizeof(ctx)); memset(&cmd, 0, sizeof(cmd)); path = ecalloc(strlen(couchbase_res->bucket) + 80, 1); len = sprintf(path, "/pools/default/buckets/%s/ddocs", couchbase_res->bucket); cmd.v.v0.path = path; cmd.v.v0.npath = len; cmd.v.v0.method = LCB_HTTP_METHOD_GET; cmd.v.v0.content_type = "application/json"; old = lcb_set_http_complete_callback(instance, http_callback); lcb_behavior_set_syncmode(instance, LCB_SYNCHRONOUS); rc = lcb_make_http_request(instance, &ctx, LCB_HTTP_TYPE_MANAGEMENT, &cmd, NULL); lcb_behavior_set_syncmode(instance, LCB_ASYNCHRONOUS); old = lcb_set_http_complete_callback(instance, old); efree(path); if (rc == LCB_SUCCESS) { rc = ctx.error; } couchbase_res->rc = rc; if (rc != LCB_SUCCESS) { /* An error occured occurred on libcouchbase level */ efree(ctx.payload); couchbase_report_error(INTERNAL_FUNCTION_PARAM_PASSTHRU, oo, cb_lcb_exception, "Failed to retrieve design doc: %s", lcb_strerror(instance, rc)); return; } switch (ctx.status) { case LCB_HTTP_STATUS_OK: RETURN_STRING(ctx.payload, 0); case LCB_HTTP_STATUS_UNAUTHORIZED: couchbase_report_error(INTERNAL_FUNCTION_PARAM_PASSTHRU, oo, cb_auth_exception, "Incorrect credentials"); break; default: if (ctx.payload == NULL) { couchbase_report_error(INTERNAL_FUNCTION_PARAM_PASSTHRU, oo, cb_server_exception, "{\"errors\":{\"http response\": %d }}", (int)ctx.status); } else { couchbase_report_error(INTERNAL_FUNCTION_PARAM_PASSTHRU, oo, cb_server_exception, ctx.payload); } } efree(ctx.payload); }
couchbase_con* couchbase_connect(struct cachedb_id* id, int is_reconnect) { couchbase_con *con; struct lcb_create_st options; lcb_t instance; lcb_error_t rc; if (id == NULL) { LM_ERR("null cachedb_id\n"); return 0; } con = pkg_malloc(sizeof(couchbase_con)); if (con == NULL) { LM_ERR("no more pkg \n"); return 0; } memset(con,0,sizeof(couchbase_con)); con->id = id; con->ref = 1; /* TODO - support custom ports - couchbase expects host:port in id->host */ memset(&options,0,sizeof(struct lcb_create_st)); options.version = 0; options.v.v0.host = id->host; options.v.v0.user = id->username; options.v.v0.passwd = id->password; options.v.v0.bucket = id->database; rc=lcb_create(&instance, &options); if (rc!=LCB_SUCCESS) { LM_ERR("Failed to create libcouchbase instance: 0x%02x, %s\n", rc, lcb_strerror(NULL, rc)); return 0; } (void)lcb_set_error_callback(instance, couchbase_error_cb); (void)lcb_set_get_callback(instance, couchbase_get_cb); (void)lcb_set_store_callback(instance, couchbase_store_cb); (void)lcb_set_remove_callback(instance, couchbase_remove_cb); (void)lcb_set_arithmetic_callback(instance,couchbase_arithmetic_cb); (void)lcb_set_timeout(instance,couch_timeout_usec); //Set to synchronous mode lcb_behavior_set_syncmode(instance, LCB_SYNCHRONOUS); if (couch_lazy_connect == 0 || is_reconnect == 1) { rc=lcb_connect(instance); /*Check connection*/ if (rc != LCB_SUCCESS) { /*Consider these connect failurs as fatal*/ if(rc == LCB_AUTH_ERROR || rc == LCB_INVALID_HOST_FORMAT || rc == LCB_INVALID_CHAR) { LM_ERR("Fatal connection error to Couchbase. Host: %s Bucket: %s Error: %s", id->host, id->database, lcb_strerror(instance, rc)); lcb_destroy(instance); return 0; } else { /* Non-fatal errors, we may be able to connect later */ LM_ERR("Non-Fatal connection error to Couchbase. Host: %s Bucket: %s Error: %s", id->host, id->database, lcb_strerror(instance, rc)); } } else { LM_DBG("Succesfully connected to Couchbase Server. Host: %s Bucket: %s\n", id->host, id->database); } } con->couchcon = instance; return con; }
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)); } }
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; }
PHP_COUCHBASE_LOCAL void php_couchbase_touch_impl(INTERNAL_FUNCTION_PARAMETERS, int oo) { struct touch_cookie cookie; char *key = NULL; long nkey = 0; lcb_time_t exp = 0; long expiry; php_couchbase_res *couchbase_res; int argflags; lcb_t instance; lcb_error_t retval; lcb_touch_cmd_t cmd; const lcb_touch_cmd_t *const commands[] = { &cmd }; /* parameter handling and return_value setup: */ if (oo) { argflags = PHP_COUCHBASE_ARG_F_OO; } else { argflags = PHP_COUCHBASE_ARG_F_FUNCTIONAL; } PHP_COUCHBASE_GET_PARAMS(couchbase_res, argflags, "sl", &key, &nkey, &expiry); if (!nkey) { couchbase_report_error(INTERNAL_FUNCTION_PARAM_PASSTHRU, oo, cb_illegal_key_exception, "No key specified: Empty key"); return; } if (couchbase_res->prefix_key_len) { nkey = spprintf(&key, 0, "%s_%s", couchbase_res->prefix_key, key); } if (expiry) { exp = pcbc_check_expiry(expiry); } memset(&cmd, 0, sizeof(cmd)); cmd.v.v0.key = key; cmd.v.v0.nkey = nkey; cmd.v.v0.exptime = exp; instance = couchbase_res->handle; cookie.error = LCB_ERROR; lcb_set_touch_callback(instance, single_touch_callback); lcb_behavior_set_syncmode(instance, LCB_SYNCHRONOUS); retval = lcb_touch(instance, &cookie, 1, commands); lcb_behavior_set_syncmode(instance, LCB_ASYNCHRONOUS); if (retval == LCB_SUCCESS) { retval = cookie.error; } couchbase_res->rc = retval; if (couchbase_res->prefix_key_len) { efree(key); } if (retval != LCB_SUCCESS) { couchbase_report_error(INTERNAL_FUNCTION_PARAM_PASSTHRU, oo, cb_lcb_exception, "Failed to touch key: %s", lcb_strerror(instance, retval)); return; } else { Z_TYPE_P(return_value) = IS_STRING; Z_STRLEN_P(return_value) = spprintf(&(Z_STRVAL_P(return_value)), 0, "%llu", cookie.cas); } }
PHP_COUCHBASE_LOCAL void php_couchbase_touch_multi_impl(INTERNAL_FUNCTION_PARAMETERS, int oo) { int argflags; int idx = 0; int ii; lcb_error_t retval; lcb_t instance; lcb_time_t exp = 0; lcb_touch_cmd_t **commands; lcb_touch_cmd_t *cmd; long expiry; php_couchbase_res *couchbase_res; struct multi_touch_cookie cookie; zval **ppzval; zval *arr_keys; /* parameter handling and return_value setup: */ if (oo) { argflags = PHP_COUCHBASE_ARG_F_OO; } else { argflags = PHP_COUCHBASE_ARG_F_FUNCTIONAL; } PHP_COUCHBASE_GET_PARAMS(couchbase_res, argflags, "al", &arr_keys, &expiry); instance = couchbase_res->handle; memset(&cookie, 0, sizeof(cookie)); cookie.nkeys = zend_hash_num_elements(Z_ARRVAL_P(arr_keys)); cookie.keys = ecalloc(cookie.nkeys, sizeof(struct touch_cookie)); for (ii = 0, zend_hash_internal_pointer_reset(Z_ARRVAL_P(arr_keys)); zend_hash_has_more_elements(Z_ARRVAL_P(arr_keys)) == SUCCESS; zend_hash_move_forward(Z_ARRVAL_P(arr_keys)), ii++) { if (zend_hash_get_current_data(Z_ARRVAL_P(arr_keys), (void **)&ppzval) == FAILURE) { continue; } if (IS_ARRAY != Z_TYPE_PP(ppzval)) { convert_to_string_ex(ppzval); } if (!Z_STRLEN_PP(ppzval)) { continue; } if (couchbase_res->prefix_key_len) { cookie.keys[idx].nkey = spprintf(&(cookie.keys[idx].key), 0, "%s_%s", couchbase_res->prefix_key, Z_STRVAL_PP(ppzval)); } else { cookie.keys[idx].key = Z_STRVAL_PP(ppzval); cookie.keys[idx].nkey = Z_STRLEN_PP(ppzval); } ++idx; } if (idx == 0) { efree(cookie.keys); couchbase_report_error(INTERNAL_FUNCTION_PARAM_PASSTHRU, oo, cb_illegal_key_exception, "No keys specified"); return; } if (expiry) { exp = pcbc_check_expiry(expiry); } cmd = ecalloc(idx, sizeof(lcb_touch_cmd_t)); commands = ecalloc(idx, sizeof(lcb_touch_cmd_t *)); for (ii = 0; ii < idx; ++ii) { cmd[ii].v.v0.key = cookie.keys[ii].key; cmd[ii].v.v0.nkey = cookie.keys[ii].nkey; cmd[ii].v.v0.exptime = exp; commands[ii] = cmd + ii; } lcb_set_touch_callback(instance, multi_touch_callback); lcb_behavior_set_syncmode(instance, LCB_SYNCHRONOUS); retval = lcb_touch(instance, &cookie, idx, (const lcb_touch_cmd_t * const *)commands); lcb_behavior_set_syncmode(instance, LCB_ASYNCHRONOUS); if (retval == LCB_SUCCESS) { retval = cookie.error; } couchbase_res->rc = retval; if (retval == LCB_SUCCESS) { /* Time to build up the array with the keys we found etc */ array_init(return_value); for (ii = 0; ii < idx; ++ii) { char *k = cookie.keys[ii].key; if (cookie.keys[ii].error == LCB_SUCCESS) { char cas[80]; snprintf(cas, sizeof(cas), "%llu", (unsigned long long)cookie.keys[ii].cas); add_assoc_string(return_value, k, cas, 1); } else { add_assoc_bool(return_value, k, (zend_bool)0); } } } else { couchbase_report_error(INTERNAL_FUNCTION_PARAM_PASSTHRU, oo, cb_lcb_exception, "Failed to touch key: %s", lcb_strerror(instance, retval)); } /* Release allocated memory */ efree(cmd); efree(commands); if (couchbase_res->prefix_key_len) { for (ii = 0; ii < idx; ++ii) { efree(cookie.keys[ii].key); } } efree(cookie.keys); }