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,307 @@
|
|
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_arithmetic_callback(lcb_t handle, const void *cookie, lcb_error_t error, const lcb_arithmetic_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 cas, key, val, exc, res;
|
26
|
+
ID o;
|
27
|
+
|
28
|
+
ctx->nqueries--;
|
29
|
+
key = STR_NEW((const char*)resp->v.v0.key, resp->v.v0.nkey);
|
30
|
+
cb_strip_key_prefix(bucket, key);
|
31
|
+
|
32
|
+
cas = resp->v.v0.cas > 0 ? ULL2NUM(resp->v.v0.cas) : Qnil;
|
33
|
+
o = ctx->arith > 0 ? cb_sym_increment : cb_sym_decrement;
|
34
|
+
exc = cb_check_error(error, "failed to perform arithmetic operation", key);
|
35
|
+
if (exc != Qnil) {
|
36
|
+
rb_ivar_set(exc, cb_id_iv_cas, cas);
|
37
|
+
rb_ivar_set(exc, cb_id_iv_operation, o);
|
38
|
+
ctx->exception = exc;
|
39
|
+
}
|
40
|
+
val = ULL2NUM(resp->v.v0.value);
|
41
|
+
if (bucket->async) { /* asynchronous */
|
42
|
+
if (ctx->proc != Qnil) {
|
43
|
+
res = rb_class_new_instance(0, NULL, cb_cResult);
|
44
|
+
rb_ivar_set(res, cb_id_iv_error, exc);
|
45
|
+
rb_ivar_set(res, cb_id_iv_operation, o);
|
46
|
+
rb_ivar_set(res, cb_id_iv_key, key);
|
47
|
+
rb_ivar_set(res, cb_id_iv_value, val);
|
48
|
+
rb_ivar_set(res, cb_id_iv_cas, cas);
|
49
|
+
cb_proc_call(bucket, ctx->proc, 1, res);
|
50
|
+
}
|
51
|
+
} else { /* synchronous */
|
52
|
+
if (NIL_P(exc)) {
|
53
|
+
if (ctx->extended) {
|
54
|
+
rb_hash_aset(ctx->rv, key, rb_ary_new3(2, val, cas));
|
55
|
+
} else {
|
56
|
+
rb_hash_aset(ctx->rv, key, val);
|
57
|
+
}
|
58
|
+
}
|
59
|
+
}
|
60
|
+
if (ctx->nqueries == 0) {
|
61
|
+
ctx->proc = Qnil;
|
62
|
+
if (bucket->async) {
|
63
|
+
cb_context_free(ctx);
|
64
|
+
}
|
65
|
+
}
|
66
|
+
(void)handle;
|
67
|
+
}
|
68
|
+
|
69
|
+
static inline VALUE
|
70
|
+
cb_bucket_arithmetic(int sign, int argc, VALUE *argv, VALUE self)
|
71
|
+
{
|
72
|
+
struct cb_bucket_st *bucket = DATA_PTR(self);
|
73
|
+
struct cb_context_st *ctx;
|
74
|
+
VALUE rv, proc, exc;
|
75
|
+
lcb_error_t err;
|
76
|
+
struct cb_params_st params;
|
77
|
+
|
78
|
+
if (!cb_bucket_connected_bang(bucket, sign > 0 ? cb_sym_increment : cb_sym_decrement)) {
|
79
|
+
return Qnil;
|
80
|
+
}
|
81
|
+
|
82
|
+
memset(¶ms, 0, sizeof(struct cb_params_st));
|
83
|
+
rb_scan_args(argc, argv, "0*&", ¶ms.args, &proc);
|
84
|
+
if (!bucket->async && proc != Qnil) {
|
85
|
+
rb_raise(rb_eArgError, "synchronous mode doesn't support callbacks");
|
86
|
+
}
|
87
|
+
params.type = cb_cmd_arith;
|
88
|
+
params.bucket = bucket;
|
89
|
+
params.cmd.arith.sign = sign;
|
90
|
+
cb_params_build(¶ms);
|
91
|
+
ctx = cb_context_alloc_common(bucket, proc, params.cmd.arith.num);
|
92
|
+
ctx->extended = params.cmd.arith.extended;
|
93
|
+
err = lcb_arithmetic(bucket->handle, (const void *)ctx,
|
94
|
+
params.cmd.arith.num, params.cmd.arith.ptr);
|
95
|
+
cb_params_destroy(¶ms);
|
96
|
+
exc = cb_check_error(err, "failed to schedule arithmetic request", Qnil);
|
97
|
+
if (exc != Qnil) {
|
98
|
+
cb_context_free(ctx);
|
99
|
+
rb_exc_raise(exc);
|
100
|
+
}
|
101
|
+
bucket->nbytes += params.npayload;
|
102
|
+
if (bucket->async) {
|
103
|
+
cb_maybe_do_loop(bucket);
|
104
|
+
return Qnil;
|
105
|
+
} else {
|
106
|
+
if (ctx->nqueries > 0) {
|
107
|
+
/* we have some operations pending */
|
108
|
+
lcb_wait(bucket->handle);
|
109
|
+
}
|
110
|
+
exc = ctx->exception;
|
111
|
+
rv = ctx->rv;
|
112
|
+
cb_context_free(ctx);
|
113
|
+
if (exc != Qnil) {
|
114
|
+
rb_exc_raise(exc);
|
115
|
+
}
|
116
|
+
if (params.cmd.store.num > 1) {
|
117
|
+
return rv; /* return as a hash {key => cas, ...} */
|
118
|
+
} else {
|
119
|
+
VALUE vv = Qnil;
|
120
|
+
rb_hash_foreach(rv, cb_first_value_i, (VALUE)&vv);
|
121
|
+
return vv;
|
122
|
+
}
|
123
|
+
return rv;
|
124
|
+
}
|
125
|
+
}
|
126
|
+
|
127
|
+
/*
|
128
|
+
* Increment the value of an existing numeric key
|
129
|
+
*
|
130
|
+
* @since 1.0.0
|
131
|
+
*
|
132
|
+
* The increment methods allow you to increase a given stored integer
|
133
|
+
* value. These are the incremental equivalent of the decrement operations
|
134
|
+
* and work on the same basis; updating the value of a key if it can be
|
135
|
+
* parsed to an integer. The update operation occurs on the server and is
|
136
|
+
* provided at the protocol level. This simplifies what would otherwise be a
|
137
|
+
* two-stage get and set operation.
|
138
|
+
*
|
139
|
+
* @note that server values stored and transmitted as unsigned numbers,
|
140
|
+
* therefore if you try to store negative number and then increment or
|
141
|
+
* decrement it will cause overflow. (see "Integer overflow" example
|
142
|
+
* below)
|
143
|
+
*
|
144
|
+
* @overload incr(key, delta = 1, options = {})
|
145
|
+
* @param key [String, Symbol] Key used to reference the value.
|
146
|
+
* @param delta [Fixnum] Integer (up to 64 bits) value to increment
|
147
|
+
* @param options [Hash] Options for operation.
|
148
|
+
* @option options [true, false] :create (false) If set to +true+, it will
|
149
|
+
* initialize the key with zero value and zero flags (use +:initial+
|
150
|
+
* option to set another initial value). Note: it won't increment the
|
151
|
+
* missing value.
|
152
|
+
* @option options [Fixnum] :initial (0) Integer (up to 64 bits) value for
|
153
|
+
* missing key initialization. This option imply +:create+ option is
|
154
|
+
* +true+.
|
155
|
+
* @option options [Fixnum] :ttl (self.default_ttl) Expiry time for key.
|
156
|
+
* Values larger than 30*24*60*60 seconds (30 days) are interpreted as
|
157
|
+
* absolute times (from the epoch). This option ignored for existent
|
158
|
+
* keys.
|
159
|
+
* @option options [true, false] :extended (false) If set to +true+, the
|
160
|
+
* operation will return tuple +[value, cas]+, otherwise (by default) it
|
161
|
+
* returns just value.
|
162
|
+
*
|
163
|
+
* @yieldparam ret [Result] the result of operation in asynchronous mode
|
164
|
+
* (valid attributes: +error+, +operation+, +key+, +value+, +cas+).
|
165
|
+
*
|
166
|
+
* @return [Fixnum] the actual value of the key.
|
167
|
+
*
|
168
|
+
* @raise [Couchbase::Error::NotFound] if key is missing and +:create+
|
169
|
+
* option isn't +true+.
|
170
|
+
*
|
171
|
+
* @raise [Couchbase::Error::DeltaBadval] if the key contains non-numeric
|
172
|
+
* value
|
173
|
+
*
|
174
|
+
* @raise [Couchbase::Error::Connect] if connection closed (see {Bucket#reconnect})
|
175
|
+
*
|
176
|
+
* @raise [ArgumentError] when passing the block in synchronous mode
|
177
|
+
*
|
178
|
+
* @example Increment key by one
|
179
|
+
* c.incr("foo")
|
180
|
+
*
|
181
|
+
* @example Increment key by 50
|
182
|
+
* c.incr("foo", 50)
|
183
|
+
*
|
184
|
+
* @example Increment key by one <b>OR</b> initialize with zero
|
185
|
+
* c.incr("foo", :create => true) #=> will return old+1 or 0
|
186
|
+
*
|
187
|
+
* @example Increment key by one <b>OR</b> initialize with three
|
188
|
+
* c.incr("foo", 50, :initial => 3) #=> will return old+50 or 3
|
189
|
+
*
|
190
|
+
* @example Increment key and get its CAS value
|
191
|
+
* val, cas = c.incr("foo", :extended => true)
|
192
|
+
*
|
193
|
+
* @example Integer overflow
|
194
|
+
* c.set("foo", -100)
|
195
|
+
* c.get("foo") #=> -100
|
196
|
+
* c.incr("foo") #=> 18446744073709551517
|
197
|
+
*
|
198
|
+
* @example Asynchronous invocation
|
199
|
+
* c.run do
|
200
|
+
* c.incr("foo") do |ret|
|
201
|
+
* ret.operation #=> :increment
|
202
|
+
* ret.success? #=> true
|
203
|
+
* ret.key #=> "foo"
|
204
|
+
* ret.value
|
205
|
+
* ret.cas
|
206
|
+
* end
|
207
|
+
* end
|
208
|
+
*
|
209
|
+
*/
|
210
|
+
VALUE
|
211
|
+
cb_bucket_incr(int argc, VALUE *argv, VALUE self)
|
212
|
+
{
|
213
|
+
return cb_bucket_arithmetic(+1, argc, argv, self);
|
214
|
+
}
|
215
|
+
|
216
|
+
/*
|
217
|
+
* Decrement the value of an existing numeric key
|
218
|
+
*
|
219
|
+
* @since 1.0.0
|
220
|
+
*
|
221
|
+
* The decrement methods reduce the value of a given key if the
|
222
|
+
* corresponding value can be parsed to an integer value. These operations
|
223
|
+
* are provided at a protocol level to eliminate the need to get, update,
|
224
|
+
* and reset a simple integer value in the database. It supports the use of
|
225
|
+
* an explicit offset value that will be used to reduce the stored value in
|
226
|
+
* the database.
|
227
|
+
*
|
228
|
+
* @note that server values stored and transmitted as unsigned numbers,
|
229
|
+
* therefore if you try to decrement negative or zero key, you will always
|
230
|
+
* get zero.
|
231
|
+
*
|
232
|
+
* @overload decr(key, delta = 1, options = {})
|
233
|
+
* @param key [String, Symbol] Key used to reference the value.
|
234
|
+
* @param delta [Fixnum] Integer (up to 64 bits) value to decrement
|
235
|
+
* @param options [Hash] Options for operation.
|
236
|
+
* @option options [true, false] :create (false) If set to +true+, it will
|
237
|
+
* initialize the key with zero value and zero flags (use +:initial+
|
238
|
+
* option to set another initial value). Note: it won't decrement the
|
239
|
+
* missing value.
|
240
|
+
* @option options [Fixnum] :initial (0) Integer (up to 64 bits) value for
|
241
|
+
* missing key initialization. This option imply +:create+ option is
|
242
|
+
* +true+.
|
243
|
+
* @option options [Fixnum] :ttl (self.default_ttl) Expiry time for key.
|
244
|
+
* Values larger than 30*24*60*60 seconds (30 days) are interpreted as
|
245
|
+
* absolute times (from the epoch). This option ignored for existent
|
246
|
+
* keys.
|
247
|
+
* @option options [true, false] :extended (false) If set to +true+, the
|
248
|
+
* operation will return tuple +[value, cas]+, otherwise (by default) it
|
249
|
+
* returns just value.
|
250
|
+
*
|
251
|
+
* @yieldparam ret [Result] the result of operation in asynchronous mode
|
252
|
+
* (valid attributes: +error+, +operation+, +key+, +value+, +cas+).
|
253
|
+
*
|
254
|
+
* @return [Fixnum] the actual value of the key.
|
255
|
+
*
|
256
|
+
* @raise [Couchbase::Error::NotFound] if key is missing and +:create+
|
257
|
+
* option isn't +true+.
|
258
|
+
*
|
259
|
+
* @raise [Couchbase::Error::DeltaBadval] if the key contains non-numeric
|
260
|
+
* value
|
261
|
+
*
|
262
|
+
* @raise [Couchbase::Error::Connect] if connection closed (see {Bucket#reconnect})
|
263
|
+
*
|
264
|
+
* @raise [ArgumentError] when passing the block in synchronous mode
|
265
|
+
*
|
266
|
+
* @example Decrement key by one
|
267
|
+
* c.decr("foo")
|
268
|
+
*
|
269
|
+
* @example Decrement key by 50
|
270
|
+
* c.decr("foo", 50)
|
271
|
+
*
|
272
|
+
* @example Decrement key by one <b>OR</b> initialize with zero
|
273
|
+
* c.decr("foo", :create => true) #=> will return old-1 or 0
|
274
|
+
*
|
275
|
+
* @example Decrement key by one <b>OR</b> initialize with three
|
276
|
+
* c.decr("foo", 50, :initial => 3) #=> will return old-50 or 3
|
277
|
+
*
|
278
|
+
* @example Decrement key and get its CAS value
|
279
|
+
* val, cas = c.decr("foo", :extended => true)
|
280
|
+
*
|
281
|
+
* @example Decrementing zero
|
282
|
+
* c.set("foo", 0)
|
283
|
+
* c.decrement("foo", 100500) #=> 0
|
284
|
+
*
|
285
|
+
* @example Decrementing negative value
|
286
|
+
* c.set("foo", -100)
|
287
|
+
* c.decrement("foo", 100500) #=> 0
|
288
|
+
*
|
289
|
+
* @example Asynchronous invocation
|
290
|
+
* c.run do
|
291
|
+
* c.decr("foo") do |ret|
|
292
|
+
* ret.operation #=> :decrement
|
293
|
+
* ret.success? #=> true
|
294
|
+
* ret.key #=> "foo"
|
295
|
+
* ret.value
|
296
|
+
* ret.cas
|
297
|
+
* end
|
298
|
+
* end
|
299
|
+
*
|
300
|
+
*/
|
301
|
+
VALUE
|
302
|
+
cb_bucket_decr(int argc, VALUE *argv, VALUE self)
|
303
|
+
{
|
304
|
+
return cb_bucket_arithmetic(-1, argc, argv, self);
|
305
|
+
}
|
306
|
+
|
307
|
+
|
@@ -0,0 +1,1370 @@
|
|
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
|
+
static VALUE
|
21
|
+
trigger_on_connect_callback(VALUE self)
|
22
|
+
{
|
23
|
+
struct cb_bucket_st *bucket = DATA_PTR(self);
|
24
|
+
VALUE on_connect_proc = bucket->on_connect_proc;
|
25
|
+
if (RTEST(on_connect_proc)) {
|
26
|
+
VALUE res = rb_class_new_instance(0, NULL, cb_cResult);
|
27
|
+
rb_ivar_set(res, cb_id_iv_error, bucket->exception);
|
28
|
+
bucket->exception = Qnil;
|
29
|
+
rb_ivar_set(res, cb_id_iv_operation, cb_sym_connect);
|
30
|
+
rb_ivar_set(res, cb_id_iv_value, self);
|
31
|
+
return rb_funcall(on_connect_proc, cb_id_call, 1, res);
|
32
|
+
} else {
|
33
|
+
bucket->trigger_connect_cb_on_set = 1;
|
34
|
+
return Qnil;
|
35
|
+
}
|
36
|
+
}
|
37
|
+
|
38
|
+
static void
|
39
|
+
error_callback(lcb_t handle, lcb_error_t error, const char *errinfo)
|
40
|
+
{
|
41
|
+
struct cb_bucket_st *bucket = (struct cb_bucket_st *)lcb_get_cookie(handle);
|
42
|
+
|
43
|
+
lcb_breakout(handle);
|
44
|
+
bucket->exception = cb_check_error(error, errinfo, Qnil);
|
45
|
+
if (bucket->async && !bucket->connected) {
|
46
|
+
(void)trigger_on_connect_callback(bucket->self);
|
47
|
+
}
|
48
|
+
}
|
49
|
+
|
50
|
+
static void
|
51
|
+
configuration_callback(lcb_t handle, lcb_configuration_t config)
|
52
|
+
{
|
53
|
+
struct cb_bucket_st *bucket = (struct cb_bucket_st *)lcb_get_cookie(handle);
|
54
|
+
|
55
|
+
if (config == LCB_CONFIGURATION_NEW) {
|
56
|
+
bucket->connected = 1;
|
57
|
+
(void)trigger_on_connect_callback(bucket->self);
|
58
|
+
}
|
59
|
+
}
|
60
|
+
|
61
|
+
void
|
62
|
+
cb_bucket_free(void *ptr)
|
63
|
+
{
|
64
|
+
struct cb_bucket_st *bucket = ptr;
|
65
|
+
|
66
|
+
if (bucket) {
|
67
|
+
bucket->destroying = 1;
|
68
|
+
if (bucket->handle) {
|
69
|
+
lcb_destroy(bucket->handle);
|
70
|
+
lcb_destroy_io_ops(bucket->io);
|
71
|
+
}
|
72
|
+
st_free_table(bucket->object_space);
|
73
|
+
xfree(bucket);
|
74
|
+
}
|
75
|
+
}
|
76
|
+
|
77
|
+
static int
|
78
|
+
cb_bucket_mark_object_i(st_index_t key, st_data_t value, st_data_t arg)
|
79
|
+
{
|
80
|
+
((mark_f)value)((void*)key, (struct cb_bucket_st*)arg);
|
81
|
+
return ST_CONTINUE;
|
82
|
+
}
|
83
|
+
|
84
|
+
void
|
85
|
+
cb_bucket_mark(void *ptr)
|
86
|
+
{
|
87
|
+
struct cb_bucket_st *bucket = ptr;
|
88
|
+
|
89
|
+
if (bucket) {
|
90
|
+
rb_gc_mark(bucket->authority);
|
91
|
+
rb_gc_mark(bucket->hostname);
|
92
|
+
rb_gc_mark(bucket->pool);
|
93
|
+
rb_gc_mark(bucket->bucket);
|
94
|
+
rb_gc_mark(bucket->username);
|
95
|
+
rb_gc_mark(bucket->password);
|
96
|
+
rb_gc_mark(bucket->exception);
|
97
|
+
rb_gc_mark(bucket->on_error_proc);
|
98
|
+
rb_gc_mark(bucket->on_connect_proc);
|
99
|
+
rb_gc_mark(bucket->key_prefix_val);
|
100
|
+
if (bucket->object_space) {
|
101
|
+
st_foreach(bucket->object_space, cb_bucket_mark_object_i, (st_data_t)bucket);
|
102
|
+
}
|
103
|
+
}
|
104
|
+
}
|
105
|
+
|
106
|
+
static void
|
107
|
+
do_scan_connection_options(struct cb_bucket_st *bucket, int argc, VALUE *argv)
|
108
|
+
{
|
109
|
+
VALUE uri, opts, arg;
|
110
|
+
char port_s[8];
|
111
|
+
|
112
|
+
if (rb_scan_args(argc, argv, "02", &uri, &opts) > 0) {
|
113
|
+
if (TYPE(uri) == T_HASH && argc == 1) {
|
114
|
+
opts = uri;
|
115
|
+
uri = Qnil;
|
116
|
+
}
|
117
|
+
if (uri != Qnil) {
|
118
|
+
const char path_re[] = "^(/pools/([A-Za-z0-9_.-]+)(/buckets/([A-Za-z0-9_.-]+))?)?";
|
119
|
+
VALUE match, uri_obj, re;
|
120
|
+
|
121
|
+
Check_Type(uri, T_STRING);
|
122
|
+
uri_obj = rb_funcall(cb_mURI, cb_id_parse, 1, uri);
|
123
|
+
|
124
|
+
arg = rb_funcall(uri_obj, cb_id_scheme, 0);
|
125
|
+
if (arg == Qnil || rb_str_cmp(arg, STR_NEW_CSTR("http"))) {
|
126
|
+
rb_raise(rb_eArgError, "invalid URI: invalid scheme");
|
127
|
+
}
|
128
|
+
|
129
|
+
arg = rb_funcall(uri_obj, cb_id_user, 0);
|
130
|
+
if (arg != Qnil) {
|
131
|
+
bucket->username = rb_str_dup_frozen(StringValue(arg));
|
132
|
+
}
|
133
|
+
|
134
|
+
arg = rb_funcall(uri_obj, cb_id_password, 0);
|
135
|
+
if (arg != Qnil) {
|
136
|
+
bucket->password = rb_str_dup_frozen(StringValue(arg));
|
137
|
+
}
|
138
|
+
arg = rb_funcall(uri_obj, cb_id_host, 0);
|
139
|
+
if (arg != Qnil) {
|
140
|
+
bucket->hostname = rb_str_dup_frozen(StringValue(arg));
|
141
|
+
} else {
|
142
|
+
rb_raise(rb_eArgError, "invalid URI: missing hostname");
|
143
|
+
}
|
144
|
+
|
145
|
+
arg = rb_funcall(uri_obj, cb_id_port, 0);
|
146
|
+
bucket->port = NIL_P(arg) ? 8091 : (uint16_t)NUM2UINT(arg);
|
147
|
+
|
148
|
+
arg = rb_funcall(uri_obj, cb_id_path, 0);
|
149
|
+
re = rb_reg_new(path_re, sizeof(path_re) - 1, 0);
|
150
|
+
match = rb_funcall(re, cb_id_match, 1, arg);
|
151
|
+
arg = rb_reg_nth_match(2, match);
|
152
|
+
bucket->pool = NIL_P(arg) ? cb_vStrDefault : rb_str_dup_frozen(StringValue(arg));
|
153
|
+
rb_str_freeze(bucket->pool);
|
154
|
+
arg = rb_reg_nth_match(4, match);
|
155
|
+
bucket->bucket = NIL_P(arg) ? cb_vStrDefault : rb_str_dup_frozen(StringValue(arg));
|
156
|
+
rb_str_freeze(bucket->bucket);
|
157
|
+
}
|
158
|
+
if (TYPE(opts) == T_HASH) {
|
159
|
+
arg = rb_hash_aref(opts, cb_sym_type);
|
160
|
+
if (arg != Qnil) {
|
161
|
+
if (arg == cb_sym_cluster) {
|
162
|
+
bucket->type = LCB_TYPE_CLUSTER;
|
163
|
+
} else {
|
164
|
+
bucket->type = LCB_TYPE_BUCKET;
|
165
|
+
}
|
166
|
+
}
|
167
|
+
arg = rb_hash_aref(opts, cb_sym_node_list);
|
168
|
+
if (arg != Qnil) {
|
169
|
+
Check_Type(arg, T_ARRAY);
|
170
|
+
bucket->node_list = rb_ary_join(arg, STR_NEW_CSTR(";"));
|
171
|
+
rb_str_freeze(bucket->node_list);
|
172
|
+
}
|
173
|
+
arg = rb_hash_aref(opts, cb_sym_hostname);
|
174
|
+
if (arg != Qnil) {
|
175
|
+
bucket->hostname = rb_str_dup_frozen(StringValue(arg));
|
176
|
+
}
|
177
|
+
arg = rb_hash_aref(opts, cb_sym_pool);
|
178
|
+
if (arg != Qnil) {
|
179
|
+
bucket->pool = rb_str_dup_frozen(StringValue(arg));
|
180
|
+
}
|
181
|
+
arg = rb_hash_aref(opts, cb_sym_bucket);
|
182
|
+
if (arg != Qnil) {
|
183
|
+
bucket->bucket = rb_str_dup_frozen(StringValue(arg));
|
184
|
+
}
|
185
|
+
arg = rb_hash_aref(opts, cb_sym_username);
|
186
|
+
if (arg != Qnil) {
|
187
|
+
bucket->username = rb_str_dup_frozen(StringValue(arg));
|
188
|
+
}
|
189
|
+
arg = rb_hash_aref(opts, cb_sym_password);
|
190
|
+
if (arg != Qnil) {
|
191
|
+
bucket->password = rb_str_dup_frozen(StringValue(arg));
|
192
|
+
}
|
193
|
+
arg = rb_hash_aref(opts, cb_sym_port);
|
194
|
+
if (arg != Qnil) {
|
195
|
+
bucket->port = (uint16_t)NUM2UINT(arg);
|
196
|
+
}
|
197
|
+
arg = rb_hash_lookup2(opts, cb_sym_quiet, Qundef);
|
198
|
+
if (arg != Qundef) {
|
199
|
+
bucket->quiet = RTEST(arg);
|
200
|
+
}
|
201
|
+
arg = rb_hash_aref(opts, cb_sym_timeout);
|
202
|
+
if (arg != Qnil) {
|
203
|
+
bucket->timeout = (uint32_t)NUM2ULONG(arg);
|
204
|
+
}
|
205
|
+
arg = rb_hash_aref(opts, cb_sym_default_ttl);
|
206
|
+
if (arg != Qnil) {
|
207
|
+
bucket->default_ttl = (uint32_t)NUM2ULONG(arg);
|
208
|
+
}
|
209
|
+
arg = rb_hash_aref(opts, cb_sym_default_observe_timeout);
|
210
|
+
if (arg != Qnil) {
|
211
|
+
bucket->default_observe_timeout = (uint32_t)NUM2ULONG(arg);
|
212
|
+
}
|
213
|
+
arg = rb_hash_aref(opts, cb_sym_default_flags);
|
214
|
+
if (arg != Qnil) {
|
215
|
+
bucket->default_flags = (uint32_t)NUM2ULONG(arg);
|
216
|
+
}
|
217
|
+
arg = rb_hash_aref(opts, cb_sym_default_format);
|
218
|
+
if (arg != Qnil) {
|
219
|
+
if (TYPE(arg) == T_FIXNUM) {
|
220
|
+
rb_warn("numeric argument to :default_format option is deprecated, use symbol");
|
221
|
+
switch (FIX2INT(arg)) {
|
222
|
+
case CB_FMT_DOCUMENT:
|
223
|
+
arg = cb_sym_document;
|
224
|
+
break;
|
225
|
+
case CB_FMT_MARSHAL:
|
226
|
+
arg = cb_sym_marshal;
|
227
|
+
break;
|
228
|
+
case CB_FMT_PLAIN:
|
229
|
+
arg = cb_sym_plain;
|
230
|
+
break;
|
231
|
+
}
|
232
|
+
}
|
233
|
+
if (arg == cb_sym_document) {
|
234
|
+
cb_bucket_transcoder_set(bucket->self, cb_mDocument);
|
235
|
+
} else if (arg == cb_sym_marshal) {
|
236
|
+
cb_bucket_transcoder_set(bucket->self, cb_mMarshal);
|
237
|
+
} else if (arg == cb_sym_plain) {
|
238
|
+
cb_bucket_transcoder_set(bucket->self, cb_mPlain);
|
239
|
+
}
|
240
|
+
}
|
241
|
+
arg = rb_hash_lookup2(opts, cb_sym_transcoder, Qundef);
|
242
|
+
if (arg != Qundef) {
|
243
|
+
cb_bucket_transcoder_set(bucket->self, arg);
|
244
|
+
}
|
245
|
+
if (arg != Qnil) {
|
246
|
+
if (arg == cb_sym_production || arg == cb_sym_development) {
|
247
|
+
bucket->environment = arg;
|
248
|
+
}
|
249
|
+
}
|
250
|
+
arg = rb_hash_aref(opts, cb_sym_key_prefix);
|
251
|
+
if (arg != Qnil) {
|
252
|
+
bucket->key_prefix_val = rb_str_dup_frozen(StringValue(arg));
|
253
|
+
}
|
254
|
+
arg = rb_hash_aref(opts, cb_sym_default_arithmetic_init);
|
255
|
+
if (arg != Qnil) {
|
256
|
+
bucket->default_arith_create = RTEST(arg);
|
257
|
+
if (TYPE(arg) == T_FIXNUM) {
|
258
|
+
bucket->default_arith_init = NUM2ULL(arg);
|
259
|
+
}
|
260
|
+
}
|
261
|
+
arg = rb_hash_aref(opts, cb_sym_engine);
|
262
|
+
if (arg != Qnil) {
|
263
|
+
if (arg == cb_sym_default) {
|
264
|
+
bucket->engine = cb_sym_default;
|
265
|
+
} else if (arg == cb_sym_select) {
|
266
|
+
bucket->engine = cb_sym_select;
|
267
|
+
#ifdef _WIN32
|
268
|
+
} else if (arg == cb_sym_iocp) {
|
269
|
+
bucket->engine = cb_sym_iocp;
|
270
|
+
#else
|
271
|
+
} else if (arg == cb_sym_libev) {
|
272
|
+
bucket->engine = cb_sym_libev;
|
273
|
+
} else if (arg == cb_sym_libevent) {
|
274
|
+
bucket->engine = cb_sym_libevent;
|
275
|
+
#ifdef BUILD_EVENTMACHINE_PLUGIN
|
276
|
+
} else if (arg == cb_sym_eventmachine) {
|
277
|
+
bucket->engine = cb_sym_eventmachine;
|
278
|
+
#endif
|
279
|
+
#endif
|
280
|
+
} else {
|
281
|
+
VALUE ins = rb_funcall(arg, rb_intern("inspect"), 0);
|
282
|
+
rb_raise(rb_eArgError, "Couchbase: unknown engine %s", RSTRING_PTR(ins));
|
283
|
+
}
|
284
|
+
}
|
285
|
+
bucket->async = RTEST(rb_hash_aref(opts, cb_sym_async));
|
286
|
+
arg = rb_hash_aref(opts, cb_sym_transcoder);
|
287
|
+
if (arg != Qnil) {
|
288
|
+
bucket->default_arith_create = RTEST(arg);
|
289
|
+
if (TYPE(arg) == T_FIXNUM) {
|
290
|
+
bucket->default_arith_init = NUM2ULL(arg);
|
291
|
+
}
|
292
|
+
}
|
293
|
+
} else {
|
294
|
+
opts = Qnil;
|
295
|
+
}
|
296
|
+
}
|
297
|
+
if (RTEST(bucket->password) && !RTEST(bucket->username)) {
|
298
|
+
bucket->username = bucket->bucket;
|
299
|
+
}
|
300
|
+
if (bucket->default_observe_timeout < 2) {
|
301
|
+
rb_raise(rb_eArgError, "default_observe_timeout is too low");
|
302
|
+
}
|
303
|
+
snprintf(port_s, sizeof(port_s), ":%u", bucket->port);
|
304
|
+
bucket->authority = rb_str_dup(bucket->hostname);
|
305
|
+
rb_str_cat2(bucket->authority, port_s);
|
306
|
+
rb_str_freeze(bucket->authority);
|
307
|
+
}
|
308
|
+
|
309
|
+
static VALUE
|
310
|
+
em_disconnect_block(VALUE unused, VALUE self)
|
311
|
+
{
|
312
|
+
struct cb_bucket_st *bucket = DATA_PTR(self);
|
313
|
+
if (bucket->handle) {
|
314
|
+
return cb_bucket_disconnect(self);
|
315
|
+
}
|
316
|
+
(void)unused;
|
317
|
+
return Qnil;
|
318
|
+
}
|
319
|
+
|
320
|
+
static void
|
321
|
+
do_connect(struct cb_bucket_st *bucket)
|
322
|
+
{
|
323
|
+
lcb_error_t err;
|
324
|
+
struct lcb_create_st create_opts;
|
325
|
+
|
326
|
+
if (bucket->handle) {
|
327
|
+
cb_bucket_disconnect(bucket->self);
|
328
|
+
}
|
329
|
+
|
330
|
+
{
|
331
|
+
struct lcb_create_io_ops_st ciops;
|
332
|
+
memset(&ciops, 0, sizeof(ciops));
|
333
|
+
ciops.version = 0;
|
334
|
+
|
335
|
+
if (bucket->engine == cb_sym_libevent) {
|
336
|
+
ciops.v.v0.type = LCB_IO_OPS_LIBEVENT;
|
337
|
+
} else if (bucket->engine == cb_sym_select) {
|
338
|
+
ciops.v.v0.type = LCB_IO_OPS_SELECT;
|
339
|
+
#ifdef _WIN32
|
340
|
+
} else if (bucket->engine == cb_sym_iocp) {
|
341
|
+
ciops.v.v0.type = LCB_IO_OPS_WINIOCP;
|
342
|
+
#endif
|
343
|
+
} else if (bucket->engine == cb_sym_libev) {
|
344
|
+
ciops.v.v0.type = LCB_IO_OPS_LIBEV;
|
345
|
+
} else if (bucket->engine == cb_sym_eventmachine) {
|
346
|
+
ciops.version = 1;
|
347
|
+
ciops.v.v1.sofile = NULL;
|
348
|
+
ciops.v.v1.symbol = "cb_create_ruby_em_io_opts";
|
349
|
+
ciops.v.v1.cookie = bucket;
|
350
|
+
} else {
|
351
|
+
#ifdef _WIN32
|
352
|
+
ciops.v.v0.type = LCB_IO_OPS_DEFAULT;
|
353
|
+
#else
|
354
|
+
ciops.version = 1;
|
355
|
+
ciops.v.v1.sofile = NULL;
|
356
|
+
ciops.v.v1.symbol = "cb_create_ruby_mt_io_opts";
|
357
|
+
ciops.v.v1.cookie = NULL;
|
358
|
+
#endif
|
359
|
+
}
|
360
|
+
err = lcb_create_io_ops(&bucket->io, &ciops);
|
361
|
+
if (err != LCB_SUCCESS) {
|
362
|
+
rb_exc_raise(cb_check_error(err, "failed to create IO instance", Qnil));
|
363
|
+
}
|
364
|
+
}
|
365
|
+
|
366
|
+
memset(&create_opts, 0, sizeof(struct lcb_create_st));
|
367
|
+
create_opts.version = 1;
|
368
|
+
create_opts.v.v1.type = bucket->type;
|
369
|
+
create_opts.v.v1.host = RTEST(bucket->node_list) ? RSTRING_PTR(bucket-> node_list) : RSTRING_PTR(bucket->authority);
|
370
|
+
create_opts.v.v1.user = RTEST(bucket->username) ? RSTRING_PTR(bucket->username) : NULL;
|
371
|
+
create_opts.v.v1.passwd = RTEST(bucket->password) ? RSTRING_PTR(bucket->password) : NULL;
|
372
|
+
create_opts.v.v1.bucket = RSTRING_PTR(bucket->bucket);
|
373
|
+
create_opts.v.v1.io = bucket->io;
|
374
|
+
err = lcb_create(&bucket->handle, &create_opts);
|
375
|
+
if (err != LCB_SUCCESS) {
|
376
|
+
bucket->handle = NULL;
|
377
|
+
rb_exc_raise(cb_check_error(err, "failed to create libcouchbase instance", Qnil));
|
378
|
+
}
|
379
|
+
lcb_set_cookie(bucket->handle, bucket);
|
380
|
+
(void)lcb_set_error_callback(bucket->handle, error_callback);
|
381
|
+
(void)lcb_set_store_callback(bucket->handle, cb_storage_callback);
|
382
|
+
(void)lcb_set_get_callback(bucket->handle, cb_get_callback);
|
383
|
+
(void)lcb_set_touch_callback(bucket->handle, cb_touch_callback);
|
384
|
+
(void)lcb_set_remove_callback(bucket->handle, cb_delete_callback);
|
385
|
+
(void)lcb_set_stat_callback(bucket->handle, cb_stat_callback);
|
386
|
+
(void)lcb_set_arithmetic_callback(bucket->handle, cb_arithmetic_callback);
|
387
|
+
(void)lcb_set_version_callback(bucket->handle, cb_version_callback);
|
388
|
+
(void)lcb_set_http_complete_callback(bucket->handle, cb_http_complete_callback);
|
389
|
+
(void)lcb_set_http_data_callback(bucket->handle, cb_http_data_callback);
|
390
|
+
(void)lcb_set_observe_callback(bucket->handle, cb_observe_callback);
|
391
|
+
(void)lcb_set_unlock_callback(bucket->handle, cb_unlock_callback);
|
392
|
+
(void)lcb_set_configuration_callback(bucket->handle, configuration_callback);
|
393
|
+
|
394
|
+
if (bucket->timeout > 0) {
|
395
|
+
lcb_set_timeout(bucket->handle, bucket->timeout);
|
396
|
+
} else {
|
397
|
+
bucket->timeout = lcb_get_timeout(bucket->handle);
|
398
|
+
}
|
399
|
+
err = lcb_connect(bucket->handle);
|
400
|
+
if (err != LCB_SUCCESS) {
|
401
|
+
cb_bucket_disconnect(bucket->self);
|
402
|
+
rb_exc_raise(cb_check_error(err, "failed to connect libcouchbase instance to server", Qnil));
|
403
|
+
}
|
404
|
+
bucket->exception = Qnil;
|
405
|
+
if (bucket->engine == cb_sym_eventmachine && !bucket->async_disconnect_hook_set) {
|
406
|
+
bucket->async_disconnect_hook_set = 1;
|
407
|
+
rb_block_call(em_m, cb_id_add_shutdown_hook, 0, NULL, em_disconnect_block, bucket->self);
|
408
|
+
}
|
409
|
+
if (!bucket->async) {
|
410
|
+
lcb_wait(bucket->handle);
|
411
|
+
if (bucket->exception != Qnil) {
|
412
|
+
cb_bucket_disconnect(bucket->self);
|
413
|
+
rb_exc_raise(bucket->exception);
|
414
|
+
}
|
415
|
+
}
|
416
|
+
}
|
417
|
+
|
418
|
+
VALUE
|
419
|
+
cb_bucket_alloc(VALUE klass)
|
420
|
+
{
|
421
|
+
VALUE obj;
|
422
|
+
struct cb_bucket_st *bucket;
|
423
|
+
|
424
|
+
/* allocate new bucket struct and set it to zero */
|
425
|
+
obj = Data_Make_Struct(klass, struct cb_bucket_st, cb_bucket_mark, cb_bucket_free,
|
426
|
+
bucket);
|
427
|
+
return obj;
|
428
|
+
}
|
429
|
+
|
430
|
+
/*
|
431
|
+
* Initialize new Bucket.
|
432
|
+
*
|
433
|
+
* @since 1.0.0
|
434
|
+
*
|
435
|
+
* @overload initialize(url, options = {})
|
436
|
+
* Initialize bucket using URI of the cluster and options. It is possible
|
437
|
+
* to override some parts of URI using the options keys (e.g. :host or
|
438
|
+
* :port)
|
439
|
+
*
|
440
|
+
* @param [String] url The full URL of management API of the cluster.
|
441
|
+
* @param [Hash] options The options for connection. See options definition
|
442
|
+
* below.
|
443
|
+
*
|
444
|
+
* @overload initialize(options = {})
|
445
|
+
* Initialize bucket using options only.
|
446
|
+
*
|
447
|
+
* @param [Hash] options The options for operation for connection
|
448
|
+
* @option options [Array] :node_list (nil) the list of nodes to connect
|
449
|
+
* to. If specified it takes precedence over +:host+ option. The list
|
450
|
+
* must be array of strings in form of host names or host names with
|
451
|
+
* ports (in first case port 8091 will be used, see examples).
|
452
|
+
* @option options [String] :host ("localhost") the hostname or IP address
|
453
|
+
* of the node
|
454
|
+
* @option options [Fixnum] :port (8091) the port of the managemenent API
|
455
|
+
* @option options [String] :pool ("default") the pool name
|
456
|
+
* @option options [String] :bucket ("default") the bucket name
|
457
|
+
* @option options [Fixnum] :default_ttl (0) the TTL used by default during
|
458
|
+
* storing key-value pairs.
|
459
|
+
* @option options [Fixnum] :default_flags (0) the default flags.
|
460
|
+
* @option options [Symbol] :default_format (:document) the format, which
|
461
|
+
* will be used for values by default. Note that changing format will
|
462
|
+
* amend flags. (see {Bucket#default_format})
|
463
|
+
* @option options [String] :username (nil) the user name to connect to the
|
464
|
+
* cluster. Used to authenticate on management API. The username could
|
465
|
+
* be skipped for protected buckets, the bucket name will be used
|
466
|
+
* instead.
|
467
|
+
* @option options [String] :password (nil) the password of the user.
|
468
|
+
* @option options [true, false] :quiet (false) the flag controlling if raising
|
469
|
+
* exception when the client executes operations on non-existent keys. If it
|
470
|
+
* is +true+ it will raise {Couchbase::Error::NotFound} exceptions. The
|
471
|
+
* default behaviour is to return +nil+ value silently (might be useful in
|
472
|
+
* Rails cache).
|
473
|
+
* @option options [Symbol] :environment (:production) the mode of the
|
474
|
+
* connection. Currently it influences only on design documents set. If
|
475
|
+
* the environment is +:development+, you will able to get design
|
476
|
+
* documents with 'dev_' prefix, otherwise (in +:production+ mode) the
|
477
|
+
* library will hide them from you.
|
478
|
+
* @option options [String] :key_prefix (nil) the prefix string which will
|
479
|
+
* be prepended to each key before sending out, and sripped before
|
480
|
+
* returning back to the application.
|
481
|
+
* @option options [Fixnum] :timeout (2500000) the timeout for IO
|
482
|
+
* operations (in microseconds)
|
483
|
+
* @option options [Fixnum, true] :default_arithmetic_init (0) the default
|
484
|
+
* initial value for arithmetic operations. Setting this option to any
|
485
|
+
* non positive number forces creation missing keys with given default
|
486
|
+
* value. Setting it to +true+ will use zero as initial value. (see
|
487
|
+
* {Bucket#incr} and {Bucket#decr}).
|
488
|
+
* @option options [Symbol] :engine (:default) the IO engine to use
|
489
|
+
* Currently following engines are supported:
|
490
|
+
* :default :: Built-in engine (multi-thread friendly)
|
491
|
+
* :select :: select(2) IO plugin from libcouchbase
|
492
|
+
* :iocp :: "I/O Completion Ports" plugin from libcouchbase (windows only)
|
493
|
+
* :libevent :: libevent IO plugin from libcouchbase (optional)
|
494
|
+
* :libev :: libev IO plugin from libcouchbase (optional)
|
495
|
+
* :eventmachine :: EventMachine plugin (builtin, but requires EM gem and ruby 1.9+)
|
496
|
+
* @option options [true, false] :async (false) If true, the
|
497
|
+
* connection instance will be considered always asynchronous and
|
498
|
+
* IO interaction will be occured only when {Couchbase::Bucket#run}
|
499
|
+
* called. See {Couchbase::Bucket#on_connect} to hook your code
|
500
|
+
* after the instance will be connected.
|
501
|
+
*
|
502
|
+
* @example Initialize connection using default options
|
503
|
+
* Couchbase.new
|
504
|
+
*
|
505
|
+
* @example Select custom bucket
|
506
|
+
* Couchbase.new(:bucket => 'foo')
|
507
|
+
* Couchbase.new('http://localhost:8091/pools/default/buckets/foo')
|
508
|
+
*
|
509
|
+
* @example Connect to protected bucket
|
510
|
+
* Couchbase.new(:bucket => 'protected', :username => 'protected', :password => 'secret')
|
511
|
+
* Couchbase.new('http://localhost:8091/pools/default/buckets/protected',
|
512
|
+
* :username => 'protected', :password => 'secret')
|
513
|
+
*
|
514
|
+
* @example Use list of nodes, in case some nodes might be dead
|
515
|
+
* Couchbase.new(:node_list => ['example.com:8091', 'example.org:8091', 'example.net'])
|
516
|
+
*
|
517
|
+
* @raise [Couchbase::Error::BucketNotFound] if there is no such bucket to
|
518
|
+
* connect to
|
519
|
+
*
|
520
|
+
* @raise [Couchbase::Error::Connect] if the socket wasn't accessible
|
521
|
+
* (doesn't accept connections or doesn't respond in time)
|
522
|
+
*
|
523
|
+
* @return [Bucket]
|
524
|
+
*/
|
525
|
+
VALUE
|
526
|
+
cb_bucket_init(int argc, VALUE *argv, VALUE self)
|
527
|
+
{
|
528
|
+
struct cb_bucket_st *bucket = DATA_PTR(self);
|
529
|
+
bucket->self = self;
|
530
|
+
bucket->exception = Qnil;
|
531
|
+
bucket->type = LCB_TYPE_BUCKET;
|
532
|
+
bucket->hostname = cb_vStrLocalhost;
|
533
|
+
bucket->port = 8091;
|
534
|
+
bucket->pool = cb_vStrDefault;
|
535
|
+
bucket->bucket = cb_vStrDefault;
|
536
|
+
bucket->username = Qnil;
|
537
|
+
bucket->password = Qnil;
|
538
|
+
bucket->engine = cb_sym_default;
|
539
|
+
bucket->async = 0;
|
540
|
+
bucket->quiet = 0;
|
541
|
+
bucket->default_ttl = 0;
|
542
|
+
bucket->default_flags = 0;
|
543
|
+
cb_bucket_transcoder_set(self, cb_mDocument);
|
544
|
+
bucket->default_observe_timeout = 2500000;
|
545
|
+
bucket->on_error_proc = Qnil;
|
546
|
+
bucket->on_connect_proc = Qnil;
|
547
|
+
bucket->timeout = 0;
|
548
|
+
bucket->environment = cb_sym_production;
|
549
|
+
bucket->key_prefix_val = Qnil;
|
550
|
+
bucket->node_list = Qnil;
|
551
|
+
bucket->object_space = st_init_numtable();
|
552
|
+
bucket->destroying = 0;
|
553
|
+
bucket->connected = 0;
|
554
|
+
bucket->on_connect_proc = Qnil;
|
555
|
+
bucket->async_disconnect_hook_set = 0;
|
556
|
+
|
557
|
+
do_scan_connection_options(bucket, argc, argv);
|
558
|
+
do_connect(bucket);
|
559
|
+
|
560
|
+
return self;
|
561
|
+
}
|
562
|
+
|
563
|
+
/*
|
564
|
+
* Initialize copy
|
565
|
+
*
|
566
|
+
* Initializes copy of the object, used by {Couchbase::Bucket#dup}
|
567
|
+
*
|
568
|
+
* @param orig [Couchbase::Bucket] the source for copy
|
569
|
+
*
|
570
|
+
* @return [Couchbase::Bucket]
|
571
|
+
*/
|
572
|
+
VALUE
|
573
|
+
cb_bucket_init_copy(VALUE copy, VALUE orig)
|
574
|
+
{
|
575
|
+
struct cb_bucket_st *copy_b;
|
576
|
+
struct cb_bucket_st *orig_b;
|
577
|
+
|
578
|
+
if (copy == orig)
|
579
|
+
return copy;
|
580
|
+
|
581
|
+
if (TYPE(orig) != T_DATA || TYPE(copy) != T_DATA ||
|
582
|
+
RDATA(orig)->dfree != (RUBY_DATA_FUNC)cb_bucket_free) {
|
583
|
+
rb_raise(rb_eTypeError, "wrong argument type");
|
584
|
+
}
|
585
|
+
|
586
|
+
copy_b = DATA_PTR(copy);
|
587
|
+
orig_b = DATA_PTR(orig);
|
588
|
+
|
589
|
+
copy_b->self = copy_b->self;
|
590
|
+
copy_b->port = orig_b->port;
|
591
|
+
copy_b->authority = orig_b->authority;
|
592
|
+
copy_b->hostname = orig_b->hostname;
|
593
|
+
copy_b->pool = orig_b->pool;
|
594
|
+
copy_b->bucket = orig_b->bucket;
|
595
|
+
copy_b->username = orig_b->username;
|
596
|
+
copy_b->password = orig_b->password;
|
597
|
+
copy_b->engine = orig_b->engine;
|
598
|
+
copy_b->async = orig_b->async;
|
599
|
+
copy_b->quiet = orig_b->quiet;
|
600
|
+
copy_b->transcoder = orig_b->transcoder;
|
601
|
+
copy_b->default_flags = orig_b->default_flags;
|
602
|
+
copy_b->default_ttl = orig_b->default_ttl;
|
603
|
+
copy_b->environment = orig_b->environment;
|
604
|
+
copy_b->timeout = orig_b->timeout;
|
605
|
+
copy_b->exception = Qnil;
|
606
|
+
copy_b->async_disconnect_hook_set = 0;
|
607
|
+
if (orig_b->on_error_proc != Qnil) {
|
608
|
+
copy_b->on_error_proc = rb_funcall(orig_b->on_error_proc, cb_id_dup, 0);
|
609
|
+
}
|
610
|
+
if (orig_b->on_connect_proc != Qnil) {
|
611
|
+
copy_b->on_connect_proc = rb_funcall(orig_b->on_connect_proc, cb_id_dup, 0);
|
612
|
+
}
|
613
|
+
copy_b->key_prefix_val = orig_b->key_prefix_val;
|
614
|
+
copy_b->object_space = st_init_numtable();
|
615
|
+
copy_b->destroying = 0;
|
616
|
+
copy_b->connected = 0;
|
617
|
+
|
618
|
+
do_connect(copy_b);
|
619
|
+
|
620
|
+
return copy;
|
621
|
+
}
|
622
|
+
|
623
|
+
/*
|
624
|
+
* Reconnect the bucket
|
625
|
+
*
|
626
|
+
* @since 1.1.0
|
627
|
+
*
|
628
|
+
* Reconnect the bucket using initial configuration with optional
|
629
|
+
* redefinition.
|
630
|
+
*
|
631
|
+
* @overload reconnect(url, options = {})
|
632
|
+
* see {Bucket#initialize Bucket#initialize(url, options)}
|
633
|
+
* @return [Couchbase::Bucket]
|
634
|
+
*
|
635
|
+
* @overload reconnect(options = {})
|
636
|
+
* see {Bucket#initialize Bucket#initialize(options)}
|
637
|
+
* @return [Couchbase::Bucket]
|
638
|
+
*
|
639
|
+
* @example reconnect with current parameters
|
640
|
+
* c.reconnect
|
641
|
+
*
|
642
|
+
* @example reconnect the instance to another bucket
|
643
|
+
* c.reconnect(:bucket => 'new')
|
644
|
+
*/
|
645
|
+
VALUE
|
646
|
+
cb_bucket_reconnect(int argc, VALUE *argv, VALUE self)
|
647
|
+
{
|
648
|
+
struct cb_bucket_st *bucket = DATA_PTR(self);
|
649
|
+
|
650
|
+
do_scan_connection_options(bucket, argc, argv);
|
651
|
+
do_connect(bucket);
|
652
|
+
|
653
|
+
return self;
|
654
|
+
}
|
655
|
+
|
656
|
+
/* Document-method: connected?
|
657
|
+
* Check whether the instance connected to the cluster.
|
658
|
+
*
|
659
|
+
* @since 1.1.0
|
660
|
+
*
|
661
|
+
* @return [true, false] +true+ if the instance connected to the cluster
|
662
|
+
*/
|
663
|
+
VALUE
|
664
|
+
cb_bucket_connected_p(VALUE self)
|
665
|
+
{
|
666
|
+
struct cb_bucket_st *bucket = DATA_PTR(self);
|
667
|
+
return (bucket->handle && bucket->connected) ? Qtrue : Qfalse;
|
668
|
+
}
|
669
|
+
|
670
|
+
/* Document-method: async?
|
671
|
+
* Check whether the connection asynchronous.
|
672
|
+
*
|
673
|
+
* @since 1.0.0
|
674
|
+
*
|
675
|
+
* By default all operations are synchronous and block waiting for
|
676
|
+
* results, but you can make them asynchronous and run event loop
|
677
|
+
* explicitly. (see {Bucket#run})
|
678
|
+
*
|
679
|
+
* @example Return value of #get operation depending on async flag
|
680
|
+
* connection = Connection.new
|
681
|
+
* connection.async? #=> false
|
682
|
+
*
|
683
|
+
* connection.run do |conn|
|
684
|
+
* conn.async? #=> true
|
685
|
+
* end
|
686
|
+
*
|
687
|
+
* @return [true, false] +true+ if the connection if asynchronous
|
688
|
+
*
|
689
|
+
* @see Bucket#run
|
690
|
+
*/
|
691
|
+
VALUE
|
692
|
+
cb_bucket_async_p(VALUE self)
|
693
|
+
{
|
694
|
+
struct cb_bucket_st *bucket = DATA_PTR(self);
|
695
|
+
return bucket->async ? Qtrue : Qfalse;
|
696
|
+
}
|
697
|
+
|
698
|
+
VALUE
|
699
|
+
cb_bucket_quiet_get(VALUE self)
|
700
|
+
{
|
701
|
+
struct cb_bucket_st *bucket = DATA_PTR(self);
|
702
|
+
return bucket->quiet ? Qtrue : Qfalse;
|
703
|
+
}
|
704
|
+
|
705
|
+
VALUE
|
706
|
+
cb_bucket_quiet_set(VALUE self, VALUE val)
|
707
|
+
{
|
708
|
+
struct cb_bucket_st *bucket = DATA_PTR(self);
|
709
|
+
VALUE new;
|
710
|
+
|
711
|
+
bucket->quiet = RTEST(val);
|
712
|
+
new = bucket->quiet ? Qtrue : Qfalse;
|
713
|
+
return new;
|
714
|
+
}
|
715
|
+
|
716
|
+
VALUE
|
717
|
+
cb_bucket_default_flags_get(VALUE self)
|
718
|
+
{
|
719
|
+
struct cb_bucket_st *bucket = DATA_PTR(self);
|
720
|
+
return ULONG2NUM(bucket->default_flags);
|
721
|
+
}
|
722
|
+
|
723
|
+
VALUE
|
724
|
+
cb_bucket_default_flags_set(VALUE self, VALUE val)
|
725
|
+
{
|
726
|
+
struct cb_bucket_st *bucket = DATA_PTR(self);
|
727
|
+
|
728
|
+
bucket->default_flags = (uint32_t)NUM2ULONG(val);
|
729
|
+
return val;
|
730
|
+
}
|
731
|
+
|
732
|
+
VALUE
|
733
|
+
cb_bucket_transcoder_get(VALUE self)
|
734
|
+
{
|
735
|
+
struct cb_bucket_st *bucket = DATA_PTR(self);
|
736
|
+
return bucket->transcoder;
|
737
|
+
}
|
738
|
+
|
739
|
+
VALUE
|
740
|
+
cb_bucket_transcoder_set(VALUE self, VALUE val)
|
741
|
+
{
|
742
|
+
struct cb_bucket_st *bucket = DATA_PTR(self);
|
743
|
+
|
744
|
+
if (val != Qnil && !rb_respond_to(val, cb_id_dump) && !rb_respond_to(val, cb_id_load)) {
|
745
|
+
rb_raise(rb_eArgError, "transcoder must respond to dump and load methods");
|
746
|
+
}
|
747
|
+
bucket->transcoder = val;
|
748
|
+
|
749
|
+
return bucket->transcoder;
|
750
|
+
}
|
751
|
+
|
752
|
+
VALUE
|
753
|
+
cb_bucket_default_format_get(VALUE self)
|
754
|
+
{
|
755
|
+
struct cb_bucket_st *bucket = DATA_PTR(self);
|
756
|
+
|
757
|
+
if (bucket->transcoder == cb_mDocument) {
|
758
|
+
return cb_sym_document;
|
759
|
+
} else if (bucket->transcoder == cb_mMarshal) {
|
760
|
+
return cb_sym_marshal;
|
761
|
+
} else if (bucket->transcoder == cb_mPlain) {
|
762
|
+
return cb_sym_plain;
|
763
|
+
}
|
764
|
+
return Qnil;
|
765
|
+
}
|
766
|
+
|
767
|
+
VALUE
|
768
|
+
cb_bucket_default_format_set(VALUE self, VALUE val)
|
769
|
+
{
|
770
|
+
if (TYPE(val) == T_FIXNUM) {
|
771
|
+
rb_warn("numeric argument to #default_format option is deprecated, use symbol");
|
772
|
+
switch (FIX2INT(val)) {
|
773
|
+
case CB_FMT_DOCUMENT:
|
774
|
+
val = cb_sym_document;
|
775
|
+
break;
|
776
|
+
case CB_FMT_MARSHAL:
|
777
|
+
val = cb_sym_marshal;
|
778
|
+
break;
|
779
|
+
case CB_FMT_PLAIN:
|
780
|
+
val = cb_sym_plain;
|
781
|
+
break;
|
782
|
+
}
|
783
|
+
}
|
784
|
+
if (val == cb_sym_document) {
|
785
|
+
cb_bucket_transcoder_set(self, cb_mDocument);
|
786
|
+
} else if (val == cb_sym_marshal) {
|
787
|
+
cb_bucket_transcoder_set(self, cb_mMarshal);
|
788
|
+
} else if (val == cb_sym_plain) {
|
789
|
+
cb_bucket_transcoder_set(self, cb_mPlain);
|
790
|
+
} else {
|
791
|
+
rb_raise(rb_eArgError, "unknown format");
|
792
|
+
}
|
793
|
+
|
794
|
+
return val;
|
795
|
+
}
|
796
|
+
|
797
|
+
VALUE
|
798
|
+
cb_bucket_on_error_set(VALUE self, VALUE val)
|
799
|
+
{
|
800
|
+
struct cb_bucket_st *bucket = DATA_PTR(self);
|
801
|
+
|
802
|
+
if (rb_respond_to(val, cb_id_call)) {
|
803
|
+
bucket->on_error_proc = val;
|
804
|
+
} else {
|
805
|
+
bucket->on_error_proc = Qnil;
|
806
|
+
}
|
807
|
+
|
808
|
+
return bucket->on_error_proc;
|
809
|
+
}
|
810
|
+
|
811
|
+
VALUE
|
812
|
+
cb_bucket_on_error_get(VALUE self)
|
813
|
+
{
|
814
|
+
struct cb_bucket_st *bucket = DATA_PTR(self);
|
815
|
+
|
816
|
+
if (rb_block_given_p()) {
|
817
|
+
return cb_bucket_on_error_set(self, rb_block_proc());
|
818
|
+
} else {
|
819
|
+
return bucket->on_error_proc;
|
820
|
+
}
|
821
|
+
}
|
822
|
+
|
823
|
+
static
|
824
|
+
VALUE trigger_on_connect_callback_block(VALUE nil, VALUE self)
|
825
|
+
{
|
826
|
+
(void)nil;
|
827
|
+
return trigger_on_connect_callback(self);
|
828
|
+
}
|
829
|
+
|
830
|
+
VALUE
|
831
|
+
cb_bucket_on_connect_set(VALUE self, VALUE val)
|
832
|
+
{
|
833
|
+
struct cb_bucket_st *bucket = DATA_PTR(self);
|
834
|
+
|
835
|
+
if (rb_respond_to(val, cb_id_call)) {
|
836
|
+
bucket->on_connect_proc = val;
|
837
|
+
if (bucket->trigger_connect_cb_on_set) {
|
838
|
+
bucket->trigger_connect_cb_on_set = 0;
|
839
|
+
if (bucket->async) {
|
840
|
+
VALUE args[] = {INT2FIX(0)};
|
841
|
+
/* setup timer with zero interval to call on_connect
|
842
|
+
* callback on the next tick */
|
843
|
+
rb_block_call(bucket->self, cb_id_create_timer, 1,
|
844
|
+
args, trigger_on_connect_callback_block, bucket->self);
|
845
|
+
} else {
|
846
|
+
trigger_on_connect_callback(self);
|
847
|
+
}
|
848
|
+
}
|
849
|
+
} else {
|
850
|
+
bucket->on_connect_proc = Qnil;
|
851
|
+
}
|
852
|
+
|
853
|
+
return bucket->on_connect_proc;
|
854
|
+
}
|
855
|
+
|
856
|
+
VALUE
|
857
|
+
cb_bucket_on_connect_get(VALUE self)
|
858
|
+
{
|
859
|
+
struct cb_bucket_st *bucket = DATA_PTR(self);
|
860
|
+
|
861
|
+
if (rb_block_given_p()) {
|
862
|
+
return cb_bucket_on_connect_set(self, rb_block_proc());
|
863
|
+
} else {
|
864
|
+
return bucket->on_connect_proc;
|
865
|
+
}
|
866
|
+
}
|
867
|
+
|
868
|
+
VALUE
|
869
|
+
cb_bucket_timeout_get(VALUE self)
|
870
|
+
{
|
871
|
+
struct cb_bucket_st *bucket = DATA_PTR(self);
|
872
|
+
return ULONG2NUM(bucket->timeout);
|
873
|
+
}
|
874
|
+
|
875
|
+
VALUE
|
876
|
+
cb_bucket_timeout_set(VALUE self, VALUE val)
|
877
|
+
{
|
878
|
+
struct cb_bucket_st *bucket = DATA_PTR(self);
|
879
|
+
VALUE tmval;
|
880
|
+
|
881
|
+
bucket->timeout = (uint32_t)NUM2ULONG(val);
|
882
|
+
lcb_set_timeout(bucket->handle, bucket->timeout);
|
883
|
+
tmval = ULONG2NUM(bucket->timeout);
|
884
|
+
|
885
|
+
return tmval;
|
886
|
+
}
|
887
|
+
|
888
|
+
VALUE
|
889
|
+
cb_bucket_default_arithmetic_init_get(VALUE self)
|
890
|
+
{
|
891
|
+
struct cb_bucket_st *bucket = DATA_PTR(self);
|
892
|
+
return ULL2NUM(bucket->default_arith_init);
|
893
|
+
}
|
894
|
+
|
895
|
+
VALUE
|
896
|
+
cb_bucket_default_arithmetic_init_set(VALUE self, VALUE val)
|
897
|
+
{
|
898
|
+
struct cb_bucket_st *bucket = DATA_PTR(self);
|
899
|
+
|
900
|
+
bucket->default_arith_create = RTEST(val);
|
901
|
+
if (bucket->default_arith_create) {
|
902
|
+
bucket->default_arith_init = NUM2ULL(val);
|
903
|
+
} else {
|
904
|
+
bucket->default_arith_init = 0;
|
905
|
+
}
|
906
|
+
return ULL2NUM(bucket->default_arith_init);
|
907
|
+
}
|
908
|
+
|
909
|
+
VALUE
|
910
|
+
cb_bucket_key_prefix_get(VALUE self)
|
911
|
+
{
|
912
|
+
struct cb_bucket_st *bucket = DATA_PTR(self);
|
913
|
+
return bucket->key_prefix_val;
|
914
|
+
}
|
915
|
+
|
916
|
+
VALUE
|
917
|
+
cb_bucket_key_prefix_set(VALUE self, VALUE val)
|
918
|
+
{
|
919
|
+
struct cb_bucket_st *bucket = DATA_PTR(self);
|
920
|
+
|
921
|
+
bucket->key_prefix_val = rb_str_dup_frozen(StringValue(val));
|
922
|
+
|
923
|
+
return bucket->key_prefix_val;
|
924
|
+
}
|
925
|
+
|
926
|
+
/* Document-method: hostname
|
927
|
+
*
|
928
|
+
* @since 1.0.0
|
929
|
+
*
|
930
|
+
* @return [String] the host name of the management interface (default: "localhost")
|
931
|
+
*/
|
932
|
+
VALUE
|
933
|
+
cb_bucket_hostname_get(VALUE self)
|
934
|
+
{
|
935
|
+
struct cb_bucket_st *bucket = DATA_PTR(self);
|
936
|
+
|
937
|
+
if (bucket->handle) {
|
938
|
+
const char * host = lcb_get_host(bucket->handle);
|
939
|
+
unsigned long len = RSTRING_LEN(bucket->hostname);
|
940
|
+
if (len != strlen(host) || strncmp(RSTRING_PTR(bucket->hostname), host, len) != 0) {
|
941
|
+
bucket->hostname = STR_NEW_CSTR(host);
|
942
|
+
rb_str_freeze(bucket->hostname);
|
943
|
+
}
|
944
|
+
}
|
945
|
+
return bucket->hostname;
|
946
|
+
}
|
947
|
+
|
948
|
+
/* Document-method: port
|
949
|
+
*
|
950
|
+
* @since 1.0.0
|
951
|
+
*
|
952
|
+
* @return [Fixnum] the port number of the management interface (default: 8091)
|
953
|
+
*/
|
954
|
+
VALUE
|
955
|
+
cb_bucket_port_get(VALUE self)
|
956
|
+
{
|
957
|
+
struct cb_bucket_st *bucket = DATA_PTR(self);
|
958
|
+
if (bucket->handle) {
|
959
|
+
bucket->port = atoi(lcb_get_port(bucket->handle));
|
960
|
+
}
|
961
|
+
return UINT2NUM(bucket->port);
|
962
|
+
}
|
963
|
+
|
964
|
+
/* Document-method: authority
|
965
|
+
*
|
966
|
+
* @since 1.0.0
|
967
|
+
*
|
968
|
+
* @return [String] host with port
|
969
|
+
*/
|
970
|
+
VALUE
|
971
|
+
cb_bucket_authority_get(VALUE self)
|
972
|
+
{
|
973
|
+
struct cb_bucket_st *bucket = DATA_PTR(self);
|
974
|
+
VALUE old_hostname = bucket->hostname;
|
975
|
+
uint16_t old_port = bucket->port;
|
976
|
+
VALUE hostname = cb_bucket_hostname_get(self);
|
977
|
+
cb_bucket_port_get(self);
|
978
|
+
|
979
|
+
if (hostname != old_hostname || bucket->port != old_port) {
|
980
|
+
char port_s[8];
|
981
|
+
snprintf(port_s, sizeof(port_s), ":%u", bucket->port);
|
982
|
+
bucket->authority = rb_str_dup(hostname);
|
983
|
+
rb_str_cat2(bucket->authority, port_s);
|
984
|
+
rb_str_freeze(bucket->authority);
|
985
|
+
}
|
986
|
+
return bucket->authority;
|
987
|
+
}
|
988
|
+
|
989
|
+
/* Document-method: bucket
|
990
|
+
*
|
991
|
+
* @since 1.0.0
|
992
|
+
*
|
993
|
+
* @return [String] the bucket name
|
994
|
+
*/
|
995
|
+
VALUE
|
996
|
+
cb_bucket_bucket_get(VALUE self)
|
997
|
+
{
|
998
|
+
struct cb_bucket_st *bucket = DATA_PTR(self);
|
999
|
+
return bucket->bucket;
|
1000
|
+
}
|
1001
|
+
|
1002
|
+
/* Document-method: pool
|
1003
|
+
*
|
1004
|
+
* @since 1.0.0
|
1005
|
+
*
|
1006
|
+
* @return [String] the pool name (usually "default")
|
1007
|
+
*/
|
1008
|
+
VALUE
|
1009
|
+
cb_bucket_pool_get(VALUE self)
|
1010
|
+
{
|
1011
|
+
struct cb_bucket_st *bucket = DATA_PTR(self);
|
1012
|
+
return bucket->pool;
|
1013
|
+
}
|
1014
|
+
|
1015
|
+
/* Document-method: username
|
1016
|
+
*
|
1017
|
+
* @since 1.0.0
|
1018
|
+
*
|
1019
|
+
* @return [String] the username for protected buckets (usually matches
|
1020
|
+
* the bucket name)
|
1021
|
+
*/
|
1022
|
+
VALUE
|
1023
|
+
cb_bucket_username_get(VALUE self)
|
1024
|
+
{
|
1025
|
+
struct cb_bucket_st *bucket = DATA_PTR(self);
|
1026
|
+
return bucket->username;
|
1027
|
+
}
|
1028
|
+
|
1029
|
+
/* Document-method: password
|
1030
|
+
*
|
1031
|
+
* @since 1.0.0
|
1032
|
+
*
|
1033
|
+
* @return [String] the password for protected buckets
|
1034
|
+
*/
|
1035
|
+
VALUE
|
1036
|
+
cb_bucket_password_get(VALUE self)
|
1037
|
+
{
|
1038
|
+
struct cb_bucket_st *bucket = DATA_PTR(self);
|
1039
|
+
return bucket->password;
|
1040
|
+
}
|
1041
|
+
|
1042
|
+
/* Document-method: environment
|
1043
|
+
*
|
1044
|
+
* @since 1.2.0
|
1045
|
+
*
|
1046
|
+
* @see Bucket#initialize
|
1047
|
+
*
|
1048
|
+
* @return [Symbol] the environment (+:development+ or +:production+)
|
1049
|
+
*/
|
1050
|
+
VALUE
|
1051
|
+
cb_bucket_environment_get(VALUE self)
|
1052
|
+
{
|
1053
|
+
struct cb_bucket_st *bucket = DATA_PTR(self);
|
1054
|
+
return bucket->environment;
|
1055
|
+
}
|
1056
|
+
/* Document-method: num_replicas
|
1057
|
+
*
|
1058
|
+
* @since 1.2.0.dp6
|
1059
|
+
*
|
1060
|
+
* The numbers of the replicas for each node in the cluster
|
1061
|
+
*
|
1062
|
+
* @return [Fixnum]
|
1063
|
+
*/
|
1064
|
+
VALUE
|
1065
|
+
cb_bucket_num_replicas_get(VALUE self)
|
1066
|
+
{
|
1067
|
+
struct cb_bucket_st *bucket = DATA_PTR(self);
|
1068
|
+
int32_t nr = lcb_get_num_replicas(bucket->handle);
|
1069
|
+
if (nr < 0) {
|
1070
|
+
return Qnil;
|
1071
|
+
} else {
|
1072
|
+
return INT2FIX(nr);
|
1073
|
+
}
|
1074
|
+
}
|
1075
|
+
/* Document-method: default_observe_timeout
|
1076
|
+
*
|
1077
|
+
* @since 1.2.0.dp6
|
1078
|
+
*
|
1079
|
+
* Get default timeout value for {Bucket#observe_and_wait} operation in
|
1080
|
+
* microseconds
|
1081
|
+
*
|
1082
|
+
* @return [Fixnum]
|
1083
|
+
*/
|
1084
|
+
VALUE
|
1085
|
+
cb_bucket_default_observe_timeout_get(VALUE self)
|
1086
|
+
{
|
1087
|
+
struct cb_bucket_st *bucket = DATA_PTR(self);
|
1088
|
+
return INT2FIX(bucket->default_observe_timeout);
|
1089
|
+
}
|
1090
|
+
|
1091
|
+
/* Document-method: default_observe_timeout=
|
1092
|
+
*
|
1093
|
+
* @since 1.2.0.dp6
|
1094
|
+
*
|
1095
|
+
* Set default timeout value for {Bucket#observe_and_wait} operation in
|
1096
|
+
* microseconds
|
1097
|
+
*
|
1098
|
+
* @return [Fixnum]
|
1099
|
+
*/
|
1100
|
+
VALUE
|
1101
|
+
cb_bucket_default_observe_timeout_set(VALUE self, VALUE val)
|
1102
|
+
{
|
1103
|
+
struct cb_bucket_st *bucket = DATA_PTR(self);
|
1104
|
+
bucket->default_observe_timeout = FIX2INT(val);
|
1105
|
+
return val;
|
1106
|
+
}
|
1107
|
+
/* Document-method: url
|
1108
|
+
*
|
1109
|
+
* @since 1.0.0
|
1110
|
+
*
|
1111
|
+
* @return [String] the address of the cluster management interface
|
1112
|
+
*/
|
1113
|
+
VALUE
|
1114
|
+
cb_bucket_url_get(VALUE self)
|
1115
|
+
{
|
1116
|
+
struct cb_bucket_st *bucket = DATA_PTR(self);
|
1117
|
+
VALUE str;
|
1118
|
+
|
1119
|
+
(void)cb_bucket_authority_get(self);
|
1120
|
+
str = rb_str_buf_new2("http://");
|
1121
|
+
rb_str_append(str, bucket->authority);
|
1122
|
+
rb_str_buf_cat2(str, "/pools/");
|
1123
|
+
rb_str_append(str, bucket->pool);
|
1124
|
+
rb_str_buf_cat2(str, "/buckets/");
|
1125
|
+
rb_str_append(str, bucket->bucket);
|
1126
|
+
rb_str_buf_cat2(str, "/");
|
1127
|
+
return str;
|
1128
|
+
}
|
1129
|
+
|
1130
|
+
/*
|
1131
|
+
* Returns a string containing a human-readable representation of the
|
1132
|
+
* {Bucket}.
|
1133
|
+
*
|
1134
|
+
* @since 1.0.0
|
1135
|
+
*
|
1136
|
+
* @return [String]
|
1137
|
+
*/
|
1138
|
+
VALUE
|
1139
|
+
cb_bucket_inspect(VALUE self)
|
1140
|
+
{
|
1141
|
+
VALUE str;
|
1142
|
+
struct cb_bucket_st *bucket = DATA_PTR(self);
|
1143
|
+
char buf[200];
|
1144
|
+
|
1145
|
+
str = rb_str_buf_new2("#<");
|
1146
|
+
rb_str_buf_cat2(str, rb_obj_classname(self));
|
1147
|
+
snprintf(buf, 25, ":%p \"", (void *)self);
|
1148
|
+
(void)cb_bucket_authority_get(self);
|
1149
|
+
rb_str_buf_cat2(str, buf);
|
1150
|
+
rb_str_buf_cat2(str, "http://");
|
1151
|
+
rb_str_append(str, bucket->authority);
|
1152
|
+
rb_str_buf_cat2(str, "/pools/");
|
1153
|
+
rb_str_append(str, bucket->pool);
|
1154
|
+
rb_str_buf_cat2(str, "/buckets/");
|
1155
|
+
rb_str_append(str, bucket->bucket);
|
1156
|
+
rb_str_buf_cat2(str, "/\" transcoder=");
|
1157
|
+
rb_str_append(str, rb_inspect(bucket->transcoder));
|
1158
|
+
snprintf(buf, 150, ", default_flags=0x%x, quiet=%s, connected=%s, timeout=%u",
|
1159
|
+
bucket->default_flags,
|
1160
|
+
bucket->quiet ? "true" : "false",
|
1161
|
+
(bucket->handle && bucket->connected) ? "true" : "false",
|
1162
|
+
bucket->timeout);
|
1163
|
+
rb_str_buf_cat2(str, buf);
|
1164
|
+
if (RTEST(bucket->key_prefix_val)) {
|
1165
|
+
rb_str_buf_cat2(str, ", key_prefix=");
|
1166
|
+
rb_str_append(str, rb_inspect(bucket->key_prefix_val));
|
1167
|
+
}
|
1168
|
+
rb_str_buf_cat2(str, ">");
|
1169
|
+
|
1170
|
+
return str;
|
1171
|
+
}
|
1172
|
+
|
1173
|
+
static void
|
1174
|
+
do_loop(struct cb_bucket_st *bucket)
|
1175
|
+
{
|
1176
|
+
lcb_wait(bucket->handle);
|
1177
|
+
bucket->nbytes = 0;
|
1178
|
+
}
|
1179
|
+
|
1180
|
+
void
|
1181
|
+
cb_maybe_do_loop(struct cb_bucket_st *bucket)
|
1182
|
+
{
|
1183
|
+
if (bucket->threshold != 0 && bucket->nbytes > bucket->threshold) {
|
1184
|
+
do_loop(bucket);
|
1185
|
+
}
|
1186
|
+
}
|
1187
|
+
|
1188
|
+
static VALUE
|
1189
|
+
do_run(VALUE *args)
|
1190
|
+
{
|
1191
|
+
VALUE self = args[0], opts = args[1], proc = args[2], exc;
|
1192
|
+
VALUE was_async = args[3];
|
1193
|
+
struct cb_bucket_st *bucket = DATA_PTR(self);
|
1194
|
+
|
1195
|
+
if (bucket->handle == NULL) {
|
1196
|
+
rb_raise(cb_eConnectError, "closed connection");
|
1197
|
+
}
|
1198
|
+
|
1199
|
+
if (bucket->running) {
|
1200
|
+
rb_raise(cb_eInvalidError, "nested #run");
|
1201
|
+
}
|
1202
|
+
bucket->threshold = 0;
|
1203
|
+
if (opts != Qnil) {
|
1204
|
+
VALUE arg;
|
1205
|
+
Check_Type(opts, T_HASH);
|
1206
|
+
arg = rb_hash_aref(opts, cb_sym_send_threshold);
|
1207
|
+
if (arg != Qnil) {
|
1208
|
+
bucket->threshold = (uint32_t)NUM2ULONG(arg);
|
1209
|
+
}
|
1210
|
+
}
|
1211
|
+
bucket->async = 1;
|
1212
|
+
bucket->running = 1;
|
1213
|
+
if (proc != Qnil) {
|
1214
|
+
cb_proc_call(bucket, proc, 1, self);
|
1215
|
+
}
|
1216
|
+
if (bucket->exception != Qnil) {
|
1217
|
+
exc = bucket->exception;
|
1218
|
+
bucket->exception = Qnil;
|
1219
|
+
if (was_async) {
|
1220
|
+
cb_async_error_notify(bucket, exc);
|
1221
|
+
/* XXX return here? */
|
1222
|
+
} else {
|
1223
|
+
rb_exc_raise(exc);
|
1224
|
+
}
|
1225
|
+
}
|
1226
|
+
do_loop(bucket);
|
1227
|
+
if (bucket->exception != Qnil) {
|
1228
|
+
exc = bucket->exception;
|
1229
|
+
bucket->exception = Qnil;
|
1230
|
+
if (!was_async) {
|
1231
|
+
rb_exc_raise(exc);
|
1232
|
+
}
|
1233
|
+
/* async connections notified immediately from the callbacks
|
1234
|
+
* via cb_async_error_notify() */
|
1235
|
+
}
|
1236
|
+
return Qnil;
|
1237
|
+
}
|
1238
|
+
|
1239
|
+
static VALUE
|
1240
|
+
ensure_run(VALUE *args)
|
1241
|
+
{
|
1242
|
+
VALUE self = args[0];
|
1243
|
+
struct cb_bucket_st *bucket = DATA_PTR(self);
|
1244
|
+
|
1245
|
+
bucket->running = 0;
|
1246
|
+
bucket->async = args[3];
|
1247
|
+
bucket->running = args[4];
|
1248
|
+
return Qnil;
|
1249
|
+
}
|
1250
|
+
|
1251
|
+
/*
|
1252
|
+
* Run the event loop.
|
1253
|
+
*
|
1254
|
+
* @since 1.0.0
|
1255
|
+
*
|
1256
|
+
* @param [Hash] options The options for operation for connection
|
1257
|
+
* @option options [Fixnum] :send_threshold (0) if the internal command
|
1258
|
+
* buffer will exceeds this value, then the library will start network
|
1259
|
+
* interaction and block the current thread until all scheduled commands
|
1260
|
+
* will be completed.
|
1261
|
+
*
|
1262
|
+
* @yieldparam [Bucket] bucket the bucket instance
|
1263
|
+
*
|
1264
|
+
* @example Use block to run the loop
|
1265
|
+
* c = Couchbase.new
|
1266
|
+
* c.run do
|
1267
|
+
* c.get("foo") {|ret| puts ret.value}
|
1268
|
+
* end
|
1269
|
+
*
|
1270
|
+
* @example Use lambda to run the loop
|
1271
|
+
* c = Couchbase.new
|
1272
|
+
* operations = lambda do |c|
|
1273
|
+
* c.get("foo") {|ret| puts ret.value}
|
1274
|
+
* end
|
1275
|
+
* c.run(&operations)
|
1276
|
+
*
|
1277
|
+
* @example Use threshold to send out commands automatically
|
1278
|
+
* c = Couchbase.connect
|
1279
|
+
* sent = 0
|
1280
|
+
* c.run(:send_threshold => 8192) do # 8Kb
|
1281
|
+
* c.set("foo1", "x" * 100) {|r| sent += 1}
|
1282
|
+
* # 128 bytes buffered, sent is 0 now
|
1283
|
+
* c.set("foo2", "x" * 10000) {|r| sent += 1}
|
1284
|
+
* # 10028 bytes added, sent is 2 now
|
1285
|
+
* c.set("foo3", "x" * 100) {|r| sent += 1}
|
1286
|
+
* end
|
1287
|
+
* # all commands were executed and sent is 3 now
|
1288
|
+
*
|
1289
|
+
* @example Use {Couchbase::Bucket#run} without block for async connection
|
1290
|
+
* c = Couchbase.new(:async => true)
|
1291
|
+
* c.run # ensure that instance connected
|
1292
|
+
* c.set("foo", "bar"){|r| puts r.cas}
|
1293
|
+
* c.run
|
1294
|
+
*
|
1295
|
+
* @return [nil]
|
1296
|
+
*
|
1297
|
+
* @raise [Couchbase::Error::Connect] if connection closed (see {Bucket#reconnect})
|
1298
|
+
*/
|
1299
|
+
VALUE
|
1300
|
+
cb_bucket_run(int argc, VALUE *argv, VALUE self)
|
1301
|
+
{
|
1302
|
+
struct cb_bucket_st *bucket = DATA_PTR(self);
|
1303
|
+
VALUE args[5];
|
1304
|
+
|
1305
|
+
/* it is allowed to omit block for async connections */
|
1306
|
+
if (!bucket->async) {
|
1307
|
+
rb_need_block();
|
1308
|
+
}
|
1309
|
+
args[0] = self;
|
1310
|
+
rb_scan_args(argc, argv, "01&", &args[1], &args[2]);
|
1311
|
+
args[3] = bucket->async;
|
1312
|
+
args[4] = bucket->running;
|
1313
|
+
rb_ensure(do_run, (VALUE)args, ensure_run, (VALUE)args);
|
1314
|
+
return Qnil;
|
1315
|
+
}
|
1316
|
+
|
1317
|
+
/*
|
1318
|
+
* Stop the event loop.
|
1319
|
+
*
|
1320
|
+
* @since 1.2.0
|
1321
|
+
*
|
1322
|
+
* @example Breakout the event loop when 5th request is completed
|
1323
|
+
* c = Couchbase.connect
|
1324
|
+
* c.run do
|
1325
|
+
* 10.times do |ii|
|
1326
|
+
* c.get("foo") do |ret|
|
1327
|
+
* puts ii
|
1328
|
+
* c.stop if ii == 5
|
1329
|
+
* end
|
1330
|
+
* end
|
1331
|
+
* end
|
1332
|
+
*
|
1333
|
+
* @return [nil]
|
1334
|
+
*/
|
1335
|
+
VALUE
|
1336
|
+
cb_bucket_stop(VALUE self)
|
1337
|
+
{
|
1338
|
+
struct cb_bucket_st *bucket = DATA_PTR(self);
|
1339
|
+
lcb_breakout(bucket->handle);
|
1340
|
+
return Qnil;
|
1341
|
+
}
|
1342
|
+
|
1343
|
+
/*
|
1344
|
+
* Close the connection to the cluster
|
1345
|
+
*
|
1346
|
+
* @since 1.1.0
|
1347
|
+
*
|
1348
|
+
* @return [true]
|
1349
|
+
*
|
1350
|
+
* @raise [Couchbase::Error::Connect] if connection closed (see {Bucket#reconnect})
|
1351
|
+
*/
|
1352
|
+
VALUE
|
1353
|
+
cb_bucket_disconnect(VALUE self)
|
1354
|
+
{
|
1355
|
+
struct cb_bucket_st *bucket = DATA_PTR(self);
|
1356
|
+
|
1357
|
+
if (bucket->handle) {
|
1358
|
+
lcb_destroy(bucket->handle);
|
1359
|
+
lcb_destroy_io_ops(bucket->io);
|
1360
|
+
bucket->handle = NULL;
|
1361
|
+
bucket->io = NULL;
|
1362
|
+
bucket->connected = 0;
|
1363
|
+
return Qtrue;
|
1364
|
+
} else {
|
1365
|
+
rb_raise(cb_eConnectError, "closed connection");
|
1366
|
+
return Qfalse;
|
1367
|
+
}
|
1368
|
+
}
|
1369
|
+
|
1370
|
+
|