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.
Files changed (92) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/.travis.yml +22 -0
  4. data/.yardopts +5 -0
  5. data/CONTRIBUTING.markdown +75 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE +201 -0
  8. data/Makefile +3 -0
  9. data/README.markdown +649 -0
  10. data/RELEASE_NOTES.markdown +796 -0
  11. data/Rakefile +20 -0
  12. data/couchbase.gemspec +49 -0
  13. data/examples/chat-em/Gemfile +7 -0
  14. data/examples/chat-em/README.markdown +45 -0
  15. data/examples/chat-em/server.rb +82 -0
  16. data/examples/chat-goliath-grape/Gemfile +5 -0
  17. data/examples/chat-goliath-grape/README.markdown +50 -0
  18. data/examples/chat-goliath-grape/app.rb +67 -0
  19. data/examples/chat-goliath-grape/config/app.rb +20 -0
  20. data/examples/transcoders/Gemfile +3 -0
  21. data/examples/transcoders/README.markdown +59 -0
  22. data/examples/transcoders/cb-zcat +40 -0
  23. data/examples/transcoders/cb-zcp +45 -0
  24. data/examples/transcoders/gzip_transcoder.rb +49 -0
  25. data/examples/transcoders/options.rb +54 -0
  26. data/ext/couchbase_ext/.gitignore +4 -0
  27. data/ext/couchbase_ext/arguments.c +956 -0
  28. data/ext/couchbase_ext/arithmetic.c +307 -0
  29. data/ext/couchbase_ext/bucket.c +1370 -0
  30. data/ext/couchbase_ext/context.c +65 -0
  31. data/ext/couchbase_ext/couchbase_ext.c +1364 -0
  32. data/ext/couchbase_ext/couchbase_ext.h +644 -0
  33. data/ext/couchbase_ext/delete.c +163 -0
  34. data/ext/couchbase_ext/eventmachine_plugin.c +452 -0
  35. data/ext/couchbase_ext/extconf.rb +168 -0
  36. data/ext/couchbase_ext/get.c +316 -0
  37. data/ext/couchbase_ext/gethrtime.c +129 -0
  38. data/ext/couchbase_ext/http.c +432 -0
  39. data/ext/couchbase_ext/multithread_plugin.c +1090 -0
  40. data/ext/couchbase_ext/observe.c +171 -0
  41. data/ext/couchbase_ext/plugin_common.c +171 -0
  42. data/ext/couchbase_ext/result.c +129 -0
  43. data/ext/couchbase_ext/stats.c +163 -0
  44. data/ext/couchbase_ext/store.c +542 -0
  45. data/ext/couchbase_ext/timer.c +192 -0
  46. data/ext/couchbase_ext/touch.c +186 -0
  47. data/ext/couchbase_ext/unlock.c +176 -0
  48. data/ext/couchbase_ext/utils.c +551 -0
  49. data/ext/couchbase_ext/version.c +142 -0
  50. data/lib/action_dispatch/middleware/session/couchbase_store.rb +38 -0
  51. data/lib/active_support/cache/couchbase_store.rb +430 -0
  52. data/lib/couchbase.rb +155 -0
  53. data/lib/couchbase/bucket.rb +457 -0
  54. data/lib/couchbase/cluster.rb +119 -0
  55. data/lib/couchbase/connection_pool.rb +58 -0
  56. data/lib/couchbase/constants.rb +12 -0
  57. data/lib/couchbase/result.rb +26 -0
  58. data/lib/couchbase/transcoder.rb +120 -0
  59. data/lib/couchbase/utils.rb +62 -0
  60. data/lib/couchbase/version.rb +21 -0
  61. data/lib/couchbase/view.rb +506 -0
  62. data/lib/couchbase/view_row.rb +272 -0
  63. data/lib/ext/multi_json_fix.rb +56 -0
  64. data/lib/rack/session/couchbase.rb +108 -0
  65. data/tasks/benchmark.rake +6 -0
  66. data/tasks/compile.rake +158 -0
  67. data/tasks/test.rake +100 -0
  68. data/tasks/util.rake +21 -0
  69. data/test/profile/.gitignore +1 -0
  70. data/test/profile/Gemfile +6 -0
  71. data/test/profile/benchmark.rb +195 -0
  72. data/test/setup.rb +178 -0
  73. data/test/test_arithmetic.rb +185 -0
  74. data/test/test_async.rb +316 -0
  75. data/test/test_bucket.rb +250 -0
  76. data/test/test_cas.rb +235 -0
  77. data/test/test_couchbase.rb +77 -0
  78. data/test/test_couchbase_connection_pool.rb +77 -0
  79. data/test/test_couchbase_rails_cache_store.rb +361 -0
  80. data/test/test_delete.rb +120 -0
  81. data/test/test_errors.rb +82 -0
  82. data/test/test_eventmachine.rb +70 -0
  83. data/test/test_format.rb +164 -0
  84. data/test/test_get.rb +407 -0
  85. data/test/test_stats.rb +57 -0
  86. data/test/test_store.rb +216 -0
  87. data/test/test_timer.rb +42 -0
  88. data/test/test_touch.rb +97 -0
  89. data/test/test_unlock.rb +119 -0
  90. data/test/test_utils.rb +58 -0
  91. data/test/test_version.rb +52 -0
  92. 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(&params, 0, sizeof(struct cb_params_st));
243
+ rb_scan_args(argc, argv, "0*&", &params.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(&params);
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(&params);
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
+