Ejemplo n.º 1
0
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);
	}
}
Ejemplo n.º 2
0
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);
}
Ejemplo n.º 3
0
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);
}
Ejemplo n.º 4
0
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);
}
Ejemplo n.º 5
0
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);
	}
}
Ejemplo n.º 6
0
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;
		}
	}
}
Ejemplo n.º 7
0
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;
}
Ejemplo n.º 8
0
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);
		}
	}
}
Ejemplo n.º 9
0
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;
}