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.
- data/.gitignore +2 -1
- data/.travis.yml +12 -1
- data/HISTORY.markdown +112 -1
- data/README.markdown +149 -6
- data/couchbase.gemspec +5 -1
- data/ext/couchbase_ext/.gitignore +4 -0
- data/ext/couchbase_ext/arguments.c +973 -0
- data/ext/couchbase_ext/arithmetic.c +322 -0
- data/ext/couchbase_ext/bucket.c +1092 -0
- data/ext/couchbase_ext/couchbase_ext.c +618 -3247
- data/ext/couchbase_ext/couchbase_ext.h +519 -0
- data/ext/couchbase_ext/delete.c +167 -0
- data/ext/couchbase_ext/extconf.rb +24 -5
- data/ext/couchbase_ext/get.c +301 -0
- data/ext/couchbase_ext/gethrtime.c +124 -0
- data/ext/couchbase_ext/http.c +402 -0
- data/ext/couchbase_ext/observe.c +174 -0
- data/ext/couchbase_ext/result.c +126 -0
- data/ext/couchbase_ext/stats.c +169 -0
- data/ext/couchbase_ext/store.c +522 -0
- data/ext/couchbase_ext/timer.c +192 -0
- data/ext/couchbase_ext/touch.c +190 -0
- data/ext/couchbase_ext/unlock.c +180 -0
- data/ext/couchbase_ext/utils.c +471 -0
- data/ext/couchbase_ext/version.c +147 -0
- data/lib/action_dispatch/middleware/session/couchbase_store.rb +38 -0
- data/lib/active_support/cache/couchbase_store.rb +356 -0
- data/lib/couchbase.rb +24 -3
- data/lib/couchbase/bucket.rb +372 -9
- data/lib/couchbase/result.rb +26 -0
- data/lib/couchbase/utils.rb +59 -0
- data/lib/couchbase/version.rb +1 -1
- data/lib/couchbase/view.rb +305 -0
- data/lib/couchbase/view_row.rb +230 -0
- data/lib/ext/multi_json_fix.rb +47 -0
- data/lib/rack/session/couchbase.rb +104 -0
- data/tasks/compile.rake +5 -14
- data/test/setup.rb +6 -2
- data/test/test_arithmetic.rb +32 -2
- data/test/test_async.rb +18 -4
- data/test/test_bucket.rb +11 -1
- data/test/test_cas.rb +13 -3
- data/test/test_couchbase_rails_cache_store.rb +294 -0
- data/test/test_delete.rb +60 -3
- data/test/test_format.rb +28 -17
- data/test/test_get.rb +91 -14
- data/test/test_store.rb +31 -1
- data/test/{test_flush.rb → test_timer.rb} +11 -18
- data/test/test_touch.rb +33 -5
- data/test/test_unlock.rb +120 -0
- data/test/test_utils.rb +26 -0
- 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(¶ms, 0, sizeof(struct params_st));
|
126
|
+
params.type = cmd_store;
|
127
|
+
params.bucket = bucket;
|
128
|
+
params.cmd.store.operation = cmd;
|
129
|
+
cb_params_build(¶ms, 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(¶ms);
|
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
|
+
|