couchbase 1.3.4-x64-mingw32

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