couchbase 1.1.5-x86-mingw32 → 1.2.0.beta-x86-mingw32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/.gitignore +2 -1
  2. data/.travis.yml +12 -1
  3. data/HISTORY.markdown +112 -1
  4. data/README.markdown +149 -6
  5. data/couchbase.gemspec +5 -1
  6. data/ext/couchbase_ext/.gitignore +4 -0
  7. data/ext/couchbase_ext/arguments.c +973 -0
  8. data/ext/couchbase_ext/arithmetic.c +322 -0
  9. data/ext/couchbase_ext/bucket.c +1092 -0
  10. data/ext/couchbase_ext/couchbase_ext.c +618 -3247
  11. data/ext/couchbase_ext/couchbase_ext.h +519 -0
  12. data/ext/couchbase_ext/delete.c +167 -0
  13. data/ext/couchbase_ext/extconf.rb +24 -5
  14. data/ext/couchbase_ext/get.c +301 -0
  15. data/ext/couchbase_ext/gethrtime.c +124 -0
  16. data/ext/couchbase_ext/http.c +402 -0
  17. data/ext/couchbase_ext/observe.c +174 -0
  18. data/ext/couchbase_ext/result.c +126 -0
  19. data/ext/couchbase_ext/stats.c +169 -0
  20. data/ext/couchbase_ext/store.c +522 -0
  21. data/ext/couchbase_ext/timer.c +192 -0
  22. data/ext/couchbase_ext/touch.c +190 -0
  23. data/ext/couchbase_ext/unlock.c +180 -0
  24. data/ext/couchbase_ext/utils.c +471 -0
  25. data/ext/couchbase_ext/version.c +147 -0
  26. data/lib/action_dispatch/middleware/session/couchbase_store.rb +38 -0
  27. data/lib/active_support/cache/couchbase_store.rb +356 -0
  28. data/lib/couchbase.rb +24 -3
  29. data/lib/couchbase/bucket.rb +372 -9
  30. data/lib/couchbase/result.rb +26 -0
  31. data/lib/couchbase/utils.rb +59 -0
  32. data/lib/couchbase/version.rb +1 -1
  33. data/lib/couchbase/view.rb +305 -0
  34. data/lib/couchbase/view_row.rb +230 -0
  35. data/lib/ext/multi_json_fix.rb +47 -0
  36. data/lib/rack/session/couchbase.rb +104 -0
  37. data/tasks/compile.rake +5 -14
  38. data/test/setup.rb +6 -2
  39. data/test/test_arithmetic.rb +32 -2
  40. data/test/test_async.rb +18 -4
  41. data/test/test_bucket.rb +11 -1
  42. data/test/test_cas.rb +13 -3
  43. data/test/test_couchbase_rails_cache_store.rb +294 -0
  44. data/test/test_delete.rb +60 -3
  45. data/test/test_format.rb +28 -17
  46. data/test/test_get.rb +91 -14
  47. data/test/test_store.rb +31 -1
  48. data/test/{test_flush.rb → test_timer.rb} +11 -18
  49. data/test/test_touch.rb +33 -5
  50. data/test/test_unlock.rb +120 -0
  51. data/test/test_utils.rb +26 -0
  52. metadata +102 -12
@@ -15,3344 +15,528 @@
15
15
  * limitations under the License.
16
16
  */
17
17
 
18
- #include <ruby.h>
19
- #ifndef RUBY_ST_H
20
- #include <st.h>
21
- #endif
22
18
 
23
- #include <time.h>
24
- #include <libcouchbase/couchbase.h>
25
- #include "couchbase_config.h"
19
+ #include "couchbase_ext.h"
20
+
21
+ /* Classes */
22
+ VALUE cBucket;
23
+ VALUE cCouchRequest;
24
+ VALUE cResult;
25
+ VALUE cTimer;
26
+
27
+ /* Modules */
28
+ VALUE mCouchbase;
29
+ VALUE mError;
30
+ VALUE mMarshal;
31
+ VALUE mMultiJson;
32
+ VALUE mURI;
33
+
34
+ /* Symbols */
35
+ ID sym_add;
36
+ ID sym_append;
37
+ ID sym_assemble_hash;
38
+ ID sym_body;
39
+ ID sym_bucket;
40
+ ID sym_cas;
41
+ ID sym_chunked;
42
+ ID sym_content_type;
43
+ ID sym_create;
44
+ ID sym_decrement;
45
+ ID sym_default_flags;
46
+ ID sym_default_format;
47
+ ID sym_default_observe_timeout;
48
+ ID sym_default_ttl;
49
+ ID sym_delete;
50
+ ID sym_delta;
51
+ ID sym_development;
52
+ ID sym_document;
53
+ ID sym_environment;
54
+ ID sym_extended;
55
+ ID sym_flags;
56
+ ID sym_format;
57
+ ID sym_found;
58
+ ID sym_get;
59
+ ID sym_hostname;
60
+ ID sym_http_request;
61
+ ID sym_increment;
62
+ ID sym_initial;
63
+ ID sym_key_prefix;
64
+ ID sym_lock;
65
+ ID sym_management;
66
+ ID sym_marshal;
67
+ ID sym_method;
68
+ ID sym_node_list;
69
+ ID sym_not_found;
70
+ ID sym_num_replicas;
71
+ ID sym_observe;
72
+ ID sym_password;
73
+ ID sym_periodic;
74
+ ID sym_persisted;
75
+ ID sym_plain;
76
+ ID sym_pool;
77
+ ID sym_port;
78
+ ID sym_post;
79
+ ID sym_prepend;
80
+ ID sym_production;
81
+ ID sym_put;
82
+ ID sym_quiet;
83
+ ID sym_replace;
84
+ ID sym_replica;
85
+ ID sym_send_threshold;
86
+ ID sym_set;
87
+ ID sym_stats;
88
+ ID sym_timeout;
89
+ ID sym_touch;
90
+ ID sym_ttl;
91
+ ID sym_type;
92
+ ID sym_unlock;
93
+ ID sym_username;
94
+ ID sym_version;
95
+ ID sym_view;
96
+ ID id_arity;
97
+ ID id_call;
98
+ ID id_delete;
99
+ ID id_dump;
100
+ ID id_dup;
101
+ ID id_flatten_bang;
102
+ ID id_has_key_p;
103
+ ID id_host;
104
+ ID id_iv_cas;
105
+ ID id_iv_completed;
106
+ ID id_iv_error;
107
+ ID id_iv_flags;
108
+ ID id_iv_from_master;
109
+ ID id_iv_headers;
110
+ ID id_iv_key;
111
+ ID id_iv_node;
112
+ ID id_iv_operation;
113
+ ID id_iv_status;
114
+ ID id_iv_time_to_persist;
115
+ ID id_iv_time_to_replicate;
116
+ ID id_iv_value;
117
+ ID id_load;
118
+ ID id_match;
119
+ ID id_observe_and_wait;
120
+ ID id_parse;
121
+ ID id_password;
122
+ ID id_path;
123
+ ID id_port;
124
+ ID id_scheme;
125
+ ID id_to_s;
126
+ ID id_user;
127
+ ID id_verify_observe_options;
128
+
129
+ /* Errors */
130
+ VALUE eBaseError;
131
+ VALUE eValueFormatError;
132
+ /* LCB_SUCCESS = 0x00 */
133
+ /* LCB_AUTH_CONTINUE = 0x01 */
134
+ VALUE eAuthError; /* LCB_AUTH_ERROR = 0x02 */
135
+ VALUE eDeltaBadvalError; /* LCB_DELTA_BADVAL = 0x03 */
136
+ VALUE eTooBigError; /* LCB_E2BIG = 0x04 */
137
+ VALUE eBusyError; /* LCB_EBUSY = 0x05 */
138
+ VALUE eInternalError; /* LCB_EINTERNAL = 0x06 */
139
+ VALUE eInvalidError; /* LCB_EINVAL = 0x07 */
140
+ VALUE eNoMemoryError; /* LCB_ENOMEM = 0x08 */
141
+ VALUE eRangeError; /* LCB_ERANGE = 0x09 */
142
+ VALUE eLibcouchbaseError; /* LCB_ERROR = 0x0a */
143
+ VALUE eTmpFailError; /* LCB_ETMPFAIL = 0x0b */
144
+ VALUE eKeyExistsError; /* LCB_KEY_EEXISTS = 0x0c */
145
+ VALUE eNotFoundError; /* LCB_KEY_ENOENT = 0x0d */
146
+ VALUE eLibeventError; /* LCB_LIBEVENT_ERROR = 0x0e */
147
+ VALUE eNetworkError; /* LCB_NETWORK_ERROR = 0x0f */
148
+ VALUE eNotMyVbucketError; /* LCB_NOT_MY_VBUCKET = 0x10 */
149
+ VALUE eNotStoredError; /* LCB_NOT_STORED = 0x11 */
150
+ VALUE eNotSupportedError; /* LCB_NOT_SUPPORTED = 0x12 */
151
+ VALUE eUnknownCommandError; /* LCB_UNKNOWN_COMMAND = 0x13 */
152
+ VALUE eUnknownHostError; /* LCB_UNKNOWN_HOST = 0x14 */
153
+ VALUE eProtocolError; /* LCB_PROTOCOL_ERROR = 0x15 */
154
+ VALUE eTimeoutError; /* LCB_ETIMEDOUT = 0x16 */
155
+ VALUE eConnectError; /* LCB_CONNECT_ERROR = 0x17 */
156
+ VALUE eBucketNotFoundError; /* LCB_BUCKET_ENOENT = 0x18 */
157
+ VALUE eClientNoMemoryError; /* LCB_CLIENT_ENOMEM = 0x19 */
158
+ VALUE eClientTmpFailError; /* LCB_CLIENT_ETMPFAIL = 0x20 */
26
159
 
27
- #ifdef HAVE_RUBY_ENCODING_H
28
- #include "ruby/encoding.h"
29
- #define STR_NEW(ptr, len) rb_external_str_new((ptr), (len))
30
- #define STR_NEW_CSTR(str) rb_external_str_new_cstr((str))
31
- #else
32
- #define STR_NEW(ptr, len) rb_str_new((ptr), (len))
33
- #define STR_NEW_CSTR(str) rb_str_new2((str))
34
- #endif
35
-
36
- #ifdef HAVE_STDARG_PROTOTYPES
37
- #include <stdarg.h>
38
- #define va_init_list(a,b) va_start(a,b)
39
- #else
40
- #include <varargs.h>
41
- #define va_init_list(a,b) va_start(a)
42
- #endif
43
-
44
- #define debug_object(OBJ) \
45
- rb_funcall(rb_stderr, rb_intern("print"), 1, rb_funcall(OBJ, rb_intern("object_id"), 0)); \
46
- rb_funcall(rb_stderr, rb_intern("print"), 1, STR_NEW_CSTR(" ")); \
47
- rb_funcall(rb_stderr, rb_intern("print"), 1, rb_funcall(OBJ, rb_intern("class"), 0)); \
48
- rb_funcall(rb_stderr, rb_intern("print"), 1, STR_NEW_CSTR(" ")); \
49
- rb_funcall(rb_stderr, rb_intern("puts"), 1, rb_funcall(OBJ, rb_intern("inspect"), 0));
50
-
51
- #define FMT_MASK 0x3
52
- #define FMT_DOCUMENT 0x0
53
- #define FMT_MARSHAL 0x1
54
- #define FMT_PLAIN 0x2
55
-
56
- typedef struct
57
- {
58
- libcouchbase_t handle;
59
- struct libcouchbase_io_opt_st *io;
60
- uint16_t port;
61
- char *authority;
62
- char *hostname;
63
- char *pool;
64
- char *bucket;
65
- char *username;
66
- char *password;
67
- int async;
68
- int quiet;
69
- long seqno;
70
- VALUE default_format; /* should update +default_flags+ on change */
71
- uint32_t default_flags;
72
- time_t default_ttl;
73
- uint32_t timeout;
74
- VALUE exception; /* error delivered by error_callback */
75
- VALUE on_error_proc; /* is using to deliver errors in async mode */
76
- VALUE object_space;
77
- char *node_list;
78
- } bucket_t;
79
-
80
- typedef struct
81
- {
82
- bucket_t* bucket;
83
- int extended;
84
- VALUE proc;
85
- void *rv;
86
- VALUE exception;
87
- VALUE force_format;
88
- int quiet;
89
- int arithm; /* incr: +1, decr: -1, other: 0 */
90
- } context_t;
91
-
92
- struct key_traits
93
- {
94
- VALUE keys_ary;
95
- size_t nkeys;
96
- char **keys;
97
- libcouchbase_size_t *lens;
98
- time_t *ttls;
99
- int extended;
100
- int explicit_ttl;
101
- int quiet;
102
- int mgat;
103
- VALUE force_format;
104
- };
105
-
106
- static VALUE mCouchbase, mError, mJSON, mURI, mMarshal, cBucket, cResult;
107
-
108
- static ID sym_add,
109
- sym_append,
110
- sym_bucket,
111
- sym_cas,
112
- sym_create,
113
- sym_decrement,
114
- sym_default_flags,
115
- sym_default_format,
116
- sym_default_ttl,
117
- sym_delete,
118
- sym_document,
119
- sym_extended,
120
- sym_flags,
121
- sym_flush,
122
- sym_format,
123
- sym_get,
124
- sym_hostname,
125
- sym_increment,
126
- sym_initial,
127
- sym_marshal,
128
- sym_node_list,
129
- sym_password,
130
- sym_plain,
131
- sym_pool,
132
- sym_port,
133
- sym_prepend,
134
- sym_quiet,
135
- sym_replace,
136
- sym_set,
137
- sym_stats,
138
- sym_timeout,
139
- sym_touch,
140
- sym_ttl,
141
- sym_username,
142
- sym_version,
143
- id_arity,
144
- id_call,
145
- id_dump,
146
- id_flatten_bang,
147
- id_has_key_p,
148
- id_host,
149
- id_iv_cas,
150
- id_iv_error,
151
- id_iv_flags,
152
- id_iv_key,
153
- id_iv_node,
154
- id_iv_operation,
155
- id_iv_value,
156
- id_dup,
157
- id_load,
158
- id_match,
159
- id_parse,
160
- id_password,
161
- id_path,
162
- id_port,
163
- id_scheme,
164
- id_to_s,
165
- id_user;
166
-
167
- /* base error */
168
- static VALUE eBaseError;
169
- static VALUE eValueFormatError;
170
-
171
- /* libcouchbase errors */
172
- /*LIBCOUCHBASE_SUCCESS = 0x00*/
173
- /*LIBCOUCHBASE_AUTH_CONTINUE = 0x01*/
174
- static VALUE eAuthError; /*LIBCOUCHBASE_AUTH_ERROR = 0x02*/
175
- static VALUE eDeltaBadvalError; /*LIBCOUCHBASE_DELTA_BADVAL = 0x03*/
176
- static VALUE eTooBigError; /*LIBCOUCHBASE_E2BIG = 0x04*/
177
- static VALUE eBusyError; /*LIBCOUCHBASE_EBUSY = 0x05*/
178
- static VALUE eInternalError; /*LIBCOUCHBASE_EINTERNAL = 0x06*/
179
- static VALUE eInvalidError; /*LIBCOUCHBASE_EINVAL = 0x07*/
180
- static VALUE eNoMemoryError; /*LIBCOUCHBASE_ENOMEM = 0x08*/
181
- static VALUE eRangeError; /*LIBCOUCHBASE_ERANGE = 0x09*/
182
- static VALUE eLibcouchbaseError; /*LIBCOUCHBASE_ERROR = 0x0a*/
183
- static VALUE eTmpFailError; /*LIBCOUCHBASE_ETMPFAIL = 0x0b*/
184
- static VALUE eKeyExistsError; /*LIBCOUCHBASE_KEY_EEXISTS = 0x0c*/
185
- static VALUE eNotFoundError; /*LIBCOUCHBASE_KEY_ENOENT = 0x0d*/
186
- static VALUE eLibeventError; /*LIBCOUCHBASE_LIBEVENT_ERROR = 0x0e*/
187
- static VALUE eNetworkError; /*LIBCOUCHBASE_NETWORK_ERROR = 0x0f*/
188
- static VALUE eNotMyVbucketError; /*LIBCOUCHBASE_NOT_MY_VBUCKET = 0x10*/
189
- static VALUE eNotStoredError; /*LIBCOUCHBASE_NOT_STORED = 0x11*/
190
- static VALUE eNotSupportedError; /*LIBCOUCHBASE_NOT_SUPPORTED = 0x12*/
191
- static VALUE eUnknownCommandError; /*LIBCOUCHBASE_UNKNOWN_COMMAND = 0x13*/
192
- static VALUE eUnknownHostError; /*LIBCOUCHBASE_UNKNOWN_HOST = 0x14*/
193
- static VALUE eProtocolError; /*LIBCOUCHBASE_PROTOCOL_ERROR = 0x15*/
194
- static VALUE eTimeoutError; /*LIBCOUCHBASE_ETIMEDOUT = 0x16*/
195
- static VALUE eConnectError; /*LIBCOUCHBASE_CONNECT_ERROR = 0x17*/
196
- static VALUE eBucketNotFoundError; /*LIBCOUCHBASE_BUCKET_ENOENT = 0x18*/
197
-
198
- static void
199
- cb_gc_protect(bucket_t *bucket, VALUE val)
200
- {
201
- rb_hash_aset(bucket->object_space, val|1, val);
202
- }
203
-
204
- static void
205
- cb_gc_unprotect(bucket_t *bucket, VALUE val)
206
- {
207
- rb_hash_delete(bucket->object_space, val|1);
208
- }
209
-
210
- static VALUE
211
- cb_proc_call(VALUE recv, int argc, ...)
212
- {
213
- VALUE *argv;
214
- va_list ar;
215
- int arity;
216
- int ii;
217
-
218
- arity = FIX2INT(rb_funcall(recv, id_arity, 0));
219
- if (arity < 0) {
220
- arity = argc;
221
- }
222
- if (arity > 0) {
223
- va_init_list(ar, argc);
224
- argv = ALLOCA_N(VALUE, argc);
225
- for (ii = 0; ii < arity; ++ii) {
226
- if (ii < argc) {
227
- argv[ii] = va_arg(ar, VALUE);
228
- } else {
229
- argv[ii] = Qnil;
230
- }
231
- }
232
- va_end(ar);
233
- } else {
234
- argv = NULL;
235
- }
236
- return rb_funcall2(recv, id_call, arity, argv);
237
- }
238
-
239
- /* Helper to conver return code from libcouchbase to meaningful exception.
240
- * Returns nil if the code considering successful and exception object
241
- * otherwise. Store given string to exceptions as message, and also
242
- * initialize +error+ attribute with given return code. */
243
- static VALUE
244
- cb_check_error(libcouchbase_error_t rc, const char *msg, VALUE key)
245
- {
246
- VALUE klass, exc, str;
247
- char buf[300];
248
-
249
- if (rc == LIBCOUCHBASE_SUCCESS || rc == LIBCOUCHBASE_AUTH_CONTINUE) {
250
- return Qnil;
251
- }
252
- switch (rc) {
253
- case LIBCOUCHBASE_AUTH_ERROR:
254
- klass = eAuthError;
255
- break;
256
- case LIBCOUCHBASE_DELTA_BADVAL:
257
- klass = eDeltaBadvalError;
258
- break;
259
- case LIBCOUCHBASE_E2BIG:
260
- klass = eTooBigError;
261
- break;
262
- case LIBCOUCHBASE_EBUSY:
263
- klass = eBusyError;
264
- break;
265
- case LIBCOUCHBASE_EINTERNAL:
266
- klass = eInternalError;
267
- break;
268
- case LIBCOUCHBASE_EINVAL:
269
- klass = eInvalidError;
270
- break;
271
- case LIBCOUCHBASE_ENOMEM:
272
- klass = eNoMemoryError;
273
- break;
274
- case LIBCOUCHBASE_ERANGE:
275
- klass = eRangeError;
276
- break;
277
- case LIBCOUCHBASE_ETMPFAIL:
278
- klass = eTmpFailError;
279
- break;
280
- case LIBCOUCHBASE_KEY_EEXISTS:
281
- klass = eKeyExistsError;
282
- break;
283
- case LIBCOUCHBASE_KEY_ENOENT:
284
- klass = eNotFoundError;
285
- break;
286
- case LIBCOUCHBASE_LIBEVENT_ERROR:
287
- klass = eLibeventError;
288
- break;
289
- case LIBCOUCHBASE_NETWORK_ERROR:
290
- klass = eNetworkError;
291
- break;
292
- case LIBCOUCHBASE_NOT_MY_VBUCKET:
293
- klass = eNotMyVbucketError;
294
- break;
295
- case LIBCOUCHBASE_NOT_STORED:
296
- klass = eNotStoredError;
297
- break;
298
- case LIBCOUCHBASE_NOT_SUPPORTED:
299
- klass = eNotSupportedError;
300
- break;
301
- case LIBCOUCHBASE_UNKNOWN_COMMAND:
302
- klass = eUnknownCommandError;
303
- break;
304
- case LIBCOUCHBASE_UNKNOWN_HOST:
305
- klass = eUnknownHostError;
306
- break;
307
- case LIBCOUCHBASE_PROTOCOL_ERROR:
308
- klass = eProtocolError;
309
- break;
310
- case LIBCOUCHBASE_ETIMEDOUT:
311
- klass = eTimeoutError;
312
- break;
313
- case LIBCOUCHBASE_CONNECT_ERROR:
314
- klass = eConnectError;
315
- break;
316
- case LIBCOUCHBASE_BUCKET_ENOENT:
317
- klass = eBucketNotFoundError;
318
- break;
319
- case LIBCOUCHBASE_ERROR:
320
- /* fall through */
321
- default:
322
- klass = eLibcouchbaseError;
323
- }
324
-
325
- str = rb_str_buf_new2(msg ? msg : "");
326
- rb_str_buf_cat2(str, " (");
327
- if (key != Qnil) {
328
- snprintf(buf, 300, "key=\"%s\", ", RSTRING_PTR(key));
329
- rb_str_buf_cat2(str, buf);
330
- }
331
- snprintf(buf, 300, "error=0x%02x)", rc);
332
- rb_str_buf_cat2(str, buf);
333
- exc = rb_exc_new3(klass, str);
334
- rb_ivar_set(exc, id_iv_error, INT2FIX(rc));
335
- rb_ivar_set(exc, id_iv_key, key);
336
- rb_ivar_set(exc, id_iv_cas, Qnil);
337
- rb_ivar_set(exc, id_iv_operation, Qnil);
338
- return exc;
339
- }
340
-
341
- static inline uint32_t
342
- flags_set_format(uint32_t flags, ID format)
343
- {
344
- flags &= ~((uint32_t)FMT_MASK); /* clear format bits */
345
-
346
- if (format == sym_document) {
347
- return flags | FMT_DOCUMENT;
348
- } else if (format == sym_marshal) {
349
- return flags | FMT_MARSHAL;
350
- } else if (format == sym_plain) {
351
- return flags | FMT_PLAIN;
352
- }
353
- return flags; /* document is the default */
354
- }
355
-
356
- static inline ID
357
- flags_get_format(uint32_t flags)
358
- {
359
- flags &= FMT_MASK; /* select format bits */
360
-
361
- switch (flags) {
362
- case FMT_DOCUMENT:
363
- return sym_document;
364
- case FMT_MARSHAL:
365
- return sym_marshal;
366
- case FMT_PLAIN:
367
- /* fall through */
368
- default:
369
- /* all other formats treated as plain */
370
- return sym_plain;
371
- }
372
- }
373
-
374
-
375
- static VALUE
376
- do_encode(VALUE *args)
377
- {
378
- VALUE val = args[0];
379
- uint32_t flags = ((uint32_t)args[1] & FMT_MASK);
380
-
381
- switch (flags) {
382
- case FMT_DOCUMENT:
383
- return rb_funcall(mJSON, id_dump, 1, val);
384
- case FMT_MARSHAL:
385
- return rb_funcall(mMarshal, id_dump, 1, val);
386
- case FMT_PLAIN:
387
- /* fall through */
388
- default:
389
- /* all other formats treated as plain */
390
- return val;
391
- }
392
- }
393
-
394
- static VALUE
395
- do_decode(VALUE *args)
396
- {
397
- VALUE blob = args[0];
398
- VALUE force_format = args[2];
399
-
400
- if (TYPE(force_format) == T_SYMBOL) {
401
- if (force_format == sym_document) {
402
- return rb_funcall(mJSON, id_load, 1, blob);
403
- } else if (force_format == sym_marshal) {
404
- return rb_funcall(mMarshal, id_load, 1, blob);
405
- } else { /* sym_plain and any other symbol */
406
- return blob;
407
- }
408
- } else {
409
- uint32_t flags = ((uint32_t)args[1] & FMT_MASK);
410
-
411
- switch (flags) {
412
- case FMT_DOCUMENT:
413
- return rb_funcall(mJSON, id_load, 1, blob);
414
- case FMT_MARSHAL:
415
- return rb_funcall(mMarshal, id_load, 1, blob);
416
- case FMT_PLAIN:
417
- /* fall through */
418
- default:
419
- /* all other formats treated as plain */
420
- return blob;
421
- }
422
- }
423
- }
424
-
425
- static VALUE
426
- coding_failed(void)
427
- {
428
- return Qundef;
429
- }
430
-
431
- static VALUE
432
- encode_value(VALUE val, uint32_t flags)
433
- {
434
- VALUE blob, args[2];
435
-
436
- args[0] = val;
437
- args[1] = (VALUE)flags;
438
- blob = rb_rescue(do_encode, (VALUE)args, coding_failed, 0);
439
- /* it must be bytestring after all */
440
- if (TYPE(blob) != T_STRING) {
441
- return Qundef;
442
- }
443
- return blob;
444
- }
445
-
446
- static VALUE
447
- decode_value(VALUE blob, uint32_t flags, VALUE force_format)
448
- {
449
- VALUE val, args[3];
450
-
451
- /* first it must be bytestring */
452
- if (TYPE(blob) != T_STRING) {
453
- return Qundef;
454
- }
455
- args[0] = blob;
456
- args[1] = (VALUE)flags;
457
- args[2] = (VALUE)force_format;
458
- val = rb_rescue(do_decode, (VALUE)args, coding_failed, 0);
459
- return val;
460
- }
461
-
462
- static VALUE
463
- unify_key(VALUE key)
464
- {
465
- switch (TYPE(key)) {
466
- case T_STRING:
467
- return key;
468
- case T_SYMBOL:
469
- return STR_NEW_CSTR(rb_id2name(SYM2ID(key)));
470
- default: /* call #to_str or raise error */
471
- return StringValue(key);
472
- }
473
- }
474
-
475
- static int
476
- cb_extract_keys_i(VALUE key, VALUE value, VALUE arg)
477
- {
478
- struct key_traits *traits = (struct key_traits *)arg;
479
- key = unify_key(key);
480
- rb_ary_push(traits->keys_ary, key);
481
- traits->keys[traits->nkeys] = RSTRING_PTR(key);
482
- traits->lens[traits->nkeys] = RSTRING_LEN(key);
483
- traits->ttls[traits->nkeys] = NUM2ULONG(value);
484
- traits->nkeys++;
485
- return ST_CONTINUE;
486
- }
487
-
488
- static long
489
- cb_args_scan_keys(long argc, VALUE argv, bucket_t *bucket, struct key_traits *traits)
490
- {
491
- VALUE key, *keys_ptr, opts, ttl, ext;
492
- long nn = 0, ii;
493
- time_t exp;
494
-
495
- traits->keys_ary = rb_ary_new();
496
- traits->quiet = bucket->quiet;
497
- traits->mgat = 0;
498
-
499
- if (argc > 0) {
500
- /* keys with custom options */
501
- opts = RARRAY_PTR(argv)[argc-1];
502
- exp = bucket->default_ttl;
503
- ext = Qfalse;
504
- if (argc > 1 && TYPE(opts) == T_HASH) {
505
- (void)rb_ary_pop(argv);
506
- if (RTEST(rb_funcall(opts, id_has_key_p, 1, sym_quiet))) {
507
- traits->quiet = RTEST(rb_hash_aref(opts, sym_quiet));
508
- }
509
- traits->force_format = rb_hash_aref(opts, sym_format);
510
- if (traits->force_format != Qnil) {
511
- Check_Type(traits->force_format, T_SYMBOL);
512
- }
513
- ext = rb_hash_aref(opts, sym_extended);
514
- ttl = rb_hash_aref(opts, sym_ttl);
515
- if (ttl != Qnil) {
516
- traits->explicit_ttl = 1;
517
- exp = NUM2ULONG(ttl);
518
- }
519
- nn = RARRAY_LEN(argv);
520
- } else {
521
- nn = argc;
522
- }
523
- if (nn < 1) {
524
- rb_raise(rb_eArgError, "must be at least one key");
525
- }
526
- keys_ptr = RARRAY_PTR(argv);
527
- traits->extended = RTEST(ext) ? 1 : 0;
528
- if (nn == 1 && TYPE(keys_ptr[0]) == T_HASH) {
529
- /* hash of key-ttl pairs */
530
- nn = RHASH_SIZE(keys_ptr[0]);
531
- traits->keys = xcalloc(nn, sizeof(char *));
532
- traits->lens = xcalloc(nn, sizeof(size_t));
533
- traits->explicit_ttl = 1;
534
- traits->mgat = 1;
535
- traits->ttls = xcalloc(nn, sizeof(time_t));
536
- rb_hash_foreach(keys_ptr[0], cb_extract_keys_i, (VALUE)traits);
537
- } else {
538
- /* the list of keys */
539
- traits->nkeys = nn;
540
- traits->keys = xcalloc(nn, sizeof(char *));
541
- traits->lens = xcalloc(nn, sizeof(size_t));
542
- traits->ttls = xcalloc(nn, sizeof(time_t));
543
- for (ii = 0; ii < nn; ii++) {
544
- key = unify_key(keys_ptr[ii]);
545
- rb_ary_push(traits->keys_ary, key);
546
- traits->keys[ii] = RSTRING_PTR(key);
547
- traits->lens[ii] = RSTRING_LEN(key);
548
- traits->ttls[ii] = exp;
549
- }
550
- }
551
- }
552
-
553
- return nn;
554
- }
555
-
556
- static void
557
- error_callback(libcouchbase_t handle, libcouchbase_error_t error, const char *errinfo)
558
- {
559
- bucket_t *bucket = (bucket_t *)libcouchbase_get_cookie(handle);
560
-
561
- bucket->io->stop_event_loop(bucket->io);
562
- bucket->exception = cb_check_error(error, errinfo, Qnil);
563
- }
564
-
565
- static void
566
- storage_callback(libcouchbase_t handle, const void *cookie,
567
- libcouchbase_storage_t operation, libcouchbase_error_t error,
568
- const void *key, libcouchbase_size_t nkey, libcouchbase_cas_t cas)
569
- {
570
- context_t *ctx = (context_t *)cookie;
571
- bucket_t *bucket = ctx->bucket;
572
- VALUE k, c, *rv = ctx->rv, exc, res;
573
- ID o;
574
-
575
- bucket->seqno--;
576
-
577
- k = STR_NEW((const char*)key, nkey);
578
- c = cas > 0 ? ULL2NUM(cas) : Qnil;
579
- switch(operation) {
580
- case LIBCOUCHBASE_ADD:
581
- o = sym_add;
582
- break;
583
- case LIBCOUCHBASE_REPLACE:
584
- o = sym_replace;
585
- break;
586
- case LIBCOUCHBASE_SET:
587
- o = sym_set;
588
- break;
589
- case LIBCOUCHBASE_APPEND:
590
- o = sym_append;
591
- break;
592
- case LIBCOUCHBASE_PREPEND:
593
- o = sym_prepend;
594
- break;
595
- default:
596
- o = Qnil;
597
- }
598
- exc = cb_check_error(error, "failed to store value", k);
599
- if (exc != Qnil) {
600
- rb_ivar_set(exc, id_iv_cas, c);
601
- rb_ivar_set(exc, id_iv_operation, o);
602
- if (NIL_P(ctx->exception)) {
603
- ctx->exception = exc;
604
- cb_gc_protect(bucket, ctx->exception);
605
- }
606
- }
607
- if (bucket->async) { /* asynchronous */
608
- if (ctx->proc != Qnil) {
609
- res = rb_class_new_instance(0, NULL, cResult);
610
- rb_ivar_set(res, id_iv_error, exc);
611
- rb_ivar_set(res, id_iv_key, k);
612
- rb_ivar_set(res, id_iv_operation, o);
613
- rb_ivar_set(res, id_iv_cas, c);
614
- cb_proc_call(ctx->proc, 1, res);
615
- }
616
- } else { /* synchronous */
617
- *rv = c;
618
- }
619
-
620
- if (bucket->seqno == 0) {
621
- bucket->io->stop_event_loop(bucket->io);
622
- cb_gc_unprotect(bucket, ctx->proc);
623
- }
624
- (void)handle;
625
- }
626
-
627
- static void
628
- delete_callback(libcouchbase_t handle, const void *cookie,
629
- libcouchbase_error_t error, const void *key,
630
- libcouchbase_size_t nkey)
631
- {
632
- context_t *ctx = (context_t *)cookie;
633
- bucket_t *bucket = ctx->bucket;
634
- VALUE k, *rv = ctx->rv, exc = Qnil, res;
635
-
636
- bucket->seqno--;
637
-
638
- k = STR_NEW((const char*)key, nkey);
639
- if (error != LIBCOUCHBASE_KEY_ENOENT || !ctx->quiet) {
640
- exc = cb_check_error(error, "failed to remove value", k);
641
- if (exc != Qnil) {
642
- rb_ivar_set(exc, id_iv_operation, sym_delete);
643
- if (NIL_P(ctx->exception)) {
644
- ctx->exception = exc;
645
- cb_gc_protect(bucket, ctx->exception);
646
- }
647
- }
648
- }
649
- if (bucket->async) { /* asynchronous */
650
- if (ctx->proc != Qnil) {
651
- res = rb_class_new_instance(0, NULL, cResult);
652
- rb_ivar_set(res, id_iv_error, exc);
653
- rb_ivar_set(res, id_iv_operation, sym_delete);
654
- rb_ivar_set(res, id_iv_key, k);
655
- cb_proc_call(ctx->proc, 1, res);
656
- }
657
- } else { /* synchronous */
658
- *rv = (error == LIBCOUCHBASE_SUCCESS) ? Qtrue : Qfalse;
659
- }
660
- if (bucket->seqno == 0) {
661
- bucket->io->stop_event_loop(bucket->io);
662
- cb_gc_unprotect(bucket, ctx->proc);
663
- }
664
- (void)handle;
665
- }
666
-
667
- static void
668
- get_callback(libcouchbase_t handle, const void *cookie,
669
- libcouchbase_error_t error, const void *key,
670
- libcouchbase_size_t nkey, const void *bytes,
671
- libcouchbase_size_t nbytes, libcouchbase_uint32_t flags,
672
- libcouchbase_cas_t cas)
673
- {
674
- context_t *ctx = (context_t *)cookie;
675
- bucket_t *bucket = ctx->bucket;
676
- VALUE k, v, f, c, *rv = ctx->rv, exc = Qnil, res;
677
-
678
- bucket->seqno--;
679
-
680
- k = STR_NEW((const char*)key, nkey);
681
- if (error != LIBCOUCHBASE_KEY_ENOENT || !ctx->quiet) {
682
- exc = cb_check_error(error, "failed to get value", k);
683
- if (exc != Qnil) {
684
- rb_ivar_set(exc, id_iv_operation, sym_get);
685
- if (NIL_P(ctx->exception)) {
686
- ctx->exception = exc;
687
- cb_gc_protect(bucket, ctx->exception);
688
- }
689
- }
690
- }
691
-
692
- f = ULONG2NUM(flags);
693
- c = ULL2NUM(cas);
694
- v = Qnil;
695
- if (nbytes != 0) {
696
- v = decode_value(STR_NEW((const char*)bytes, nbytes), flags, ctx->force_format);
697
- if (v == Qundef) {
698
- if (ctx->exception != Qnil) {
699
- cb_gc_unprotect(bucket, ctx->exception);
700
- }
701
- ctx->exception = rb_exc_new2(eValueFormatError, "unable to convert value");
702
- rb_ivar_set(ctx->exception, id_iv_operation, sym_get);
703
- rb_ivar_set(ctx->exception, id_iv_key, k);
704
- cb_gc_protect(bucket, ctx->exception);
705
- }
706
- } else if (flags_get_format(flags) == sym_plain) {
707
- v = STR_NEW_CSTR("");
708
- }
709
- if (bucket->async) { /* asynchronous */
710
- if (ctx->proc != Qnil) {
711
- res = rb_class_new_instance(0, NULL, cResult);
712
- rb_ivar_set(res, id_iv_error, exc);
713
- rb_ivar_set(res, id_iv_operation, sym_get);
714
- rb_ivar_set(res, id_iv_key, k);
715
- rb_ivar_set(res, id_iv_value, v);
716
- rb_ivar_set(res, id_iv_flags, f);
717
- rb_ivar_set(res, id_iv_cas, c);
718
- cb_proc_call(ctx->proc, 1, res);
719
- }
720
- } else { /* synchronous */
721
- if (NIL_P(exc) && error != LIBCOUCHBASE_KEY_ENOENT) {
722
- if (ctx->extended) {
723
- rb_hash_aset(*rv, k, rb_ary_new3(3, v, f, c));
724
- } else {
725
- rb_hash_aset(*rv, k, v);
726
- }
727
- }
728
- }
729
-
730
- if (bucket->seqno == 0) {
731
- bucket->io->stop_event_loop(bucket->io);
732
- cb_gc_unprotect(bucket, ctx->proc);
733
- }
734
- (void)handle;
735
- }
736
-
737
- static void
738
- flush_callback(libcouchbase_t handle, const void* cookie,
739
- const char* authority, libcouchbase_error_t error)
740
- {
741
- context_t *ctx = (context_t *)cookie;
742
- bucket_t *bucket = ctx->bucket;
743
- VALUE node, success = Qtrue, *rv = ctx->rv, exc, res;
744
-
745
- node = authority ? STR_NEW_CSTR(authority) : Qnil;
746
- exc = cb_check_error(error, "failed to flush bucket", node);
747
- if (exc != Qnil) {
748
- rb_ivar_set(exc, id_iv_operation, sym_flush);
749
- if (NIL_P(ctx->exception)) {
750
- ctx->exception = exc;
751
- cb_gc_protect(bucket, ctx->exception);
752
- }
753
- success = Qfalse;
754
- }
755
-
756
- if (authority) {
757
- if (bucket->async) { /* asynchronous */
758
- if (ctx->proc != Qnil) {
759
- res = rb_class_new_instance(0, NULL, cResult);
760
- rb_ivar_set(res, id_iv_error, exc);
761
- rb_ivar_set(res, id_iv_operation, sym_flush);
762
- rb_ivar_set(res, id_iv_node, node);
763
- cb_proc_call(ctx->proc, 1, res);
764
- }
765
- } else { /* synchronous */
766
- if (RTEST(*rv)) {
767
- /* rewrite status for positive values only */
768
- *rv = success;
769
- }
770
- }
771
- } else {
772
- bucket->seqno--;
773
- if (bucket->seqno == 0) {
774
- bucket->io->stop_event_loop(bucket->io);
775
- cb_gc_unprotect(bucket, ctx->proc);
776
- }
777
- }
778
-
779
- (void)handle;
780
- }
781
-
782
- static void
783
- version_callback(libcouchbase_t handle, const void *cookie,
784
- const char *authority, libcouchbase_error_t error,
785
- const char *bytes, libcouchbase_size_t nbytes)
786
- {
787
- context_t *ctx = (context_t *)cookie;
788
- bucket_t *bucket = ctx->bucket;
789
- VALUE node, v, *rv = ctx->rv, exc, res;
790
-
791
- node = authority ? STR_NEW_CSTR(authority) : Qnil;
792
- exc = cb_check_error(error, "failed to get version", node);
793
- if (exc != Qnil) {
794
- rb_ivar_set(exc, id_iv_operation, sym_flush);
795
- if (NIL_P(ctx->exception)) {
796
- ctx->exception = exc;
797
- cb_gc_protect(bucket, ctx->exception);
798
- }
799
- }
800
-
801
- if (authority) {
802
- v = STR_NEW((const char*)bytes, nbytes);
803
- if (bucket->async) { /* asynchronous */
804
- if (ctx->proc != Qnil) {
805
- res = rb_class_new_instance(0, NULL, cResult);
806
- rb_ivar_set(res, id_iv_error, exc);
807
- rb_ivar_set(res, id_iv_operation, sym_version);
808
- rb_ivar_set(res, id_iv_node, node);
809
- rb_ivar_set(res, id_iv_value, v);
810
- cb_proc_call(ctx->proc, 1, res);
811
- }
812
- } else { /* synchronous */
813
- if (NIL_P(exc)) {
814
- rb_hash_aset(*rv, node, v);
815
- }
816
- }
817
- } else {
818
- bucket->seqno--;
819
- if (bucket->seqno == 0) {
820
- bucket->io->stop_event_loop(bucket->io);
821
- cb_gc_unprotect(bucket, ctx->proc);
822
- }
823
- }
824
-
825
- (void)handle;
826
- }
827
-
828
- static void
829
- stat_callback(libcouchbase_t handle, const void* cookie,
830
- const char* authority, libcouchbase_error_t error, const void* key,
831
- libcouchbase_size_t nkey, const void* bytes,
832
- libcouchbase_size_t nbytes)
833
- {
834
- context_t *ctx = (context_t *)cookie;
835
- bucket_t *bucket = ctx->bucket;
836
- VALUE stats, node, k, v, *rv = ctx->rv, exc = Qnil, res;
837
-
838
- node = authority ? STR_NEW_CSTR(authority) : Qnil;
839
- exc = cb_check_error(error, "failed to fetch stats", node);
840
- if (exc != Qnil) {
841
- rb_ivar_set(exc, id_iv_operation, sym_stats);
842
- if (NIL_P(ctx->exception)) {
843
- ctx->exception = exc;
844
- cb_gc_protect(bucket, ctx->exception);
845
- }
846
- }
847
- if (authority) {
848
- k = STR_NEW((const char*)key, nkey);
849
- v = STR_NEW((const char*)bytes, nbytes);
850
- if (bucket->async) { /* asynchronous */
851
- if (ctx->proc != Qnil) {
852
- res = rb_class_new_instance(0, NULL, cResult);
853
- rb_ivar_set(res, id_iv_error, exc);
854
- rb_ivar_set(res, id_iv_operation, sym_stats);
855
- rb_ivar_set(res, id_iv_node, node);
856
- rb_ivar_set(res, id_iv_key, k);
857
- rb_ivar_set(res, id_iv_value, v);
858
- cb_proc_call(ctx->proc, 1, res);
859
- }
860
- } else { /* synchronous */
861
- if (NIL_P(exc)) {
862
- stats = rb_hash_aref(*rv, k);
863
- if (NIL_P(stats)) {
864
- stats = rb_hash_new();
865
- rb_hash_aset(*rv, k, stats);
866
- }
867
- rb_hash_aset(stats, node, v);
868
- }
869
- }
870
- } else {
871
- bucket->seqno--;
872
- if (bucket->seqno == 0) {
873
- bucket->io->stop_event_loop(bucket->io);
874
- cb_gc_unprotect(bucket, ctx->proc);
875
- }
876
- }
877
- (void)handle;
878
- }
879
-
880
- static void
881
- touch_callback(libcouchbase_t handle, const void *cookie,
882
- libcouchbase_error_t error, const void *key,
883
- libcouchbase_size_t nkey)
884
- {
885
- context_t *ctx = (context_t *)cookie;
886
- bucket_t *bucket = ctx->bucket;
887
- VALUE k, success, *rv = ctx->rv, exc = Qnil, res;
888
-
889
- bucket->seqno--;
890
- k = STR_NEW((const char*)key, nkey);
891
- if (error != LIBCOUCHBASE_KEY_ENOENT || !ctx->quiet) {
892
- exc = cb_check_error(error, "failed to touch value", k);
893
- if (exc != Qnil) {
894
- rb_ivar_set(exc, id_iv_operation, sym_touch);
895
- if (NIL_P(ctx->exception)) {
896
- ctx->exception = exc;
897
- cb_gc_protect(bucket, ctx->exception);
898
- }
899
- }
900
- }
901
-
902
- if (bucket->async) { /* asynchronous */
903
- if (ctx->proc != Qnil) {
904
- res = rb_class_new_instance(0, NULL, cResult);
905
- rb_ivar_set(res, id_iv_error, exc);
906
- rb_ivar_set(res, id_iv_operation, sym_touch);
907
- rb_ivar_set(res, id_iv_key, k);
908
- cb_proc_call(ctx->proc, 1, res);
909
- }
910
- } else { /* synchronous */
911
- if (NIL_P(exc)) {
912
- success = (error == LIBCOUCHBASE_KEY_ENOENT) ? Qfalse : Qtrue;
913
- rb_hash_aset(*rv, k, success);
914
- }
915
- }
916
- if (bucket->seqno == 0) {
917
- bucket->io->stop_event_loop(bucket->io);
918
- cb_gc_unprotect(bucket, ctx->proc);
919
- }
920
- (void)handle;
921
- }
922
-
923
- static void
924
- arithmetic_callback(libcouchbase_t handle, const void *cookie,
925
- libcouchbase_error_t error, const void *key,
926
- libcouchbase_size_t nkey, libcouchbase_uint64_t value,
927
- libcouchbase_cas_t cas)
928
- {
929
- context_t *ctx = (context_t *)cookie;
930
- bucket_t *bucket = ctx->bucket;
931
- VALUE c, k, v, *rv = ctx->rv, exc, res;
932
- ID o;
933
-
934
- bucket->seqno--;
935
-
936
- k = STR_NEW((const char*)key, nkey);
937
- c = cas > 0 ? ULL2NUM(cas) : Qnil;
938
- o = ctx->arithm > 0 ? sym_increment : sym_decrement;
939
- exc = cb_check_error(error, "failed to perform arithmetic operation", k);
940
- if (exc != Qnil) {
941
- rb_ivar_set(exc, id_iv_cas, c);
942
- rb_ivar_set(exc, id_iv_operation, o);
943
- if (bucket->async) {
944
- if (bucket->on_error_proc != Qnil) {
945
- cb_proc_call(bucket->on_error_proc, 3, o, k, exc);
946
- } else {
947
- if (NIL_P(bucket->exception)) {
948
- bucket->exception = exc;
949
- }
950
- }
951
- }
952
- if (NIL_P(ctx->exception)) {
953
- ctx->exception = exc;
954
- cb_gc_protect(bucket, ctx->exception);
955
- }
956
- }
957
- v = ULL2NUM(value);
958
- if (bucket->async) { /* asynchronous */
959
- if (ctx->proc != Qnil) {
960
- res = rb_class_new_instance(0, NULL, cResult);
961
- rb_ivar_set(res, id_iv_error, exc);
962
- rb_ivar_set(res, id_iv_operation, o);
963
- rb_ivar_set(res, id_iv_key, k);
964
- rb_ivar_set(res, id_iv_value, v);
965
- rb_ivar_set(res, id_iv_cas, c);
966
- cb_proc_call(ctx->proc, 1, res);
967
- }
968
- } else { /* synchronous */
969
- if (NIL_P(exc)) {
970
- if (ctx->extended) {
971
- *rv = rb_ary_new3(2, v, c);
972
- } else {
973
- *rv = v;
974
- }
975
- }
976
- }
977
- if (bucket->seqno == 0) {
978
- bucket->io->stop_event_loop(bucket->io);
979
- cb_gc_unprotect(bucket, ctx->proc);
980
- }
981
- (void)handle;
982
- }
983
-
984
- static int
985
- cb_first_value_i(VALUE key, VALUE value, VALUE arg)
986
- {
987
- VALUE *val = (VALUE *)arg;
988
-
989
- *val = value;
990
- (void)key;
991
- return ST_STOP;
992
- }
993
-
994
- /*
995
- * @private
996
- * @return [Fixnum] number of scheduled operations
997
- */
998
- static VALUE
999
- cb_bucket_seqno(VALUE self)
1000
- {
1001
- bucket_t *bucket = DATA_PTR(self);
1002
-
1003
- return LONG2FIX(bucket->seqno);
1004
- }
1005
-
1006
- void
1007
- cb_bucket_free(void *ptr)
1008
- {
1009
- bucket_t *bucket = ptr;
1010
-
1011
- if (bucket) {
1012
- if (bucket->handle) {
1013
- libcouchbase_destroy(bucket->handle);
1014
- }
1015
- xfree(bucket->authority);
1016
- xfree(bucket->hostname);
1017
- xfree(bucket->pool);
1018
- xfree(bucket->bucket);
1019
- xfree(bucket->username);
1020
- xfree(bucket->password);
1021
- xfree(bucket);
1022
- }
1023
- }
1024
-
1025
- void
1026
- cb_bucket_mark(void *ptr)
1027
- {
1028
- bucket_t *bucket = ptr;
1029
-
1030
- if (bucket) {
1031
- rb_gc_mark(bucket->exception);
1032
- rb_gc_mark(bucket->on_error_proc);
1033
- rb_gc_mark(bucket->object_space);
1034
- }
1035
- }
1036
-
1037
- static void
1038
- do_scan_connection_options(bucket_t *bucket, int argc, VALUE *argv)
1039
- {
1040
- VALUE uri, opts, arg;
1041
- size_t len;
1042
-
1043
- if (rb_scan_args(argc, argv, "02", &uri, &opts) > 0) {
1044
- if (TYPE(uri) == T_HASH && argc == 1) {
1045
- opts = uri;
1046
- uri = Qnil;
1047
- }
1048
- if (uri != Qnil) {
1049
- const char path_re[] = "^(/pools/([A-Za-z0-9_.-]+)(/buckets/([A-Za-z0-9_.-]+))?)?";
1050
- VALUE match, uri_obj, re;
1051
-
1052
- Check_Type(uri, T_STRING);
1053
- uri_obj = rb_funcall(mURI, id_parse, 1, uri);
1054
-
1055
- arg = rb_funcall(uri_obj, id_scheme, 0);
1056
- if (arg == Qnil || rb_str_cmp(arg, STR_NEW_CSTR("http"))) {
1057
- rb_raise(rb_eArgError, "invalid URI: invalid scheme");
1058
- }
1059
-
1060
- arg = rb_funcall(uri_obj, id_user, 0);
1061
- if (arg != Qnil) {
1062
- xfree(bucket->username);
1063
- bucket->username = strdup(RSTRING_PTR(arg));
1064
- if (bucket->username == NULL) {
1065
- rb_raise(eNoMemoryError, "failed to allocate memory for Bucket");
1066
- }
1067
- }
1068
-
1069
- arg = rb_funcall(uri_obj, id_password, 0);
1070
- if (arg != Qnil) {
1071
- xfree(bucket->password);
1072
- bucket->password = strdup(RSTRING_PTR(arg));
1073
- if (bucket->password == NULL) {
1074
- rb_raise(eNoMemoryError, "failed to allocate memory for Bucket");
1075
- }
1076
- }
1077
- arg = rb_funcall(uri_obj, id_host, 0);
1078
- if (arg != Qnil) {
1079
- xfree(bucket->hostname);
1080
- bucket->hostname = strdup(RSTRING_PTR(arg));
1081
- if (bucket->hostname == NULL) {
1082
- rb_raise(eNoMemoryError, "failed to allocate memory for Bucket");
1083
- }
1084
- } else {
1085
- rb_raise(rb_eArgError, "invalid URI: missing hostname");
1086
- }
1087
-
1088
- arg = rb_funcall(uri_obj, id_port, 0);
1089
- bucket->port = NIL_P(arg) ? 8091 : (uint16_t)NUM2UINT(arg);
1090
-
1091
- arg = rb_funcall(uri_obj, id_path, 0);
1092
- re = rb_reg_new(path_re, sizeof(path_re) - 1, 0);
1093
- match = rb_funcall(re, id_match, 1, arg);
1094
- arg = rb_reg_nth_match(2, match);
1095
- xfree(bucket->pool);
1096
- bucket->pool = strdup(NIL_P(arg) ? "default" : RSTRING_PTR(arg));
1097
- arg = rb_reg_nth_match(4, match);
1098
- xfree(bucket->bucket);
1099
- bucket->bucket = strdup(NIL_P(arg) ? "default" : RSTRING_PTR(arg));
1100
- }
1101
- if (TYPE(opts) == T_HASH) {
1102
- arg = rb_hash_aref(opts, sym_node_list);
1103
- if (arg != Qnil) {
1104
- VALUE tt;
1105
- free(bucket->node_list);
1106
- Check_Type(arg, T_ARRAY);
1107
- tt = rb_ary_join(arg, rb_str_new2(";"));
1108
- bucket->node_list = strdup(StringValueCStr(tt));
1109
- }
1110
- arg = rb_hash_aref(opts, sym_hostname);
1111
- if (arg != Qnil) {
1112
- if (bucket->hostname) {
1113
- xfree(bucket->hostname);
1114
- }
1115
- bucket->hostname = strdup(StringValueCStr(arg));
1116
- }
1117
- arg = rb_hash_aref(opts, sym_pool);
1118
- if (arg != Qnil) {
1119
- if (bucket->pool) {
1120
- xfree(bucket->pool);
1121
- }
1122
- bucket->pool = strdup(StringValueCStr(arg));
1123
- }
1124
- arg = rb_hash_aref(opts, sym_bucket);
1125
- if (arg != Qnil) {
1126
- if (bucket->bucket) {
1127
- xfree(bucket->bucket);
1128
- }
1129
- bucket->bucket = strdup(StringValueCStr(arg));
1130
- }
1131
- arg = rb_hash_aref(opts, sym_username);
1132
- if (arg != Qnil) {
1133
- if (bucket->username) {
1134
- xfree(bucket->username);
1135
- }
1136
- bucket->username = strdup(StringValueCStr(arg));
1137
- }
1138
- arg = rb_hash_aref(opts, sym_password);
1139
- if (arg != Qnil) {
1140
- if (bucket->password) {
1141
- xfree(bucket->password);
1142
- }
1143
- bucket->password = strdup(StringValueCStr(arg));
1144
- }
1145
- arg = rb_hash_aref(opts, sym_port);
1146
- if (arg != Qnil) {
1147
- bucket->port = (uint16_t)NUM2UINT(arg);
1148
- }
1149
- if (RTEST(rb_funcall(opts, id_has_key_p, 1, sym_quiet))) {
1150
- bucket->quiet = RTEST(rb_hash_aref(opts, sym_quiet));
1151
- }
1152
- arg = rb_hash_aref(opts, sym_timeout);
1153
- if (arg != Qnil) {
1154
- bucket->timeout = (uint32_t)NUM2ULONG(arg);
1155
- }
1156
- arg = rb_hash_aref(opts, sym_default_ttl);
1157
- if (arg != Qnil) {
1158
- bucket->default_ttl = (uint32_t)NUM2ULONG(arg);
1159
- }
1160
- arg = rb_hash_aref(opts, sym_default_flags);
1161
- if (arg != Qnil) {
1162
- bucket->default_flags = (uint32_t)NUM2ULONG(arg);
1163
- }
1164
- arg = rb_hash_aref(opts, sym_default_format);
1165
- if (arg != Qnil) {
1166
- if (TYPE(arg) == T_FIXNUM) {
1167
- switch (FIX2INT(arg)) {
1168
- case FMT_DOCUMENT:
1169
- arg = sym_document;
1170
- break;
1171
- case FMT_MARSHAL:
1172
- arg = sym_marshal;
1173
- break;
1174
- case FMT_PLAIN:
1175
- arg = sym_plain;
1176
- break;
1177
- }
1178
- }
1179
- if (arg == sym_document || arg == sym_marshal || arg == sym_plain) {
1180
- bucket->default_format = arg;
1181
- bucket->default_flags = flags_set_format(bucket->default_flags, arg);
1182
- }
1183
- }
1184
- } else {
1185
- opts = Qnil;
1186
- }
1187
- }
1188
- len = strlen(bucket->hostname) + 10;
1189
- if (bucket->authority) {
1190
- xfree(bucket->authority);
1191
- }
1192
- bucket->authority = xcalloc(len, sizeof(char));
1193
- if (bucket->authority == NULL) {
1194
- rb_raise(eNoMemoryError, "failed to allocate memory for Bucket");
1195
- }
1196
- snprintf(bucket->authority, len, "%s:%u", bucket->hostname, bucket->port);
1197
- }
1198
-
1199
- static void
1200
- do_connect(bucket_t *bucket)
1201
- {
1202
- libcouchbase_error_t err;
1203
-
1204
- if (bucket->handle) {
1205
- libcouchbase_destroy(bucket->handle);
1206
- bucket->handle = NULL;
1207
- bucket->io = NULL;
1208
- }
1209
- bucket->io = libcouchbase_create_io_ops(LIBCOUCHBASE_IO_OPS_DEFAULT, NULL, &err);
1210
- if (bucket->io == NULL && err != LIBCOUCHBASE_SUCCESS) {
1211
- rb_exc_raise(cb_check_error(err, "failed to create IO instance", Qnil));
1212
- }
1213
- bucket->handle = libcouchbase_create(bucket->node_list ? bucket-> node_list : bucket->authority,
1214
- bucket->username, bucket->password, bucket->bucket, bucket->io);
1215
- if (bucket->handle == NULL) {
1216
- rb_raise(eLibcouchbaseError, "failed to create libcouchbase instance");
1217
- }
1218
- libcouchbase_set_cookie(bucket->handle, bucket);
1219
- (void)libcouchbase_set_error_callback(bucket->handle, error_callback);
1220
- (void)libcouchbase_set_storage_callback(bucket->handle, storage_callback);
1221
- (void)libcouchbase_set_get_callback(bucket->handle, get_callback);
1222
- (void)libcouchbase_set_touch_callback(bucket->handle, touch_callback);
1223
- (void)libcouchbase_set_remove_callback(bucket->handle, delete_callback);
1224
- (void)libcouchbase_set_stat_callback(bucket->handle, stat_callback);
1225
- (void)libcouchbase_set_flush_callback(bucket->handle, flush_callback);
1226
- (void)libcouchbase_set_arithmetic_callback(bucket->handle, arithmetic_callback);
1227
- (void)libcouchbase_set_version_callback(bucket->handle, version_callback);
1228
-
1229
- err = libcouchbase_connect(bucket->handle);
1230
- if (err != LIBCOUCHBASE_SUCCESS) {
1231
- libcouchbase_destroy(bucket->handle);
1232
- bucket->handle = NULL;
1233
- bucket->io = NULL;
1234
- rb_exc_raise(cb_check_error(err, "failed to connect libcouchbase instance to server", Qnil));
1235
- }
1236
- bucket->exception = Qnil;
1237
- libcouchbase_wait(bucket->handle);
1238
- if (bucket->exception != Qnil) {
1239
- libcouchbase_destroy(bucket->handle);
1240
- bucket->handle = NULL;
1241
- bucket->io = NULL;
1242
- rb_exc_raise(bucket->exception);
1243
- }
1244
-
1245
- if (bucket->timeout > 0) {
1246
- libcouchbase_set_timeout(bucket->handle, bucket->timeout);
1247
- } else {
1248
- bucket->timeout = libcouchbase_get_timeout(bucket->handle);
1249
- }
1250
- }
1251
-
1252
- static VALUE
1253
- cb_bucket_alloc(VALUE klass)
1254
- {
1255
- VALUE obj;
1256
- bucket_t *bucket;
1257
-
1258
- /* allocate new bucket struct and set it to zero */
1259
- obj = Data_Make_Struct(klass, bucket_t, cb_bucket_mark, cb_bucket_free,
1260
- bucket);
1261
- return obj;
1262
- }
1263
-
1264
- /*
1265
- * Initialize new Bucket.
1266
- *
1267
- * @overload initialize(url, options = {})
1268
- * Initialize bucket using URI of the cluster and options. It is possible
1269
- * to override some parts of URI using the options keys (e.g. :host or
1270
- * :port)
1271
- *
1272
- * @param [String] url The full URL of management API of the cluster.
1273
- * @param [Hash] options The options for connection. See options definition
1274
- * below.
1275
- *
1276
- * @overload initialize(options = {})
1277
- * Initialize bucket using options only.
1278
- *
1279
- * @param [Hash] options The options for operation for connection
1280
- * @option options [Array] :node_list (nil) the list of nodes to connect
1281
- * to. If specified it takes precedence over +:host+ option. The list
1282
- * must be array of strings in form of host names or host names with
1283
- * ports (in first case port 8091 will be used, see examples).
1284
- * @option options [String] :host ("localhost") the hostname or IP address
1285
- * of the node
1286
- * @option options [Fixnum] :port (8091) the port of the managemenent API
1287
- * @option options [String] :pool ("default") the pool name
1288
- * @option options [String] :bucket ("default") the bucket name
1289
- * @option options [Fixnum] :default_ttl (0) the TTL used by default during
1290
- * storing key-value pairs.
1291
- * @option options [Fixnum] :default_flags (0) the default flags.
1292
- * @option options [Symbol] :default_format (:document) the format, which
1293
- * will be used for values by default. Note that changing format will
1294
- * amend flags. (see {Bucket#default_format})
1295
- * @option options [String] :username (nil) the user name to connect to the
1296
- * cluster. Used to authenticate on management API.
1297
- * @option options [String] :password (nil) the password of the user.
1298
- * @option options [Boolean] :quiet (true) the flag controlling if raising
1299
- * exception when the client executes operations on unexising keys. If it
1300
- * is +true+ it will raise {Couchbase::Error::NotFound} exceptions. The
1301
- * default behaviour is to return +nil+ value silently (might be useful in
1302
- * Rails cache).
1303
- *
1304
- * @example Initialize connection using default options
1305
- * Couchbase.new
1306
- *
1307
- * @example Select custom bucket
1308
- * Couchbase.new(:bucket => 'foo')
1309
- * Couchbase.new('http://localhost:8091/pools/default/buckets/foo')
1310
- *
1311
- * @example Connect to protected bucket
1312
- * Couchbase.new(:bucket => 'protected', :username => 'protected', :password => 'secret')
1313
- * Couchbase.new('http://localhost:8091/pools/default/buckets/protected',
1314
- * :username => 'protected', :password => 'secret')
1315
- *
1316
- * @example Use list of nodes, in case some nodes might be dead
1317
- * Couchbase.new(:node_list => ['example.com:8091', 'example.org:8091', 'example.net'])
1318
- *
1319
- * @return [Bucket]
1320
- */
1321
- static VALUE
1322
- cb_bucket_init(int argc, VALUE *argv, VALUE self)
1323
- {
1324
- bucket_t *bucket = DATA_PTR(self);
1325
-
1326
- bucket->exception = Qnil;
1327
- bucket->hostname = strdup("localhost");
1328
- bucket->port = 8091;
1329
- bucket->pool = strdup("default");
1330
- bucket->bucket = strdup("default");
1331
- bucket->async = 0;
1332
- bucket->quiet = 1;
1333
- bucket->default_ttl = 0;
1334
- bucket->default_flags = 0;
1335
- bucket->default_format = sym_document;
1336
- bucket->on_error_proc = Qnil;
1337
- bucket->timeout = 0;
1338
- bucket->object_space = rb_hash_new();
1339
- bucket->node_list = NULL;
1340
-
1341
- do_scan_connection_options(bucket, argc, argv);
1342
- do_connect(bucket);
1343
-
1344
- return self;
1345
- }
1346
-
1347
- /*
1348
- * Initialize copy
1349
- *
1350
- * Initializes copy of the object, used by {Couchbase::Bucket#dup}
1351
- *
1352
- * @param orig [Couchbase::Bucket] the source for copy
1353
- *
1354
- * @return [Couchbase::Bucket]
1355
- */
1356
- static VALUE
1357
- cb_bucket_init_copy(VALUE copy, VALUE orig)
1358
- {
1359
- bucket_t *copy_b;
1360
- bucket_t *orig_b;
1361
-
1362
- if (copy == orig)
1363
- return copy;
1364
-
1365
- if (TYPE(orig) != T_DATA || TYPE(copy) != T_DATA ||
1366
- RDATA(orig)->dfree != (RUBY_DATA_FUNC)cb_bucket_free) {
1367
- rb_raise(rb_eTypeError, "wrong argument type");
1368
- }
1369
-
1370
- copy_b = DATA_PTR(copy);
1371
- orig_b = DATA_PTR(orig);
1372
-
1373
- copy_b->port = orig_b->port;
1374
- copy_b->authority = strdup(orig_b->authority);
1375
- copy_b->hostname = strdup(orig_b->hostname);
1376
- copy_b->pool = strdup(orig_b->pool);
1377
- copy_b->bucket = strdup(orig_b->bucket);
1378
- if (orig_b->username) {
1379
- copy_b->username = strdup(orig_b->username);
1380
- }
1381
- if (orig_b->password) {
1382
- copy_b->password = strdup(orig_b->password);
1383
- }
1384
- copy_b->async = orig_b->async;
1385
- copy_b->quiet = orig_b->quiet;
1386
- copy_b->seqno = orig_b->seqno;
1387
- copy_b->default_format = orig_b->default_format;
1388
- copy_b->default_flags = orig_b->default_flags;
1389
- copy_b->default_ttl = orig_b->default_ttl;
1390
- copy_b->timeout = orig_b->timeout;
1391
- copy_b->exception = Qnil;
1392
- if (orig_b->on_error_proc != Qnil) {
1393
- copy_b->on_error_proc = rb_funcall(orig_b->on_error_proc, id_dup, 0);
1394
- }
1395
-
1396
- do_connect(copy_b);
1397
-
1398
- return copy;
1399
- }
1400
-
1401
- /*
1402
- * Reconnect the bucket
1403
- *
1404
- * Reconnect the bucket using initial configuration with optional
1405
- * redefinition.
1406
- *
1407
- * @overload reconnect(url, options = {})
1408
- * see {Bucket#initialize Bucket#initialize(url, options)}
1409
- *
1410
- * @overload reconnect(options = {})
1411
- * see {Bucket#initialize Bucket#initialize(options)}
1412
- *
1413
- * @example reconnect with current parameters
1414
- * c.reconnect
1415
- *
1416
- * @example reconnect the instance to another bucket
1417
- * c.reconnect(:bucket => 'new')
1418
- */
1419
- static VALUE
1420
- cb_bucket_reconnect(int argc, VALUE *argv, VALUE self)
1421
- {
1422
- bucket_t *bucket = DATA_PTR(self);
1423
-
1424
- do_scan_connection_options(bucket, argc, argv);
1425
- do_connect(bucket);
1426
-
1427
- return self;
1428
- }
1429
-
1430
- /* Document-method: connected?
1431
- * Check whether the instance connected to the cluster.
1432
- *
1433
- * @return [Boolean] +true+ if the instance connected to the cluster
1434
- */
1435
- static VALUE
1436
- cb_bucket_connected_p(VALUE self)
1437
- {
1438
- bucket_t *bucket = DATA_PTR(self);
1439
- return bucket->handle ? Qtrue : Qfalse;
1440
- }
1441
-
1442
- /* Document-method: async?
1443
- * Check whether the connection asynchronous.
1444
- *
1445
- * By default all operations are synchronous and block waiting for
1446
- * results, but you can make them asynchronous and run event loop
1447
- * explicitly. (see {Bucket#run})
1448
- *
1449
- * @example Return value of #get operation depending on async flag
1450
- * connection = Connection.new
1451
- * connection.async? #=> false
1452
- *
1453
- * connection.run do |conn|
1454
- * conn.async? #=> true
1455
- * end
1456
- *
1457
- * @return [Boolean] +true+ if the connection if asynchronous
1458
- *
1459
- * @see Bucket#run
1460
- */
1461
- static VALUE
1462
- cb_bucket_async_p(VALUE self)
1463
- {
1464
- bucket_t *bucket = DATA_PTR(self);
1465
- return bucket->async ? Qtrue : Qfalse;
1466
- }
1467
-
1468
- static VALUE
1469
- cb_bucket_quiet_get(VALUE self)
1470
- {
1471
- bucket_t *bucket = DATA_PTR(self);
1472
- return bucket->quiet ? Qtrue : Qfalse;
1473
- }
1474
-
1475
- static VALUE
1476
- cb_bucket_quiet_set(VALUE self, VALUE val)
1477
- {
1478
- bucket_t *bucket = DATA_PTR(self);
1479
- VALUE new;
1480
-
1481
- bucket->quiet = RTEST(val);
1482
- new = bucket->quiet ? Qtrue : Qfalse;
1483
- return new;
1484
- }
1485
-
1486
- static VALUE
1487
- cb_bucket_default_flags_get(VALUE self)
1488
- {
1489
- bucket_t *bucket = DATA_PTR(self);
1490
- return ULONG2NUM(bucket->default_flags);
1491
- }
1492
-
1493
- static VALUE
1494
- cb_bucket_default_flags_set(VALUE self, VALUE val)
1495
- {
1496
- bucket_t *bucket = DATA_PTR(self);
1497
-
1498
- bucket->default_flags = (uint32_t)NUM2ULONG(val);
1499
- bucket->default_format = flags_get_format(bucket->default_flags);
1500
- return val;
1501
- }
1502
-
1503
- static VALUE
1504
- cb_bucket_default_format_get(VALUE self)
1505
- {
1506
- bucket_t *bucket = DATA_PTR(self);
1507
- return bucket->default_format;
1508
- }
1509
-
1510
- static VALUE
1511
- cb_bucket_default_format_set(VALUE self, VALUE val)
1512
- {
1513
- bucket_t *bucket = DATA_PTR(self);
1514
-
1515
- if (TYPE(val) == T_FIXNUM) {
1516
- switch (FIX2INT(val)) {
1517
- case FMT_DOCUMENT:
1518
- val = sym_document;
1519
- break;
1520
- case FMT_MARSHAL:
1521
- val = sym_marshal;
1522
- break;
1523
- case FMT_PLAIN:
1524
- val = sym_plain;
1525
- break;
1526
- }
1527
- }
1528
- if (val == sym_document || val == sym_marshal || val == sym_plain) {
1529
- bucket->default_format = val;
1530
- bucket->default_flags = flags_set_format(bucket->default_flags, val);
1531
- }
1532
-
1533
- return val;
1534
- }
1535
-
1536
- static VALUE
1537
- cb_bucket_on_error_set(VALUE self, VALUE val)
1538
- {
1539
- bucket_t *bucket = DATA_PTR(self);
1540
-
1541
- if (rb_respond_to(val, id_call)) {
1542
- bucket->on_error_proc = val;
1543
- } else {
1544
- bucket->on_error_proc = Qnil;
1545
- }
1546
-
1547
- return bucket->on_error_proc;
1548
- }
1549
-
1550
- static VALUE
1551
- cb_bucket_on_error_get(VALUE self)
1552
- {
1553
- bucket_t *bucket = DATA_PTR(self);
1554
-
1555
- if (rb_block_given_p()) {
1556
- return cb_bucket_on_error_set(self, rb_block_proc());
1557
- } else {
1558
- return bucket->on_error_proc;
1559
- }
1560
- }
1561
-
1562
- static VALUE
1563
- cb_bucket_timeout_get(VALUE self)
1564
- {
1565
- bucket_t *bucket = DATA_PTR(self);
1566
- return ULONG2NUM(bucket->timeout);
1567
- }
1568
-
1569
- static VALUE
1570
- cb_bucket_timeout_set(VALUE self, VALUE val)
1571
- {
1572
- bucket_t *bucket = DATA_PTR(self);
1573
- VALUE tmval;
1574
-
1575
- bucket->timeout = (uint32_t)NUM2ULONG(val);
1576
- libcouchbase_set_timeout(bucket->handle, bucket->timeout);
1577
- tmval = ULONG2NUM(bucket->timeout);
1578
-
1579
- return tmval;
1580
- }
1581
-
1582
- /* Document-method: hostname
1583
- * @return [String] the host name of the management interface (default: "localhost")
1584
- */
1585
- static VALUE
1586
- cb_bucket_hostname_get(VALUE self)
1587
- {
1588
- bucket_t *bucket = DATA_PTR(self);
1589
- if (bucket->handle) {
1590
- if (bucket->hostname) {
1591
- xfree(bucket->hostname);
1592
- bucket->hostname = NULL;
1593
- }
1594
- bucket->hostname = strdup(libcouchbase_get_host(bucket->handle));
1595
- if (bucket->hostname == NULL) {
1596
- rb_raise(eNoMemoryError, "failed to allocate memory for Bucket");
1597
- }
1598
- }
1599
- return STR_NEW_CSTR(bucket->hostname);
1600
- }
1601
-
1602
- /* Document-method: port
1603
- * @return [Fixnum] the port number of the management interface (default: 8091)
1604
- */
1605
- static VALUE
1606
- cb_bucket_port_get(VALUE self)
1607
- {
1608
- bucket_t *bucket = DATA_PTR(self);
1609
- if (bucket->handle) {
1610
- bucket->port = atoi(libcouchbase_get_port(bucket->handle));
1611
- }
1612
- return UINT2NUM(bucket->port);
1613
- }
1614
-
1615
- /* Document-method: authority
1616
- * @return [String] host with port
1617
- */
1618
- static VALUE
1619
- cb_bucket_authority_get(VALUE self)
1620
- {
1621
- bucket_t *bucket = DATA_PTR(self);
1622
- size_t len;
1623
-
1624
- (void)cb_bucket_hostname_get(self);
1625
- (void)cb_bucket_port_get(self);
1626
- len = strlen(bucket->hostname) + 10;
1627
- bucket->authority = xcalloc(len, sizeof(char));
1628
- if (bucket->authority == NULL) {
1629
- rb_raise(eNoMemoryError, "failed to allocate memory for Bucket");
1630
- }
1631
- snprintf(bucket->authority, len, "%s:%u", bucket->hostname, bucket->port);
1632
- return STR_NEW_CSTR(bucket->authority);
1633
- }
1634
-
1635
- /* Document-method: bucket
1636
- * @return [String] the bucket name
1637
- */
1638
- static VALUE
1639
- cb_bucket_bucket_get(VALUE self)
1640
- {
1641
- bucket_t *bucket = DATA_PTR(self);
1642
- return STR_NEW_CSTR(bucket->bucket);
1643
- }
1644
-
1645
- /* Document-method: pool
1646
- * @return [String] the pool name (usually "default")
1647
- */
1648
- static VALUE
1649
- cb_bucket_pool_get(VALUE self)
1650
- {
1651
- bucket_t *bucket = DATA_PTR(self);
1652
- return STR_NEW_CSTR(bucket->pool);
1653
- }
1654
-
1655
- /* Document-method: username
1656
- * @return [String] the username for protected buckets (usually matches
1657
- * the bucket name)
1658
- */
1659
- static VALUE
1660
- cb_bucket_username_get(VALUE self)
1661
- {
1662
- bucket_t *bucket = DATA_PTR(self);
1663
- return STR_NEW_CSTR(bucket->username);
1664
- }
1665
-
1666
- /* Document-method: password
1667
- * @return [String] the password for protected buckets
1668
- */
1669
- static VALUE
1670
- cb_bucket_password_get(VALUE self)
1671
- {
1672
- bucket_t *bucket = DATA_PTR(self);
1673
- return STR_NEW_CSTR(bucket->password);
1674
- }
1675
-
1676
- /* Document-method: url
1677
- * @return [String] the address of the cluster management interface
1678
- */
1679
- static VALUE
1680
- cb_bucket_url_get(VALUE self)
1681
- {
1682
- bucket_t *bucket = DATA_PTR(self);
1683
- VALUE str;
1684
-
1685
- (void)cb_bucket_authority_get(self);
1686
- str = rb_str_buf_new2("http://");
1687
- rb_str_buf_cat2(str, bucket->authority);
1688
- rb_str_buf_cat2(str, "/pools/");
1689
- rb_str_buf_cat2(str, bucket->pool);
1690
- rb_str_buf_cat2(str, "/buckets/");
1691
- rb_str_buf_cat2(str, bucket->bucket);
1692
- rb_str_buf_cat2(str, "/");
1693
- return str;
1694
- }
1695
-
1696
- /*
1697
- * Returns a string containing a human-readable representation of the
1698
- * Bucket.
1699
- *
1700
- * @return [String]
1701
- */
1702
- static VALUE
1703
- cb_bucket_inspect(VALUE self)
1704
- {
1705
- VALUE str;
1706
- bucket_t *bucket = DATA_PTR(self);
1707
- char buf[200];
1708
-
1709
- str = rb_str_buf_new2("#<");
1710
- rb_str_buf_cat2(str, rb_obj_classname(self));
1711
- snprintf(buf, 25, ":%p \"", (void *)self);
1712
- (void)cb_bucket_authority_get(self);
1713
- rb_str_buf_cat2(str, buf);
1714
- rb_str_buf_cat2(str, "http://");
1715
- rb_str_buf_cat2(str, bucket->authority);
1716
- rb_str_buf_cat2(str, "/pools/");
1717
- rb_str_buf_cat2(str, bucket->pool);
1718
- rb_str_buf_cat2(str, "/buckets/");
1719
- rb_str_buf_cat2(str, bucket->bucket);
1720
- rb_str_buf_cat2(str, "/");
1721
- snprintf(buf, 150, "\" default_format=:%s, default_flags=0x%x, quiet=%s, connected=%s, timeout=%u>",
1722
- rb_id2name(SYM2ID(bucket->default_format)),
1723
- bucket->default_flags,
1724
- bucket->quiet ? "true" : "false",
1725
- bucket->handle ? "true" : "false",
1726
- bucket->timeout);
1727
- rb_str_buf_cat2(str, buf);
1728
-
1729
- return str;
1730
- }
1731
-
1732
- /*
1733
- * Delete the specified key
1734
- *
1735
- * @overload delete(key, options = {})
1736
- * @param key [String, Symbol] Key used to reference the value.
1737
- * @param options [Hash] Options for operation.
1738
- * @option options [Boolean] :quiet (self.quiet) If set to +true+, the
1739
- * operation won't raise error for missing key, it will return +nil+.
1740
- * Otherwise it will raise error in synchronous mode. In asynchronous
1741
- * mode this option ignored.
1742
- * @option options [Fixnum] :cas The CAS value for an object. This value
1743
- * created on the server and is guaranteed to be unique for each value of
1744
- * a given key. This value is used to provide simple optimistic
1745
- * concurrency control when multiple clients or threads try to
1746
- * update/delete an item simultaneously.
1747
- *
1748
- * @raise [Couchbase::Error::Connect] if connection closed (see {Bucket#reconnect})
1749
- * @raise [ArgumentError] when passing the block in synchronous mode
1750
- * @raise [Couchbase::Error::KeyExists] on CAS mismatch
1751
- * @raise [Couchbase::Error::NotFound] if key is missing in verbose mode
1752
- *
1753
- * @example Delete the key in quiet mode (default)
1754
- * c.set("foo", "bar")
1755
- * c.delete("foo") #=> true
1756
- * c.delete("foo") #=> false
1757
- *
1758
- * @example Delete the key verbosely
1759
- * c.set("foo", "bar")
1760
- * c.delete("foo", :quiet => false) #=> true
1761
- * c.delete("foo", :quiet => false) #=> will raise Couchbase::Error::NotFound
1762
- *
1763
- * @example Delete the key with version check
1764
- * ver = c.set("foo", "bar") #=> 5992859822302167040
1765
- * c.delete("foo", :cas => 123456) #=> will raise Couchbase::Error::KeyExists
1766
- * c.delete("foo", :cas => ver) #=> true
1767
- */
1768
- static VALUE
1769
- cb_bucket_delete(int argc, VALUE *argv, VALUE self)
1770
- {
1771
- bucket_t *bucket = DATA_PTR(self);
1772
- context_t *ctx;
1773
- VALUE k, c, rv, proc, exc, opts;
1774
- char *key;
1775
- size_t nkey;
1776
- libcouchbase_cas_t cas = 0;
1777
- libcouchbase_error_t err;
1778
- long seqno;
1779
-
1780
- if (bucket->handle == NULL) {
1781
- rb_raise(eConnectError, "closed connection");
1782
- }
1783
- rb_scan_args(argc, argv, "11&", &k, &opts, &proc);
1784
- if (!bucket->async && proc != Qnil) {
1785
- rb_raise(rb_eArgError, "synchronous mode doesn't support callbacks");
1786
- }
1787
- k = unify_key(k);
1788
- key = RSTRING_PTR(k);
1789
- nkey = RSTRING_LEN(k);
1790
- ctx = xcalloc(1, sizeof(context_t));
1791
- ctx->quiet = bucket->quiet;
1792
- if (ctx == NULL) {
1793
- rb_raise(eNoMemoryError, "failed to allocate memory for context");
1794
- }
1795
- if (opts != Qnil) {
1796
- if (TYPE(opts) == T_BIGNUM || TYPE(opts) == T_FIXNUM) {
1797
- cas = NUM2ULL(opts);
1798
- } else {
1799
- Check_Type(opts, T_HASH);
1800
- if ((c = rb_hash_aref(opts, sym_cas)) != Qnil) {
1801
- cas = NUM2ULL(c);
1802
- }
1803
- if (RTEST(rb_funcall(opts, id_has_key_p, 1, sym_quiet))) {
1804
- ctx->quiet = RTEST(rb_hash_aref(opts, sym_quiet));
1805
- }
1806
- }
1807
- }
1808
- ctx->proc = proc;
1809
- cb_gc_protect(bucket, ctx->proc);
1810
- rv = rb_ary_new();
1811
- ctx->rv = &rv;
1812
- ctx->bucket = bucket;
1813
- ctx->exception = Qnil;
1814
- seqno = bucket->seqno;
1815
- bucket->seqno++;
1816
- err = libcouchbase_remove(bucket->handle, (const void *)ctx,
1817
- (const void *)key, nkey, cas);
1818
- exc = cb_check_error(err, "failed to schedule delete request", Qnil);
1819
- if (exc != Qnil) {
1820
- xfree(ctx);
1821
- rb_exc_raise(exc);
1822
- }
1823
- if (bucket->async) {
1824
- return Qnil;
1825
- } else {
1826
- if (bucket->seqno - seqno > 0) {
1827
- /* we have some operations pending */
1828
- bucket->io->run_event_loop(bucket->io);
1829
- }
1830
- exc = ctx->exception;
1831
- xfree(ctx);
1832
- if (exc != Qnil) {
1833
- cb_gc_unprotect(bucket, exc);
1834
- rb_exc_raise(exc);
1835
- }
1836
- return rv;
1837
- }
1838
- }
1839
-
1840
- static inline VALUE
1841
- cb_bucket_store(libcouchbase_storage_t cmd, int argc, VALUE *argv, VALUE self)
1842
- {
1843
- bucket_t *bucket = DATA_PTR(self);
1844
- context_t *ctx;
1845
- VALUE k, v, arg, opts, rv, proc, exc, fmt;
1846
- char *key, *bytes;
1847
- size_t nkey, nbytes;
1848
- uint32_t flags;
1849
- time_t exp = 0;
1850
- libcouchbase_cas_t cas = 0;
1851
- libcouchbase_error_t err;
1852
- long seqno;
1853
-
1854
- if (bucket->handle == NULL) {
1855
- rb_raise(eConnectError, "closed connection");
1856
- }
1857
- rb_scan_args(argc, argv, "21&", &k, &v, &opts, &proc);
1858
- if (!bucket->async && proc != Qnil) {
1859
- rb_raise(rb_eArgError, "synchronous mode doesn't support callbacks");
1860
- }
1861
- k = unify_key(k);
1862
- flags = bucket->default_flags;
1863
- if (opts != Qnil) {
1864
- Check_Type(opts, T_HASH);
1865
- arg = rb_hash_aref(opts, sym_flags);
1866
- if (arg != Qnil) {
1867
- flags = (uint32_t)NUM2ULONG(arg);
1868
- }
1869
- arg = rb_hash_aref(opts, sym_ttl);
1870
- if (arg != Qnil) {
1871
- exp = NUM2ULONG(arg);
1872
- }
1873
- arg = rb_hash_aref(opts, sym_cas);
1874
- if (arg != Qnil) {
1875
- cas = NUM2ULL(arg);
1876
- }
1877
- fmt = rb_hash_aref(opts, sym_format);
1878
- if (fmt != Qnil) { /* rewrite format bits */
1879
- flags = flags_set_format(flags, fmt);
1880
- }
1881
- }
1882
- key = RSTRING_PTR(k);
1883
- nkey = RSTRING_LEN(k);
1884
- v = encode_value(v, flags);
1885
- if (v == Qundef) {
1886
- rb_raise(eValueFormatError,
1887
- "unable to convert value for key '%s'", key);
1888
- }
1889
- bytes = RSTRING_PTR(v);
1890
- nbytes = RSTRING_LEN(v);
1891
- ctx = xcalloc(1, sizeof(context_t));
1892
- if (ctx == NULL) {
1893
- rb_raise(eNoMemoryError, "failed to allocate memory for context");
1894
- }
1895
- rv = Qnil;
1896
- ctx->rv = &rv;
1897
- ctx->bucket = bucket;
1898
- ctx->proc = proc;
1899
- cb_gc_protect(bucket, ctx->proc);
1900
- ctx->exception = Qnil;
1901
- seqno = bucket->seqno;
1902
- bucket->seqno++;
1903
- err = libcouchbase_store(bucket->handle, (const void *)ctx, cmd,
1904
- (const void *)key, nkey, bytes, nbytes, flags, exp, cas);
1905
- exc = cb_check_error(err, "failed to schedule set request", Qnil);
1906
- if (exc != Qnil) {
1907
- xfree(ctx);
1908
- rb_exc_raise(exc);
1909
- }
1910
- if (bucket->async) {
1911
- return Qnil;
1912
- } else {
1913
- if (bucket->seqno - seqno > 0) {
1914
- /* we have some operations pending */
1915
- bucket->io->run_event_loop(bucket->io);
1916
- }
1917
- exc = ctx->exception;
1918
- xfree(ctx);
1919
- if (exc != Qnil) {
1920
- cb_gc_unprotect(bucket, exc);
1921
- rb_exc_raise(exc);
1922
- }
1923
- if (bucket->exception != Qnil) {
1924
- rb_exc_raise(bucket->exception);
1925
- }
1926
- return rv;
1927
- }
1928
- }
1929
-
1930
- static inline VALUE
1931
- cb_bucket_arithmetic(int sign, int argc, VALUE *argv, VALUE self)
1932
- {
1933
- bucket_t *bucket = DATA_PTR(self);
1934
- context_t *ctx;
1935
- VALUE k, d, arg, opts, rv, proc, exc;
1936
- char *key;
1937
- size_t nkey;
1938
- time_t exp;
1939
- uint64_t delta = 0, initial = 0;
1940
- int create = 0;
1941
- libcouchbase_error_t err;
1942
- long seqno;
1943
-
1944
- if (bucket->handle == NULL) {
1945
- rb_raise(eConnectError, "closed connection");
1946
- }
1947
- rb_scan_args(argc, argv, "12&", &k, &d, &opts, &proc);
1948
- if (!bucket->async && proc != Qnil) {
1949
- rb_raise(rb_eArgError, "synchronous mode doesn't support callbacks");
1950
- }
1951
- k = unify_key(k);
1952
- ctx = xcalloc(1, sizeof(context_t));
1953
- if (ctx == NULL) {
1954
- rb_raise(eNoMemoryError, "failed to allocate memory for context");
1955
- }
1956
- if (argc == 2 && TYPE(d) == T_HASH) {
1957
- opts = d;
1958
- d = Qnil;
1959
- }
1960
- exp = bucket->default_ttl;
1961
- if (opts != Qnil) {
1962
- Check_Type(opts, T_HASH);
1963
- create = RTEST(rb_hash_aref(opts, sym_create));
1964
- ctx->extended = RTEST(rb_hash_aref(opts, sym_extended));
1965
- arg = rb_hash_aref(opts, sym_ttl);
1966
- if (arg != Qnil) {
1967
- exp = NUM2ULONG(arg);
1968
- }
1969
- arg = rb_hash_aref(opts, sym_initial);
1970
- if (arg != Qnil) {
1971
- initial = NUM2ULL(arg);
1972
- create = 1;
1973
- }
1974
- }
1975
- key = RSTRING_PTR(k);
1976
- nkey = RSTRING_LEN(k);
1977
- if (NIL_P(d)) {
1978
- delta = 1 * sign;
1979
- } else {
1980
- delta = NUM2ULL(d) * sign;
1981
- }
1982
- rv = Qnil;
1983
- ctx->rv = &rv;
1984
- ctx->bucket = bucket;
1985
- ctx->proc = proc;
1986
- cb_gc_protect(bucket, ctx->proc);
1987
- ctx->exception = Qnil;
1988
- ctx->arithm = sign;
1989
- seqno = bucket->seqno;
1990
- bucket->seqno++;
1991
- err = libcouchbase_arithmetic(bucket->handle, (const void *)ctx,
1992
- (const void *)key, nkey, delta, exp, create, initial);
1993
- exc = cb_check_error(err, "failed to schedule arithmetic request", k);
1994
- if (exc != Qnil) {
1995
- xfree(ctx);
1996
- rb_exc_raise(exc);
1997
- }
1998
- if (bucket->async) {
1999
- return Qnil;
2000
- } else {
2001
- if (bucket->seqno - seqno > 0) {
2002
- /* we have some operations pending */
2003
- bucket->io->run_event_loop(bucket->io);
2004
- }
2005
- exc = ctx->exception;
2006
- xfree(ctx);
2007
- if (exc != Qnil) {
2008
- cb_gc_unprotect(bucket, exc);
2009
- rb_exc_raise(exc);
2010
- }
2011
- return rv;
2012
- }
2013
- }
2014
-
2015
- /*
2016
- * Increment the value of an existing numeric key
2017
- *
2018
- * The increment methods enable you to increase a given stored integer
2019
- * value. These are the incremental equivalent of the decrement operations
2020
- * and work on the same basis; updating the value of a key if it can be
2021
- * parsed to an integer. The update operation occurs on the server and is
2022
- * provided at the protocol level. This simplifies what would otherwise be a
2023
- * two-stage get and set operation.
2024
- *
2025
- * @note that server values stored and transmitted as unsigned numbers,
2026
- * therefore if you try to store negative number and then increment or
2027
- * decrement it will cause overflow. (see "Integer overflow" example
2028
- * below)
2029
- *
2030
- * @overload incr(key, delta = 1, options = {})
2031
- * @param key [String, Symbol] Key used to reference the value.
2032
- * @param delta [Fixnum] Integer (up to 64 bits) value to increment
2033
- * @param options [Hash] Options for operation.
2034
- * @option options [Boolean] :create (false) If set to +true+, it will
2035
- * initialize the key with zero value and zero flags (use +:initial+
2036
- * option to set another initial value). Note: it won't increment the
2037
- * missing value.
2038
- * @option options [Fixnum] :initial (0) Integer (up to 64 bits) value for
2039
- * missing key initialization. This option imply +:create+ option is
2040
- * +true+.
2041
- * @option options [Fixnum] :ttl (self.default_ttl) Expiry time for key.
2042
- * Values larger than 30*24*60*60 seconds (30 days) are interpreted as
2043
- * absolute times (from the epoch). This option ignored for existent
2044
- * keys.
2045
- * @option options [Boolean] :extended (false) If set to +true+, the
2046
- * operation will return tuple +[value, cas]+, otherwise (by default) it
2047
- * returns just value.
2048
- *
2049
- * @yieldparam ret [Result] the result of operation in asynchronous mode
2050
- * (valid attributes: +error+, +operation+, +key+, +value+, +cas+).
2051
- *
2052
- * @return [Fixnum] the actual value of the key.
2053
- *
2054
- * @raise [Couchbase::Error::NotFound] if key is missing and +:create+
2055
- * option isn't +true+.
2056
- *
2057
- * @raise [Couchbase::Error::DeltaBadval] if the key contains non-numeric
2058
- * value
2059
- *
2060
- * @raise [Couchbase::Error::Connect] if connection closed (see {Bucket#reconnect})
2061
- *
2062
- * @raise [ArgumentError] when passing the block in synchronous mode
2063
- *
2064
- * @example Increment key by one
2065
- * c.incr("foo")
2066
- *
2067
- * @example Increment key by 50
2068
- * c.incr("foo", 50)
2069
- *
2070
- * @example Increment key by one <b>OR</b> initialize with zero
2071
- * c.incr("foo", :create => true) #=> will return old+1 or 0
2072
- *
2073
- * @example Increment key by one <b>OR</b> initialize with three
2074
- * c.incr("foo", 50, :initial => 3) #=> will return old+50 or 3
2075
- *
2076
- * @example Increment key and get its CAS value
2077
- * val, cas = c.incr("foo", :extended => true)
2078
- *
2079
- * @example Integer overflow
2080
- * c.set("foo", -100)
2081
- * c.get("foo") #=> -100
2082
- * c.incr("foo") #=> 18446744073709551517
2083
- *
2084
- * @example Asynchronous invocation
2085
- * c.run do
2086
- * c.incr("foo") do |ret|
2087
- * ret.operation #=> :increment
2088
- * ret.success? #=> true
2089
- * ret.key #=> "foo"
2090
- * ret.value
2091
- * ret.cas
2092
- * end
2093
- * end
2094
- *
2095
- */
2096
- static VALUE
2097
- cb_bucket_incr(int argc, VALUE *argv, VALUE self)
2098
- {
2099
- return cb_bucket_arithmetic(+1, argc, argv, self);
2100
- }
2101
-
2102
- /*
2103
- * Decrement the value of an existing numeric key
2104
- *
2105
- * The decrement methods reduce the value of a given key if the
2106
- * corresponding value can be parsed to an integer value. These operations
2107
- * are provided at a protocol level to eliminate the need to get, update,
2108
- * and reset a simple integer value in the database. It supports the use of
2109
- * an explicit offset value that will be used to reduce the stored value in
2110
- * the database.
2111
- *
2112
- * @note that server values stored and transmitted as unsigned numbers,
2113
- * therefore if you try to decrement negative or zero key, you will always
2114
- * get zero.
2115
- *
2116
- * @overload decr(key, delta = 1, options = {})
2117
- * @param key [String, Symbol] Key used to reference the value.
2118
- * @param delta [Fixnum] Integer (up to 64 bits) value to decrement
2119
- * @param options [Hash] Options for operation.
2120
- * @option options [Boolean] :create (false) If set to +true+, it will
2121
- * initialize the key with zero value and zero flags (use +:initial+
2122
- * option to set another initial value). Note: it won't decrement the
2123
- * missing value.
2124
- * @option options [Fixnum] :initial (0) Integer (up to 64 bits) value for
2125
- * missing key initialization. This option imply +:create+ option is
2126
- * +true+.
2127
- * @option options [Fixnum] :ttl (self.default_ttl) Expiry time for key.
2128
- * Values larger than 30*24*60*60 seconds (30 days) are interpreted as
2129
- * absolute times (from the epoch). This option ignored for existent
2130
- * keys.
2131
- * @option options [Boolean] :extended (false) If set to +true+, the
2132
- * operation will return tuple +[value, cas]+, otherwise (by default) it
2133
- * returns just value.
2134
- *
2135
- * @yieldparam ret [Result] the result of operation in asynchronous mode
2136
- * (valid attributes: +error+, +operation+, +key+, +value+, +cas+).
2137
- *
2138
- * @return [Fixnum] the actual value of the key.
2139
- *
2140
- * @raise [Couchbase::Error::NotFound] if key is missing and +:create+
2141
- * option isn't +true+.
2142
- *
2143
- * @raise [Couchbase::Error::DeltaBadval] if the key contains non-numeric
2144
- * value
2145
- *
2146
- * @raise [Couchbase::Error::Connect] if connection closed (see {Bucket#reconnect})
2147
- *
2148
- * @raise [ArgumentError] when passing the block in synchronous mode
2149
- *
2150
- * @example Decrement key by one
2151
- * c.decr("foo")
2152
- *
2153
- * @example Decrement key by 50
2154
- * c.decr("foo", 50)
2155
- *
2156
- * @example Decrement key by one <b>OR</b> initialize with zero
2157
- * c.decr("foo", :create => true) #=> will return old-1 or 0
2158
- *
2159
- * @example Decrement key by one <b>OR</b> initialize with three
2160
- * c.decr("foo", 50, :initial => 3) #=> will return old-50 or 3
2161
- *
2162
- * @example Decrement key and get its CAS value
2163
- * val, cas = c.decr("foo", :extended => true)
2164
- *
2165
- * @example Decrementing zero
2166
- * c.set("foo", 0)
2167
- * c.decrement("foo", 100500) #=> 0
2168
- *
2169
- * @example Decrementing negative value
2170
- * c.set("foo", -100)
2171
- * c.decrement("foo", 100500) #=> 0
2172
- *
2173
- * @example Asynchronous invocation
2174
- * c.run do
2175
- * c.decr("foo") do |ret|
2176
- * ret.operation #=> :decrement
2177
- * ret.success? #=> true
2178
- * ret.key #=> "foo"
2179
- * ret.value
2180
- * ret.cas
2181
- * end
2182
- * end
2183
- *
2184
- */
2185
- static VALUE
2186
- cb_bucket_decr(int argc, VALUE *argv, VALUE self)
2187
- {
2188
- return cb_bucket_arithmetic(-1, argc, argv, self);
2189
- }
2190
-
2191
- /*
2192
- * Obtain an object stored in Couchbase by given key.
2193
- *
2194
- * @overload get(*keys, options = {})
2195
- * @param keys [String, Symbol, Array] One or several keys to fetch
2196
- * @param options [Hash] Options for operation.
2197
- * @option options [Boolean] :extended (false) If set to +true+, the
2198
- * operation will return tuple +[value, flags, cas]+, otherwise (by
2199
- * default) it returns just value.
2200
- * @option options [Fixnum] :ttl (self.default_ttl) Expiry time for key.
2201
- * Values larger than 30*24*60*60 seconds (30 days) are interpreted as
2202
- * absolute times (from the epoch).
2203
- * @option options [Boolean] :quiet (self.quiet) If set to +true+, the
2204
- * operation won't raise error for missing key, it will return +nil+.
2205
- * Otherwise it will raise error in synchronous mode. In asynchronous
2206
- * mode this option ignored.
2207
- * @option options [Symbol] :format (nil) Explicitly choose the decoder
2208
- * for this key (+:plain+, +:document+, +:marshal+). See
2209
- * {Bucket#default_format}.
2210
- *
2211
- * @yieldparam ret [Result] the result of operation in asynchronous mode
2212
- * (valid attributes: +error+, +operation+, +key+, +value+, +flags+,
2213
- * +cas+).
2214
- *
2215
- * @return [Object, Array, Hash] the value(s) (or tuples in extended mode)
2216
- * assiciated with the key.
2217
- *
2218
- * @raise [Couchbase::Error::NotFound] if the key is missing in the
2219
- * bucket.
2220
- *
2221
- * @raise [Couchbase::Error::Connect] if connection closed (see {Bucket#reconnect})
2222
- *
2223
- * @raise [ArgumentError] when passing the block in synchronous mode
2224
- *
2225
- * @example Get single value in quite mode (the default)
2226
- * c.get("foo") #=> the associated value or nil
2227
- *
2228
- * @example Use alternative hash-like syntax
2229
- * c["foo"] #=> the associated value or nil
2230
- *
2231
- * @example Get single value in verbose mode
2232
- * c.get("missing-foo", :quiet => false) #=> raises Couchbase::NotFound
2233
- *
2234
- * @example Get and touch single value. The key won't be accessible after 10 seconds
2235
- * c.get("foo", :ttl => 10)
2236
- *
2237
- * @example Extended get
2238
- * val, flags, cas = c.get("foo", :extended => true)
2239
- *
2240
- * @example Get multiple keys
2241
- * c.get("foo", "bar", "baz") #=> [val1, val2, val3]
2242
- *
2243
- * @example Extended get multiple keys
2244
- * c.get("foo", "bar", :extended => true)
2245
- * #=> {"foo" => [val1, flags1, cas1], "bar" => [val2, flags2, cas2]}
2246
- *
2247
- * @example Asynchronous get
2248
- * c.run do
2249
- * c.get("foo", "bar", "baz") do |res|
2250
- * ret.operation #=> :get
2251
- * ret.success? #=> true
2252
- * ret.key #=> "foo", "bar" or "baz" in separate calls
2253
- * ret.value
2254
- * ret.flags
2255
- * ret.cas
2256
- * end
2257
- * end
2258
- *
2259
- * @overload get(keys, options = {})
2260
- * When the method receive hash map, it will behave like it receive list
2261
- * of keys (+keys.keys+), but also touch each key setting expiry time to
2262
- * the corresponding value. But unlike usual get this command always
2263
- * return hash map +{key => value}+ or +{key => [value, flags, cas]}+.
2264
- *
2265
- * @param keys [Hash] Map key-ttl
2266
- * @param options [Hash] Options for operation. (see options definition
2267
- * above)
2268
- *
2269
- * @return [Hash] the values (or tuples in extended mode) assiciated with
2270
- * the keys.
2271
- *
2272
- * @example Get and touch multiple keys
2273
- * c.get("foo" => 10, "bar" => 20) #=> {"foo" => val1, "bar" => val2}
2274
- *
2275
- * @example Extended get and touch multiple keys
2276
- * c.get({"foo" => 10, "bar" => 20}, :extended => true)
2277
- * #=> {"foo" => [val1, flags1, cas1], "bar" => [val2, flags2, cas2]}
2278
- */
2279
- static VALUE
2280
- cb_bucket_get(int argc, VALUE *argv, VALUE self)
2281
- {
2282
- bucket_t *bucket = DATA_PTR(self);
2283
- context_t *ctx;
2284
- VALUE args, rv, proc, exc, keys;
2285
- long nn;
2286
- libcouchbase_error_t err;
2287
- struct key_traits *traits;
2288
- int extended, mgat;
2289
- long seqno;
2290
-
2291
- if (bucket->handle == NULL) {
2292
- rb_raise(eConnectError, "closed connection");
2293
- }
2294
- rb_scan_args(argc, argv, "0*&", &args, &proc);
2295
- if (!bucket->async && proc != Qnil) {
2296
- rb_raise(rb_eArgError, "synchronous mode doesn't support callbacks");
2297
- }
2298
- rb_funcall(args, id_flatten_bang, 0);
2299
- traits = xcalloc(1, sizeof(struct key_traits));
2300
- nn = cb_args_scan_keys(RARRAY_LEN(args), args, bucket, traits);
2301
- ctx = xcalloc(1, sizeof(context_t));
2302
- if (ctx == NULL) {
2303
- rb_raise(eNoMemoryError, "failed to allocate memory for context");
2304
- }
2305
- mgat = traits->mgat;
2306
- keys = traits->keys_ary;
2307
- ctx->proc = proc;
2308
- cb_gc_protect(bucket, ctx->proc);
2309
- ctx->bucket = bucket;
2310
- ctx->extended = traits->extended;
2311
- ctx->quiet = traits->quiet;
2312
- ctx->force_format = traits->force_format;
2313
- rv = rb_hash_new();
2314
- ctx->rv = &rv;
2315
- ctx->exception = Qnil;
2316
- seqno = bucket->seqno;
2317
- bucket->seqno += nn;
2318
- err = libcouchbase_mget(bucket->handle, (const void *)ctx,
2319
- traits->nkeys, (const void * const *)traits->keys,
2320
- traits->lens, (traits->explicit_ttl) ? traits->ttls : NULL);
2321
- xfree(traits->keys);
2322
- xfree(traits->lens);
2323
- xfree(traits->ttls);
2324
- xfree(traits);
2325
- exc = cb_check_error(err, "failed to schedule get request", Qnil);
2326
- if (exc != Qnil) {
2327
- xfree(ctx);
2328
- rb_exc_raise(exc);
2329
- }
2330
- if (bucket->async) {
2331
- return Qnil;
2332
- } else {
2333
- if (bucket->seqno - seqno > 0) {
2334
- /* we have some operations pending */
2335
- bucket->io->run_event_loop(bucket->io);
2336
- }
2337
- exc = ctx->exception;
2338
- extended = ctx->extended;
2339
- xfree(ctx);
2340
- if (exc != Qnil) {
2341
- cb_gc_unprotect(bucket, exc);
2342
- rb_exc_raise(exc);
2343
- }
2344
- if (bucket->exception != Qnil) {
2345
- rb_exc_raise(bucket->exception);
2346
- }
2347
- if (mgat || (extended && nn > 1)) {
2348
- return rv; /* return as a hash {key => [value, flags, cas], ...} */
2349
- }
2350
- if (nn > 1) {
2351
- long ii;
2352
- VALUE *keys_ptr, ret;
2353
- ret = rb_ary_new();
2354
- keys_ptr = RARRAY_PTR(keys);
2355
- for (ii = 0; ii < nn; ii++) {
2356
- rb_ary_push(ret, rb_hash_aref(rv, keys_ptr[ii]));
2357
- }
2358
- return ret; /* return as an array [value1, value2, ...] */
2359
- } else {
2360
- VALUE vv = Qnil;
2361
- rb_hash_foreach(rv, cb_first_value_i, (VALUE)&vv);
2362
- return vv;
2363
- }
2364
- }
2365
- }
2366
-
2367
- /*
2368
- * Update the expiry time of an item
2369
- *
2370
- * The +touch+ method allow you to update the expiration time on a given
2371
- * key. This can be useful for situations where you want to prevent an item
2372
- * from expiring without resetting the associated value. For example, for a
2373
- * session database you might want to keep the session alive in the database
2374
- * each time the user accesses a web page without explicitly updating the
2375
- * session value, keeping the user's session active and available.
2376
- *
2377
- * @overload touch(key, options = {})
2378
- * @param key [String, Symbol] Key used to reference the value.
2379
- * @param options [Hash] Options for operation.
2380
- * @option options [Fixnum] :ttl (self.default_ttl) Expiry time for key.
2381
- * Values larger than 30*24*60*60 seconds (30 days) are interpreted as
2382
- * absolute times (from the epoch).
2383
- *
2384
- * @yieldparam ret [Result] the result of operation in asynchronous mode
2385
- * (valid attributes: +error+, +operation+, +key+).
2386
- *
2387
- * @return [Boolean] +true+ if the operation was successful and +false+
2388
- * otherwise.
2389
- *
2390
- * @raise [Couchbase::Error::Connect] if connection closed (see {Bucket#reconnect})
2391
- *
2392
- * @raise [ArgumentError] when passing the block in synchronous mode
2393
- *
2394
- * @example Touch value using +default_ttl+
2395
- * c.touch("foo")
2396
- *
2397
- * @example Touch value using custom TTL (10 seconds)
2398
- * c.touch("foo", :ttl => 10)
2399
- *
2400
- * @overload touch(keys)
2401
- * @param keys [Hash] The Hash where keys represent the keys in the
2402
- * database, values -- the expiry times for corresponding key. See
2403
- * description of +:ttl+ argument above for more information about TTL
2404
- * values.
2405
- *
2406
- * @yieldparam ret [Result] the result of operation for each key in
2407
- * asynchronous mode (valid attributes: +error+, +operation+, +key+).
2408
- *
2409
- * @return [Hash] Mapping keys to result of touch operation (+true+ if the
2410
- * operation was successful and +false+ otherwise)
2411
- *
2412
- * @example Touch several values
2413
- * c.touch("foo" => 10, :bar => 20) #=> {"foo" => true, "bar" => true}
2414
- *
2415
- * @example Touch several values in async mode
2416
- * c.run do
2417
- * c.touch("foo" => 10, :bar => 20) do |ret|
2418
- * ret.operation #=> :touch
2419
- * ret.success? #=> true
2420
- * ret.key #=> "foo" and "bar" in separate calls
2421
- * end
2422
- * end
2423
- *
2424
- * @example Touch single value
2425
- * c.touch("foo" => 10) #=> true
2426
- *
2427
- */
2428
- static VALUE
2429
- cb_bucket_touch(int argc, VALUE *argv, VALUE self)
2430
- {
2431
- bucket_t *bucket = DATA_PTR(self);
2432
- context_t *ctx;
2433
- VALUE args, rv, proc, exc;
2434
- size_t nn;
2435
- libcouchbase_error_t err;
2436
- struct key_traits *traits;
2437
- long seqno;
2438
-
2439
- if (bucket->handle == NULL) {
2440
- rb_raise(eConnectError, "closed connection");
2441
- }
2442
- rb_scan_args(argc, argv, "0*&", &args, &proc);
2443
- if (!bucket->async && proc != Qnil) {
2444
- rb_raise(rb_eArgError, "synchronous mode doesn't support callbacks");
2445
- }
2446
- rb_funcall(args, id_flatten_bang, 0);
2447
- traits = xcalloc(1, sizeof(struct key_traits));
2448
- nn = cb_args_scan_keys(RARRAY_LEN(args), args, bucket, traits);
2449
- ctx = xcalloc(1, sizeof(context_t));
2450
- if (ctx == NULL) {
2451
- rb_raise(eNoMemoryError, "failed to allocate memory for context");
2452
- }
2453
- ctx->proc = proc;
2454
- cb_gc_protect(bucket, ctx->proc);
2455
- ctx->bucket = bucket;
2456
- rv = rb_hash_new();
2457
- ctx->rv = &rv;
2458
- ctx->exception = Qnil;
2459
- seqno = bucket->seqno;
2460
- bucket->seqno += nn;
2461
- err = libcouchbase_mtouch(bucket->handle, (const void *)ctx,
2462
- traits->nkeys, (const void * const *)traits->keys,
2463
- traits->lens, traits->ttls);
2464
- xfree(traits->keys);
2465
- xfree(traits->lens);
2466
- xfree(traits);
2467
- exc = cb_check_error(err, "failed to schedule touch request", Qnil);
2468
- if (exc != Qnil) {
2469
- xfree(ctx);
2470
- rb_exc_raise(exc);
2471
- }
2472
- if (bucket->async) {
2473
- return Qnil;
2474
- } else {
2475
- if (bucket->seqno - seqno > 0) {
2476
- /* we have some operations pending */
2477
- bucket->io->run_event_loop(bucket->io);
2478
- }
2479
- exc = ctx->exception;
2480
- xfree(ctx);
2481
- if (exc != Qnil) {
2482
- cb_gc_unprotect(bucket, exc);
2483
- rb_exc_raise(exc);
2484
- }
2485
- if (bucket->exception != Qnil) {
2486
- rb_exc_raise(bucket->exception);
2487
- }
2488
- if (nn > 1) {
2489
- return rv; /* return as a hash {key => true, ...} */
2490
- } else {
2491
- VALUE vv = Qnil;
2492
- rb_hash_foreach(rv, cb_first_value_i, (VALUE)&vv);
2493
- return vv;
2494
- }
2495
- }
2496
- }
2497
-
2498
- /*
2499
- * Deletes all values from a server
2500
- *
2501
- * @overload flush
2502
- * @yieldparam [Result] ret the object with +error+, +node+ and +operation+
2503
- * attributes.
2504
- *
2505
- * @return [Boolean] +true+ on success
2506
- *
2507
- * @raise [Couchbase::Error::Connect] if connection closed (see {Bucket#reconnect})
2508
- * @raise [ArgumentError] when passing the block in synchronous mode
2509
- *
2510
- * @example Simple flush the bucket
2511
- * c.flush #=> true
2512
- *
2513
- * @example Asynchronous flush
2514
- * c.run do
2515
- * c.flush do |ret|
2516
- * ret.operation #=> :flush
2517
- * ret.success? #=> true
2518
- * ret.node #=> "localhost:11211"
2519
- * end
2520
- * end
2521
- */
2522
- static VALUE
2523
- cb_bucket_flush(VALUE self)
2524
- {
2525
- bucket_t *bucket = DATA_PTR(self);
2526
- context_t *ctx;
2527
- VALUE rv, exc;
2528
- libcouchbase_error_t err;
2529
- long seqno;
2530
-
2531
- if (bucket->handle == NULL) {
2532
- rb_raise(eConnectError, "closed connection");
2533
- }
2534
- if (!bucket->async && rb_block_given_p()) {
2535
- rb_raise(rb_eArgError, "synchronous mode doesn't support callbacks");
2536
- }
2537
- ctx = xcalloc(1, sizeof(context_t));
2538
- if (ctx == NULL) {
2539
- rb_raise(eNoMemoryError, "failed to allocate memory for context");
2540
- }
2541
- rv = Qtrue; /* optimistic by default */
2542
- ctx->rv = &rv;
2543
- ctx->bucket = bucket;
2544
- ctx->exception = Qnil;
2545
- if (rb_block_given_p()) {
2546
- ctx->proc = rb_block_proc();
2547
- } else {
2548
- ctx->proc = Qnil;
2549
- }
2550
- cb_gc_protect(bucket, ctx->proc);
2551
- seqno = bucket->seqno;
2552
- bucket->seqno++;
2553
- err = libcouchbase_flush(bucket->handle, (const void *)ctx);
2554
- exc = cb_check_error(err, "failed to schedule flush request", Qnil);
2555
- if (exc != Qnil) {
2556
- xfree(ctx);
2557
- rb_exc_raise(exc);
2558
- }
2559
- if (bucket->async) {
2560
- return Qnil;
2561
- } else {
2562
- if (bucket->seqno - seqno > 0) {
2563
- /* we have some operations pending */
2564
- bucket->io->run_event_loop(bucket->io);
2565
- }
2566
- exc = ctx->exception;
2567
- xfree(ctx);
2568
- if (exc != Qnil) {
2569
- cb_gc_unprotect(bucket, exc);
2570
- rb_exc_raise(exc);
2571
- }
2572
- return rv;
2573
- }
2574
- }
2575
-
2576
- /*
2577
- * Returns versions of the server for each node in the cluster
2578
- *
2579
- * @overload version
2580
- * @yieldparam [Result] ret the object with +error+, +node+, +operation+
2581
- * and +value+ attributes.
2582
- *
2583
- * @return [Hash] node-version pairs
2584
- *
2585
- * @raise [Couchbase::Error::Connect] if connection closed (see {Bucket#reconnect})
2586
- * @raise [ArgumentError] when passing the block in synchronous mode
2587
- *
2588
- * @example Synchronous version request
2589
- * c.version #=> will render version
2590
- *
2591
- * @example Asynchronous version request
2592
- * c.run do
2593
- * c.version do |ret|
2594
- * ret.operation #=> :version
2595
- * ret.success? #=> true
2596
- * ret.node #=> "localhost:11211"
2597
- * ret.value #=> will render version
2598
- * end
2599
- * end
2600
- */
2601
- static VALUE
2602
- cb_bucket_version(VALUE self)
2603
- {
2604
- bucket_t *bucket = DATA_PTR(self);
2605
- context_t *ctx;
2606
- VALUE rv, exc;
2607
- libcouchbase_error_t err;
2608
- long seqno;
2609
-
2610
- if (bucket->handle == NULL) {
2611
- rb_raise(eConnectError, "closed connection");
2612
- }
2613
- if (!bucket->async && rb_block_given_p()) {
2614
- rb_raise(rb_eArgError, "synchronous mode doesn't support callbacks");
2615
- }
2616
- ctx = xcalloc(1, sizeof(context_t));
2617
- if (ctx == NULL) {
2618
- rb_raise(eNoMemoryError, "failed to allocate memory for context");
2619
- }
2620
- rv = rb_hash_new();
2621
- ctx->rv = &rv;
2622
- ctx->bucket = bucket;
2623
- ctx->exception = Qnil;
2624
- if (rb_block_given_p()) {
2625
- ctx->proc = rb_block_proc();
2626
- } else {
2627
- ctx->proc = Qnil;
2628
- }
2629
- cb_gc_protect(bucket, ctx->proc);
2630
- seqno = bucket->seqno;
2631
- bucket->seqno++;
2632
- err = libcouchbase_server_versions(bucket->handle, (const void *)ctx);
2633
- exc = cb_check_error(err, "failed to schedule version request", Qnil);
2634
- if (exc != Qnil) {
2635
- xfree(ctx);
2636
- rb_exc_raise(exc);
2637
- }
2638
- if (bucket->async) {
2639
- return Qnil;
2640
- } else {
2641
- if (bucket->seqno - seqno > 0) {
2642
- /* we have some operations pending */
2643
- bucket->io->run_event_loop(bucket->io);
2644
- }
2645
- exc = ctx->exception;
2646
- xfree(ctx);
2647
- if (exc != Qnil) {
2648
- cb_gc_unprotect(bucket, exc);
2649
- rb_exc_raise(exc);
2650
- }
2651
- return rv;
2652
- }
2653
- }
2654
-
2655
- /*
2656
- * Request server statistics.
2657
- *
2658
- * Fetches stats from each node in cluster. Without a key specified the
2659
- * server will respond with a "default" set of statistical information. In
2660
- * asynchronous mode each statistic is returned in separate call where the
2661
- * Result object yielded (+#key+ contains the name of the statistical item
2662
- * and the +#value+ contains the value, the +#node+ will indicate the server
2663
- * address). In synchronous mode it returns the hash of stats keys and
2664
- * node-value pairs as a value.
2665
- *
2666
- * @overload stats(arg = nil)
2667
- * @param [String] arg argument to STATS query
2668
- * @yieldparam [Result] ret the object with +node+, +key+ and +value+
2669
- * attributes.
2670
- *
2671
- * @example Found how many items in the bucket
2672
- * total = 0
2673
- * c.stats["total_items"].each do |key, value|
2674
- * total += value.to_i
2675
- * end
2676
- *
2677
- * @example Found total items number asynchronously
2678
- * total = 0
2679
- * c.run do
2680
- * c.stats do |ret|
2681
- * if ret.key == "total_items"
2682
- * total += ret.value.to_i
2683
- * end
2684
- * end
2685
- * end
2686
- *
2687
- * @example Get memory stats (works on couchbase buckets)
2688
- * c.stats(:memory) #=> {"mem_used"=>{...}, ...}
2689
- *
2690
- * @return [Hash] where keys are stat keys, values are host-value pairs
2691
- *
2692
- * @raise [Couchbase::Error::Connect] if connection closed (see {Bucket#reconnect})
2693
- * @raise [ArgumentError] when passing the block in synchronous mode
2694
- */
2695
- static VALUE
2696
- cb_bucket_stats(int argc, VALUE *argv, VALUE self)
2697
- {
2698
- bucket_t *bucket = DATA_PTR(self);
2699
- context_t *ctx;
2700
- VALUE rv, exc, arg, proc;
2701
- char *key;
2702
- size_t nkey;
2703
- libcouchbase_error_t err;
2704
- long seqno;
2705
-
2706
- if (bucket->handle == NULL) {
2707
- rb_raise(eConnectError, "closed connection");
2708
- }
2709
- rb_scan_args(argc, argv, "01&", &arg, &proc);
2710
- if (!bucket->async && proc != Qnil) {
2711
- rb_raise(rb_eArgError, "synchronous mode doesn't support callbacks");
2712
- }
2713
-
2714
- ctx = xcalloc(1, sizeof(context_t));
2715
- if (ctx == NULL) {
2716
- rb_raise(eNoMemoryError, "failed to allocate memory for context");
2717
- }
2718
- rv = rb_hash_new();
2719
- ctx->rv = &rv;
2720
- ctx->bucket = bucket;
2721
- ctx->proc = proc;
2722
- cb_gc_protect(bucket, ctx->proc);
2723
- ctx->exception = Qnil;
2724
- if (arg != Qnil) {
2725
- arg = unify_key(arg);
2726
- key = RSTRING_PTR(arg);
2727
- nkey = RSTRING_LEN(arg);
2728
- } else {
2729
- key = NULL;
2730
- nkey = 0;
2731
- }
2732
- seqno = bucket->seqno;
2733
- bucket->seqno++;
2734
- err = libcouchbase_server_stats(bucket->handle, (const void *)ctx,
2735
- key, nkey);
2736
- exc = cb_check_error(err, "failed to schedule stat request", Qnil);
2737
- if (exc != Qnil) {
2738
- xfree(ctx);
2739
- rb_exc_raise(exc);
2740
- }
2741
- if (bucket->async) {
2742
- return Qnil;
2743
- } else {
2744
- if (bucket->seqno - seqno > 0) {
2745
- /* we have some operations pending */
2746
- bucket->io->run_event_loop(bucket->io);
2747
- }
2748
- exc = ctx->exception;
2749
- xfree(ctx);
2750
- if (exc != Qnil) {
2751
- cb_gc_unprotect(bucket, exc);
2752
- rb_exc_raise(exc);
2753
- }
2754
- if (bucket->exception != Qnil) {
2755
- rb_exc_raise(bucket->exception);
2756
- }
2757
- return rv;
2758
- }
2759
-
2760
- return Qnil;
2761
- }
2762
-
2763
- static VALUE
2764
- do_run(VALUE *args)
2765
- {
2766
- VALUE self = args[0], proc = args[1], exc;
2767
- bucket_t *bucket = DATA_PTR(self);
2768
- time_t tm;
2769
- uint32_t old_tmo, new_tmo, diff;
2770
-
2771
- if (bucket->handle == NULL) {
2772
- rb_raise(eConnectError, "closed connection");
2773
- }
2774
- if (bucket->async) {
2775
- rb_raise(eInvalidError, "nested #run");
2776
- }
2777
- bucket->seqno = 0;
2778
- bucket->async = 1;
2779
-
2780
- tm = time(NULL);
2781
- cb_proc_call(proc, 1, self);
2782
- if (bucket->seqno > 0) {
2783
- old_tmo = libcouchbase_get_timeout(bucket->handle);
2784
- diff = (uint32_t)(time(NULL) - tm + 1);
2785
- diff *= 1000000;
2786
- new_tmo = bucket->timeout += diff;
2787
- libcouchbase_set_timeout(bucket->handle, bucket->timeout);
2788
- bucket->io->run_event_loop(bucket->io);
2789
- /* restore timeout if it wasn't changed */
2790
- if (bucket->timeout == new_tmo) {
2791
- libcouchbase_set_timeout(bucket->handle, old_tmo);
2792
- }
2793
- if (bucket->exception != Qnil) {
2794
- exc = bucket->exception;
2795
- bucket->exception = Qnil;
2796
- rb_exc_raise(exc);
2797
- }
2798
- }
2799
- return Qnil;
2800
- }
2801
-
2802
- static VALUE
2803
- ensure_run(VALUE *args)
2804
- {
2805
- VALUE self = args[0];
2806
- bucket_t *bucket = DATA_PTR(self);
2807
-
2808
- bucket->async = 0;
2809
- return Qnil;
2810
- }
2811
-
2812
- /*
2813
- * Run the event loop.
2814
- *
2815
- * @yieldparam [Bucket] bucket the bucket instance
2816
- *
2817
- * @example Use block to run the loop
2818
- * c = Couchbase.new
2819
- * c.run do
2820
- * c.get("foo") {|ret| puts ret.value}
2821
- * end
2822
- *
2823
- * @example Use lambda to run the loop
2824
- * c = Couchbase.new
2825
- * operations = lambda do |c|
2826
- * c.get("foo") {|ret| puts ret.value}
2827
- * end
2828
- * c.run(&operations)
2829
- *
2830
- * @return [nil]
2831
- *
2832
- * @raise [Couchbase::Error::Connect] if connection closed (see {Bucket#reconnect})
2833
- */
2834
- static VALUE
2835
- cb_bucket_run(VALUE self)
2836
- {
2837
- VALUE args[2];
2838
-
2839
- rb_need_block();
2840
- args[0] = self;
2841
- args[1] = rb_block_proc();
2842
- rb_ensure(do_run, (VALUE)args, ensure_run, (VALUE)args);
2843
- return Qnil;
2844
- }
2845
-
2846
- /*
2847
- * Unconditionally store the object in the Couchbase
2848
- *
2849
- * @overload set(key, value, options = {})
2850
- *
2851
- * @param key [String, Symbol] Key used to reference the value.
2852
- * @param value [Object] Value to be stored
2853
- * @param options [Hash] Options for operation.
2854
- * @option options [Fixnum] :ttl (self.default_ttl) Expiry time for key.
2855
- * Values larger than 30*24*60*60 seconds (30 days) are interpreted as
2856
- * absolute times (from the epoch).
2857
- * @option options [Fixnum] :flags (self.default_flags) Flags for storage
2858
- * options. Flags are ignored by the server but preserved for use by the
2859
- * client. For more info see {Bucket#default_flags}.
2860
- * @option options [Symbol] :format (self.default_format) The
2861
- * representation for storing the value in the bucket. For more info see
2862
- * {Bucket#default_format}.
2863
- * @option options [Fixnum] :cas The CAS value for an object. This value
2864
- * created on the server and is guaranteed to be unique for each value of
2865
- * a given key. This value is used to provide simple optimistic
2866
- * concurrency control when multiple clients or threads try to update an
2867
- * item simultaneously.
2868
- *
2869
- * @yieldparam ret [Result] the result of operation in asynchronous mode
2870
- * (valid attributes: +error+, +operation+, +key+).
2871
- *
2872
- * @return [Fixnum] The CAS value of the object.
2873
- *
2874
- * @raise [Couchbase::Error::Connect] if connection closed (see {Bucket#reconnect}).
2875
- * @raise [Couchbase::Error::KeyExists] if the key already exists on the
2876
- * server.
2877
- * @raise [Couchbase::Error::ValueFormat] if the value cannot be serialized
2878
- * with chosen encoder, e.g. if you try to store the Hash in +:plain+
2879
- * mode.
2880
- * @raise [ArgumentError] when passing the block in synchronous mode
2881
- *
2882
- * @example Store the key which will be expired in 2 seconds using relative TTL.
2883
- * c.set("foo", "bar", :ttl => 2)
2884
- *
2885
- * @example Store the key which will be expired in 2 seconds using absolute TTL.
2886
- * c.set("foo", "bar", :ttl => Time.now.to_i + 2)
2887
- *
2888
- * @example Force JSON document format for value
2889
- * c.set("foo", {"bar" => "baz}, :format => :document)
2890
- *
2891
- * @example Use hash-like syntax to store the value
2892
- * c.set["foo"] = {"bar" => "baz}
2893
- *
2894
- * @example Use extended hash-like syntax
2895
- * c["foo", {:flags => 0x1000, :format => :plain}] = "bar"
2896
- * c["foo", :flags => 0x1000] = "bar" # for ruby 1.9.x only
2897
- *
2898
- * @example Set application specific flags (note that it will be OR-ed with format flags)
2899
- * c.set("foo", "bar", :flags => 0x1000)
2900
- *
2901
- * @example Perform optimistic locking by specifying last known CAS version
2902
- * c.set("foo", "bar", :cas => 8835713818674332672)
2903
- *
2904
- * @example Perform asynchronous call
2905
- * c.run do
2906
- * c.set("foo", "bar") do |ret|
2907
- * ret.operation #=> :set
2908
- * ret.success? #=> true
2909
- * ret.key #=> "foo"
2910
- * ret.cas
2911
- * end
2912
- * end
2913
- */
2914
- static VALUE
2915
- cb_bucket_set(int argc, VALUE *argv, VALUE self)
2916
- {
2917
- return cb_bucket_store(LIBCOUCHBASE_SET, argc, argv, self);
2918
- }
2919
-
2920
- /*
2921
- * Add the item to the database, but fail if the object exists already
2922
- *
2923
- * @overload add(key, value, options = {})
2924
- * @param key [String, Symbol] Key used to reference the value.
2925
- * @param value [Object] Value to be stored
2926
- * @param options [Hash] Options for operation.
2927
- * @option options [Fixnum] :ttl (self.default_ttl) Expiry time for key.
2928
- * Values larger than 30*24*60*60 seconds (30 days) are interpreted as
2929
- * absolute times (from the epoch).
2930
- * @option options [Fixnum] :flags (self.default_flags) Flags for storage
2931
- * options. Flags are ignored by the server but preserved for use by the
2932
- * client. For more info see {Bucket#default_flags}.
2933
- * @option options [Symbol] :format (self.default_format) The
2934
- * representation for storing the value in the bucket. For more info see
2935
- * {Bucket#default_format}.
2936
- * @option options [Fixnum] :cas The CAS value for an object. This value
2937
- * created on the server and is guaranteed to be unique for each value of
2938
- * a given key. This value is used to provide simple optimistic
2939
- * concurrency control when multiple clients or threads try to update an
2940
- * item simultaneously.
2941
- *
2942
- * @yieldparam ret [Result] the result of operation in asynchronous mode
2943
- * (valid attributes: +error+, +operation+, +key+).
2944
- *
2945
- * @return [Fixnum] The CAS value of the object.
2946
- *
2947
- * @raise [Couchbase::Error::Connect] if connection closed (see {Bucket#reconnect})
2948
- * @raise [Couchbase::Error::KeyExists] if the key already exists on the
2949
- * server
2950
- * @raise [Couchbase::Error::ValueFormat] if the value cannot be serialized
2951
- * with chosen encoder, e.g. if you try to store the Hash in +:plain+
2952
- * mode.
2953
- * @raise [ArgumentError] when passing the block in synchronous mode
2954
- *
2955
- * @example Add the same key twice
2956
- * c.add("foo", "bar") #=> stored successully
2957
- * c.add("foo", "baz") #=> will raise Couchbase::Error::KeyExists: failed to store value (key="foo", error=0x0c)
2958
- */
2959
- static VALUE
2960
- cb_bucket_add(int argc, VALUE *argv, VALUE self)
2961
- {
2962
- return cb_bucket_store(LIBCOUCHBASE_ADD, argc, argv, self);
2963
- }
2964
-
2965
- /*
2966
- * Replace the existing object in the database
2967
- *
2968
- * @overload replace(key, value, options = {})
2969
- * @param key [String, Symbol] Key used to reference the value.
2970
- * @param value [Object] Value to be stored
2971
- * @param options [Hash] Options for operation.
2972
- * @option options [Fixnum] :ttl (self.default_ttl) Expiry time for key.
2973
- * Values larger than 30*24*60*60 seconds (30 days) are interpreted as
2974
- * absolute times (from the epoch).
2975
- * @option options [Fixnum] :flags (self.default_flags) Flags for storage
2976
- * options. Flags are ignored by the server but preserved for use by the
2977
- * client. For more info see {Bucket#default_flags}.
2978
- * @option options [Symbol] :format (self.default_format) The
2979
- * representation for storing the value in the bucket. For more info see
2980
- * {Bucket#default_format}.
2981
- *
2982
- * @return [Fixnum] The CAS value of the object.
2983
- *
2984
- * @raise [Couchbase::Error::Connect] if connection closed (see {Bucket#reconnect})
2985
- * @raise [Couchbase::Error::NotFound] if the key doesn't exists
2986
- * @raise [Couchbase::Error::KeyExists] on CAS mismatch
2987
- * @raise [ArgumentError] when passing the block in synchronous mode
2988
- *
2989
- * @example Replacing missing key
2990
- * c.replace("foo", "baz") #=> will raise Couchbase::Error::NotFound: failed to store value (key="foo", error=0x0d)
2991
- */
2992
- static VALUE
2993
- cb_bucket_replace(int argc, VALUE *argv, VALUE self)
2994
- {
2995
- return cb_bucket_store(LIBCOUCHBASE_REPLACE, argc, argv, self);
2996
- }
2997
-
2998
- /*
2999
- * Append this object to the existing object
3000
- *
3001
- * @note This operation is kind of data-aware from server point of view.
3002
- * This mean that the server treats value as binary stream and just
3003
- * perform concatenation, therefore it won't work with +:marshal+ and
3004
- * +:document+ formats, because of lack of knowledge how to merge values
3005
- * in these formats. See Bucket#cas for workaround.
3006
- *
3007
- * @overload append(key, value, options = {})
3008
- * @param key [String, Symbol] Key used to reference the value.
3009
- * @param value [Object] Value to be stored
3010
- * @param options [Hash] Options for operation.
3011
- * @option options [Fixnum] :cas The CAS value for an object. This value
3012
- * created on the server and is guaranteed to be unique for each value of
3013
- * a given key. This value is used to provide simple optimistic
3014
- * concurrency control when multiple clients or threads try to update an
3015
- * item simultaneously.
3016
- * @option options [Symbol] :format (self.default_format) The
3017
- * representation for storing the value in the bucket. For more info see
3018
- * {Bucket#default_format}.
3019
- *
3020
- * @return [Fixnum] The CAS value of the object.
3021
- *
3022
- * @raise [Couchbase::Error::Connect] if connection closed (see {Bucket#reconnect})
3023
- * @raise [Couchbase::Error::KeyExists] on CAS mismatch
3024
- * @raise [Couchbase::Error::NotStored] if the key doesn't exist
3025
- * @raise [ArgumentError] when passing the block in synchronous mode
3026
- *
3027
- * @example Simple append
3028
- * c.set("foo", "aaa")
3029
- * c.append("foo", "bbb")
3030
- * c.get("foo") #=> "aaabbb"
3031
- *
3032
- * @example Implementing sets using append
3033
- * def set_add(key, *values)
3034
- * encoded = values.flatten.map{|v| "+#{v} "}.join
3035
- * append(key, encoded)
3036
- * end
3037
- *
3038
- * def set_remove(key, *values)
3039
- * encoded = values.flatten.map{|v| "-#{v} "}.join
3040
- * append(key, encoded)
3041
- * end
3042
- *
3043
- * def set_get(key)
3044
- * encoded = get(key)
3045
- * ret = Set.new
3046
- * encoded.split(' ').each do |v|
3047
- * op, val = v[0], v[1..-1]
3048
- * case op
3049
- * when "-"
3050
- * ret.delete(val)
3051
- * when "+"
3052
- * ret.add(val)
3053
- * end
3054
- * end
3055
- * ret
3056
- * end
3057
- *
3058
- * @example Using optimistic locking. The operation will fail on CAS mismatch
3059
- * ver = c.set("foo", "aaa")
3060
- * c.append("foo", "bbb", :cas => ver)
3061
- */
3062
- static VALUE
3063
- cb_bucket_append(int argc, VALUE *argv, VALUE self)
3064
- {
3065
- return cb_bucket_store(LIBCOUCHBASE_APPEND, argc, argv, self);
3066
- }
3067
-
3068
- /*
3069
- * Prepend this object to the existing object
3070
- *
3071
- * @note This operation is kind of data-aware from server point of view.
3072
- * This mean that the server treats value as binary stream and just
3073
- * perform concatenation, therefore it won't work with +:marshal+ and
3074
- * +:document+ formats, because of lack of knowledge how to merge values
3075
- * in these formats. See Bucket#cas for workaround.
3076
- *
3077
- * @overload prepend(key, value, options = {})
3078
- * @param key [String, Symbol] Key used to reference the value.
3079
- * @param value [Object] Value to be stored
3080
- * @param options [Hash] Options for operation.
3081
- * @option options [Fixnum] :cas The CAS value for an object. This value
3082
- * created on the server and is guaranteed to be unique for each value of
3083
- * a given key. This value is used to provide simple optimistic
3084
- * concurrency control when multiple clients or threads try to update an
3085
- * item simultaneously.
3086
- * @option options [Symbol] :format (self.default_format) The
3087
- * representation for storing the value in the bucket. For more info see
3088
- * {Bucket#default_format}.
3089
- *
3090
- * @raise [Couchbase::Error::Connect] if connection closed (see {Bucket#reconnect})
3091
- * @raise [Couchbase::Error::KeyExists] on CAS mismatch
3092
- * @raise [Couchbase::Error::NotStored] if the key doesn't exist
3093
- * @raise [ArgumentError] when passing the block in synchronous mode
3094
- *
3095
- * @example Simple prepend example
3096
- * c.set("foo", "aaa")
3097
- * c.prepend("foo", "bbb")
3098
- * c.get("foo") #=> "bbbaaa"
3099
- *
3100
- * @example Using explicit format option
3101
- * c.default_format #=> :document
3102
- * c.set("foo", {"y" => "z"})
3103
- * c.prepend("foo", '[', :format => :plain)
3104
- * c.append("foo", ', {"z": "y"}]', :format => :plain)
3105
- * c.get("foo") #=> [{"y"=>"z"}, {"z"=>"y"}]
3106
- *
3107
- * @example Using optimistic locking. The operation will fail on CAS mismatch
3108
- * ver = c.set("foo", "aaa")
3109
- * c.prepend("foo", "bbb", :cas => ver)
3110
- */
3111
- static VALUE
3112
- cb_bucket_prepend(int argc, VALUE *argv, VALUE self)
3113
- {
3114
- return cb_bucket_store(LIBCOUCHBASE_PREPEND, argc, argv, self);
3115
- }
3116
-
3117
- static VALUE
3118
- cb_bucket_aset(int argc, VALUE *argv, VALUE self)
3119
- {
3120
- VALUE temp;
3121
-
3122
- if (argc == 3) {
3123
- /* swap opts and value, because value goes last for []= */
3124
- temp = argv[2];
3125
- argv[2] = argv[1];
3126
- argv[1] = temp;
3127
- }
3128
- return cb_bucket_set(argc, argv, self);
3129
- }
3130
-
3131
- /*
3132
- * Close the connection to the cluster
3133
- *
3134
- * @return [true]
3135
- *
3136
- * @raise [Couchbase::Error::Connect] if connection closed (see {Bucket#reconnect})
3137
- */
3138
- static VALUE
3139
- cb_bucket_disconnect(VALUE self)
3140
- {
3141
- bucket_t *bucket = DATA_PTR(self);
3142
-
3143
- if (bucket->handle) {
3144
- libcouchbase_destroy(bucket->handle);
3145
- bucket->handle = NULL;
3146
- bucket->io = NULL;
3147
- return Qtrue;
3148
- } else {
3149
- rb_raise(eConnectError, "closed connection");
3150
- }
3151
- }
3152
-
3153
- /*
3154
- * Check if result of operation was successful.
3155
- *
3156
- * @return [Boolean] +false+ if there is an +error+ object attached,
3157
- * +false+ otherwise.
3158
- */
3159
- static VALUE
3160
- cb_result_success_p(VALUE self)
3161
- {
3162
- return RTEST(rb_ivar_get(self, id_iv_error)) ? Qfalse : Qtrue;
3163
- }
3164
-
3165
- /*
3166
- * Returns a string containing a human-readable representation of the Result.
3167
- *
3168
- * @return [String]
3169
- */
3170
- static VALUE
3171
- cb_result_inspect(VALUE self)
3172
- {
3173
- VALUE str, attr, error;
3174
- char buf[100];
3175
-
3176
- str = rb_str_buf_new2("#<");
3177
- rb_str_buf_cat2(str, rb_obj_classname(self));
3178
- snprintf(buf, 100, ":%p", (void *)self);
3179
- rb_str_buf_cat2(str, buf);
3180
-
3181
- attr = rb_ivar_get(self, id_iv_error);
3182
- if (RTEST(attr)) {
3183
- error = rb_ivar_get(attr, id_iv_error);
3184
- } else {
3185
- error = INT2FIX(0);
3186
- }
3187
- rb_str_buf_cat2(str, " error=0x");
3188
- rb_str_append(str, rb_funcall(error, id_to_s, 1, INT2FIX(16)));
3189
-
3190
- attr = rb_ivar_get(self, id_iv_key);
3191
- if (RTEST(attr)) {
3192
- rb_str_buf_cat2(str, " key=");
3193
- rb_str_append(str, rb_inspect(attr));
3194
- }
3195
-
3196
- attr = rb_ivar_get(self, id_iv_cas);
3197
- if (RTEST(attr)) {
3198
- rb_str_buf_cat2(str, " cas=");
3199
- rb_str_append(str, rb_inspect(attr));
3200
- }
3201
-
3202
- attr = rb_ivar_get(self, id_iv_flags);
3203
- if (RTEST(attr)) {
3204
- rb_str_buf_cat2(str, " flags=0x");
3205
- rb_str_append(str, rb_funcall(attr, id_to_s, 1, INT2FIX(16)));
3206
- }
3207
-
3208
- attr = rb_ivar_get(self, id_iv_node);
3209
- if (RTEST(attr)) {
3210
- rb_str_buf_cat2(str, " node=");
3211
- rb_str_append(str, rb_inspect(attr));
3212
- }
3213
- rb_str_buf_cat2(str, ">");
3214
-
3215
- return str;
3216
- }
3217
160
 
3218
161
  /* Ruby Extension initializer */
3219
162
  void
3220
163
  Init_couchbase_ext(void)
3221
164
  {
3222
- mJSON = rb_const_get(rb_cObject, rb_intern("JSON"));
165
+ mMultiJson = rb_const_get(rb_cObject, rb_intern("MultiJson"));
3223
166
  mURI = rb_const_get(rb_cObject, rb_intern("URI"));
3224
167
  mMarshal = rb_const_get(rb_cObject, rb_intern("Marshal"));
3225
168
  mCouchbase = rb_define_module("Couchbase");
3226
169
 
3227
170
  mError = rb_define_module_under(mCouchbase, "Error");
3228
171
  /* Document-class: Couchbase::Error::Base
3229
- * The base error class */
3230
- eBaseError = rb_define_class_under(mError, "Base", rb_eRuntimeError);
172
+ * The base error class
173
+ *
174
+ * @since 1.0.0
175
+ */
176
+ eBaseError = rb_define_class_under(mError, "Base", rb_eStandardError);
3231
177
  /* Document-class: Couchbase::Error::Auth
3232
- * Authentication error */
178
+ * Authentication error
179
+ *
180
+ * @since 1.0.0
181
+ */
3233
182
  eAuthError = rb_define_class_under(mError, "Auth", eBaseError);
3234
183
  /* Document-class: Couchbase::Error::BucketNotFound
3235
- * The given bucket not found in the cluster */
184
+ * The given bucket not found in the cluster
185
+ *
186
+ * @since 1.0.0
187
+ */
3236
188
  eBucketNotFoundError = rb_define_class_under(mError, "BucketNotFound", eBaseError);
3237
189
  /* Document-class: Couchbase::Error::Busy
3238
- * The cluster is too busy now. Try again later */
190
+ * The cluster is too busy now. Try again later
191
+ *
192
+ * @since 1.0.0
193
+ */
3239
194
  eBusyError = rb_define_class_under(mError, "Busy", eBaseError);
3240
195
  /* Document-class: Couchbase::Error::DeltaBadval
3241
- * The given value is not a number */
196
+ * The given value is not a number
197
+ *
198
+ * @since 1.0.0
199
+ */
3242
200
  eDeltaBadvalError = rb_define_class_under(mError, "DeltaBadval", eBaseError);
3243
201
  /* Document-class: Couchbase::Error::Internal
3244
- * Internal error */
202
+ * Internal error
203
+ *
204
+ * @since 1.0.0
205
+ */
3245
206
  eInternalError = rb_define_class_under(mError, "Internal", eBaseError);
3246
207
  /* Document-class: Couchbase::Error::Invalid
3247
- * Invalid arguments */
208
+ * Invalid arguments
209
+ *
210
+ * @since 1.0.0
211
+ */
3248
212
  eInvalidError = rb_define_class_under(mError, "Invalid", eBaseError);
3249
213
  /* Document-class: Couchbase::Error::KeyExists
3250
- * Key already exists */
214
+ * Key already exists
215
+ *
216
+ * @since 1.0.0
217
+ */
3251
218
  eKeyExistsError = rb_define_class_under(mError, "KeyExists", eBaseError);
3252
219
  /* Document-class: Couchbase::Error::Libcouchbase
3253
- * Generic error */
220
+ * Generic error
221
+ *
222
+ * @since 1.0.0
223
+ */
3254
224
  eLibcouchbaseError = rb_define_class_under(mError, "Libcouchbase", eBaseError);
3255
225
  /* Document-class: Couchbase::Error::Libevent
3256
- * Problem using libevent */
226
+ * Problem using libevent
227
+ *
228
+ * @since 1.0.0
229
+ */
3257
230
  eLibeventError = rb_define_class_under(mError, "Libevent", eBaseError);
3258
231
  /* Document-class: Couchbase::Error::Network
3259
- * Network error */
232
+ * Network error
233
+ *
234
+ * @since 1.0.0
235
+ */
3260
236
  eNetworkError = rb_define_class_under(mError, "Network", eBaseError);
3261
237
  /* Document-class: Couchbase::Error::NoMemory
3262
- * Out of memory error */
238
+ * Out of memory error (on Server)
239
+ *
240
+ * @since 1.0.0
241
+ */
3263
242
  eNoMemoryError = rb_define_class_under(mError, "NoMemory", eBaseError);
243
+ /* Document-class: Couchbase::Error::ClientNoMemory
244
+ * Out of memory error (on Client)
245
+ *
246
+ * @since 1.2.0.dp6
247
+ */
248
+ eClientNoMemoryError = rb_define_class_under(mError, "ClientNoMemory", eBaseError);
3264
249
  /* Document-class: Couchbase::Error::NotFound
3265
- * No such key */
250
+ * No such key
251
+ *
252
+ * @since 1.0.0
253
+ */
3266
254
  eNotFoundError = rb_define_class_under(mError, "NotFound", eBaseError);
3267
255
  /* Document-class: Couchbase::Error::NotMyVbucket
3268
- * The vbucket is not located on this server */
256
+ * The vbucket is not located on this server
257
+ *
258
+ * @since 1.0.0
259
+ */
3269
260
  eNotMyVbucketError = rb_define_class_under(mError, "NotMyVbucket", eBaseError);
3270
261
  /* Document-class: Couchbase::Error::NotStored
3271
- * Not stored */
262
+ * Not stored
263
+ *
264
+ * @since 1.0.0
265
+ */
3272
266
  eNotStoredError = rb_define_class_under(mError, "NotStored", eBaseError);
3273
267
  /* Document-class: Couchbase::Error::NotSupported
3274
- * Not supported */
268
+ * Not supported
269
+ *
270
+ * @since 1.0.0
271
+ */
3275
272
  eNotSupportedError = rb_define_class_under(mError, "NotSupported", eBaseError);
3276
273
  /* Document-class: Couchbase::Error::Range
3277
- * Invalid range */
274
+ * Invalid range
275
+ *
276
+ * @since 1.0.0
277
+ */
3278
278
  eRangeError = rb_define_class_under(mError, "Range", eBaseError);
3279
279
  /* Document-class: Couchbase::Error::TemporaryFail
3280
- * Temporary failure. Try again later */
280
+ * Temporary failure. Try again later
281
+ *
282
+ * @since 1.0.0
283
+ */
3281
284
  eTmpFailError = rb_define_class_under(mError, "TemporaryFail", eBaseError);
285
+ /* Document-class: Couchbase::Error::ClientTemporaryFail
286
+ * Temporary failure (on Client)
287
+ *
288
+ * @since 1.2.0
289
+ */
290
+ eClientTmpFailError = rb_define_class_under(mError, "ClientTemporaryFail", eBaseError);
3282
291
  /* Document-class: Couchbase::Error::TooBig
3283
- * Object too big */
292
+ * Object too big
293
+ *
294
+ * @since 1.0.0
295
+ */
3284
296
  eTooBigError = rb_define_class_under(mError, "TooBig", eBaseError);
3285
297
  /* Document-class: Couchbase::Error::UnknownCommand
3286
- * Unknown command */
298
+ * Unknown command
299
+ *
300
+ * @since 1.0.0
301
+ */
3287
302
  eUnknownCommandError = rb_define_class_under(mError, "UnknownCommand", eBaseError);
3288
303
  /* Document-class: Couchbase::Error::UnknownHost
3289
- * Unknown host */
304
+ * Unknown host
305
+ *
306
+ * @since 1.0.0
307
+ */
3290
308
  eUnknownHostError = rb_define_class_under(mError, "UnknownHost", eBaseError);
3291
309
  /* Document-class: Couchbase::Error::ValueFormat
3292
- * Failed to decode or encode value */
310
+ * Failed to decode or encode value
311
+ *
312
+ * @since 1.0.0
313
+ */
3293
314
  eValueFormatError = rb_define_class_under(mError, "ValueFormat", eBaseError);
3294
315
  /* Document-class: Couchbase::Error::Protocol
3295
- * Protocol error */
316
+ * Protocol error
317
+ *
318
+ * @since 1.0.0
319
+ */
3296
320
  eProtocolError = rb_define_class_under(mError, "Protocol", eBaseError);
3297
321
  /* Document-class: Couchbase::Error::Timeout
3298
- * Timeout error */
322
+ * Timeout error
323
+ *
324
+ * @since 1.1.0
325
+ */
3299
326
  eTimeoutError = rb_define_class_under(mError, "Timeout", eBaseError);
3300
327
  /* Document-class: Couchbase::Error::Connect
3301
- * Connect error */
328
+ * Connect error
329
+ *
330
+ * @since 1.1.0
331
+ */
3302
332
  eConnectError = rb_define_class_under(mError, "Connect", eBaseError);
3303
333
 
3304
334
  /* Document-method: error
3305
- * @return [Boolean] the error code from libcouchbase */
335
+ *
336
+ * The underlying libcouchbase library could return one of the following
337
+ * error codes. The ruby client will wrap these errors into appropriate
338
+ * exception class, derived from {Couchbase::Error::Base}.
339
+ *
340
+ * 0x00 :: LCB_SUCCESS (Success)
341
+ * 0x01 :: LCB_AUTH_CONTINUE (Continue authentication)
342
+ * 0x02 :: LCB_AUTH_ERROR (Authentication error)
343
+ * 0x03 :: LCB_DELTA_BADVAL (Not a number)
344
+ * 0x04 :: LCB_E2BIG (Object too big)
345
+ * 0x05 :: LCB_EBUSY (Too busy. Try again later)
346
+ * 0x06 :: LCB_EINTERNAL (Internal error)
347
+ * 0x07 :: LCB_EINVAL (Invalid arguments)
348
+ * 0x08 :: LCB_ENOMEM (Out of memory)
349
+ * 0x09 :: LCB_ERANGE (Invalid range)
350
+ * 0x0a :: LCB_ERROR (Generic error)
351
+ * 0x0b :: LCB_ETMPFAIL (Temporary failure. Try again later)
352
+ * 0x0c :: LCB_KEY_EEXISTS (Key exists (with a different CAS value))
353
+ * 0x0d :: LCB_KEY_ENOENT (No such key)
354
+ * 0x0e :: LCB_LIBEVENT_ERROR (Problem using libevent)
355
+ * 0x0f :: LCB_NETWORK_ERROR (Network error)
356
+ * 0x10 :: LCB_NOT_MY_VBUCKET (The vbucket is not located on this server)
357
+ * 0x11 :: LCB_NOT_STORED (Not stored)
358
+ * 0x12 :: LCB_NOT_SUPPORTED (Not supported)
359
+ * 0x13 :: LCB_UNKNOWN_COMMAND (Unknown command)
360
+ * 0x14 :: LCB_UNKNOWN_HOST (Unknown host)
361
+ * 0x15 :: LCB_PROTOCOL_ERROR (Protocol error)
362
+ * 0x16 :: LCB_ETIMEDOUT (Operation timed out)
363
+ * 0x17 :: LCB_CONNECT_ERROR (Connection failure)
364
+ * 0x18 :: LCB_BUCKET_ENOENT (No such bucket)
365
+ * 0x18 :: LCB_CLIENT_ENOMEM (Out of memory on the client)
366
+ *
367
+ * @since 1.0.0
368
+ *
369
+ * @return [Fixnum] the error code from libcouchbase
370
+ */
3306
371
  rb_define_attr(eBaseError, "error", 1, 0);
3307
372
  id_iv_error = rb_intern("@error");
373
+ /* Document-method: status
374
+ *
375
+ * @since 1.2.0.beta
376
+ *
377
+ * @return [Fixnum] The HTTP status code */
378
+ rb_define_attr(eBaseError, "status", 1, 0);
379
+ id_iv_status = rb_intern("@status");
3308
380
  /* Document-method: key
381
+ *
382
+ * @since 1.0.0
383
+ *
3309
384
  * @return [String] the key which generated error */
3310
385
  rb_define_attr(eBaseError, "key", 1, 0);
3311
386
  id_iv_key = rb_intern("@key");
3312
387
  /* Document-method: cas
388
+ *
389
+ * @since 1.0.0
390
+ *
3313
391
  * @return [Fixnum] the version of the key (+nil+ unless accessible) */
3314
392
  rb_define_attr(eBaseError, "cas", 1, 0);
3315
393
  id_iv_cas = rb_intern("@cas");
3316
394
  /* Document-method: operation
395
+ *
396
+ * @since 1.0.0
397
+ *
3317
398
  * @return [Symbol] the operation (+nil+ unless accessible) */
3318
399
  rb_define_attr(eBaseError, "operation", 1, 0);
3319
400
  id_iv_operation = rb_intern("@operation");
3320
401
 
3321
402
  /* Document-class: Couchbase::Result
3322
- * The object which yielded to asynchronous callbacks */
403
+ *
404
+ * The object which yielded to asynchronous callbacks
405
+ *
406
+ * @since 1.0.0
407
+ */
3323
408
  cResult = rb_define_class_under(mCouchbase, "Result", rb_cObject);
3324
409
  rb_define_method(cResult, "inspect", cb_result_inspect, 0);
3325
410
  rb_define_method(cResult, "success?", cb_result_success_p, 0);
3326
411
  /* Document-method: operation
3327
- * @return [Symbol] */
412
+ *
413
+ * @since 1.0.0
414
+ *
415
+ * @return [Symbol]
416
+ */
3328
417
  rb_define_attr(cResult, "operation", 1, 0);
3329
418
  /* Document-method: error
3330
- * @return [Couchbase::Error::Base] */
419
+ *
420
+ * @since 1.0.0
421
+ *
422
+ * @return [Couchbase::Error::Base]
423
+ */
3331
424
  rb_define_attr(cResult, "error", 1, 0);
3332
425
  /* Document-method: key
3333
- * @return [String] */
426
+ *
427
+ * @since 1.0.0
428
+ *
429
+ * @return [String]
430
+ */
3334
431
  rb_define_attr(cResult, "key", 1, 0);
3335
432
  id_iv_key = rb_intern("@key");
3336
433
  /* Document-method: value
3337
- * @return [String] */
434
+ *
435
+ * @since 1.0.0
436
+ *
437
+ * @return [String]
438
+ */
3338
439
  rb_define_attr(cResult, "value", 1, 0);
3339
440
  id_iv_value = rb_intern("@value");
3340
441
  /* Document-method: cas
3341
- * @return [Fixnum] */
442
+ *
443
+ * @since 1.0.0
444
+ *
445
+ * @return [Fixnum]
446
+ */
3342
447
  rb_define_attr(cResult, "cas", 1, 0);
3343
448
  id_iv_cas = rb_intern("@cas");
3344
449
  /* Document-method: flags
3345
- * @return [Fixnum] */
450
+ *
451
+ * @since 1.0.0
452
+ *
453
+ * @return [Fixnum]
454
+ */
3346
455
  rb_define_attr(cResult, "flags", 1, 0);
3347
456
  id_iv_flags = rb_intern("@flags");
3348
457
  /* Document-method: node
3349
- * @return [String] */
458
+ *
459
+ * @since 1.0.0
460
+ *
461
+ * @return [String]
462
+ */
3350
463
  rb_define_attr(cResult, "node", 1, 0);
3351
464
  id_iv_node = rb_intern("@node");
465
+ /* Document-method: headers
466
+ *
467
+ * @since 1.2.0
468
+ *
469
+ * HTTP headers
470
+ *
471
+ * @return [Hash]
472
+ */
473
+ rb_define_attr(cResult, "headers", 1, 0);
474
+ id_iv_headers = rb_intern("@headers");
475
+ /* Document-method: completed
476
+ * In {Bucket::CouchRequest} operations used to mark the final call
477
+ * @return [Boolean] */
478
+ rb_define_attr(cResult, "completed", 1, 0);
479
+ rb_define_alias(cResult, "completed?", "completed");
480
+ id_iv_completed = rb_intern("@completed");
481
+ /* Document-method: status
482
+ *
483
+ * @since 1.2.0.dp6
484
+ *
485
+ * @see Bucket#observe
486
+ *
487
+ * Status of the key. Possible values:
488
+ * +:found+ :: Key found in cache, but not yet persisted
489
+ * +:persisted+ :: Key found and persisted
490
+ * +:not_found+ :: Key not found
491
+ *
492
+ * @return [Symbol]
493
+ */
494
+ rb_define_attr(cResult, "status", 1, 0);
495
+ id_iv_status = rb_intern("@status");
496
+ /* Document-method: from_master
497
+ *
498
+ * @since 1.2.0.dp6
499
+ *
500
+ * @see Bucket#observe
501
+ *
502
+ * True if key stored on master
503
+ * @return [Boolean]
504
+ */
505
+ rb_define_attr(cResult, "from_master", 1, 0);
506
+ rb_define_alias(cResult, "from_master?", "from_master");
507
+ id_iv_from_master = rb_intern("@from_master");
508
+ /* Document-method: time_to_persist
509
+ *
510
+ * @since 1.2.0.dp6
511
+ *
512
+ * @see Bucket#observe
513
+ *
514
+ * Average time needed to persist key on the disk (zero if unavailable)
515
+ * @return [Fixnum]
516
+ */
517
+ rb_define_attr(cResult, "time_to_persist", 1, 0);
518
+ rb_define_alias(cResult, "ttp", "time_to_persist");
519
+ id_iv_time_to_persist = rb_intern("@time_to_persist");
520
+ /* Document-method: time_to_persist
521
+ *
522
+ * @since 1.2.0.dp6
523
+ *
524
+ * @see Bucket#observe
525
+ *
526
+ * Average time needed to replicate key on the disk (zero if unavailable)
527
+ * @return [Fixnum]
528
+ */
529
+ rb_define_attr(cResult, "time_to_replicate", 1, 0);
530
+ rb_define_alias(cResult, "ttr", "time_to_replicate");
531
+ id_iv_time_to_replicate = rb_intern("@time_to_replicate");
3352
532
 
3353
533
  /* Document-class: Couchbase::Bucket
534
+ *
3354
535
  * This class in charge of all stuff connected to communication with
3355
- * Couchbase. */
536
+ * Couchbase.
537
+ *
538
+ * @since 1.0.0
539
+ */
3356
540
  cBucket = rb_define_class_under(mCouchbase, "Bucket", rb_cObject);
3357
541
 
3358
542
  /* 0x03: Bitmask for flag bits responsible for format */
@@ -3378,27 +562,25 @@ Init_couchbase_ext(void)
3378
562
  rb_define_method(cBucket, "initialize_copy", cb_bucket_init_copy, 1);
3379
563
  rb_define_method(cBucket, "inspect", cb_bucket_inspect, 0);
3380
564
 
3381
- /* Document-method: seqno
3382
- * The number of scheduled commands */
3383
- /* rb_define_attr(cBucket, "seqno", 1, 0); */
3384
- rb_define_method(cBucket, "seqno", cb_bucket_seqno, 0);
3385
-
3386
565
  rb_define_method(cBucket, "add", cb_bucket_add, -1);
3387
566
  rb_define_method(cBucket, "append", cb_bucket_append, -1);
3388
567
  rb_define_method(cBucket, "prepend", cb_bucket_prepend, -1);
3389
568
  rb_define_method(cBucket, "replace", cb_bucket_replace, -1);
3390
569
  rb_define_method(cBucket, "set", cb_bucket_set, -1);
3391
570
  rb_define_method(cBucket, "get", cb_bucket_get, -1);
3392
- rb_define_method(cBucket, "run", cb_bucket_run, 0);
571
+ rb_define_method(cBucket, "run", cb_bucket_run, -1);
572
+ rb_define_method(cBucket, "stop", cb_bucket_stop, 0);
3393
573
  rb_define_method(cBucket, "touch", cb_bucket_touch, -1);
3394
574
  rb_define_method(cBucket, "delete", cb_bucket_delete, -1);
3395
575
  rb_define_method(cBucket, "stats", cb_bucket_stats, -1);
3396
- rb_define_method(cBucket, "flush", cb_bucket_flush, 0);
3397
- rb_define_method(cBucket, "version", cb_bucket_version, 0);
576
+ rb_define_method(cBucket, "version", cb_bucket_version, -1);
3398
577
  rb_define_method(cBucket, "incr", cb_bucket_incr, -1);
3399
578
  rb_define_method(cBucket, "decr", cb_bucket_decr, -1);
579
+ rb_define_method(cBucket, "unlock", cb_bucket_unlock, -1);
3400
580
  rb_define_method(cBucket, "disconnect", cb_bucket_disconnect, 0);
3401
581
  rb_define_method(cBucket, "reconnect", cb_bucket_reconnect, -1);
582
+ rb_define_method(cBucket, "make_http_request", cb_bucket_make_http_request, -1);
583
+ rb_define_method(cBucket, "observe", cb_bucket_observe, -1);
3402
584
 
3403
585
  rb_define_alias(cBucket, "decrement", "decr");
3404
586
  rb_define_alias(cBucket, "increment", "incr");
@@ -3413,6 +595,8 @@ Init_couchbase_ext(void)
3413
595
  /* Document-method: quiet
3414
596
  * Flag specifying behaviour for operations on missing keys
3415
597
  *
598
+ * @since 1.0.0
599
+ *
3416
600
  * If it is +true+, the operations will silently return +nil+ or +false+
3417
601
  * instead of raising {Couchbase::Error::NotFound}.
3418
602
  *
@@ -3424,7 +608,7 @@ Init_couchbase_ext(void)
3424
608
  * connection.quiet = false
3425
609
  * connection.get("miss") #=> will raise Couchbase::Error::NotFound
3426
610
  *
3427
- * @return [Boolean] */
611
+ * @return [true, false] */
3428
612
  /* rb_define_attr(cBucket, "quiet", 1, 1); */
3429
613
  rb_define_method(cBucket, "quiet", cb_bucket_quiet_get, 0);
3430
614
  rb_define_method(cBucket, "quiet=", cb_bucket_quiet_set, 1);
@@ -3433,6 +617,8 @@ Init_couchbase_ext(void)
3433
617
  /* Document-method: default_flags
3434
618
  * Default flags for new values.
3435
619
  *
620
+ * @since 1.0.0
621
+ *
3436
622
  * The library reserves last two lower bits to store the format of the
3437
623
  * value. The can be masked via FMT_MASK constant.
3438
624
  *
@@ -3452,6 +638,10 @@ Init_couchbase_ext(void)
3452
638
  /* Document-method: default_format
3453
639
  * Default format for new values.
3454
640
  *
641
+ * @since 1.0.0
642
+ *
643
+ * @see http://couchbase.com/docs/couchbase-manual-2.0/couchbase-views-datastore.html
644
+ *
3455
645
  * It uses flags field to store the format. It accepts either the Symbol
3456
646
  * (+:document+, +:marshal+, +:plain+) or Fixnum (use constants
3457
647
  * FMT_DOCUMENT, FMT_MARSHAL, FMT_PLAIN) and silently ignores all
@@ -3487,16 +677,31 @@ Init_couchbase_ext(void)
3487
677
  rb_define_method(cBucket, "default_format=", cb_bucket_default_format_set, 1);
3488
678
 
3489
679
  /* Document-method: timeout
3490
- * @return [Fixnum] The timeout for the operations. The client will
3491
- * raise {Couchbase::Error::Timeout} exception for all commands which
3492
- * weren't completed in given timeslot. */
680
+ *
681
+ * @since 1.1.0
682
+ *
683
+ * @return [Fixnum] The timeout for the operations in microseconds. The
684
+ * client will raise {Couchbase::Error::Timeout} exception for all
685
+ * commands which weren't completed in given timeslot. */
3493
686
  /* rb_define_attr(cBucket, "timeout", 1, 1); */
3494
687
  rb_define_method(cBucket, "timeout", cb_bucket_timeout_get, 0);
3495
688
  rb_define_method(cBucket, "timeout=", cb_bucket_timeout_set, 1);
3496
689
 
690
+ /* Document-method: key_prefix
691
+ *
692
+ * @since 1.2.0.dp5
693
+ *
694
+ * @return [String] The library will prepend +key_prefix+ to each key to
695
+ * provide simple namespacing. */
696
+ /* rb_define_attr(cBucket, "key_prefix", 1, 1); */
697
+ rb_define_method(cBucket, "key_prefix", cb_bucket_key_prefix_get, 0);
698
+ rb_define_method(cBucket, "key_prefix=", cb_bucket_key_prefix_set, 1);
699
+
3497
700
  /* Document-method: on_error
3498
701
  * Error callback for asynchronous mode.
3499
702
  *
703
+ * @since 1.0.0
704
+ *
3500
705
  * This callback is using to deliver exceptions in asynchronous mode.
3501
706
  *
3502
707
  * @yieldparam [Symbol] op The operation caused the error
@@ -3520,27 +725,166 @@ Init_couchbase_ext(void)
3520
725
  rb_define_method(cBucket, "on_error", cb_bucket_on_error_get, 0);
3521
726
  rb_define_method(cBucket, "on_error=", cb_bucket_on_error_set, 1);
3522
727
 
728
+ /* Document-method: url
729
+ *
730
+ * The config url for this connection.
731
+ *
732
+ * Generally it is the bootstrap URL, but it could be different after
733
+ * cluster upgrade. This url is used to fetch the cluster
734
+ * configuration.
735
+ *
736
+ * @since 1.0.0
737
+ *
738
+ * @return [String] the address of the cluster management interface
739
+ */
3523
740
  /* rb_define_attr(cBucket, "url", 1, 0); */
3524
741
  rb_define_method(cBucket, "url", cb_bucket_url_get, 0);
742
+ /* Document-method: hostname
743
+ *
744
+ * The hostname of the current node
745
+ *
746
+ * @see Bucket#url
747
+ *
748
+ * @since 1.0.0
749
+ *
750
+ * @return [String] the host name of the management interface (default: "localhost")
751
+ */
3525
752
  /* rb_define_attr(cBucket, "hostname", 1, 0); */
3526
753
  rb_define_method(cBucket, "hostname", cb_bucket_hostname_get, 0);
754
+ /* Document-method: port
755
+ *
756
+ * The port of the current node
757
+ *
758
+ * @see Bucket#url
759
+ *
760
+ * @since 1.0.0
761
+ *
762
+ * @return [Fixnum] the port number of the management interface (default: 8091)
763
+ */
3527
764
  /* rb_define_attr(cBucket, "port", 1, 0); */
3528
765
  rb_define_method(cBucket, "port", cb_bucket_port_get, 0);
766
+ /* Document-method: authority
767
+ *
768
+ * The authority ("hostname:port") of the current node
769
+ *
770
+ * @see Bucket#url
771
+ *
772
+ * @since 1.0.0
773
+ *
774
+ * @return [String] host with port
775
+ */
3529
776
  /* rb_define_attr(cBucket, "authority", 1, 0); */
3530
777
  rb_define_method(cBucket, "authority", cb_bucket_authority_get, 0);
778
+ /* Document-method: bucket
779
+ *
780
+ * The bucket name of the current connection
781
+ *
782
+ * @see Bucket#url
783
+ *
784
+ * @since 1.0.0
785
+ *
786
+ * @return [String] the bucket name
787
+ */
3531
788
  /* rb_define_attr(cBucket, "bucket", 1, 0); */
3532
789
  rb_define_method(cBucket, "bucket", cb_bucket_bucket_get, 0);
3533
790
  rb_define_alias(cBucket, "name", "bucket");
791
+ /* Document-method: pool
792
+ *
793
+ * The pool name of the current connection
794
+ *
795
+ * @see Bucket#url
796
+ *
797
+ * @since 1.0.0
798
+ *
799
+ * @return [String] the pool name (usually "default")
800
+ */
3534
801
  /* rb_define_attr(cBucket, "pool", 1, 0); */
3535
802
  rb_define_method(cBucket, "pool", cb_bucket_pool_get, 0);
803
+ /* Document-method: username
804
+ *
805
+ * The user name used to connect to the cluster
806
+ *
807
+ * @see Bucket#url
808
+ *
809
+ * @since 1.0.0
810
+ *
811
+ * @return [String] the username for protected buckets (usually matches
812
+ * the bucket name)
813
+ */
3536
814
  /* rb_define_attr(cBucket, "username", 1, 0); */
3537
815
  rb_define_method(cBucket, "username", cb_bucket_username_get, 0);
816
+ /* Document-method: password
817
+ *
818
+ * The password used to connect to the cluster
819
+ *
820
+ * @since 1.0.0
821
+ *
822
+ * @return [String] the password for protected buckets
823
+ */
3538
824
  /* rb_define_attr(cBucket, "password", 1, 0); */
3539
825
  rb_define_method(cBucket, "password", cb_bucket_password_get, 0);
826
+ /* Document-method: environment
827
+ *
828
+ * The environment of the connection (+:development+ or +:production+)
829
+ *
830
+ * @since 1.2.0
831
+ *
832
+ * @return [Symbol]
833
+ */
834
+ /* rb_define_attr(cBucket, "environment", 1, 0); */
835
+ rb_define_method(cBucket, "environment", cb_bucket_environment_get, 0);
836
+ /* Document-method: num_replicas
837
+ *
838
+ * @since 1.2.0.dp6
839
+ *
840
+ * The numbers of the replicas for each node in the cluster
841
+ *
842
+ * @return [Fixnum]
843
+ */
844
+ /* rb_define_attr(cBucket, "num_replicas", 1, 0); */
845
+ rb_define_method(cBucket, "num_replicas", cb_bucket_num_replicas_get, 0);
846
+ /* Document-method: default_observe_timeout
847
+ *
848
+ * @since 1.2.0.dp6
849
+ *
850
+ * The default timeout value for {Bucket#observe_and_wait} operation in
851
+ * microseconds
852
+ *
853
+ * @return [Fixnum]
854
+ */
855
+ /* rb_define_attr(cBucket, "default_observe_timeout", 1, 1); */
856
+ rb_define_method(cBucket, "default_observe_timeout", cb_bucket_default_observe_timeout_get, 0);
857
+ rb_define_method(cBucket, "default_observe_timeout=", cb_bucket_default_observe_timeout_set, 1);
858
+
859
+ cCouchRequest = rb_define_class_under(cBucket, "CouchRequest", rb_cObject);
860
+ rb_define_alloc_func(cCouchRequest, cb_http_request_alloc);
861
+
862
+ rb_define_method(cCouchRequest, "initialize", cb_http_request_init, -1);
863
+ rb_define_method(cCouchRequest, "inspect", cb_http_request_inspect, 0);
864
+ rb_define_method(cCouchRequest, "on_body", cb_http_request_on_body, 0);
865
+ rb_define_method(cCouchRequest, "perform", cb_http_request_perform, 0);
866
+ rb_define_method(cCouchRequest, "pause", cb_http_request_pause, 0);
867
+ rb_define_method(cCouchRequest, "continue", cb_http_request_continue, 0);
868
+
869
+ /* rb_define_attr(cCouchRequest, "path", 1, 0); */
870
+ rb_define_method(cCouchRequest, "path", cb_http_request_path_get, 0);
871
+ /* rb_define_attr(cCouchRequest, "extended", 1, 0); */
872
+ rb_define_method(cCouchRequest, "extended", cb_http_request_extended_get, 0);
873
+ rb_define_alias(cCouchRequest, "extended?", "extended");
874
+ /* rb_define_attr(cCouchRequest, "chunked", 1, 0); */
875
+ rb_define_method(cCouchRequest, "chunked", cb_http_request_chunked_get, 0);
876
+ rb_define_alias(cCouchRequest, "chunked?", "chunked");
877
+
878
+ cTimer = rb_define_class_under(mCouchbase, "Timer", rb_cObject);
879
+ rb_define_alloc_func(cTimer, cb_timer_alloc);
880
+ rb_define_method(cTimer, "initialize", cb_timer_init, -1);
881
+ rb_define_method(cTimer, "inspect", cb_timer_inspect, 0);
882
+ rb_define_method(cTimer, "cancel", cb_timer_cancel, 0);
3540
883
 
3541
884
  /* Define symbols */
3542
885
  id_arity = rb_intern("arity");
3543
886
  id_call = rb_intern("call");
887
+ id_delete = rb_intern("delete");
3544
888
  id_dump = rb_intern("dump");
3545
889
  id_dup = rb_intern("dup");
3546
890
  id_flatten_bang = rb_intern("flatten!");
@@ -3548,6 +892,7 @@ Init_couchbase_ext(void)
3548
892
  id_host = rb_intern("host");
3549
893
  id_load = rb_intern("load");
3550
894
  id_match = rb_intern("match");
895
+ id_observe_and_wait = rb_intern("observe_and_wait");
3551
896
  id_parse = rb_intern("parse");
3552
897
  id_password = rb_intern("password");
3553
898
  id_path = rb_intern("path");
@@ -3555,40 +900,66 @@ Init_couchbase_ext(void)
3555
900
  id_scheme = rb_intern("scheme");
3556
901
  id_to_s = rb_intern("to_s");
3557
902
  id_user = rb_intern("user");
903
+ id_verify_observe_options = rb_intern("verify_observe_options");
3558
904
 
3559
905
  sym_add = ID2SYM(rb_intern("add"));
3560
906
  sym_append = ID2SYM(rb_intern("append"));
907
+ sym_assemble_hash = ID2SYM(rb_intern("assemble_hash"));
908
+ sym_body = ID2SYM(rb_intern("body"));
3561
909
  sym_bucket = ID2SYM(rb_intern("bucket"));
3562
910
  sym_cas = ID2SYM(rb_intern("cas"));
911
+ sym_chunked = ID2SYM(rb_intern("chunked"));
912
+ sym_content_type = ID2SYM(rb_intern("content_type"));
3563
913
  sym_create = ID2SYM(rb_intern("create"));
3564
914
  sym_decrement = ID2SYM(rb_intern("decrement"));
3565
915
  sym_default_flags = ID2SYM(rb_intern("default_flags"));
3566
916
  sym_default_format = ID2SYM(rb_intern("default_format"));
3567
917
  sym_default_ttl = ID2SYM(rb_intern("default_ttl"));
3568
918
  sym_delete = ID2SYM(rb_intern("delete"));
919
+ sym_delta = ID2SYM(rb_intern("delta"));
920
+ sym_development = ID2SYM(rb_intern("development"));
3569
921
  sym_document = ID2SYM(rb_intern("document"));
922
+ sym_environment = ID2SYM(rb_intern("environment"));
3570
923
  sym_extended = ID2SYM(rb_intern("extended"));
3571
924
  sym_flags = ID2SYM(rb_intern("flags"));
3572
- sym_flush = ID2SYM(rb_intern("flush"));
3573
925
  sym_format = ID2SYM(rb_intern("format"));
926
+ sym_found = ID2SYM(rb_intern("found"));
3574
927
  sym_get = ID2SYM(rb_intern("get"));
3575
928
  sym_hostname = ID2SYM(rb_intern("hostname"));
929
+ sym_http_request = ID2SYM(rb_intern("http_request"));
3576
930
  sym_increment = ID2SYM(rb_intern("increment"));
3577
931
  sym_initial = ID2SYM(rb_intern("initial"));
932
+ sym_key_prefix = ID2SYM(rb_intern("key_prefix"));
933
+ sym_lock = ID2SYM(rb_intern("lock"));
934
+ sym_management = ID2SYM(rb_intern("management"));
3578
935
  sym_marshal = ID2SYM(rb_intern("marshal"));
936
+ sym_method = ID2SYM(rb_intern("method"));
3579
937
  sym_node_list = ID2SYM(rb_intern("node_list"));
938
+ sym_not_found = ID2SYM(rb_intern("not_found"));
939
+ sym_num_replicas = ID2SYM(rb_intern("num_replicas"));
940
+ sym_observe = ID2SYM(rb_intern("observe"));
3580
941
  sym_password = ID2SYM(rb_intern("password"));
942
+ sym_periodic = ID2SYM(rb_intern("periodic"));
943
+ sym_persisted = ID2SYM(rb_intern("persisted"));
3581
944
  sym_plain = ID2SYM(rb_intern("plain"));
3582
945
  sym_pool = ID2SYM(rb_intern("pool"));
3583
946
  sym_port = ID2SYM(rb_intern("port"));
947
+ sym_post = ID2SYM(rb_intern("post"));
3584
948
  sym_prepend = ID2SYM(rb_intern("prepend"));
949
+ sym_production = ID2SYM(rb_intern("production"));
950
+ sym_put = ID2SYM(rb_intern("put"));
3585
951
  sym_quiet = ID2SYM(rb_intern("quiet"));
3586
952
  sym_replace = ID2SYM(rb_intern("replace"));
953
+ sym_replica = ID2SYM(rb_intern("replica"));
954
+ sym_send_threshold = ID2SYM(rb_intern("send_threshold"));
3587
955
  sym_set = ID2SYM(rb_intern("set"));
3588
956
  sym_stats = ID2SYM(rb_intern("stats"));
3589
957
  sym_timeout = ID2SYM(rb_intern("timeout"));
3590
958
  sym_touch = ID2SYM(rb_intern("touch"));
3591
959
  sym_ttl = ID2SYM(rb_intern("ttl"));
960
+ sym_type = ID2SYM(rb_intern("type"));
961
+ sym_unlock = ID2SYM(rb_intern("unlock"));
3592
962
  sym_username = ID2SYM(rb_intern("username"));
3593
963
  sym_version = ID2SYM(rb_intern("version"));
964
+ sym_view = ID2SYM(rb_intern("view"));
3594
965
  }