Ejemplo n.º 1
0
static void get_callback(lcb_t instance, const void *cookie, lcb_error_t err, 
   const lcb_get_resp_t *resp)
{
    //  If you can't read from active, read from replica.
    if (err != LCB_SUCCESS && flag == 0 ) {
        printf("REPLICA\t");
        printf("Failed to read from active copy: %s\n", lcb_strerror(instance,err));
        fprintf(stderr, "Reading from REPLICA. Failed to read from active copy: %s\n", lcb_strerror(instance,err));

        lcb_get_replica_cmd_t rcmd = {0};
        const lcb_get_replica_cmd_t *rcmdlist = &rcmd;
        rcmd.v.v1.key = resp->v.v0.key;
        rcmd.v.v1.nkey = (int)resp->v.v0.nkey;
        rcmd.v.v1.strategy = LCB_REPLICA_FIRST;
        err = lcb_get_replica(instance, NULL, 1, &rcmdlist);
        flag=1;
        lcb_wait(instance); // get_replica_callback is invoked here

    }
    else if (err != LCB_SUCCESS && flag == 1){
        // If you fail to read from active and replica, just print the below message and the key.
        flag=0;
        printf("Failed to read from replica too: %s \n",lcb_strerror(instance,err));
        fprintf(stderr, "Failed to read from replica too: %s\n", lcb_strerror(instance, err));
        }
    else {
        // If you were able to get the key, print the key and value.
        printf("Retrieved key %.*s\t\t", (int)resp->v.v0.nkey, resp->v.v0.key);
        printf("Value is %.*s\n", (int)resp->v.v0.nbytes, resp->v.v0.bytes);
        fprintf(stderr, "Retrieved key %.*s\t value is %.*s\n", (int)resp->v.v0.nkey, resp->v.v0.key, (int)resp->v.v0.nbytes, resp->v.v0.bytes);
        flag=0;
    }

}
Ejemplo n.º 2
0
/*
 * Obtain an object stored in Couchbase by given key.
 *
 * @since 1.0.0
 *
 * @see http://couchbase.com/docs/couchbase-manual-2.0/couchbase-architecture-apis-memcached-protocol-additions.html#couchbase-architecture-apis-memcached-protocol-additions-getl
 *
 * @overload get(*keys, options = {})
 *   @param keys [String, Symbol, Array] One or several keys to fetch
 *   @param options [Hash] Options for operation.
 *   @option options [true, false] :extended (false) If set to +true+, the
 *     operation will return a tuple +[value, flags, cas]+, otherwise (by
 *     default) it returns just the value.
 *   @option options [Fixnum] :ttl (self.default_ttl) Expiry time for key.
 *     Values larger than 30*24*60*60 seconds (30 days) are interpreted as
 *     absolute times (from the epoch).
 *   @option options [true, false] :quiet (self.quiet) If set to +true+, the
 *     operation won't raise error for missing key, it will return +nil+.
 *     Otherwise it will raise error in synchronous mode. In asynchronous
 *     mode this option ignored.
 *   @option options [Symbol] :format (nil) Explicitly choose the decoder
 *     for this key (+:plain+, +:document+, +:marshal+). See
 *     {Bucket#default_format}.
 *   @option options [Fixnum, Boolean] :lock Lock the keys for time span.
 *     If this parameter is +true+ the key(s) will be locked for default
 *     timeout. Also you can use number to setup your own timeout in
 *     seconds. If it will be lower that zero or exceed the maximum, the
 *     server will use default value. You can determine actual default and
 *     maximum values calling {Bucket#stats} without arguments and
 *     inspecting keys  "ep_getl_default_timeout" and "ep_getl_max_timeout"
 *     correspondingly. See overloaded hash syntax to specify custom timeout
 *     per each key.
 *   @option options [true, false] :assemble_hash (false) Assemble Hash for
 *     results. Hash assembled automatically if +:extended+ option is true
 *     or in case of "get and touch" multimple keys.
 *   @option options [true, false, :all, :first, Fixnum] :replica
 *     (false) Read key from replica node. Options +:ttl+ and +:lock+
 *     are not compatible with +:replica+. Value +true+ is a synonym to
 *     +:first+, which means sequentially iterate over all replicas
 *     and return first successful response, skipping all failures.
 *     It is also possible to query all replicas in parallel using
 *     the +:all+ option, or pass a replica index, starting from zero.
 *
 *   @yieldparam ret [Result] the result of operation in asynchronous mode
 *     (valid attributes: +error+, +operation+, +key+, +value+, +flags+,
 *     +cas+).
 *
 *   @return [Object, Array, Hash] the value(s) (or tuples in extended mode)
 *     associated with the key.
 *
 *   @raise [Couchbase::Error::NotFound] if the key is missing in the
 *     bucket.
 *
 *   @raise [Couchbase::Error::Connect] if connection closed (see {Bucket#reconnect})
 *
 *   @raise [ArgumentError] when passing the block in synchronous mode
 *
 *   @example Get single value in quiet mode (the default)
 *     c.get("foo")     #=> the associated value or nil
 *
 *   @example Use alternative hash-like syntax
 *     c["foo"]         #=> the associated value or nil
 *
 *   @example Get single value in verbose mode
 *     c.get("missing-foo", :quiet => false)  #=> raises Couchbase::NotFound
 *     c.get("missing-foo", :quiet => true)   #=> returns nil
 *
 *   @example Get and touch single value. The key won't be accessible after 10 seconds
 *     c.get("foo", :ttl => 10)
 *
 *   @example Extended get
 *     val, flags, cas = c.get("foo", :extended => true)
 *
 *   @example Get multiple keys
 *     c.get("foo", "bar", "baz")   #=> [val1, val2, val3]
 *
 *   @example Get multiple keys with assembing result into the Hash
 *     c.get("foo", "bar", "baz", :assemble_hash => true)
 *     #=> {"foo" => val1, "bar" => val2, "baz" => val3}
 *
 *   @example Extended get multiple keys
 *     c.get("foo", "bar", :extended => true)
 *     #=> {"foo" => [val1, flags1, cas1], "bar" => [val2, flags2, cas2]}
 *
 *   @example Asynchronous get
 *     c.run do
 *       c.get("foo", "bar", "baz") do |res|
 *         ret.operation   #=> :get
 *         ret.success?    #=> true
 *         ret.key         #=> "foo", "bar" or "baz" in separate calls
 *         ret.value
 *         ret.flags
 *         ret.cas
 *       end
 *     end
 *
 *   @example Get and lock key using default timeout
 *     c.get("foo", :lock => true)
 *
 *   @example Determine lock timeout parameters
 *     c.stats.values_at("ep_getl_default_timeout", "ep_getl_max_timeout")
 *     #=> [{"127.0.0.1:11210"=>"15"}, {"127.0.0.1:11210"=>"30"}]
 *
 *   @example Get and lock key using custom timeout
 *     c.get("foo", :lock => 3)
 *
 *   @example Get and lock multiple keys using custom timeout
 *     c.get("foo", "bar", :lock => 3)
 *
 * @overload get(keys, options = {})
 *   When the method receive hash map, it will behave like it receive list
 *   of keys (+keys.keys+), but also touch each key setting expiry time to
 *   the corresponding value. But unlike usual get this command always
 *   return hash map +{key => value}+ or +{key => [value, flags, cas]}+.
 *
 *   @param keys [Hash] Map key-ttl
 *   @param options [Hash] Options for operation. (see options definition
 *     above)
 *
 *   @return [Hash] the values (or tuples in extended mode) associated with
 *     the keys.
 *
 *   @example Get and touch multiple keys
 *     c.get("foo" => 10, "bar" => 20)   #=> {"foo" => val1, "bar" => val2}
 *
 *   @example Extended get and touch multiple keys
 *     c.get({"foo" => 10, "bar" => 20}, :extended => true)
 *     #=> {"foo" => [val1, flags1, cas1], "bar" => [val2, flags2, cas2]}
 *
 *   @example Get and lock multiple keys for chosen period in seconds
 *     c.get("foo" => 10, "bar" => 20, :lock => true)
 *     #=> {"foo" => val1, "bar" => val2}
 */
    VALUE
cb_bucket_get(int argc, VALUE *argv, VALUE self)
{
    struct cb_bucket_st *bucket = DATA_PTR(self);
    struct cb_context_st *ctx;
    VALUE rv, proc, exc;
    size_t ii;
    lcb_error_t err = LCB_SUCCESS;
    struct cb_params_st params;

    if (!cb_bucket_connected_bang(bucket, cb_sym_get)) {
        return Qnil;
    }

    memset(&params, 0, sizeof(struct cb_params_st));
    rb_scan_args(argc, argv, "0*&", &params.args, &proc);
    if (!bucket->async && proc != Qnil) {
        rb_raise(rb_eArgError, "synchronous mode doesn't support callbacks");
    }
    params.type = cb_cmd_get;
    params.bucket = bucket;
    params.cmd.get.keys_ary = rb_ary_new();
    cb_params_build(&params);
    ctx = cb_context_alloc_common(bucket, proc, params.cmd.get.num);
    ctx->extended = params.cmd.get.extended;
    ctx->quiet = params.cmd.get.quiet;
    ctx->transcoder = params.cmd.get.transcoder;
    ctx->transcoder_opts = params.cmd.get.transcoder_opts;
    if (RTEST(params.cmd.get.replica)) {
        if (params.cmd.get.replica == cb_sym_all) {
            ctx->nqueries = lcb_get_num_replicas(bucket->handle);
            ctx->all_replicas = 1;
        }
        err = lcb_get_replica(bucket->handle, (const void *)ctx,
                params.cmd.get.num, params.cmd.get.ptr_gr);
    } else {
        err = lcb_get(bucket->handle, (const void *)ctx,
                params.cmd.get.num, params.cmd.get.ptr);
    }
    cb_params_destroy(&params);
    exc = cb_check_error(err, "failed to schedule get request", Qnil);
    if (exc != Qnil) {
        cb_context_free(ctx);
        rb_exc_raise(exc);
    }
    bucket->nbytes += params.npayload;
    if (bucket->async) {
        cb_maybe_do_loop(bucket);
        return Qnil;
    } else {
        if (ctx->nqueries > 0) {
            /* we have some operations pending */
            lcb_wait(bucket->handle);
        }
        exc = ctx->exception;
        rv = ctx->rv;
        cb_context_free(ctx);
        if (exc != Qnil) {
            rb_exc_raise(exc);
        }
        exc = bucket->exception;
        if (exc != Qnil) {
            bucket->exception = Qnil;
            rb_exc_raise(exc);
        }
        if (params.cmd.get.gat || params.cmd.get.assemble_hash ||
                (params.cmd.get.extended && (params.cmd.get.num > 1 || params.cmd.get.array))) {
            return rv;  /* return as a hash {key => [value, flags, cas], ...} */
        }
        if (params.cmd.get.num > 1 || params.cmd.get.array) {
            VALUE keys, ret;
            ret = rb_ary_new();
            /* make sure ret is guarded so not invisible in a register
             * when stack scanning */
            RB_GC_GUARD(ret);
            keys = params.cmd.get.keys_ary;
            for (ii = 0; ii < params.cmd.get.num; ++ii) {
                rb_ary_push(ret, rb_hash_aref(rv, rb_ary_entry(keys, ii)));
            }
            return ret;  /* return as an array [value1, value2, ...] */
        } else {
            VALUE vv = Qnil;
            rb_hash_foreach(rv, cb_first_value_i, (VALUE)&vv);
            return vv;
        }
    }
}
Ejemplo n.º 3
0
PHP_COUCHBASE_LOCAL
void php_couchbase_get_impl(INTERNAL_FUNCTION_PARAMETERS,
							int multi, int oo, int lock, int touch, int replica)
{
	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;
	zend_fcall_info fci = {0};
	zend_fcall_info_cache fci_cache;

	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|f!z", &key, &klen,
											 &fci, &fci_cache,
											 &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);
		}
	}
	if (replica) {
		lcb_get_replica_cmd_t **commands = ecalloc(nkey, sizeof(lcb_get_replica_cmd_t *));
		int ii;

		for (ii = 0; ii < nkey; ++ii) {
			lcb_get_replica_cmd_t *cmd = ecalloc(1, sizeof(lcb_get_replica_cmd_t));
			commands[ii] = cmd;
			cmd->v.v0.key = keys[ii];
			cmd->v.v0.nkey = klens[ii];
		}

		ctx = ecalloc(1, sizeof(php_couchbase_ctx));
		ctx->res = couchbase_res;
		ctx->rv	 = return_value;
		ctx->cas = cas_token;

		retval = lcb_get_replica(couchbase_res->handle, ctx,
								 nkey, (const lcb_get_replica_cmd_t * const *)commands);
		for (ii = 0; ii < nkey; ++ii) {
			efree(commands[ii]);
		}
		efree(commands);
	} else {
		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 (ctx->res->rc != LCB_SUCCESS) {
		if (!multi) {
			RETVAL_FALSE;
		}
		if (ctx->res->rc == LCB_KEY_ENOENT) {
			if (fci.size) {
				zval *result;
				zval *zkey;
				zval *retval_ptr = NULL;
				zval **params[3];
				int cbret;

				MAKE_STD_ZVAL(result);
				MAKE_STD_ZVAL(zkey);
				ZVAL_NULL(result);
				ZVAL_STRINGL(zkey, key, klen, 1);

				params[0] = &res;
				params[1] = &zkey;
				params[2] = &result;
				fci.retval_ptr_ptr = &retval_ptr;
				fci.param_count = 3;
				fci.params = params;

				cbret = zend_call_function(&fci, &fci_cache TSRMLS_CC);

				if (cbret == SUCCESS && fci.retval_ptr_ptr && *fci.retval_ptr_ptr) {
					if (Z_TYPE_P(retval_ptr) == IS_BOOL && Z_BVAL_P(retval_ptr)) {
						zval_ptr_dtor(fci.retval_ptr_ptr);
						zval_ptr_dtor(&zkey);
						efree(ctx);
						if (multi) {
							zval_dtor(return_value);
						}
						RETURN_ZVAL(result, 1, 1);
					}
					zval_ptr_dtor(fci.retval_ptr_ptr);
				}
				zval_ptr_dtor(&zkey);
				zval_ptr_dtor(&result);
			}
		} else {
			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);
	}
}