couchbase 1.3.4-x64-mingw32
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/.travis.yml +22 -0
- data/.yardopts +5 -0
- data/CONTRIBUTING.markdown +75 -0
- data/Gemfile +4 -0
- data/LICENSE +201 -0
- data/Makefile +3 -0
- data/README.markdown +649 -0
- data/RELEASE_NOTES.markdown +796 -0
- data/Rakefile +20 -0
- data/couchbase.gemspec +49 -0
- data/examples/chat-em/Gemfile +7 -0
- data/examples/chat-em/README.markdown +45 -0
- data/examples/chat-em/server.rb +82 -0
- data/examples/chat-goliath-grape/Gemfile +5 -0
- data/examples/chat-goliath-grape/README.markdown +50 -0
- data/examples/chat-goliath-grape/app.rb +67 -0
- data/examples/chat-goliath-grape/config/app.rb +20 -0
- data/examples/transcoders/Gemfile +3 -0
- data/examples/transcoders/README.markdown +59 -0
- data/examples/transcoders/cb-zcat +40 -0
- data/examples/transcoders/cb-zcp +45 -0
- data/examples/transcoders/gzip_transcoder.rb +49 -0
- data/examples/transcoders/options.rb +54 -0
- data/ext/couchbase_ext/.gitignore +4 -0
- data/ext/couchbase_ext/arguments.c +956 -0
- data/ext/couchbase_ext/arithmetic.c +307 -0
- data/ext/couchbase_ext/bucket.c +1370 -0
- data/ext/couchbase_ext/context.c +65 -0
- data/ext/couchbase_ext/couchbase_ext.c +1364 -0
- data/ext/couchbase_ext/couchbase_ext.h +644 -0
- data/ext/couchbase_ext/delete.c +163 -0
- data/ext/couchbase_ext/eventmachine_plugin.c +452 -0
- data/ext/couchbase_ext/extconf.rb +168 -0
- data/ext/couchbase_ext/get.c +316 -0
- data/ext/couchbase_ext/gethrtime.c +129 -0
- data/ext/couchbase_ext/http.c +432 -0
- data/ext/couchbase_ext/multithread_plugin.c +1090 -0
- data/ext/couchbase_ext/observe.c +171 -0
- data/ext/couchbase_ext/plugin_common.c +171 -0
- data/ext/couchbase_ext/result.c +129 -0
- data/ext/couchbase_ext/stats.c +163 -0
- data/ext/couchbase_ext/store.c +542 -0
- data/ext/couchbase_ext/timer.c +192 -0
- data/ext/couchbase_ext/touch.c +186 -0
- data/ext/couchbase_ext/unlock.c +176 -0
- data/ext/couchbase_ext/utils.c +551 -0
- data/ext/couchbase_ext/version.c +142 -0
- data/lib/action_dispatch/middleware/session/couchbase_store.rb +38 -0
- data/lib/active_support/cache/couchbase_store.rb +430 -0
- data/lib/couchbase.rb +155 -0
- data/lib/couchbase/bucket.rb +457 -0
- data/lib/couchbase/cluster.rb +119 -0
- data/lib/couchbase/connection_pool.rb +58 -0
- data/lib/couchbase/constants.rb +12 -0
- data/lib/couchbase/result.rb +26 -0
- data/lib/couchbase/transcoder.rb +120 -0
- data/lib/couchbase/utils.rb +62 -0
- data/lib/couchbase/version.rb +21 -0
- data/lib/couchbase/view.rb +506 -0
- data/lib/couchbase/view_row.rb +272 -0
- data/lib/ext/multi_json_fix.rb +56 -0
- data/lib/rack/session/couchbase.rb +108 -0
- data/tasks/benchmark.rake +6 -0
- data/tasks/compile.rake +158 -0
- data/tasks/test.rake +100 -0
- data/tasks/util.rake +21 -0
- data/test/profile/.gitignore +1 -0
- data/test/profile/Gemfile +6 -0
- data/test/profile/benchmark.rb +195 -0
- data/test/setup.rb +178 -0
- data/test/test_arithmetic.rb +185 -0
- data/test/test_async.rb +316 -0
- data/test/test_bucket.rb +250 -0
- data/test/test_cas.rb +235 -0
- data/test/test_couchbase.rb +77 -0
- data/test/test_couchbase_connection_pool.rb +77 -0
- data/test/test_couchbase_rails_cache_store.rb +361 -0
- data/test/test_delete.rb +120 -0
- data/test/test_errors.rb +82 -0
- data/test/test_eventmachine.rb +70 -0
- data/test/test_format.rb +164 -0
- data/test/test_get.rb +407 -0
- data/test/test_stats.rb +57 -0
- data/test/test_store.rb +216 -0
- data/test/test_timer.rb +42 -0
- data/test/test_touch.rb +97 -0
- data/test/test_unlock.rb +119 -0
- data/test/test_utils.rb +58 -0
- data/test/test_version.rb +52 -0
- metadata +336 -0
@@ -0,0 +1,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(¶ms, 0, sizeof(struct cb_params_st));
|
121
|
+
rb_scan_args(argc, argv, "0*&", ¶ms.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(¶ms);
|
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(¶ms);
|
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(¶ms, 0, sizeof(struct cb_params_st));
|
128
|
+
rb_scan_args(argc, argv, "0*&", ¶ms.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(¶ms);
|
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(¶ms);
|
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
|
+
|