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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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
@@ -0,0 +1,522 @@
1
+ /* vim: ft=c et ts=8 sts=4 sw=4 cino=
2
+ *
3
+ * Copyright 2011, 2012 Couchbase, Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ #include "couchbase_ext.h"
19
+
20
+ static VALUE
21
+ storage_observe_callback(VALUE args, VALUE cookie)
22
+ {
23
+ struct context_st *ctx = (struct context_st *)cookie;
24
+ VALUE res = rb_ary_shift(args);
25
+
26
+ if (ctx->proc != Qnil) {
27
+ rb_ivar_set(res, id_iv_operation, ctx->operation);
28
+ cb_proc_call(ctx->proc, 1, res);
29
+ }
30
+ if (!RTEST(ctx->observe_options)) {
31
+ ctx->nqueries--;
32
+ if (ctx->nqueries == 0) {
33
+ cb_gc_unprotect(ctx->bucket, ctx->proc);
34
+ }
35
+ }
36
+ return Qnil;
37
+ }
38
+
39
+ void
40
+ storage_callback(lcb_t handle, const void *cookie, lcb_storage_t operation,
41
+ lcb_error_t error, const lcb_store_resp_t *resp)
42
+ {
43
+ struct context_st *ctx = (struct context_st *)cookie;
44
+ struct bucket_st *bucket = ctx->bucket;
45
+ VALUE key, cas, *rv = ctx->rv, exc, res;
46
+
47
+ key = STR_NEW((const char*)resp->v.v0.key, resp->v.v0.nkey);
48
+ strip_key_prefix(bucket, key);
49
+
50
+ cas = resp->v.v0.cas > 0 ? ULL2NUM(resp->v.v0.cas) : Qnil;
51
+ switch(operation) {
52
+ case LCB_ADD:
53
+ ctx->operation = sym_add;
54
+ break;
55
+ case LCB_REPLACE:
56
+ ctx->operation = sym_replace;
57
+ break;
58
+ case LCB_SET:
59
+ ctx->operation = sym_set;
60
+ break;
61
+ case LCB_APPEND:
62
+ ctx->operation = sym_append;
63
+ break;
64
+ case LCB_PREPEND:
65
+ ctx->operation = sym_prepend;
66
+ break;
67
+ default:
68
+ ctx->operation = Qnil;
69
+ }
70
+ exc = cb_check_error(error, "failed to store value", key);
71
+ if (exc != Qnil) {
72
+ rb_ivar_set(exc, id_iv_cas, cas);
73
+ rb_ivar_set(exc, id_iv_operation, ctx->operation);
74
+ if (NIL_P(ctx->exception)) {
75
+ ctx->exception = cb_gc_protect(bucket, exc);
76
+ }
77
+ }
78
+
79
+ if (bucket->async) { /* asynchronous */
80
+ if (RTEST(ctx->observe_options)) {
81
+ VALUE args[2]; /* it's ok to pass pointer to stack struct here */
82
+ args[0] = rb_hash_new();
83
+ rb_hash_aset(args[0], key, cas);
84
+ args[1] = ctx->observe_options;
85
+ rb_block_call(bucket->self, id_observe_and_wait, 2, args,
86
+ storage_observe_callback, (VALUE)ctx);
87
+ cb_gc_unprotect(bucket, ctx->observe_options);
88
+ } else if (ctx->proc != Qnil) {
89
+ res = rb_class_new_instance(0, NULL, cResult);
90
+ rb_ivar_set(res, id_iv_error, exc);
91
+ rb_ivar_set(res, id_iv_key, key);
92
+ rb_ivar_set(res, id_iv_operation, ctx->operation);
93
+ rb_ivar_set(res, id_iv_cas, cas);
94
+ cb_proc_call(ctx->proc, 1, res);
95
+ }
96
+ } else { /* synchronous */
97
+ rb_hash_aset(*rv, key, cas);
98
+ }
99
+
100
+ if (!RTEST(ctx->observe_options)) {
101
+ ctx->nqueries--;
102
+ if (ctx->nqueries == 0) {
103
+ cb_gc_unprotect(bucket, ctx->proc);
104
+ }
105
+ }
106
+ (void)handle;
107
+ }
108
+
109
+ static inline VALUE
110
+ cb_bucket_store(lcb_storage_t cmd, int argc, VALUE *argv, VALUE self)
111
+ {
112
+ struct bucket_st *bucket = DATA_PTR(self);
113
+ struct context_st *ctx;
114
+ VALUE args, rv, proc, exc, obs = Qnil;
115
+ lcb_error_t err;
116
+ struct params_st params;
117
+
118
+ if (bucket->handle == NULL) {
119
+ rb_raise(eConnectError, "closed connection");
120
+ }
121
+ rb_scan_args(argc, argv, "0*&", &args, &proc);
122
+ if (!bucket->async && proc != Qnil) {
123
+ rb_raise(rb_eArgError, "synchronous mode doesn't support callbacks");
124
+ }
125
+ memset(&params, 0, sizeof(struct params_st));
126
+ params.type = cmd_store;
127
+ params.bucket = bucket;
128
+ params.cmd.store.operation = cmd;
129
+ cb_params_build(&params, RARRAY_LEN(args), args);
130
+ ctx = xcalloc(1, sizeof(struct context_st));
131
+ if (ctx == NULL) {
132
+ rb_raise(eClientNoMemoryError, "failed to allocate memory for context");
133
+ }
134
+ rv = rb_hash_new();
135
+ ctx->rv = &rv;
136
+ ctx->bucket = bucket;
137
+ ctx->proc = cb_gc_protect(bucket, proc);
138
+ ctx->observe_options = cb_gc_protect(bucket, obs);
139
+ ctx->exception = Qnil;
140
+ ctx->nqueries = params.cmd.store.num;
141
+ err = lcb_store(bucket->handle, (const void *)ctx,
142
+ params.cmd.store.num, params.cmd.store.ptr);
143
+ cb_params_destroy(&params);
144
+ exc = cb_check_error(err, "failed to schedule set request", Qnil);
145
+ if (exc != Qnil) {
146
+ xfree(ctx);
147
+ rb_exc_raise(exc);
148
+ }
149
+ bucket->nbytes += params.npayload;
150
+ if (bucket->async) {
151
+ maybe_do_loop(bucket);
152
+ return Qnil;
153
+ } else {
154
+ if (ctx->nqueries > 0) {
155
+ /* we have some operations pending */
156
+ lcb_wait(bucket->handle);
157
+ }
158
+ exc = ctx->exception;
159
+ xfree(ctx);
160
+ if (exc != Qnil) {
161
+ cb_gc_unprotect(bucket, exc);
162
+ rb_exc_raise(exc);
163
+ }
164
+ if (bucket->exception != Qnil) {
165
+ rb_exc_raise(bucket->exception);
166
+ }
167
+ if (RTEST(obs)) {
168
+ cb_gc_unprotect(bucket, obs);
169
+ return rb_funcall(bucket->self, id_observe_and_wait, 2, rv, obs);
170
+ }
171
+ if (params.cmd.store.num > 1) {
172
+ return rv; /* return as a hash {key => cas, ...} */
173
+ } else {
174
+ VALUE vv = Qnil;
175
+ rb_hash_foreach(rv, cb_first_value_i, (VALUE)&vv);
176
+ return vv;
177
+ }
178
+ }
179
+ }
180
+
181
+ /*
182
+ * Unconditionally store the object in the Couchbase
183
+ *
184
+ * @since 1.0.0
185
+ *
186
+ * @overload set(key, value, options = {})
187
+ *
188
+ * @param key [String, Symbol] Key used to reference the value.
189
+ * @param value [Object] Value to be stored
190
+ * @param options [Hash] Options for operation.
191
+ * @option options [Fixnum] :ttl (self.default_ttl) Expiry time for key.
192
+ * Values larger than 30*24*60*60 seconds (30 days) are interpreted as
193
+ * absolute times (from the epoch).
194
+ * @option options [Fixnum] :flags (self.default_flags) Flags for storage
195
+ * options. Flags are ignored by the server but preserved for use by the
196
+ * client. For more info see {Bucket#default_flags}.
197
+ * @option options [Symbol] :format (self.default_format) The
198
+ * representation for storing the value in the bucket. For more info see
199
+ * {Bucket#default_format}.
200
+ * @option options [Fixnum] :cas The CAS value for an object. This value
201
+ * created on the server and is guaranteed to be unique for each value of
202
+ * a given key. This value is used to provide simple optimistic
203
+ * concurrency control when multiple clients or threads try to update an
204
+ * item simultaneously.
205
+ * @option options [Hash] :observe Apply persistence condition before
206
+ * returning result. When this option specified the library will observe
207
+ * given condition. See {Bucket#observe_and_wait}.
208
+ *
209
+ * @yieldparam ret [Result] the result of operation in asynchronous mode
210
+ * (valid attributes: +error+, +operation+, +key+).
211
+ *
212
+ * @return [Fixnum] The CAS value of the object.
213
+ *
214
+ * @raise [Couchbase::Error::Connect] if connection closed (see {Bucket#reconnect}).
215
+ * @raise [Couchbase::Error::KeyExists] if the key already exists on the
216
+ * server.
217
+ * @raise [Couchbase::Error::ValueFormat] if the value cannot be serialized
218
+ * with chosen encoder, e.g. if you try to store the Hash in +:plain+
219
+ * mode.
220
+ * @raise [ArgumentError] when passing the block in synchronous mode
221
+ * @raise [Couchbase::Error::Timeout] if timeout interval for observe
222
+ * exceeds
223
+ *
224
+ * @example Store the key which will be expired in 2 seconds using relative TTL.
225
+ * c.set("foo", "bar", :ttl => 2)
226
+ *
227
+ * @example Store the key which will be expired in 2 seconds using absolute TTL.
228
+ * c.set("foo", "bar", :ttl => Time.now.to_i + 2)
229
+ *
230
+ * @example Force JSON document format for value
231
+ * c.set("foo", {"bar" => "baz}, :format => :document)
232
+ *
233
+ * @example Use hash-like syntax to store the value
234
+ * c.set["foo"] = {"bar" => "baz}
235
+ *
236
+ * @example Use extended hash-like syntax
237
+ * c["foo", {:flags => 0x1000, :format => :plain}] = "bar"
238
+ * c["foo", :flags => 0x1000] = "bar" # for ruby 1.9.x only
239
+ *
240
+ * @example Set application specific flags (note that it will be OR-ed with format flags)
241
+ * c.set("foo", "bar", :flags => 0x1000)
242
+ *
243
+ * @example Perform optimistic locking by specifying last known CAS version
244
+ * c.set("foo", "bar", :cas => 8835713818674332672)
245
+ *
246
+ * @example Perform asynchronous call
247
+ * c.run do
248
+ * c.set("foo", "bar") do |ret|
249
+ * ret.operation #=> :set
250
+ * ret.success? #=> true
251
+ * ret.key #=> "foo"
252
+ * ret.cas
253
+ * end
254
+ * end
255
+ *
256
+ * @example Ensure that the key will be persisted at least on the one node
257
+ * c.set("foo", "bar", :observe => {:persisted => 1})
258
+ */
259
+ VALUE
260
+ cb_bucket_set(int argc, VALUE *argv, VALUE self)
261
+ {
262
+ return cb_bucket_store(LCB_SET, argc, argv, self);
263
+ }
264
+
265
+ /*
266
+ * Add the item to the database, but fail if the object exists already
267
+ *
268
+ * @since 1.0.0
269
+ *
270
+ * @overload add(key, value, options = {})
271
+ *
272
+ * @param key [String, Symbol] Key used to reference the value.
273
+ * @param value [Object] Value to be stored
274
+ * @param options [Hash] Options for operation.
275
+ * @option options [Fixnum] :ttl (self.default_ttl) Expiry time for key.
276
+ * Values larger than 30*24*60*60 seconds (30 days) are interpreted as
277
+ * absolute times (from the epoch).
278
+ * @option options [Fixnum] :flags (self.default_flags) Flags for storage
279
+ * options. Flags are ignored by the server but preserved for use by the
280
+ * client. For more info see {Bucket#default_flags}.
281
+ * @option options [Symbol] :format (self.default_format) The
282
+ * representation for storing the value in the bucket. For more info see
283
+ * {Bucket#default_format}.
284
+ * @option options [Fixnum] :cas The CAS value for an object. This value
285
+ * created on the server and is guaranteed to be unique for each value of
286
+ * a given key. This value is used to provide simple optimistic
287
+ * concurrency control when multiple clients or threads try to update an
288
+ * item simultaneously.
289
+ * @option options [Hash] :observe Apply persistence condition before
290
+ * returning result. When this option specified the library will observe
291
+ * given condition. See {Bucket#observe_and_wait}.
292
+ *
293
+ * @yieldparam ret [Result] the result of operation in asynchronous mode
294
+ * (valid attributes: +error+, +operation+, +key+).
295
+ *
296
+ * @return [Fixnum] The CAS value of the object.
297
+ *
298
+ * @raise [Couchbase::Error::Connect] if connection closed (see {Bucket#reconnect})
299
+ * @raise [Couchbase::Error::KeyExists] if the key already exists on the
300
+ * server
301
+ * @raise [Couchbase::Error::ValueFormat] if the value cannot be serialized
302
+ * with chosen encoder, e.g. if you try to store the Hash in +:plain+
303
+ * mode.
304
+ * @raise [ArgumentError] when passing the block in synchronous mode
305
+ * @raise [Couchbase::Error::Timeout] if timeout interval for observe
306
+ * exceeds
307
+ *
308
+ * @example Add the same key twice
309
+ * c.add("foo", "bar") #=> stored successully
310
+ * c.add("foo", "baz") #=> will raise Couchbase::Error::KeyExists: failed to store value (key="foo", error=0x0c)
311
+ *
312
+ * @example Ensure that the key will be persisted at least on the one node
313
+ * c.add("foo", "bar", :observe => {:persisted => 1})
314
+ */
315
+ VALUE
316
+ cb_bucket_add(int argc, VALUE *argv, VALUE self)
317
+ {
318
+ return cb_bucket_store(LCB_ADD, argc, argv, self);
319
+ }
320
+
321
+ /*
322
+ * Replace the existing object in the database
323
+ *
324
+ * @since 1.0.0
325
+ *
326
+ * @overload replace(key, value, options = {})
327
+ * @param key [String, Symbol] Key used to reference the value.
328
+ * @param value [Object] Value to be stored
329
+ * @param options [Hash] Options for operation.
330
+ * @option options [Fixnum] :ttl (self.default_ttl) Expiry time for key.
331
+ * Values larger than 30*24*60*60 seconds (30 days) are interpreted as
332
+ * absolute times (from the epoch).
333
+ * @option options [Fixnum] :flags (self.default_flags) Flags for storage
334
+ * options. Flags are ignored by the server but preserved for use by the
335
+ * client. For more info see {Bucket#default_flags}.
336
+ * @option options [Symbol] :format (self.default_format) The
337
+ * representation for storing the value in the bucket. For more info see
338
+ * {Bucket#default_format}.
339
+ * @option options [Fixnum] :cas The CAS value for an object. This value
340
+ * created on the server and is guaranteed to be unique for each value of
341
+ * a given key. This value is used to provide simple optimistic
342
+ * concurrency control when multiple clients or threads try to update an
343
+ * item simultaneously.
344
+ * @option options [Hash] :observe Apply persistence condition before
345
+ * returning result. When this option specified the library will observe
346
+ * given condition. See {Bucket#observe_and_wait}.
347
+ *
348
+ * @return [Fixnum] The CAS value of the object.
349
+ *
350
+ * @raise [Couchbase::Error::Connect] if connection closed (see {Bucket#reconnect})
351
+ * @raise [Couchbase::Error::NotFound] if the key doesn't exists
352
+ * @raise [Couchbase::Error::KeyExists] on CAS mismatch
353
+ * @raise [ArgumentError] when passing the block in synchronous mode
354
+ * @raise [Couchbase::Error::Timeout] if timeout interval for observe
355
+ * exceeds
356
+ *
357
+ * @example Replacing missing key
358
+ * c.replace("foo", "baz") #=> will raise Couchbase::Error::NotFound: failed to store value (key="foo", error=0x0d)
359
+ *
360
+ * @example Ensure that the key will be persisted at least on the one node
361
+ * c.replace("foo", "bar", :observe => {:persisted => 1})
362
+ */
363
+ VALUE
364
+ cb_bucket_replace(int argc, VALUE *argv, VALUE self)
365
+ {
366
+ return cb_bucket_store(LCB_REPLACE, argc, argv, self);
367
+ }
368
+
369
+ /*
370
+ * Append this object to the existing object
371
+ *
372
+ * @since 1.0.0
373
+ *
374
+ * @note This operation is kind of data-aware from server point of view.
375
+ * This mean that the server treats value as binary stream and just
376
+ * perform concatenation, therefore it won't work with +:marshal+ and
377
+ * +:document+ formats, because of lack of knowledge how to merge values
378
+ * in these formats. See {Bucket#cas} for workaround.
379
+ *
380
+ * @overload append(key, value, options = {})
381
+ * @param key [String, Symbol] Key used to reference the value.
382
+ * @param value [Object] Value to be stored
383
+ * @param options [Hash] Options for operation.
384
+ * @option options [Fixnum] :cas The CAS value for an object. This value
385
+ * created on the server and is guaranteed to be unique for each value of
386
+ * a given key. This value is used to provide simple optimistic
387
+ * concurrency control when multiple clients or threads try to update an
388
+ * item simultaneously.
389
+ * @option options [Symbol] :format (self.default_format) The
390
+ * representation for storing the value in the bucket. For more info see
391
+ * {Bucket#default_format}.
392
+ * @option options [Hash] :observe Apply persistence condition before
393
+ * returning result. When this option specified the library will observe
394
+ * given condition. See {Bucket#observe_and_wait}.
395
+ *
396
+ * @return [Fixnum] The CAS value of the object.
397
+ *
398
+ * @raise [Couchbase::Error::Connect] if connection closed (see {Bucket#reconnect})
399
+ * @raise [Couchbase::Error::KeyExists] on CAS mismatch
400
+ * @raise [Couchbase::Error::NotStored] if the key doesn't exist
401
+ * @raise [ArgumentError] when passing the block in synchronous mode
402
+ * @raise [Couchbase::Error::Timeout] if timeout interval for observe
403
+ * exceeds
404
+ *
405
+ * @example Simple append
406
+ * c.set("foo", "aaa")
407
+ * c.append("foo", "bbb")
408
+ * c.get("foo") #=> "aaabbb"
409
+ *
410
+ * @example Implementing sets using append
411
+ * def set_add(key, *values)
412
+ * encoded = values.flatten.map{|v| "+#{v} "}.join
413
+ * append(key, encoded)
414
+ * end
415
+ *
416
+ * def set_remove(key, *values)
417
+ * encoded = values.flatten.map{|v| "-#{v} "}.join
418
+ * append(key, encoded)
419
+ * end
420
+ *
421
+ * def set_get(key)
422
+ * encoded = get(key)
423
+ * ret = Set.new
424
+ * encoded.split(' ').each do |v|
425
+ * op, val = v[0], v[1..-1]
426
+ * case op
427
+ * when "-"
428
+ * ret.delete(val)
429
+ * when "+"
430
+ * ret.add(val)
431
+ * end
432
+ * end
433
+ * ret
434
+ * end
435
+ *
436
+ * @example Using optimistic locking. The operation will fail on CAS mismatch
437
+ * ver = c.set("foo", "aaa")
438
+ * c.append("foo", "bbb", :cas => ver)
439
+ *
440
+ * @example Ensure that the key will be persisted at least on the one node
441
+ * c.append("foo", "bar", :observe => {:persisted => 1})
442
+ */
443
+ VALUE
444
+ cb_bucket_append(int argc, VALUE *argv, VALUE self)
445
+ {
446
+ return cb_bucket_store(LCB_APPEND, argc, argv, self);
447
+ }
448
+
449
+ /*
450
+ * Prepend this object to the existing object
451
+ *
452
+ * @since 1.0.0
453
+ *
454
+ * @note This operation is kind of data-aware from server point of view.
455
+ * This mean that the server treats value as binary stream and just
456
+ * perform concatenation, therefore it won't work with +:marshal+ and
457
+ * +:document+ formats, because of lack of knowledge how to merge values
458
+ * in these formats. See {Bucket#cas} for workaround.
459
+ *
460
+ * @overload prepend(key, value, options = {})
461
+ * @param key [String, Symbol] Key used to reference the value.
462
+ * @param value [Object] Value to be stored
463
+ * @param options [Hash] Options for operation.
464
+ * @option options [Fixnum] :cas The CAS value for an object. This value
465
+ * created on the server and is guaranteed to be unique for each value of
466
+ * a given key. This value is used to provide simple optimistic
467
+ * concurrency control when multiple clients or threads try to update an
468
+ * item simultaneously.
469
+ * @option options [Symbol] :format (self.default_format) The
470
+ * representation for storing the value in the bucket. For more info see
471
+ * {Bucket#default_format}.
472
+ * @option options [Hash] :observe Apply persistence condition before
473
+ * returning result. When this option specified the library will observe
474
+ * given condition. See {Bucket#observe_and_wait}.
475
+ *
476
+ * @raise [Couchbase::Error::Connect] if connection closed (see {Bucket#reconnect})
477
+ * @raise [Couchbase::Error::KeyExists] on CAS mismatch
478
+ * @raise [Couchbase::Error::NotStored] if the key doesn't exist
479
+ * @raise [ArgumentError] when passing the block in synchronous mode
480
+ * @raise [Couchbase::Error::Timeout] if timeout interval for observe
481
+ * exceeds
482
+ *
483
+ * @example Simple prepend example
484
+ * c.set("foo", "aaa")
485
+ * c.prepend("foo", "bbb")
486
+ * c.get("foo") #=> "bbbaaa"
487
+ *
488
+ * @example Using explicit format option
489
+ * c.default_format #=> :document
490
+ * c.set("foo", {"y" => "z"})
491
+ * c.prepend("foo", '[', :format => :plain)
492
+ * c.append("foo", ', {"z": "y"}]', :format => :plain)
493
+ * c.get("foo") #=> [{"y"=>"z"}, {"z"=>"y"}]
494
+ *
495
+ * @example Using optimistic locking. The operation will fail on CAS mismatch
496
+ * ver = c.set("foo", "aaa")
497
+ * c.prepend("foo", "bbb", :cas => ver)
498
+ *
499
+ * @example Ensure that the key will be persisted at least on the one node
500
+ * c.prepend("foo", "bar", :observe => {:persisted => 1})
501
+ */
502
+ VALUE
503
+ cb_bucket_prepend(int argc, VALUE *argv, VALUE self)
504
+ {
505
+ return cb_bucket_store(LCB_PREPEND, argc, argv, self);
506
+ }
507
+
508
+ VALUE
509
+ cb_bucket_aset(int argc, VALUE *argv, VALUE self)
510
+ {
511
+ VALUE temp;
512
+
513
+ if (argc == 3) {
514
+ /* swap opts and value, because value goes last for []= */
515
+ temp = argv[2];
516
+ argv[2] = argv[1];
517
+ argv[1] = temp;
518
+ }
519
+ return cb_bucket_set(argc, argv, self);
520
+ }
521
+
522
+