couchbase 1.3.4-x64-mingw32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/.travis.yml +22 -0
- data/.yardopts +5 -0
- data/CONTRIBUTING.markdown +75 -0
- data/Gemfile +4 -0
- data/LICENSE +201 -0
- data/Makefile +3 -0
- data/README.markdown +649 -0
- data/RELEASE_NOTES.markdown +796 -0
- data/Rakefile +20 -0
- data/couchbase.gemspec +49 -0
- data/examples/chat-em/Gemfile +7 -0
- data/examples/chat-em/README.markdown +45 -0
- data/examples/chat-em/server.rb +82 -0
- data/examples/chat-goliath-grape/Gemfile +5 -0
- data/examples/chat-goliath-grape/README.markdown +50 -0
- data/examples/chat-goliath-grape/app.rb +67 -0
- data/examples/chat-goliath-grape/config/app.rb +20 -0
- data/examples/transcoders/Gemfile +3 -0
- data/examples/transcoders/README.markdown +59 -0
- data/examples/transcoders/cb-zcat +40 -0
- data/examples/transcoders/cb-zcp +45 -0
- data/examples/transcoders/gzip_transcoder.rb +49 -0
- data/examples/transcoders/options.rb +54 -0
- data/ext/couchbase_ext/.gitignore +4 -0
- data/ext/couchbase_ext/arguments.c +956 -0
- data/ext/couchbase_ext/arithmetic.c +307 -0
- data/ext/couchbase_ext/bucket.c +1370 -0
- data/ext/couchbase_ext/context.c +65 -0
- data/ext/couchbase_ext/couchbase_ext.c +1364 -0
- data/ext/couchbase_ext/couchbase_ext.h +644 -0
- data/ext/couchbase_ext/delete.c +163 -0
- data/ext/couchbase_ext/eventmachine_plugin.c +452 -0
- data/ext/couchbase_ext/extconf.rb +168 -0
- data/ext/couchbase_ext/get.c +316 -0
- data/ext/couchbase_ext/gethrtime.c +129 -0
- data/ext/couchbase_ext/http.c +432 -0
- data/ext/couchbase_ext/multithread_plugin.c +1090 -0
- data/ext/couchbase_ext/observe.c +171 -0
- data/ext/couchbase_ext/plugin_common.c +171 -0
- data/ext/couchbase_ext/result.c +129 -0
- data/ext/couchbase_ext/stats.c +163 -0
- data/ext/couchbase_ext/store.c +542 -0
- data/ext/couchbase_ext/timer.c +192 -0
- data/ext/couchbase_ext/touch.c +186 -0
- data/ext/couchbase_ext/unlock.c +176 -0
- data/ext/couchbase_ext/utils.c +551 -0
- data/ext/couchbase_ext/version.c +142 -0
- data/lib/action_dispatch/middleware/session/couchbase_store.rb +38 -0
- data/lib/active_support/cache/couchbase_store.rb +430 -0
- data/lib/couchbase.rb +155 -0
- data/lib/couchbase/bucket.rb +457 -0
- data/lib/couchbase/cluster.rb +119 -0
- data/lib/couchbase/connection_pool.rb +58 -0
- data/lib/couchbase/constants.rb +12 -0
- data/lib/couchbase/result.rb +26 -0
- data/lib/couchbase/transcoder.rb +120 -0
- data/lib/couchbase/utils.rb +62 -0
- data/lib/couchbase/version.rb +21 -0
- data/lib/couchbase/view.rb +506 -0
- data/lib/couchbase/view_row.rb +272 -0
- data/lib/ext/multi_json_fix.rb +56 -0
- data/lib/rack/session/couchbase.rb +108 -0
- data/tasks/benchmark.rake +6 -0
- data/tasks/compile.rake +158 -0
- data/tasks/test.rake +100 -0
- data/tasks/util.rake +21 -0
- data/test/profile/.gitignore +1 -0
- data/test/profile/Gemfile +6 -0
- data/test/profile/benchmark.rb +195 -0
- data/test/setup.rb +178 -0
- data/test/test_arithmetic.rb +185 -0
- data/test/test_async.rb +316 -0
- data/test/test_bucket.rb +250 -0
- data/test/test_cas.rb +235 -0
- data/test/test_couchbase.rb +77 -0
- data/test/test_couchbase_connection_pool.rb +77 -0
- data/test/test_couchbase_rails_cache_store.rb +361 -0
- data/test/test_delete.rb +120 -0
- data/test/test_errors.rb +82 -0
- data/test/test_eventmachine.rb +70 -0
- data/test/test_format.rb +164 -0
- data/test/test_get.rb +407 -0
- data/test/test_stats.rb +57 -0
- data/test/test_store.rb +216 -0
- data/test/test_timer.rb +42 -0
- data/test/test_touch.rb +97 -0
- data/test/test_unlock.rb +119 -0
- data/test/test_utils.rb +58 -0
- data/test/test_version.rb +52 -0
- metadata +336 -0
@@ -0,0 +1,168 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# Author:: Couchbase <info@couchbase.com>
|
3
|
+
# Copyright:: 2011, 2012 Couchbase, Inc.
|
4
|
+
# License:: Apache License, Version 2.0
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
18
|
+
|
19
|
+
require 'rbconfig'
|
20
|
+
# This hack is more robust, because in bundler environment bundler touches
|
21
|
+
# all constants from rbconfig.rb before loading any scripts. This is why
|
22
|
+
# RC_ARCHS doesn't work under bundler on MacOS.
|
23
|
+
if RUBY_PLATFORM =~ /darwin/ && defined?(RbConfig::ARCHFLAGS)
|
24
|
+
[RbConfig::CONFIG, RbConfig::MAKEFILE_CONFIG].each do |cfg|
|
25
|
+
cfg["CFLAGS"].gsub!(RbConfig::ARCHFLAGS, '')
|
26
|
+
cfg["LDFLAGS"].gsub!(RbConfig::ARCHFLAGS, '')
|
27
|
+
cfg["LDSHARED"].gsub!(RbConfig::ARCHFLAGS, '')
|
28
|
+
cfg["LIBRUBY_LDSHARED"].gsub!(RbConfig::ARCHFLAGS, '')
|
29
|
+
cfg["configure_args"].gsub!(RbConfig::ARCHFLAGS, '')
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Unset RUBYOPT to avoid interferences
|
34
|
+
ENV['RUBYOPT'] = nil
|
35
|
+
|
36
|
+
require 'mkmf'
|
37
|
+
|
38
|
+
def define(macro, value = nil)
|
39
|
+
$defs.push("-D #{[macro.upcase, value].compact.join('=')}")
|
40
|
+
end
|
41
|
+
|
42
|
+
($CFLAGS ||= "") << " #{ENV["CFLAGS"]}"
|
43
|
+
($LDFLAGS ||= "") << " #{ENV["LDFLAGS"]}"
|
44
|
+
($LIBS ||= "") << " #{ENV["LIBS"]}"
|
45
|
+
|
46
|
+
$CFLAGS << ' -std=c99 -Wall -Wextra '
|
47
|
+
if ENV['DEBUG']
|
48
|
+
$CFLAGS << ' -O0 -ggdb3 -pedantic '
|
49
|
+
else
|
50
|
+
$CFLAGS << ' -O2'
|
51
|
+
$LDFLAGS << ' -Wl,--strip-debug' if RbConfig::CONFIG['target_os'] =~ /mingw32/
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
if RbConfig::CONFIG['target_os'] =~ /mingw32/
|
56
|
+
dir_config("libcouchbase")
|
57
|
+
else
|
58
|
+
LIBDIR = RbConfig::CONFIG['libdir']
|
59
|
+
INCLUDEDIR = RbConfig::CONFIG['includedir']
|
60
|
+
|
61
|
+
HEADER_DIRS = [
|
62
|
+
# First search /opt/local for macports
|
63
|
+
'/opt/local/include',
|
64
|
+
# Then search /usr/local for people that installed from source
|
65
|
+
'/usr/local/include',
|
66
|
+
# Check the ruby install locations
|
67
|
+
INCLUDEDIR,
|
68
|
+
# Finally fall back to /usr
|
69
|
+
'/usr/include'
|
70
|
+
]
|
71
|
+
|
72
|
+
LIB_DIRS = [
|
73
|
+
# First search /opt/local for macports
|
74
|
+
'/opt/local/lib',
|
75
|
+
# Then search /usr/local for people that installed from source
|
76
|
+
'/usr/local/lib',
|
77
|
+
# Check the ruby install locations
|
78
|
+
LIBDIR,
|
79
|
+
# Finally fall back to /usr
|
80
|
+
'/usr/lib'
|
81
|
+
]
|
82
|
+
|
83
|
+
# For people using homebrew
|
84
|
+
brew_prefix = `brew --prefix libevent 2> /dev/null`.chomp
|
85
|
+
unless brew_prefix.empty?
|
86
|
+
LIB_DIRS.unshift File.join(brew_prefix, 'lib')
|
87
|
+
HEADER_DIRS.unshift File.join(brew_prefix, 'include')
|
88
|
+
end
|
89
|
+
|
90
|
+
HEADER_DIRS.delete_if{|d| !File.exists?(d)}
|
91
|
+
LIB_DIRS.delete_if{|d| !File.exists?(d)}
|
92
|
+
|
93
|
+
# it will find the libcouchbase likely. you can specify its path otherwise
|
94
|
+
#
|
95
|
+
# ruby extconf.rb [--with-libcouchbase-include=<dir>] [--with-libcouchbase-lib=<dir>]
|
96
|
+
#
|
97
|
+
# or
|
98
|
+
#
|
99
|
+
# ruby extconf.rb [--with-libcouchbase-dir=<dir>]
|
100
|
+
#
|
101
|
+
dir_config("libcouchbase", HEADER_DIRS, LIB_DIRS)
|
102
|
+
end
|
103
|
+
|
104
|
+
|
105
|
+
if COMMON_HEADERS !~ /"ruby\.h"/
|
106
|
+
(COMMON_HEADERS ||= "") << %(\n#include "ruby.h"\n)
|
107
|
+
end
|
108
|
+
|
109
|
+
if try_compile(<<-SRC)
|
110
|
+
#include <stdarg.h>
|
111
|
+
int foo(int x, ...) {
|
112
|
+
va_list va;
|
113
|
+
va_start(va, x);
|
114
|
+
va_arg(va, int);
|
115
|
+
va_arg(va, char *);
|
116
|
+
va_arg(va, double);
|
117
|
+
return 0;
|
118
|
+
}
|
119
|
+
int main() {
|
120
|
+
return foo(10, "", 3.14);
|
121
|
+
return 0;
|
122
|
+
}
|
123
|
+
SRC
|
124
|
+
define("HAVE_STDARG_PROTOTYPES")
|
125
|
+
end
|
126
|
+
|
127
|
+
def die(message)
|
128
|
+
STDERR.puts "\n#{"*" * 70}"
|
129
|
+
STDERR.puts "#{message.gsub(/^/, "* ")}"
|
130
|
+
STDERR.puts "#{"*" * 70}\n\n"
|
131
|
+
abort
|
132
|
+
end
|
133
|
+
|
134
|
+
install_notice = "You must install libcouchbase >= 2.1.3\nSee http://www.couchbase.com/communities/c/ for more details"
|
135
|
+
|
136
|
+
unless try_compile(<<-SRC)
|
137
|
+
#include <libcouchbase/couchbase.h>
|
138
|
+
#include <stdio.h>
|
139
|
+
|
140
|
+
int main() {
|
141
|
+
printf("User not found: %d\\n", LCB_INVALID_USERNAME);
|
142
|
+
return 0;
|
143
|
+
}
|
144
|
+
SRC
|
145
|
+
die(install_notice)
|
146
|
+
end
|
147
|
+
|
148
|
+
# just to add -lcouchbase properly
|
149
|
+
have_library("couchbase", "lcb_verify_compiler_setup", "libcouchbase/couchbase.h") or die(install_notice)
|
150
|
+
have_header("mach/mach_time.h")
|
151
|
+
have_header("stdint.h") or die("Failed to locate stdint.h")
|
152
|
+
have_header("sys/time.h")
|
153
|
+
have_header("fcntl.h")
|
154
|
+
have_type("st_index_t")
|
155
|
+
have_func("clock_gettime")
|
156
|
+
have_func("gettimeofday")
|
157
|
+
have_func("QueryPerformanceCounter")
|
158
|
+
have_func("gethrtime")
|
159
|
+
have_func("rb_hash_lookup2")
|
160
|
+
have_func("rb_thread_fd_select")
|
161
|
+
have_func("rb_thread_blocking_region")
|
162
|
+
have_func("rb_thread_call_without_gvl")
|
163
|
+
have_func("poll", "poll.h")
|
164
|
+
have_func("ppoll", "poll.h")
|
165
|
+
have_func("rb_fiber_yield")
|
166
|
+
define("_GNU_SOURCE")
|
167
|
+
create_header("couchbase_config.h")
|
168
|
+
create_makefile("couchbase_ext")
|
@@ -0,0 +1,316 @@
|
|
1
|
+
/* vim: ft=c et ts=8 sts=4 sw=4 cino=
|
2
|
+
*
|
3
|
+
* Copyright 2011, 2012 Couchbase, Inc.
|
4
|
+
*
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
* you may not use this file except in compliance with the License.
|
7
|
+
* You may obtain a copy of the License at
|
8
|
+
*
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
*
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
* See the License for the specific language governing permissions and
|
15
|
+
* limitations under the License.
|
16
|
+
*/
|
17
|
+
|
18
|
+
#include "couchbase_ext.h"
|
19
|
+
|
20
|
+
void
|
21
|
+
cb_get_callback(lcb_t handle, const void *cookie, lcb_error_t error, const lcb_get_resp_t *resp)
|
22
|
+
{
|
23
|
+
struct cb_context_st *ctx = (struct cb_context_st *)cookie;
|
24
|
+
struct cb_bucket_st *bucket = ctx->bucket;
|
25
|
+
VALUE key, val, flags, cas, exc = Qnil, res, raw;
|
26
|
+
|
27
|
+
ctx->nqueries--;
|
28
|
+
key = STR_NEW((const char*)resp->v.v0.key, resp->v.v0.nkey);
|
29
|
+
cb_strip_key_prefix(bucket, key);
|
30
|
+
|
31
|
+
if (error != LCB_KEY_ENOENT || !ctx->quiet) {
|
32
|
+
exc = cb_check_error(error, "failed to get value", key);
|
33
|
+
if (exc != Qnil) {
|
34
|
+
rb_ivar_set(exc, cb_id_iv_operation, cb_sym_get);
|
35
|
+
ctx->exception = exc;
|
36
|
+
}
|
37
|
+
}
|
38
|
+
|
39
|
+
if (error == LCB_SUCCESS) {
|
40
|
+
flags = ULONG2NUM(resp->v.v0.flags);
|
41
|
+
cas = ULL2NUM(resp->v.v0.cas);
|
42
|
+
raw = STR_NEW((const char*)resp->v.v0.bytes, resp->v.v0.nbytes);
|
43
|
+
val = cb_decode_value(ctx->transcoder, raw, resp->v.v0.flags, ctx->transcoder_opts);
|
44
|
+
if (rb_obj_is_kind_of(val, rb_eStandardError)) {
|
45
|
+
VALUE exc_str = rb_funcall(val, cb_id_to_s, 0);
|
46
|
+
VALUE msg = rb_funcall(rb_mKernel, cb_id_sprintf, 3,
|
47
|
+
rb_str_new2("unable to convert value for key \"%s\": %s"), key, exc_str);
|
48
|
+
ctx->exception = rb_exc_new3(cb_eValueFormatError, msg);
|
49
|
+
rb_ivar_set(ctx->exception, cb_id_iv_operation, cb_sym_get);
|
50
|
+
rb_ivar_set(ctx->exception, cb_id_iv_key, key);
|
51
|
+
rb_ivar_set(ctx->exception, cb_id_iv_inner_exception, val);
|
52
|
+
val = Qnil;
|
53
|
+
}
|
54
|
+
} else {
|
55
|
+
val = flags = cas = Qnil;
|
56
|
+
}
|
57
|
+
if (bucket->async) { /* asynchronous */
|
58
|
+
if (ctx->proc != Qnil) {
|
59
|
+
res = rb_class_new_instance(0, NULL, cb_cResult);
|
60
|
+
rb_ivar_set(res, cb_id_iv_error, exc);
|
61
|
+
rb_ivar_set(res, cb_id_iv_operation, cb_sym_get);
|
62
|
+
rb_ivar_set(res, cb_id_iv_key, key);
|
63
|
+
rb_ivar_set(res, cb_id_iv_value, val);
|
64
|
+
rb_ivar_set(res, cb_id_iv_flags, flags);
|
65
|
+
rb_ivar_set(res, cb_id_iv_cas, cas);
|
66
|
+
cb_proc_call(bucket, ctx->proc, 1, res);
|
67
|
+
}
|
68
|
+
} else { /* synchronous */
|
69
|
+
if (NIL_P(exc) && error != LCB_KEY_ENOENT) {
|
70
|
+
if (ctx->extended) {
|
71
|
+
val = rb_ary_new3(3, val, flags, cas);
|
72
|
+
}
|
73
|
+
if (ctx->all_replicas) {
|
74
|
+
VALUE ary = rb_hash_aref(ctx->rv, key);
|
75
|
+
if (NIL_P(ary)) {
|
76
|
+
ary = rb_ary_new();
|
77
|
+
rb_hash_aset(ctx->rv, key, ary);
|
78
|
+
}
|
79
|
+
rb_ary_push(ary, val);
|
80
|
+
} else {
|
81
|
+
rb_hash_aset(ctx->rv, key, val);
|
82
|
+
}
|
83
|
+
}
|
84
|
+
}
|
85
|
+
|
86
|
+
if (ctx->nqueries == 0) {
|
87
|
+
ctx->proc = Qnil;
|
88
|
+
if (bucket->async) {
|
89
|
+
cb_context_free(ctx);
|
90
|
+
}
|
91
|
+
}
|
92
|
+
(void)handle;
|
93
|
+
}
|
94
|
+
|
95
|
+
/*
|
96
|
+
* Obtain an object stored in Couchbase by given key.
|
97
|
+
*
|
98
|
+
* @since 1.0.0
|
99
|
+
*
|
100
|
+
* @see http://couchbase.com/docs/couchbase-manual-2.0/couchbase-architecture-apis-memcached-protocol-additions.html#couchbase-architecture-apis-memcached-protocol-additions-getl
|
101
|
+
*
|
102
|
+
* @overload get(*keys, options = {})
|
103
|
+
* @param keys [String, Symbol, Array] One or several keys to fetch
|
104
|
+
* @param options [Hash] Options for operation.
|
105
|
+
* @option options [true, false] :extended (false) If set to +true+, the
|
106
|
+
* operation will return a tuple +[value, flags, cas]+, otherwise (by
|
107
|
+
* default) it returns just the value.
|
108
|
+
* @option options [Fixnum] :ttl (self.default_ttl) Expiry time for key.
|
109
|
+
* Values larger than 30*24*60*60 seconds (30 days) are interpreted as
|
110
|
+
* absolute times (from the epoch).
|
111
|
+
* @option options [true, false] :quiet (self.quiet) If set to +true+, the
|
112
|
+
* operation won't raise error for missing key, it will return +nil+.
|
113
|
+
* Otherwise it will raise error in synchronous mode. In asynchronous
|
114
|
+
* mode this option ignored.
|
115
|
+
* @option options [Symbol] :format (nil) Explicitly choose the decoder
|
116
|
+
* for this key (+:plain+, +:document+, +:marshal+). See
|
117
|
+
* {Bucket#default_format}.
|
118
|
+
* @option options [Fixnum, Boolean] :lock Lock the keys for time span.
|
119
|
+
* If this parameter is +true+ the key(s) will be locked for default
|
120
|
+
* timeout. Also you can use number to setup your own timeout in
|
121
|
+
* seconds. If it will be lower that zero or exceed the maximum, the
|
122
|
+
* server will use default value. You can determine actual default and
|
123
|
+
* maximum values calling {Bucket#stats} without arguments and
|
124
|
+
* inspecting keys "ep_getl_default_timeout" and "ep_getl_max_timeout"
|
125
|
+
* correspondingly. See overloaded hash syntax to specify custom timeout
|
126
|
+
* per each key.
|
127
|
+
* @option options [true, false] :assemble_hash (false) Assemble Hash for
|
128
|
+
* results. Hash assembled automatically if +:extended+ option is true
|
129
|
+
* or in case of "get and touch" multimple keys.
|
130
|
+
* @option options [true, false, :all, :first, Fixnum] :replica
|
131
|
+
* (false) Read key from replica node. Options +:ttl+ and +:lock+
|
132
|
+
* are not compatible with +:replica+. Value +true+ is a synonym to
|
133
|
+
* +:first+, which means sequentially iterate over all replicas
|
134
|
+
* and return first successful response, skipping all failures.
|
135
|
+
* It is also possible to query all replicas in parallel using
|
136
|
+
* the +:all+ option, or pass a replica index, starting from zero.
|
137
|
+
*
|
138
|
+
* @yieldparam ret [Result] the result of operation in asynchronous mode
|
139
|
+
* (valid attributes: +error+, +operation+, +key+, +value+, +flags+,
|
140
|
+
* +cas+).
|
141
|
+
*
|
142
|
+
* @return [Object, Array, Hash] the value(s) (or tuples in extended mode)
|
143
|
+
* associated with the key.
|
144
|
+
*
|
145
|
+
* @raise [Couchbase::Error::NotFound] if the key is missing in the
|
146
|
+
* bucket.
|
147
|
+
*
|
148
|
+
* @raise [Couchbase::Error::Connect] if connection closed (see {Bucket#reconnect})
|
149
|
+
*
|
150
|
+
* @raise [ArgumentError] when passing the block in synchronous mode
|
151
|
+
*
|
152
|
+
* @example Get single value in quiet mode (the default)
|
153
|
+
* c.get("foo") #=> the associated value or nil
|
154
|
+
*
|
155
|
+
* @example Use alternative hash-like syntax
|
156
|
+
* c["foo"] #=> the associated value or nil
|
157
|
+
*
|
158
|
+
* @example Get single value in verbose mode
|
159
|
+
* c.get("missing-foo", :quiet => false) #=> raises Couchbase::NotFound
|
160
|
+
* c.get("missing-foo", :quiet => true) #=> returns nil
|
161
|
+
*
|
162
|
+
* @example Get and touch single value. The key won't be accessible after 10 seconds
|
163
|
+
* c.get("foo", :ttl => 10)
|
164
|
+
*
|
165
|
+
* @example Extended get
|
166
|
+
* val, flags, cas = c.get("foo", :extended => true)
|
167
|
+
*
|
168
|
+
* @example Get multiple keys
|
169
|
+
* c.get("foo", "bar", "baz") #=> [val1, val2, val3]
|
170
|
+
*
|
171
|
+
* @example Get multiple keys with assembing result into the Hash
|
172
|
+
* c.get("foo", "bar", "baz", :assemble_hash => true)
|
173
|
+
* #=> {"foo" => val1, "bar" => val2, "baz" => val3}
|
174
|
+
*
|
175
|
+
* @example Extended get multiple keys
|
176
|
+
* c.get("foo", "bar", :extended => true)
|
177
|
+
* #=> {"foo" => [val1, flags1, cas1], "bar" => [val2, flags2, cas2]}
|
178
|
+
*
|
179
|
+
* @example Asynchronous get
|
180
|
+
* c.run do
|
181
|
+
* c.get("foo", "bar", "baz") do |res|
|
182
|
+
* ret.operation #=> :get
|
183
|
+
* ret.success? #=> true
|
184
|
+
* ret.key #=> "foo", "bar" or "baz" in separate calls
|
185
|
+
* ret.value
|
186
|
+
* ret.flags
|
187
|
+
* ret.cas
|
188
|
+
* end
|
189
|
+
* end
|
190
|
+
*
|
191
|
+
* @example Get and lock key using default timeout
|
192
|
+
* c.get("foo", :lock => true)
|
193
|
+
*
|
194
|
+
* @example Determine lock timeout parameters
|
195
|
+
* c.stats.values_at("ep_getl_default_timeout", "ep_getl_max_timeout")
|
196
|
+
* #=> [{"127.0.0.1:11210"=>"15"}, {"127.0.0.1:11210"=>"30"}]
|
197
|
+
*
|
198
|
+
* @example Get and lock key using custom timeout
|
199
|
+
* c.get("foo", :lock => 3)
|
200
|
+
*
|
201
|
+
* @example Get and lock multiple keys using custom timeout
|
202
|
+
* c.get("foo", "bar", :lock => 3)
|
203
|
+
*
|
204
|
+
* @overload get(keys, options = {})
|
205
|
+
* When the method receive hash map, it will behave like it receive list
|
206
|
+
* of keys (+keys.keys+), but also touch each key setting expiry time to
|
207
|
+
* the corresponding value. But unlike usual get this command always
|
208
|
+
* return hash map +{key => value}+ or +{key => [value, flags, cas]}+.
|
209
|
+
*
|
210
|
+
* @param keys [Hash] Map key-ttl
|
211
|
+
* @param options [Hash] Options for operation. (see options definition
|
212
|
+
* above)
|
213
|
+
*
|
214
|
+
* @return [Hash] the values (or tuples in extended mode) associated with
|
215
|
+
* the keys.
|
216
|
+
*
|
217
|
+
* @example Get and touch multiple keys
|
218
|
+
* c.get("foo" => 10, "bar" => 20) #=> {"foo" => val1, "bar" => val2}
|
219
|
+
*
|
220
|
+
* @example Extended get and touch multiple keys
|
221
|
+
* c.get({"foo" => 10, "bar" => 20}, :extended => true)
|
222
|
+
* #=> {"foo" => [val1, flags1, cas1], "bar" => [val2, flags2, cas2]}
|
223
|
+
*
|
224
|
+
* @example Get and lock multiple keys for chosen period in seconds
|
225
|
+
* c.get("foo" => 10, "bar" => 20, :lock => true)
|
226
|
+
* #=> {"foo" => val1, "bar" => val2}
|
227
|
+
*/
|
228
|
+
VALUE
|
229
|
+
cb_bucket_get(int argc, VALUE *argv, VALUE self)
|
230
|
+
{
|
231
|
+
struct cb_bucket_st *bucket = DATA_PTR(self);
|
232
|
+
struct cb_context_st *ctx;
|
233
|
+
VALUE rv, proc, exc;
|
234
|
+
size_t ii;
|
235
|
+
lcb_error_t err = LCB_SUCCESS;
|
236
|
+
struct cb_params_st params;
|
237
|
+
|
238
|
+
if (!cb_bucket_connected_bang(bucket, cb_sym_get)) {
|
239
|
+
return Qnil;
|
240
|
+
}
|
241
|
+
|
242
|
+
memset(¶ms, 0, sizeof(struct cb_params_st));
|
243
|
+
rb_scan_args(argc, argv, "0*&", ¶ms.args, &proc);
|
244
|
+
if (!bucket->async && proc != Qnil) {
|
245
|
+
rb_raise(rb_eArgError, "synchronous mode doesn't support callbacks");
|
246
|
+
}
|
247
|
+
params.type = cb_cmd_get;
|
248
|
+
params.bucket = bucket;
|
249
|
+
params.cmd.get.keys_ary = rb_ary_new();
|
250
|
+
cb_params_build(¶ms);
|
251
|
+
ctx = cb_context_alloc_common(bucket, proc, params.cmd.get.num);
|
252
|
+
ctx->extended = params.cmd.get.extended;
|
253
|
+
ctx->quiet = params.cmd.get.quiet;
|
254
|
+
ctx->transcoder = params.cmd.get.transcoder;
|
255
|
+
ctx->transcoder_opts = params.cmd.get.transcoder_opts;
|
256
|
+
if (RTEST(params.cmd.get.replica)) {
|
257
|
+
if (params.cmd.get.replica == cb_sym_all) {
|
258
|
+
ctx->nqueries = lcb_get_num_replicas(bucket->handle);
|
259
|
+
ctx->all_replicas = 1;
|
260
|
+
}
|
261
|
+
err = lcb_get_replica(bucket->handle, (const void *)ctx,
|
262
|
+
params.cmd.get.num, params.cmd.get.ptr_gr);
|
263
|
+
} else {
|
264
|
+
err = lcb_get(bucket->handle, (const void *)ctx,
|
265
|
+
params.cmd.get.num, params.cmd.get.ptr);
|
266
|
+
}
|
267
|
+
cb_params_destroy(¶ms);
|
268
|
+
exc = cb_check_error(err, "failed to schedule get request", Qnil);
|
269
|
+
if (exc != Qnil) {
|
270
|
+
cb_context_free(ctx);
|
271
|
+
rb_exc_raise(exc);
|
272
|
+
}
|
273
|
+
bucket->nbytes += params.npayload;
|
274
|
+
if (bucket->async) {
|
275
|
+
cb_maybe_do_loop(bucket);
|
276
|
+
return Qnil;
|
277
|
+
} else {
|
278
|
+
if (ctx->nqueries > 0) {
|
279
|
+
/* we have some operations pending */
|
280
|
+
lcb_wait(bucket->handle);
|
281
|
+
}
|
282
|
+
exc = ctx->exception;
|
283
|
+
rv = ctx->rv;
|
284
|
+
cb_context_free(ctx);
|
285
|
+
if (exc != Qnil) {
|
286
|
+
rb_exc_raise(exc);
|
287
|
+
}
|
288
|
+
exc = bucket->exception;
|
289
|
+
if (exc != Qnil) {
|
290
|
+
bucket->exception = Qnil;
|
291
|
+
rb_exc_raise(exc);
|
292
|
+
}
|
293
|
+
if (params.cmd.get.gat || params.cmd.get.assemble_hash ||
|
294
|
+
(params.cmd.get.extended && (params.cmd.get.num > 1 || params.cmd.get.array))) {
|
295
|
+
return rv; /* return as a hash {key => [value, flags, cas], ...} */
|
296
|
+
}
|
297
|
+
if (params.cmd.get.num > 1 || params.cmd.get.array) {
|
298
|
+
VALUE keys, ret;
|
299
|
+
ret = rb_ary_new();
|
300
|
+
/* make sure ret is guarded so not invisible in a register
|
301
|
+
* when stack scanning */
|
302
|
+
RB_GC_GUARD(ret);
|
303
|
+
keys = params.cmd.get.keys_ary;
|
304
|
+
for (ii = 0; ii < params.cmd.get.num; ++ii) {
|
305
|
+
rb_ary_push(ret, rb_hash_aref(rv, rb_ary_entry(keys, ii)));
|
306
|
+
}
|
307
|
+
return ret; /* return as an array [value1, value2, ...] */
|
308
|
+
} else {
|
309
|
+
VALUE vv = Qnil;
|
310
|
+
rb_hash_foreach(rv, cb_first_value_i, (VALUE)&vv);
|
311
|
+
return vv;
|
312
|
+
}
|
313
|
+
}
|
314
|
+
}
|
315
|
+
|
316
|
+
|