couchbase 0.9.8 → 1.0.0
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 +8 -0
- data/.yardopts +5 -0
- data/HISTORY.markdown +14 -10
- data/README.markdown +293 -98
- data/Rakefile +19 -24
- data/couchbase.gemspec +25 -7
- data/ext/couchbase_ext/couchbase_ext.c +2332 -0
- data/ext/couchbase_ext/extconf.rb +102 -0
- data/lib/couchbase.rb +20 -30
- data/lib/couchbase/bucket.rb +43 -112
- data/lib/couchbase/version.rb +3 -2
- data/tasks/benchmark.rake +6 -0
- data/tasks/compile.rake +52 -0
- data/tasks/doc.rake +27 -0
- data/tasks/test.rake +94 -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 +107 -18
- data/test/test_arithmetic.rb +98 -0
- data/test/test_async.rb +211 -0
- data/test/test_bucket.rb +126 -23
- data/test/test_cas.rb +59 -0
- data/test/test_couchbase.rb +22 -3
- data/test/test_delete.rb +63 -0
- data/test/test_errors.rb +82 -0
- data/test/test_flush.rb +49 -0
- data/test/test_format.rb +98 -0
- data/test/test_get.rb +236 -0
- data/test/test_stats.rb +53 -0
- data/test/test_store.rb +186 -0
- data/test/test_touch.rb +57 -0
- data/test/test_version.rb +17 -0
- metadata +72 -58
- data/lib/couchbase/couchdb.rb +0 -107
- data/lib/couchbase/document.rb +0 -71
- data/lib/couchbase/http_status.rb +0 -118
- data/lib/couchbase/latch.rb +0 -71
- data/lib/couchbase/memcached.rb +0 -372
- data/lib/couchbase/node.rb +0 -49
- data/lib/couchbase/rest_client.rb +0 -124
- data/lib/couchbase/view.rb +0 -182
- data/test/support/buckets-config.json +0 -843
- data/test/support/sample_design_doc.json +0 -9
- data/test/test_couchdb.rb +0 -98
- data/test/test_document.rb +0 -11
- data/test/test_latch.rb +0 -88
- data/test/test_memcached.rb +0 -59
- data/test/test_rest_client.rb +0 -14
- data/test/test_view.rb +0 -98
data/Rakefile
CHANGED
@@ -1,27 +1,22 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
1
|
+
# Author:: Couchbase <info@couchbase.com>
|
2
|
+
# Copyright:: 2011, 2012 Couchbase, Inc.
|
3
|
+
# License:: Apache License, Version 2.0
|
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
|
+
#
|
15
17
|
|
16
|
-
|
17
|
-
pkg.need_zip = true
|
18
|
-
pkg.need_tar = true
|
19
|
-
end
|
20
|
-
|
21
|
-
desc 'Start an irb session and load the library.'
|
22
|
-
task :console do
|
23
|
-
exec "irb -I lib -rcouchbase"
|
24
|
-
end
|
18
|
+
require 'bundler/gem_tasks'
|
25
19
|
|
26
|
-
|
20
|
+
Dir['tasks/*.rake'].sort.each { |f| load f }
|
27
21
|
|
22
|
+
task :default => [:clobber, :compile, :test]
|
data/couchbase.gemspec
CHANGED
@@ -1,4 +1,21 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
+
# Author:: Couchbase <info@couchbase.com>
|
3
|
+
# Copyright:: 2011, 2012 Couchbase, Inc.
|
4
|
+
# License:: Apache License, Version 2.0
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
18
|
+
|
2
19
|
$:.push File.expand_path('../lib', __FILE__)
|
3
20
|
require 'couchbase/version'
|
4
21
|
|
@@ -6,7 +23,7 @@ Gem::Specification.new do |s|
|
|
6
23
|
s.name = 'couchbase'
|
7
24
|
s.version = Couchbase::VERSION
|
8
25
|
s.author = 'Couchbase'
|
9
|
-
s.email = '
|
26
|
+
s.email = 'support@couchbase.com'
|
10
27
|
s.license = 'ASL-2'
|
11
28
|
s.homepage = 'http://couchbase.org'
|
12
29
|
s.summary = %q{Couchbase ruby driver}
|
@@ -15,14 +32,15 @@ Gem::Specification.new do |s|
|
|
15
32
|
s.files = `git ls-files`.split("\n")
|
16
33
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
17
34
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
35
|
+
s.extensions = `git ls-files -- ext/**/extconf.rb`.split("\n")
|
18
36
|
s.require_paths = ['lib']
|
19
37
|
|
20
|
-
s.add_runtime_dependency '
|
21
|
-
s.add_runtime_dependency 'yajl-ruby', '~> 0.8.2'
|
22
|
-
s.add_runtime_dependency 'curb', '~> 0.7.15'
|
23
|
-
s.add_runtime_dependency 'yaji', '~> 0.0.9'
|
38
|
+
s.add_runtime_dependency 'yajl-ruby', '~> 1.1.0'
|
24
39
|
|
25
|
-
s.add_development_dependency 'rake'
|
40
|
+
s.add_development_dependency 'rake', '~> 0.8.7'
|
26
41
|
s.add_development_dependency 'minitest'
|
27
|
-
s.add_development_dependency '
|
42
|
+
s.add_development_dependency 'rake-compiler', '>= 0.7.5'
|
43
|
+
s.add_development_dependency 'rdiscount'
|
44
|
+
s.add_development_dependency 'yard'
|
45
|
+
s.add_development_dependency RUBY_VERSION =~ /^1\.9/ ? 'ruby-debug19' : 'ruby-debug'
|
28
46
|
end
|
@@ -0,0 +1,2332 @@
|
|
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 <ruby.h>
|
19
|
+
#ifndef RUBY_ST_H
|
20
|
+
#include <st.h>
|
21
|
+
#endif
|
22
|
+
|
23
|
+
#include <libcouchbase/couchbase.h>
|
24
|
+
#include <event.h>
|
25
|
+
#include "couchbase_config.h"
|
26
|
+
|
27
|
+
#ifdef HAVE_STDARG_PROTOTYPES
|
28
|
+
#include <stdarg.h>
|
29
|
+
#define va_init_list(a,b) va_start(a,b)
|
30
|
+
#else
|
31
|
+
#include <varargs.h>
|
32
|
+
#define va_init_list(a,b) va_start(a)
|
33
|
+
#endif
|
34
|
+
|
35
|
+
#define debug_object(OBJ) \
|
36
|
+
rb_funcall(rb_stderr, rb_intern("print"), 1, rb_funcall(OBJ, rb_intern("object_id"), 0)); \
|
37
|
+
rb_funcall(rb_stderr, rb_intern("print"), 1, rb_str_new2(" ")); \
|
38
|
+
rb_funcall(rb_stderr, rb_intern("print"), 1, rb_funcall(OBJ, rb_intern("class"), 0)); \
|
39
|
+
rb_funcall(rb_stderr, rb_intern("print"), 1, rb_str_new2(" ")); \
|
40
|
+
rb_funcall(rb_stderr, rb_intern("puts"), 1, rb_funcall(OBJ, rb_intern("inspect"), 0));
|
41
|
+
|
42
|
+
#define FMT_MASK 0x3
|
43
|
+
#define FMT_DOCUMENT 0x0
|
44
|
+
#define FMT_MARSHAL 0x1
|
45
|
+
#define FMT_PLAIN 0x2
|
46
|
+
|
47
|
+
typedef struct
|
48
|
+
{
|
49
|
+
libcouchbase_t handle;
|
50
|
+
struct libcouchbase_io_opt_st *io;
|
51
|
+
uint16_t port;
|
52
|
+
char *authority;
|
53
|
+
char *hostname;
|
54
|
+
char *pool;
|
55
|
+
char *bucket;
|
56
|
+
char *username;
|
57
|
+
char *password;
|
58
|
+
int async;
|
59
|
+
int quiet;
|
60
|
+
long seqno;
|
61
|
+
VALUE default_format; /* should update +default_flags+ on change */
|
62
|
+
uint32_t default_flags;
|
63
|
+
uint32_t default_ttl;
|
64
|
+
VALUE exception; /* error delivered by error_callback */
|
65
|
+
VALUE on_error_proc; /* is using to deliver errors in async mode */
|
66
|
+
} bucket_t;
|
67
|
+
|
68
|
+
typedef struct
|
69
|
+
{
|
70
|
+
bucket_t* bucket;
|
71
|
+
int extended;
|
72
|
+
VALUE proc;
|
73
|
+
void *rv;
|
74
|
+
VALUE exception;
|
75
|
+
int quiet;
|
76
|
+
int arithm; /* incr: +1, decr: -1, other: 0 */
|
77
|
+
} context_t;
|
78
|
+
|
79
|
+
struct key_traits
|
80
|
+
{
|
81
|
+
VALUE keys_ary;
|
82
|
+
size_t nkeys;
|
83
|
+
char **keys;
|
84
|
+
size_t *lens;
|
85
|
+
time_t *ttls;
|
86
|
+
int extended;
|
87
|
+
int explicit_ttl;
|
88
|
+
int quiet;
|
89
|
+
};
|
90
|
+
|
91
|
+
static VALUE mCouchbase, mError, mJSON, mMarshal, cBucket, cResult;
|
92
|
+
static VALUE object_space;
|
93
|
+
|
94
|
+
static ID sym_add,
|
95
|
+
sym_append,
|
96
|
+
sym_bucket,
|
97
|
+
sym_cas,
|
98
|
+
sym_create,
|
99
|
+
sym_decrement,
|
100
|
+
sym_default_flags,
|
101
|
+
sym_default_format,
|
102
|
+
sym_delete,
|
103
|
+
sym_document,
|
104
|
+
sym_extended,
|
105
|
+
sym_flags,
|
106
|
+
sym_flush,
|
107
|
+
sym_format,
|
108
|
+
sym_get,
|
109
|
+
sym_hostname,
|
110
|
+
sym_increment,
|
111
|
+
sym_initial,
|
112
|
+
sym_marshal,
|
113
|
+
sym_password,
|
114
|
+
sym_plain,
|
115
|
+
sym_pool,
|
116
|
+
sym_port,
|
117
|
+
sym_prepend,
|
118
|
+
sym_quiet,
|
119
|
+
sym_replace,
|
120
|
+
sym_set,
|
121
|
+
sym_stats,
|
122
|
+
sym_touch,
|
123
|
+
sym_ttl,
|
124
|
+
sym_username,
|
125
|
+
id_arity,
|
126
|
+
id_call,
|
127
|
+
id_dump,
|
128
|
+
id_flatten_bang,
|
129
|
+
id_has_key_p,
|
130
|
+
id_load,
|
131
|
+
id_to_s,
|
132
|
+
id_iv_authority,
|
133
|
+
id_iv_bucket,
|
134
|
+
id_iv_cas,
|
135
|
+
id_iv_default_flags,
|
136
|
+
id_iv_default_format,
|
137
|
+
id_iv_error,
|
138
|
+
id_iv_flags,
|
139
|
+
id_iv_hostname,
|
140
|
+
id_iv_key,
|
141
|
+
id_iv_node,
|
142
|
+
id_iv_on_error,
|
143
|
+
id_iv_operation,
|
144
|
+
id_iv_password,
|
145
|
+
id_iv_pool,
|
146
|
+
id_iv_port,
|
147
|
+
id_iv_quiet,
|
148
|
+
id_iv_url,
|
149
|
+
id_iv_username,
|
150
|
+
id_iv_value;
|
151
|
+
|
152
|
+
/* base error */
|
153
|
+
static VALUE eBaseError;
|
154
|
+
static VALUE eValueFormatError;
|
155
|
+
|
156
|
+
/* libcouchbase errors */
|
157
|
+
/*LIBCOUCHBASE_SUCCESS = 0x00*/
|
158
|
+
/*LIBCOUCHBASE_AUTH_CONTINUE = 0x01*/
|
159
|
+
static VALUE eAuthError; /*LIBCOUCHBASE_AUTH_ERROR = 0x02*/
|
160
|
+
static VALUE eDeltaBadvalError; /*LIBCOUCHBASE_DELTA_BADVAL = 0x03*/
|
161
|
+
static VALUE eTooBigError; /*LIBCOUCHBASE_E2BIG = 0x04*/
|
162
|
+
static VALUE eBusyError; /*LIBCOUCHBASE_EBUSY = 0x05*/
|
163
|
+
static VALUE eInternalError; /*LIBCOUCHBASE_EINTERNAL = 0x06*/
|
164
|
+
static VALUE eInvalidError; /*LIBCOUCHBASE_EINVAL = 0x07*/
|
165
|
+
static VALUE eNoMemoryError; /*LIBCOUCHBASE_ENOMEM = 0x08*/
|
166
|
+
static VALUE eRangeError; /*LIBCOUCHBASE_ERANGE = 0x09*/
|
167
|
+
static VALUE eLibcouchbaseError; /*LIBCOUCHBASE_ERROR = 0x0a*/
|
168
|
+
static VALUE eTmpFailError; /*LIBCOUCHBASE_ETMPFAIL = 0x0b*/
|
169
|
+
static VALUE eKeyExistsError; /*LIBCOUCHBASE_KEY_EEXISTS = 0x0c*/
|
170
|
+
static VALUE eNotFoundError; /*LIBCOUCHBASE_KEY_ENOENT = 0x0d*/
|
171
|
+
static VALUE eLibeventError; /*LIBCOUCHBASE_LIBEVENT_ERROR = 0x0e*/
|
172
|
+
static VALUE eNetworkError; /*LIBCOUCHBASE_NETWORK_ERROR = 0x0f*/
|
173
|
+
static VALUE eNotMyVbucketError; /*LIBCOUCHBASE_NOT_MY_VBUCKET = 0x10*/
|
174
|
+
static VALUE eNotStoredError; /*LIBCOUCHBASE_NOT_STORED = 0x11*/
|
175
|
+
static VALUE eNotSupportedError; /*LIBCOUCHBASE_NOT_SUPPORTED = 0x12*/
|
176
|
+
static VALUE eUnknownCommandError; /*LIBCOUCHBASE_UNKNOWN_COMMAND = 0x13*/
|
177
|
+
static VALUE eUnknownHostError; /*LIBCOUCHBASE_UNKNOWN_HOST = 0x14*/
|
178
|
+
static VALUE eProtocolError; /*LIBCOUCHBASE_PROTOCOL_ERROR = 0x15*/
|
179
|
+
|
180
|
+
static VALUE
|
181
|
+
cb_proc_call(VALUE recv, int argc, ...)
|
182
|
+
{
|
183
|
+
VALUE *argv;
|
184
|
+
va_list ar;
|
185
|
+
int arity;
|
186
|
+
int ii;
|
187
|
+
|
188
|
+
arity = FIX2INT(rb_funcall(recv, id_arity, 0));
|
189
|
+
if (arity > 0) {
|
190
|
+
va_init_list(ar, argc);
|
191
|
+
argv = ALLOCA_N(VALUE, argc);
|
192
|
+
for (ii = 0; ii < arity; ++ii) {
|
193
|
+
if (ii < argc) {
|
194
|
+
argv[ii] = va_arg(ar, VALUE);
|
195
|
+
} else {
|
196
|
+
argv[ii] = Qnil;
|
197
|
+
}
|
198
|
+
}
|
199
|
+
va_end(ar);
|
200
|
+
} else {
|
201
|
+
arity = 0;
|
202
|
+
argv = NULL;
|
203
|
+
}
|
204
|
+
return rb_funcall2(recv, id_call, arity, argv);
|
205
|
+
}
|
206
|
+
|
207
|
+
/* Helper to conver return code from libcouchbase to meaningful exception.
|
208
|
+
* Returns nil if the code considering successful and exception object
|
209
|
+
* otherwise. Store given string to exceptions as message, and also
|
210
|
+
* initialize +error+ attribute with given return code. */
|
211
|
+
static VALUE
|
212
|
+
cb_check_error(libcouchbase_error_t rc, const char *msg, VALUE key)
|
213
|
+
{
|
214
|
+
VALUE klass, exc, str;
|
215
|
+
char buf[300];
|
216
|
+
|
217
|
+
if (rc == LIBCOUCHBASE_SUCCESS || rc == LIBCOUCHBASE_AUTH_CONTINUE) {
|
218
|
+
return Qnil;
|
219
|
+
}
|
220
|
+
switch (rc) {
|
221
|
+
case LIBCOUCHBASE_AUTH_ERROR:
|
222
|
+
klass = eAuthError;
|
223
|
+
break;
|
224
|
+
case LIBCOUCHBASE_DELTA_BADVAL:
|
225
|
+
klass = eDeltaBadvalError;
|
226
|
+
break;
|
227
|
+
case LIBCOUCHBASE_E2BIG:
|
228
|
+
klass = eTooBigError;
|
229
|
+
break;
|
230
|
+
case LIBCOUCHBASE_EBUSY:
|
231
|
+
klass = eBusyError;
|
232
|
+
break;
|
233
|
+
case LIBCOUCHBASE_EINTERNAL:
|
234
|
+
klass = eInternalError;
|
235
|
+
break;
|
236
|
+
case LIBCOUCHBASE_EINVAL:
|
237
|
+
klass = eInvalidError;
|
238
|
+
break;
|
239
|
+
case LIBCOUCHBASE_ENOMEM:
|
240
|
+
klass = eNoMemoryError;
|
241
|
+
break;
|
242
|
+
case LIBCOUCHBASE_ERANGE:
|
243
|
+
klass = eRangeError;
|
244
|
+
break;
|
245
|
+
case LIBCOUCHBASE_ETMPFAIL:
|
246
|
+
klass = eTmpFailError;
|
247
|
+
break;
|
248
|
+
case LIBCOUCHBASE_KEY_EEXISTS:
|
249
|
+
klass = eKeyExistsError;
|
250
|
+
break;
|
251
|
+
case LIBCOUCHBASE_KEY_ENOENT:
|
252
|
+
klass = eNotFoundError;
|
253
|
+
break;
|
254
|
+
case LIBCOUCHBASE_LIBEVENT_ERROR:
|
255
|
+
klass = eLibeventError;
|
256
|
+
break;
|
257
|
+
case LIBCOUCHBASE_NETWORK_ERROR:
|
258
|
+
klass = eNetworkError;
|
259
|
+
break;
|
260
|
+
case LIBCOUCHBASE_NOT_MY_VBUCKET:
|
261
|
+
klass = eNotMyVbucketError;
|
262
|
+
break;
|
263
|
+
case LIBCOUCHBASE_NOT_STORED:
|
264
|
+
klass = eNotStoredError;
|
265
|
+
break;
|
266
|
+
case LIBCOUCHBASE_NOT_SUPPORTED:
|
267
|
+
klass = eNotSupportedError;
|
268
|
+
break;
|
269
|
+
case LIBCOUCHBASE_UNKNOWN_COMMAND:
|
270
|
+
klass = eUnknownCommandError;
|
271
|
+
break;
|
272
|
+
case LIBCOUCHBASE_UNKNOWN_HOST:
|
273
|
+
klass = eUnknownHostError;
|
274
|
+
break;
|
275
|
+
case LIBCOUCHBASE_PROTOCOL_ERROR:
|
276
|
+
klass = eProtocolError;
|
277
|
+
case LIBCOUCHBASE_ERROR:
|
278
|
+
/* fall through */
|
279
|
+
default:
|
280
|
+
klass = eLibcouchbaseError;
|
281
|
+
}
|
282
|
+
|
283
|
+
str = rb_str_buf_new2(msg ? msg : "");
|
284
|
+
rb_str_buf_cat2(str, " (");
|
285
|
+
if (key != Qnil) {
|
286
|
+
snprintf(buf, 300, "key=\"%s\", ", RSTRING_PTR(key));
|
287
|
+
rb_str_buf_cat2(str, buf);
|
288
|
+
}
|
289
|
+
snprintf(buf, 300, "error=0x%x)", rc);
|
290
|
+
rb_str_buf_cat2(str, buf);
|
291
|
+
exc = rb_exc_new3(klass, str);
|
292
|
+
rb_ivar_set(exc, id_iv_error, INT2FIX(rc));
|
293
|
+
rb_ivar_set(exc, id_iv_key, key);
|
294
|
+
rb_ivar_set(exc, id_iv_cas, Qnil);
|
295
|
+
rb_ivar_set(exc, id_iv_operation, Qnil);
|
296
|
+
return exc;
|
297
|
+
}
|
298
|
+
|
299
|
+
static inline uint32_t
|
300
|
+
flags_set_format(uint32_t flags, ID format)
|
301
|
+
{
|
302
|
+
flags &= ~((uint32_t)FMT_MASK); /* clear format bits */
|
303
|
+
|
304
|
+
if (format == sym_document) {
|
305
|
+
return flags | FMT_DOCUMENT;
|
306
|
+
} else if (format == sym_marshal) {
|
307
|
+
return flags | FMT_MARSHAL;
|
308
|
+
} else if (format == sym_plain) {
|
309
|
+
return flags | FMT_PLAIN;
|
310
|
+
}
|
311
|
+
return flags; /* document is the default */
|
312
|
+
}
|
313
|
+
|
314
|
+
static inline ID
|
315
|
+
flags_get_format(uint32_t flags)
|
316
|
+
{
|
317
|
+
flags &= FMT_MASK; /* select format bits */
|
318
|
+
|
319
|
+
switch (flags) {
|
320
|
+
case FMT_DOCUMENT:
|
321
|
+
return sym_document;
|
322
|
+
case FMT_MARSHAL:
|
323
|
+
return sym_marshal;
|
324
|
+
case FMT_PLAIN:
|
325
|
+
/* fall through */
|
326
|
+
default:
|
327
|
+
/* all other formats treated as plain */
|
328
|
+
return sym_plain;
|
329
|
+
}
|
330
|
+
}
|
331
|
+
|
332
|
+
|
333
|
+
static VALUE
|
334
|
+
do_encode(VALUE *args)
|
335
|
+
{
|
336
|
+
VALUE val = args[0];
|
337
|
+
uint32_t flags = ((uint32_t)args[1] & FMT_MASK);
|
338
|
+
|
339
|
+
switch (flags) {
|
340
|
+
case FMT_DOCUMENT:
|
341
|
+
return rb_funcall(mJSON, id_dump, 1, val);
|
342
|
+
case FMT_MARSHAL:
|
343
|
+
return rb_funcall(mMarshal, id_dump, 1, val);
|
344
|
+
case FMT_PLAIN:
|
345
|
+
/* fall through */
|
346
|
+
default:
|
347
|
+
/* all other formats treated as plain */
|
348
|
+
return val;
|
349
|
+
}
|
350
|
+
}
|
351
|
+
|
352
|
+
static VALUE
|
353
|
+
do_decode(VALUE *args)
|
354
|
+
{
|
355
|
+
VALUE blob = args[0];
|
356
|
+
uint32_t flags = ((uint32_t)args[1] & FMT_MASK);
|
357
|
+
|
358
|
+
switch (flags) {
|
359
|
+
case FMT_DOCUMENT:
|
360
|
+
return rb_funcall(mJSON, id_load, 1, blob);
|
361
|
+
case FMT_MARSHAL:
|
362
|
+
return rb_funcall(mMarshal, id_load, 1, blob);
|
363
|
+
case FMT_PLAIN:
|
364
|
+
/* fall through */
|
365
|
+
default:
|
366
|
+
/* all other formats treated as plain */
|
367
|
+
return blob;
|
368
|
+
}
|
369
|
+
}
|
370
|
+
|
371
|
+
static VALUE
|
372
|
+
coding_failed(void)
|
373
|
+
{
|
374
|
+
return Qundef;
|
375
|
+
}
|
376
|
+
|
377
|
+
static VALUE
|
378
|
+
encode_value(VALUE val, uint32_t flags)
|
379
|
+
{
|
380
|
+
VALUE blob, args[2];
|
381
|
+
|
382
|
+
args[0] = val;
|
383
|
+
args[1] = (VALUE)flags;
|
384
|
+
blob = rb_rescue(do_encode, (VALUE)args, coding_failed, 0);
|
385
|
+
/* it must be bytestring after all */
|
386
|
+
if (TYPE(blob) != T_STRING) {
|
387
|
+
return Qundef;
|
388
|
+
}
|
389
|
+
return blob;
|
390
|
+
}
|
391
|
+
|
392
|
+
static VALUE
|
393
|
+
decode_value(VALUE blob, uint32_t flags)
|
394
|
+
{
|
395
|
+
VALUE val, args[2];
|
396
|
+
|
397
|
+
/* first it must be bytestring */
|
398
|
+
if (TYPE(blob) != T_STRING) {
|
399
|
+
return Qundef;
|
400
|
+
}
|
401
|
+
args[0] = blob;
|
402
|
+
args[1] = (VALUE)flags;
|
403
|
+
val = rb_rescue(do_decode, (VALUE)args, coding_failed, 0);
|
404
|
+
return val;
|
405
|
+
}
|
406
|
+
|
407
|
+
static VALUE
|
408
|
+
unify_key(VALUE key)
|
409
|
+
{
|
410
|
+
switch (TYPE(key)) {
|
411
|
+
case T_STRING:
|
412
|
+
return key;
|
413
|
+
case T_SYMBOL:
|
414
|
+
return rb_str_new2(rb_id2name(SYM2ID(key)));
|
415
|
+
default: /* call #to_str or raise error */
|
416
|
+
return StringValue(key);
|
417
|
+
}
|
418
|
+
}
|
419
|
+
|
420
|
+
static int
|
421
|
+
cb_extract_keys_i(VALUE key, VALUE value, VALUE arg)
|
422
|
+
{
|
423
|
+
struct key_traits *traits = (struct key_traits *)arg;
|
424
|
+
key = unify_key(key);
|
425
|
+
rb_ary_push(traits->keys_ary, key);
|
426
|
+
traits->keys[traits->nkeys] = RSTRING_PTR(key);
|
427
|
+
traits->lens[traits->nkeys] = RSTRING_LEN(key);
|
428
|
+
traits->ttls[traits->nkeys] = NUM2ULONG(value);
|
429
|
+
traits->nkeys++;
|
430
|
+
return ST_CONTINUE;
|
431
|
+
}
|
432
|
+
|
433
|
+
static long
|
434
|
+
cb_args_scan_keys(long argc, VALUE argv, bucket_t *bucket, struct key_traits *traits)
|
435
|
+
{
|
436
|
+
VALUE arg, key, *keys_ptr, opts, ttl, ext;
|
437
|
+
long nn = 0, ii;
|
438
|
+
time_t exp;
|
439
|
+
|
440
|
+
traits->keys_ary = rb_ary_new();
|
441
|
+
traits->quiet = bucket->quiet;
|
442
|
+
if (argc == 1) {
|
443
|
+
arg = RARRAY_PTR(argv)[0];
|
444
|
+
switch (TYPE(arg)) {
|
445
|
+
case T_HASH:
|
446
|
+
/* hash of key-ttl pairs */
|
447
|
+
nn = RHASH_SIZE(arg);
|
448
|
+
traits->keys = calloc(nn, sizeof(char *));
|
449
|
+
traits->lens = calloc(nn, sizeof(size_t));
|
450
|
+
traits->explicit_ttl = 1;
|
451
|
+
traits->ttls = calloc(nn, sizeof(time_t));
|
452
|
+
rb_hash_foreach(arg, cb_extract_keys_i, (VALUE)traits);
|
453
|
+
break;
|
454
|
+
case T_STRING:
|
455
|
+
case T_SYMBOL:
|
456
|
+
/* single key with default expiration */
|
457
|
+
nn = traits->nkeys = 1;
|
458
|
+
traits->keys = calloc(nn, sizeof(char *));
|
459
|
+
traits->lens = calloc(nn, sizeof(size_t));
|
460
|
+
traits->ttls = calloc(nn, sizeof(time_t));
|
461
|
+
key = unify_key(arg);
|
462
|
+
rb_ary_push(traits->keys_ary, key);
|
463
|
+
traits->keys[0] = RSTRING_PTR(key);
|
464
|
+
traits->lens[0] = RSTRING_LEN(key);
|
465
|
+
traits->ttls[0] = bucket->default_ttl;
|
466
|
+
break;
|
467
|
+
}
|
468
|
+
} else if (argc > 1) {
|
469
|
+
/* keys with custom options */
|
470
|
+
opts = RARRAY_PTR(argv)[argc-1];
|
471
|
+
exp = bucket->default_ttl;
|
472
|
+
ext = Qfalse;
|
473
|
+
if (TYPE(opts) == T_HASH) {
|
474
|
+
(void)rb_ary_pop(argv);
|
475
|
+
if (RTEST(rb_funcall(opts, id_has_key_p, 1, sym_quiet))) {
|
476
|
+
traits->quiet = RTEST(rb_hash_aref(opts, sym_quiet));
|
477
|
+
}
|
478
|
+
ext = rb_hash_aref(opts, sym_extended);
|
479
|
+
ttl = rb_hash_aref(opts, sym_ttl);
|
480
|
+
if (ttl != Qnil) {
|
481
|
+
traits->explicit_ttl = 1;
|
482
|
+
exp = NUM2ULONG(ttl);
|
483
|
+
}
|
484
|
+
nn = RARRAY_LEN(argv);
|
485
|
+
} else {
|
486
|
+
nn = argc;
|
487
|
+
}
|
488
|
+
if (nn < 1) {
|
489
|
+
rb_raise(rb_eArgError, "must be at least one key");
|
490
|
+
}
|
491
|
+
traits->nkeys = nn;
|
492
|
+
traits->extended = RTEST(ext) ? 1 : 0;
|
493
|
+
traits->keys = calloc(nn, sizeof(char *));
|
494
|
+
traits->lens = calloc(nn, sizeof(size_t));
|
495
|
+
traits->ttls = calloc(nn, sizeof(time_t));
|
496
|
+
keys_ptr = RARRAY_PTR(argv);
|
497
|
+
for (ii = 0; ii < nn; ii++) {
|
498
|
+
key = unify_key(keys_ptr[ii]);
|
499
|
+
rb_ary_push(traits->keys_ary, key);
|
500
|
+
traits->keys[ii] = RSTRING_PTR(key);
|
501
|
+
traits->lens[ii] = RSTRING_LEN(key);
|
502
|
+
traits->ttls[ii] = exp;
|
503
|
+
}
|
504
|
+
}
|
505
|
+
|
506
|
+
return nn;
|
507
|
+
}
|
508
|
+
|
509
|
+
static void
|
510
|
+
error_callback(libcouchbase_t handle, libcouchbase_error_t error, const char *errinfo)
|
511
|
+
{
|
512
|
+
bucket_t *bucket = (bucket_t *)libcouchbase_get_cookie(handle);
|
513
|
+
|
514
|
+
bucket->io->stop_event_loop(bucket->io);
|
515
|
+
bucket->exception = cb_check_error(error, errinfo, Qnil);
|
516
|
+
}
|
517
|
+
|
518
|
+
static void
|
519
|
+
storage_callback(libcouchbase_t handle, const void *cookie,
|
520
|
+
libcouchbase_storage_t operation, libcouchbase_error_t error,
|
521
|
+
const void *key, size_t nkey, uint64_t cas)
|
522
|
+
{
|
523
|
+
context_t *ctx = (context_t *)cookie;
|
524
|
+
bucket_t *bucket = ctx->bucket;
|
525
|
+
VALUE k, c, *rv = ctx->rv, exc, res;
|
526
|
+
ID o;
|
527
|
+
|
528
|
+
bucket->seqno--;
|
529
|
+
|
530
|
+
k = rb_str_new((const char*)key, nkey);
|
531
|
+
c = cas > 0 ? ULL2NUM(cas) : Qnil;
|
532
|
+
switch(operation) {
|
533
|
+
case LIBCOUCHBASE_ADD:
|
534
|
+
o = sym_add;
|
535
|
+
break;
|
536
|
+
case LIBCOUCHBASE_REPLACE:
|
537
|
+
o = sym_replace;
|
538
|
+
break;
|
539
|
+
case LIBCOUCHBASE_SET:
|
540
|
+
o = sym_set;
|
541
|
+
break;
|
542
|
+
case LIBCOUCHBASE_APPEND:
|
543
|
+
o = sym_append;
|
544
|
+
break;
|
545
|
+
case LIBCOUCHBASE_PREPEND:
|
546
|
+
o = sym_prepend;
|
547
|
+
break;
|
548
|
+
default:
|
549
|
+
o = Qnil;
|
550
|
+
}
|
551
|
+
exc = cb_check_error(error, "failed to store value", k);
|
552
|
+
if (exc != Qnil) {
|
553
|
+
rb_ivar_set(exc, id_iv_cas, c);
|
554
|
+
rb_ivar_set(exc, id_iv_operation, o);
|
555
|
+
if (NIL_P(ctx->exception)) {
|
556
|
+
ctx->exception = exc;
|
557
|
+
}
|
558
|
+
}
|
559
|
+
if (bucket->async) { /* asynchronous */
|
560
|
+
if (ctx->proc != Qnil) {
|
561
|
+
res = rb_class_new_instance(0, NULL, cResult);
|
562
|
+
rb_ivar_set(res, id_iv_error, exc);
|
563
|
+
rb_ivar_set(res, id_iv_key, k);
|
564
|
+
rb_ivar_set(res, id_iv_operation, o);
|
565
|
+
rb_ivar_set(res, id_iv_cas, c);
|
566
|
+
cb_proc_call(ctx->proc, 1, res);
|
567
|
+
}
|
568
|
+
} else { /* synchronous */
|
569
|
+
*rv = c;
|
570
|
+
}
|
571
|
+
|
572
|
+
if (bucket->seqno == 0) {
|
573
|
+
bucket->io->stop_event_loop(bucket->io);
|
574
|
+
rb_hash_delete(object_space, ctx->proc|1);
|
575
|
+
}
|
576
|
+
(void)handle;
|
577
|
+
}
|
578
|
+
|
579
|
+
static void
|
580
|
+
delete_callback(libcouchbase_t handle, const void *cookie,
|
581
|
+
libcouchbase_error_t error, const void *key, size_t nkey)
|
582
|
+
{
|
583
|
+
context_t *ctx = (context_t *)cookie;
|
584
|
+
bucket_t *bucket = ctx->bucket;
|
585
|
+
VALUE k, *rv = ctx->rv, exc = Qnil, res;
|
586
|
+
|
587
|
+
bucket->seqno--;
|
588
|
+
|
589
|
+
k = rb_str_new((const char*)key, nkey);
|
590
|
+
if (error != LIBCOUCHBASE_KEY_ENOENT || !ctx->quiet) {
|
591
|
+
exc = cb_check_error(error, "failed to remove value", k);
|
592
|
+
if (exc != Qnil) {
|
593
|
+
rb_ivar_set(exc, id_iv_operation, sym_delete);
|
594
|
+
if (NIL_P(ctx->exception)) {
|
595
|
+
ctx->exception = exc;
|
596
|
+
}
|
597
|
+
}
|
598
|
+
}
|
599
|
+
if (bucket->async) { /* asynchronous */
|
600
|
+
if (ctx->proc != Qnil) {
|
601
|
+
res = rb_class_new_instance(0, NULL, cResult);
|
602
|
+
rb_ivar_set(res, id_iv_error, exc);
|
603
|
+
rb_ivar_set(res, id_iv_operation, sym_delete);
|
604
|
+
rb_ivar_set(res, id_iv_key, k);
|
605
|
+
cb_proc_call(ctx->proc, 1, res);
|
606
|
+
}
|
607
|
+
} else { /* synchronous */
|
608
|
+
*rv = (error == LIBCOUCHBASE_SUCCESS) ? Qtrue : Qfalse;
|
609
|
+
}
|
610
|
+
if (bucket->seqno == 0) {
|
611
|
+
bucket->io->stop_event_loop(bucket->io);
|
612
|
+
rb_hash_delete(object_space, ctx->proc|1);
|
613
|
+
}
|
614
|
+
(void)handle;
|
615
|
+
}
|
616
|
+
|
617
|
+
static void
|
618
|
+
get_callback(libcouchbase_t handle, const void *cookie,
|
619
|
+
libcouchbase_error_t error, const void *key, size_t nkey,
|
620
|
+
const void *bytes, size_t nbytes, uint32_t flags, uint64_t cas)
|
621
|
+
{
|
622
|
+
context_t *ctx = (context_t *)cookie;
|
623
|
+
bucket_t *bucket = ctx->bucket;
|
624
|
+
VALUE k, v, f, c, *rv = ctx->rv, exc = Qnil, res;
|
625
|
+
|
626
|
+
bucket->seqno--;
|
627
|
+
|
628
|
+
k = rb_str_new((const char*)key, nkey);
|
629
|
+
if (error != LIBCOUCHBASE_KEY_ENOENT || !ctx->quiet) {
|
630
|
+
exc = cb_check_error(error, "failed to get value", k);
|
631
|
+
if (exc != Qnil) {
|
632
|
+
rb_ivar_set(exc, id_iv_operation, sym_get);
|
633
|
+
if (NIL_P(ctx->exception)) {
|
634
|
+
ctx->exception = exc;
|
635
|
+
}
|
636
|
+
}
|
637
|
+
}
|
638
|
+
|
639
|
+
f = ULONG2NUM(flags);
|
640
|
+
c = ULL2NUM(cas);
|
641
|
+
if (nbytes != 0) {
|
642
|
+
v = decode_value(rb_str_new((const char*)bytes, nbytes), flags);
|
643
|
+
if (v == Qundef) {
|
644
|
+
ctx->exception = rb_exc_new2(eValueFormatError, "unable to convert value");
|
645
|
+
v = Qnil;
|
646
|
+
}
|
647
|
+
} else {
|
648
|
+
v = Qnil;
|
649
|
+
}
|
650
|
+
if (bucket->async) { /* asynchronous */
|
651
|
+
if (ctx->proc != Qnil) {
|
652
|
+
res = rb_class_new_instance(0, NULL, cResult);
|
653
|
+
rb_ivar_set(res, id_iv_error, exc);
|
654
|
+
rb_ivar_set(res, id_iv_operation, sym_get);
|
655
|
+
rb_ivar_set(res, id_iv_key, k);
|
656
|
+
rb_ivar_set(res, id_iv_value, v);
|
657
|
+
rb_ivar_set(res, id_iv_flags, f);
|
658
|
+
rb_ivar_set(res, id_iv_cas, c);
|
659
|
+
cb_proc_call(ctx->proc, 1, res);
|
660
|
+
}
|
661
|
+
} else { /* synchronous */
|
662
|
+
if (NIL_P(exc) && v != Qnil) {
|
663
|
+
if (ctx->extended) {
|
664
|
+
rb_hash_aset(*rv, k, rb_ary_new3(3, v, f, c));
|
665
|
+
} else {
|
666
|
+
rb_hash_aset(*rv, k, v);
|
667
|
+
}
|
668
|
+
}
|
669
|
+
}
|
670
|
+
|
671
|
+
if (bucket->seqno == 0) {
|
672
|
+
bucket->io->stop_event_loop(bucket->io);
|
673
|
+
rb_hash_delete(object_space, ctx->proc|1);
|
674
|
+
}
|
675
|
+
(void)handle;
|
676
|
+
}
|
677
|
+
|
678
|
+
static void
|
679
|
+
flush_callback(libcouchbase_t handle, const void* cookie,
|
680
|
+
const char* authority, libcouchbase_error_t error)
|
681
|
+
{
|
682
|
+
context_t *ctx = (context_t *)cookie;
|
683
|
+
bucket_t *bucket = ctx->bucket;
|
684
|
+
VALUE node, success = Qtrue, *rv = ctx->rv, exc, res;
|
685
|
+
|
686
|
+
node = authority ? rb_str_new2(authority) : Qnil;
|
687
|
+
exc = cb_check_error(error, "failed to flush bucket", node);
|
688
|
+
if (exc != Qnil) {
|
689
|
+
rb_ivar_set(exc, id_iv_operation, sym_flush);
|
690
|
+
if (NIL_P(ctx->exception)) {
|
691
|
+
ctx->exception = exc;
|
692
|
+
}
|
693
|
+
success = Qfalse;
|
694
|
+
}
|
695
|
+
|
696
|
+
if (authority) {
|
697
|
+
if (bucket->async) { /* asynchronous */
|
698
|
+
if (ctx->proc != Qnil) {
|
699
|
+
res = rb_class_new_instance(0, NULL, cResult);
|
700
|
+
rb_ivar_set(res, id_iv_error, exc);
|
701
|
+
rb_ivar_set(res, id_iv_operation, sym_flush);
|
702
|
+
rb_ivar_set(res, id_iv_node, node);
|
703
|
+
cb_proc_call(ctx->proc, 1, res);
|
704
|
+
}
|
705
|
+
} else { /* synchronous */
|
706
|
+
if (RTEST(*rv)) {
|
707
|
+
/* rewrite status for positive values only */
|
708
|
+
*rv = success;
|
709
|
+
}
|
710
|
+
}
|
711
|
+
} else {
|
712
|
+
bucket->seqno--;
|
713
|
+
if (bucket->seqno == 0) {
|
714
|
+
bucket->io->stop_event_loop(bucket->io);
|
715
|
+
rb_hash_delete(object_space, ctx->proc|1);
|
716
|
+
}
|
717
|
+
}
|
718
|
+
|
719
|
+
(void)handle;
|
720
|
+
}
|
721
|
+
|
722
|
+
static void
|
723
|
+
stat_callback(libcouchbase_t handle, const void* cookie,
|
724
|
+
const char* authority, libcouchbase_error_t error, const void* key,
|
725
|
+
size_t nkey, const void* bytes, size_t nbytes)
|
726
|
+
{
|
727
|
+
context_t *ctx = (context_t *)cookie;
|
728
|
+
bucket_t *bucket = ctx->bucket;
|
729
|
+
VALUE stats, node, k, v, *rv = ctx->rv, exc = Qnil, res;
|
730
|
+
|
731
|
+
node = authority ? rb_str_new2(authority) : Qnil;
|
732
|
+
exc = cb_check_error(error, "failed to fetch stats", node);
|
733
|
+
if (exc != Qnil) {
|
734
|
+
rb_ivar_set(exc, id_iv_operation, sym_stats);
|
735
|
+
if (NIL_P(ctx->exception)) {
|
736
|
+
ctx->exception = exc;
|
737
|
+
}
|
738
|
+
}
|
739
|
+
if (authority) {
|
740
|
+
k = rb_str_new((const char*)key, nkey);
|
741
|
+
v = rb_str_new((const char*)bytes, nbytes);
|
742
|
+
if (bucket->async) { /* asynchronous */
|
743
|
+
if (ctx->proc != Qnil) {
|
744
|
+
res = rb_class_new_instance(0, NULL, cResult);
|
745
|
+
rb_ivar_set(res, id_iv_error, exc);
|
746
|
+
rb_ivar_set(res, id_iv_operation, sym_stats);
|
747
|
+
rb_ivar_set(res, id_iv_node, node);
|
748
|
+
rb_ivar_set(res, id_iv_key, k);
|
749
|
+
rb_ivar_set(res, id_iv_value, v);
|
750
|
+
cb_proc_call(ctx->proc, 1, res);
|
751
|
+
}
|
752
|
+
} else { /* synchronous */
|
753
|
+
if (NIL_P(exc)) {
|
754
|
+
stats = rb_hash_aref(*rv, node);
|
755
|
+
if (NIL_P(stats)) {
|
756
|
+
stats = rb_hash_new();
|
757
|
+
rb_hash_aset(*rv, node, stats);
|
758
|
+
}
|
759
|
+
rb_hash_aset(stats, k, v);
|
760
|
+
}
|
761
|
+
}
|
762
|
+
} else {
|
763
|
+
bucket->seqno--;
|
764
|
+
if (bucket->seqno == 0) {
|
765
|
+
bucket->io->stop_event_loop(bucket->io);
|
766
|
+
rb_hash_delete(object_space, ctx->proc|1);
|
767
|
+
}
|
768
|
+
}
|
769
|
+
(void)handle;
|
770
|
+
}
|
771
|
+
|
772
|
+
static void
|
773
|
+
touch_callback(libcouchbase_t handle, const void *cookie,
|
774
|
+
libcouchbase_error_t error, const void *key, size_t nkey)
|
775
|
+
{
|
776
|
+
context_t *ctx = (context_t *)cookie;
|
777
|
+
bucket_t *bucket = ctx->bucket;
|
778
|
+
VALUE k, success, *rv = ctx->rv, exc = Qnil, res;
|
779
|
+
|
780
|
+
bucket->seqno--;
|
781
|
+
k = rb_str_new((const char*)key, nkey);
|
782
|
+
if (error != LIBCOUCHBASE_KEY_ENOENT || !ctx->quiet) {
|
783
|
+
exc = cb_check_error(error, "failed to touch value", k);
|
784
|
+
if (exc != Qnil) {
|
785
|
+
rb_ivar_set(exc, id_iv_operation, sym_touch);
|
786
|
+
if (NIL_P(ctx->exception)) {
|
787
|
+
ctx->exception = exc;
|
788
|
+
}
|
789
|
+
}
|
790
|
+
}
|
791
|
+
|
792
|
+
if (bucket->async) { /* asynchronous */
|
793
|
+
if (ctx->proc != Qnil) {
|
794
|
+
res = rb_class_new_instance(0, NULL, cResult);
|
795
|
+
rb_ivar_set(res, id_iv_error, exc);
|
796
|
+
rb_ivar_set(res, id_iv_operation, sym_touch);
|
797
|
+
rb_ivar_set(res, id_iv_key, k);
|
798
|
+
cb_proc_call(ctx->proc, 1, res);
|
799
|
+
}
|
800
|
+
} else { /* synchronous */
|
801
|
+
if (NIL_P(exc)) {
|
802
|
+
success = (error == LIBCOUCHBASE_KEY_ENOENT) ? Qfalse : Qtrue;
|
803
|
+
rb_ary_push(*rv, success);
|
804
|
+
}
|
805
|
+
}
|
806
|
+
if (bucket->seqno == 0) {
|
807
|
+
bucket->io->stop_event_loop(bucket->io);
|
808
|
+
rb_hash_delete(object_space, ctx->proc|1);
|
809
|
+
}
|
810
|
+
(void)handle;
|
811
|
+
}
|
812
|
+
|
813
|
+
static void
|
814
|
+
arithmetic_callback(libcouchbase_t handle, const void *cookie,
|
815
|
+
libcouchbase_error_t error, const void *key, size_t nkey,
|
816
|
+
uint64_t value, uint64_t cas)
|
817
|
+
{
|
818
|
+
context_t *ctx = (context_t *)cookie;
|
819
|
+
bucket_t *bucket = ctx->bucket;
|
820
|
+
VALUE c, k, v, *rv = ctx->rv, exc, res;
|
821
|
+
ID o;
|
822
|
+
|
823
|
+
bucket->seqno--;
|
824
|
+
|
825
|
+
k = rb_str_new((const char*)key, nkey);
|
826
|
+
c = cas > 0 ? ULL2NUM(cas) : Qnil;
|
827
|
+
o = ctx->arithm > 0 ? sym_increment : sym_decrement;
|
828
|
+
exc = cb_check_error(error, "failed to perform arithmetic operation", k);
|
829
|
+
if (exc != Qnil) {
|
830
|
+
rb_ivar_set(exc, id_iv_cas, c);
|
831
|
+
rb_ivar_set(exc, id_iv_operation, o);
|
832
|
+
if (bucket->async) {
|
833
|
+
if (bucket->on_error_proc != Qnil) {
|
834
|
+
cb_proc_call(bucket->on_error_proc, 3, o, k, exc);
|
835
|
+
} else {
|
836
|
+
if (NIL_P(bucket->exception)) {
|
837
|
+
bucket->exception = exc;
|
838
|
+
}
|
839
|
+
}
|
840
|
+
}
|
841
|
+
if (NIL_P(ctx->exception)) {
|
842
|
+
ctx->exception = exc;
|
843
|
+
}
|
844
|
+
}
|
845
|
+
v = ULL2NUM(value);
|
846
|
+
if (bucket->async) { /* asynchronous */
|
847
|
+
if (ctx->proc != Qnil) {
|
848
|
+
res = rb_class_new_instance(0, NULL, cResult);
|
849
|
+
rb_ivar_set(res, id_iv_error, exc);
|
850
|
+
rb_ivar_set(res, id_iv_operation, o);
|
851
|
+
rb_ivar_set(res, id_iv_key, k);
|
852
|
+
rb_ivar_set(res, id_iv_value, v);
|
853
|
+
rb_ivar_set(res, id_iv_cas, c);
|
854
|
+
cb_proc_call(ctx->proc, 1, res);
|
855
|
+
}
|
856
|
+
} else { /* synchronous */
|
857
|
+
if (NIL_P(exc)) {
|
858
|
+
if (ctx->extended) {
|
859
|
+
*rv = rb_ary_new3(2, v, c);
|
860
|
+
} else {
|
861
|
+
*rv = v;
|
862
|
+
}
|
863
|
+
}
|
864
|
+
}
|
865
|
+
if (bucket->seqno == 0) {
|
866
|
+
bucket->io->stop_event_loop(bucket->io);
|
867
|
+
rb_hash_delete(object_space, ctx->proc|1);
|
868
|
+
}
|
869
|
+
(void)handle;
|
870
|
+
}
|
871
|
+
|
872
|
+
static char *
|
873
|
+
parse_path_segment(char *source, const char *key, char **result)
|
874
|
+
{
|
875
|
+
size_t len;
|
876
|
+
char *eot;
|
877
|
+
|
878
|
+
if (source == NULL) {
|
879
|
+
return NULL;
|
880
|
+
}
|
881
|
+
eot = strchr(source, '/');
|
882
|
+
if (eot > source && strncmp(source, key, eot - source) == 0) {
|
883
|
+
*eot = '\0';
|
884
|
+
source = eot + 1;
|
885
|
+
eot = strchr(source, '/');
|
886
|
+
len = strlen(source);
|
887
|
+
if (eot > source || len) {
|
888
|
+
if (eot) {
|
889
|
+
*eot = '\0';
|
890
|
+
eot++;
|
891
|
+
}
|
892
|
+
*result = strdup(source);
|
893
|
+
}
|
894
|
+
}
|
895
|
+
return eot;
|
896
|
+
}
|
897
|
+
|
898
|
+
static void
|
899
|
+
parse_bucket_uri(VALUE uri, bucket_t *bucket)
|
900
|
+
{
|
901
|
+
char *src, *ptr, *eot, sep = '\0';
|
902
|
+
|
903
|
+
ptr = src = strdup(StringValueCStr(uri));
|
904
|
+
eot = strchr(ptr, ':');
|
905
|
+
if (eot < ptr || strncmp(ptr, "http", eot - ptr) != 0) {
|
906
|
+
free(src);
|
907
|
+
rb_raise(rb_eArgError, "invalid URI format: missing schema");
|
908
|
+
return;
|
909
|
+
}
|
910
|
+
ptr = eot + 1;
|
911
|
+
if (ptr[0] != '/' || ptr[1] != '/') {
|
912
|
+
free(src);
|
913
|
+
rb_raise(rb_eArgError, "invalid URI format.");
|
914
|
+
return;
|
915
|
+
}
|
916
|
+
ptr += 2;
|
917
|
+
eot = ptr;
|
918
|
+
while (*eot) {
|
919
|
+
if (*eot == '?' || *eot == '#' || *eot == ':' || *eot == '/') {
|
920
|
+
break;
|
921
|
+
}
|
922
|
+
++eot;
|
923
|
+
}
|
924
|
+
if (eot > ptr) {
|
925
|
+
sep = *eot;
|
926
|
+
*eot = '\0';
|
927
|
+
bucket->hostname = strdup(ptr);
|
928
|
+
}
|
929
|
+
ptr = eot + 1;
|
930
|
+
eot = strchr(ptr, '/');
|
931
|
+
if (sep == ':') {
|
932
|
+
if (eot > ptr) {
|
933
|
+
*eot = '\0';
|
934
|
+
}
|
935
|
+
bucket->port = (uint16_t)atoi(ptr);
|
936
|
+
if (eot > ptr) {
|
937
|
+
ptr = eot + 1;
|
938
|
+
}
|
939
|
+
}
|
940
|
+
ptr = parse_path_segment(ptr, "pools", &bucket->pool);
|
941
|
+
parse_path_segment(ptr, "buckets", &bucket->bucket);
|
942
|
+
free(src);
|
943
|
+
}
|
944
|
+
|
945
|
+
static int
|
946
|
+
cb_first_value_i(VALUE key, VALUE value, VALUE arg)
|
947
|
+
{
|
948
|
+
VALUE *val = (VALUE *)arg;
|
949
|
+
|
950
|
+
*val = value;
|
951
|
+
(void)key;
|
952
|
+
return ST_STOP;
|
953
|
+
}
|
954
|
+
|
955
|
+
static VALUE
|
956
|
+
cb_bucket_inspect(VALUE self)
|
957
|
+
{
|
958
|
+
VALUE str;
|
959
|
+
bucket_t *bucket = DATA_PTR(self);
|
960
|
+
char buf[200];
|
961
|
+
|
962
|
+
str = rb_str_buf_new2("#<");
|
963
|
+
rb_str_buf_cat2(str, rb_obj_classname(self));
|
964
|
+
snprintf(buf, 25, ":%p \"", (void *)self);
|
965
|
+
rb_str_buf_cat2(str, buf);
|
966
|
+
rb_str_append(str, rb_ivar_get(self, id_iv_url));
|
967
|
+
snprintf(buf, 150, "\" default_format=:%s, default_flags=0x%x, quiet=%s>",
|
968
|
+
rb_id2name(SYM2ID(bucket->default_format)),
|
969
|
+
bucket->default_flags,
|
970
|
+
bucket->quiet ? "true" : "false");
|
971
|
+
rb_str_buf_cat2(str, buf);
|
972
|
+
|
973
|
+
return str;
|
974
|
+
}
|
975
|
+
|
976
|
+
/*
|
977
|
+
* @return [Fixnum] number of scheduled operations
|
978
|
+
*/
|
979
|
+
static VALUE
|
980
|
+
cb_bucket_seqno(VALUE self)
|
981
|
+
{
|
982
|
+
bucket_t *bucket = DATA_PTR(self);
|
983
|
+
|
984
|
+
return LONG2FIX(bucket->seqno);
|
985
|
+
}
|
986
|
+
|
987
|
+
void
|
988
|
+
cb_bucket_free(void *ptr)
|
989
|
+
{
|
990
|
+
bucket_t *bucket = ptr;
|
991
|
+
|
992
|
+
if (bucket) {
|
993
|
+
if (bucket->handle) {
|
994
|
+
libcouchbase_destroy(bucket->handle);
|
995
|
+
free(bucket->authority);
|
996
|
+
free(bucket->hostname);
|
997
|
+
free(bucket->pool);
|
998
|
+
free(bucket->bucket);
|
999
|
+
free(bucket->username);
|
1000
|
+
free(bucket->password);
|
1001
|
+
}
|
1002
|
+
free(bucket);
|
1003
|
+
}
|
1004
|
+
}
|
1005
|
+
|
1006
|
+
void
|
1007
|
+
cb_bucket_mark(void *ptr)
|
1008
|
+
{
|
1009
|
+
bucket_t *bucket = ptr;
|
1010
|
+
|
1011
|
+
if (bucket) {
|
1012
|
+
rb_gc_mark(bucket->exception);
|
1013
|
+
rb_gc_mark(bucket->on_error_proc);
|
1014
|
+
}
|
1015
|
+
}
|
1016
|
+
|
1017
|
+
/*
|
1018
|
+
* @return [Bucket] new instance (see Bucket#initialize)
|
1019
|
+
*/
|
1020
|
+
static VALUE
|
1021
|
+
cb_bucket_new(int argc, VALUE *argv, VALUE klass)
|
1022
|
+
{
|
1023
|
+
VALUE obj;
|
1024
|
+
bucket_t *bucket;
|
1025
|
+
|
1026
|
+
/* allocate new bucket struct and set it to zero */
|
1027
|
+
obj = Data_Make_Struct(klass, bucket_t, cb_bucket_mark, cb_bucket_free,
|
1028
|
+
bucket);
|
1029
|
+
rb_obj_call_init(obj, argc, argv);
|
1030
|
+
return obj;
|
1031
|
+
}
|
1032
|
+
|
1033
|
+
/*
|
1034
|
+
* @overload initialize(url, options = {})
|
1035
|
+
* Initialize bucket using URI of the cluster and options. It is possible
|
1036
|
+
* to override some parts of URI using the options keys (e.g. :host or
|
1037
|
+
* :port)
|
1038
|
+
*
|
1039
|
+
* @param [String] url The full URL of management API of the cluster.
|
1040
|
+
* @param [Hash] options The options for connection. See options definition
|
1041
|
+
* below.
|
1042
|
+
*
|
1043
|
+
* @overload initialize(options = {})
|
1044
|
+
* Initialize bucket using options only.
|
1045
|
+
*
|
1046
|
+
* @param [Hash] options The options for operation for connection
|
1047
|
+
* @option options [String] :host ("localhost") the hostname or IP address
|
1048
|
+
* of the node
|
1049
|
+
* @option options [Fixnum] :port (8091) the port of the managemenent API
|
1050
|
+
* @option options [String] :pool ("default") the pool name
|
1051
|
+
* @option options [String] :bucket ("default") the bucket name
|
1052
|
+
* @option options [Fixnum] :default_ttl (0) the TTL used by default during
|
1053
|
+
* storing key-value pairs.
|
1054
|
+
* @option options [Fixnum] :default_flags (0) the default flags.
|
1055
|
+
* @option options [Symbol] :default_format (:document) the format, which
|
1056
|
+
* will be used for values by default. Note that changing format will
|
1057
|
+
* amend flags. (see Bucket#default_format)
|
1058
|
+
* @option options [String] :username (nil) the user name to connect to the
|
1059
|
+
* cluster. Used to authenticate on management API.
|
1060
|
+
* @option options [String] :password (nil) the password of the user.
|
1061
|
+
* @option options [Boolean] :quiet (true) the flag controlling if raising
|
1062
|
+
* exception when the client executes operations on unexising keys. If it
|
1063
|
+
* is +true+ it will raise +Couchbase::NotFoundError+ exceptions. The
|
1064
|
+
* default behaviour is to return +nil+ value silently (might be useful in
|
1065
|
+
* Rails cache).
|
1066
|
+
*
|
1067
|
+
* @example Initialize connection using default options
|
1068
|
+
* Couchbase.new
|
1069
|
+
*
|
1070
|
+
* @example Select custom bucket
|
1071
|
+
* Couchbase.new(:bucket => 'foo')
|
1072
|
+
* Couchbase.new('http://localhost:8091/pools/default/buckets/foo')
|
1073
|
+
*
|
1074
|
+
* @example Connect to protected bucket
|
1075
|
+
* Couchbase.new(:bucket => 'protected', :username => 'protected', :password => 'secret')
|
1076
|
+
* Couchbase.new('http://localhost:8091/pools/default/buckets/protected',
|
1077
|
+
* :username => 'protected', :password => 'secret')
|
1078
|
+
*
|
1079
|
+
* @return [Bucket]
|
1080
|
+
*/
|
1081
|
+
static VALUE
|
1082
|
+
cb_bucket_init(int argc, VALUE *argv, VALUE self)
|
1083
|
+
{
|
1084
|
+
VALUE uri, opts, arg, buf;
|
1085
|
+
libcouchbase_error_t err;
|
1086
|
+
bucket_t *bucket = DATA_PTR(self);
|
1087
|
+
size_t len;
|
1088
|
+
|
1089
|
+
bucket->exception = Qnil;
|
1090
|
+
bucket->hostname = strdup("localhost");
|
1091
|
+
bucket->port = 8091;
|
1092
|
+
bucket->pool = strdup("default");
|
1093
|
+
bucket->bucket = strdup("default");
|
1094
|
+
bucket->async = 0;
|
1095
|
+
bucket->quiet = 1;
|
1096
|
+
bucket->default_flags = 0;
|
1097
|
+
bucket->default_format = sym_document;
|
1098
|
+
bucket->on_error_proc = Qnil;
|
1099
|
+
|
1100
|
+
if (rb_scan_args(argc, argv, "02", &uri, &opts) > 0) {
|
1101
|
+
if (TYPE(uri) == T_HASH && argc == 1) {
|
1102
|
+
opts = uri;
|
1103
|
+
uri = Qnil;
|
1104
|
+
}
|
1105
|
+
if (uri != Qnil) {
|
1106
|
+
Check_Type(uri, T_STRING);
|
1107
|
+
parse_bucket_uri(uri, bucket);
|
1108
|
+
}
|
1109
|
+
if (TYPE(opts) == T_HASH) {
|
1110
|
+
arg = rb_hash_aref(opts, sym_hostname);
|
1111
|
+
if (arg != Qnil) {
|
1112
|
+
if (bucket->hostname) {
|
1113
|
+
free(bucket->hostname);
|
1114
|
+
}
|
1115
|
+
bucket->hostname = strdup(StringValueCStr(arg));
|
1116
|
+
}
|
1117
|
+
arg = rb_hash_aref(opts, sym_pool);
|
1118
|
+
if (arg != Qnil) {
|
1119
|
+
if (bucket->pool) {
|
1120
|
+
free(bucket->pool);
|
1121
|
+
}
|
1122
|
+
bucket->pool = strdup(StringValueCStr(arg));
|
1123
|
+
}
|
1124
|
+
arg = rb_hash_aref(opts, sym_bucket);
|
1125
|
+
if (arg != Qnil) {
|
1126
|
+
if (bucket->bucket) {
|
1127
|
+
free(bucket->bucket);
|
1128
|
+
}
|
1129
|
+
bucket->bucket = strdup(StringValueCStr(arg));
|
1130
|
+
}
|
1131
|
+
arg = rb_hash_aref(opts, sym_username);
|
1132
|
+
if (arg != Qnil) {
|
1133
|
+
bucket->username = strdup(StringValueCStr(arg));
|
1134
|
+
}
|
1135
|
+
arg = rb_hash_aref(opts, sym_password);
|
1136
|
+
if (arg != Qnil) {
|
1137
|
+
bucket->password = strdup(StringValueCStr(arg));
|
1138
|
+
}
|
1139
|
+
arg = rb_hash_aref(opts, sym_port);
|
1140
|
+
if (arg != Qnil) {
|
1141
|
+
bucket->port = (uint16_t)NUM2UINT(arg);
|
1142
|
+
}
|
1143
|
+
if (RTEST(rb_funcall(opts, id_has_key_p, 1, sym_quiet))) {
|
1144
|
+
bucket->quiet = RTEST(rb_hash_aref(opts, sym_quiet));
|
1145
|
+
}
|
1146
|
+
arg = rb_hash_aref(opts, sym_default_flags);
|
1147
|
+
if (arg != Qnil) {
|
1148
|
+
bucket->default_flags = (uint32_t)NUM2ULONG(arg);
|
1149
|
+
}
|
1150
|
+
arg = rb_hash_aref(opts, sym_default_format);
|
1151
|
+
if (arg != Qnil) {
|
1152
|
+
if (TYPE(arg) == T_FIXNUM) {
|
1153
|
+
switch (FIX2INT(arg)) {
|
1154
|
+
case FMT_DOCUMENT:
|
1155
|
+
arg = sym_document;
|
1156
|
+
break;
|
1157
|
+
case FMT_MARSHAL:
|
1158
|
+
arg = sym_marshal;
|
1159
|
+
break;
|
1160
|
+
case FMT_PLAIN:
|
1161
|
+
arg = sym_plain;
|
1162
|
+
break;
|
1163
|
+
}
|
1164
|
+
}
|
1165
|
+
if (arg == sym_document || arg == sym_marshal || arg == sym_plain) {
|
1166
|
+
bucket->default_format = arg;
|
1167
|
+
bucket->default_flags = flags_set_format(bucket->default_flags, arg);
|
1168
|
+
}
|
1169
|
+
}
|
1170
|
+
} else {
|
1171
|
+
opts = Qnil;
|
1172
|
+
}
|
1173
|
+
}
|
1174
|
+
len = strlen(bucket->hostname) + 10;
|
1175
|
+
bucket->authority = calloc(len, sizeof(char));
|
1176
|
+
if (bucket->authority == NULL) {
|
1177
|
+
rb_raise(eNoMemoryError, "failed to allocate memory for Bucket");
|
1178
|
+
}
|
1179
|
+
snprintf(bucket->authority, len, "%s:%u", bucket->hostname, bucket->port);
|
1180
|
+
bucket->io = libcouchbase_create_io_ops(LIBCOUCHBASE_IO_OPS_DEFAULT, NULL, &err);
|
1181
|
+
if (bucket->io == NULL) {
|
1182
|
+
rb_exc_raise(cb_check_error(err, "failed to create IO instance", Qnil));
|
1183
|
+
}
|
1184
|
+
bucket->handle = libcouchbase_create(bucket->authority,
|
1185
|
+
bucket->username, bucket->password, bucket->bucket, bucket->io);
|
1186
|
+
if (bucket->handle == NULL) {
|
1187
|
+
rb_raise(eLibcouchbaseError, "failed to create libcouchbase instance");
|
1188
|
+
}
|
1189
|
+
libcouchbase_set_cookie(bucket->handle, bucket);
|
1190
|
+
(void)libcouchbase_set_error_callback(bucket->handle, error_callback);
|
1191
|
+
(void)libcouchbase_set_storage_callback(bucket->handle, storage_callback);
|
1192
|
+
(void)libcouchbase_set_get_callback(bucket->handle, get_callback);
|
1193
|
+
(void)libcouchbase_set_touch_callback(bucket->handle, touch_callback);
|
1194
|
+
(void)libcouchbase_set_remove_callback(bucket->handle, delete_callback);
|
1195
|
+
(void)libcouchbase_set_stat_callback(bucket->handle, stat_callback);
|
1196
|
+
(void)libcouchbase_set_flush_callback(bucket->handle, flush_callback);
|
1197
|
+
(void)libcouchbase_set_arithmetic_callback(bucket->handle, arithmetic_callback);
|
1198
|
+
|
1199
|
+
err = libcouchbase_connect(bucket->handle);
|
1200
|
+
if (err != LIBCOUCHBASE_SUCCESS) {
|
1201
|
+
rb_exc_raise(cb_check_error(err, "failed to connect libcouchbase instance to server", Qnil));
|
1202
|
+
}
|
1203
|
+
libcouchbase_wait(bucket->handle);
|
1204
|
+
if (bucket->exception != Qnil) {
|
1205
|
+
rb_exc_raise(bucket->exception);
|
1206
|
+
}
|
1207
|
+
|
1208
|
+
rb_ivar_set(self, id_iv_authority, rb_str_new2(bucket->authority));
|
1209
|
+
rb_ivar_set(self, id_iv_bucket, rb_str_new2(bucket->bucket));
|
1210
|
+
rb_ivar_set(self, id_iv_hostname, rb_str_new2(bucket->hostname));
|
1211
|
+
rb_ivar_set(self, id_iv_password, bucket->password ? rb_str_new2(bucket->password) : Qnil);
|
1212
|
+
rb_ivar_set(self, id_iv_pool, rb_str_new2(bucket->pool));
|
1213
|
+
rb_ivar_set(self, id_iv_port, UINT2NUM(bucket->port));
|
1214
|
+
rb_ivar_set(self, id_iv_username, bucket->username ? rb_str_new2(bucket->username) : Qnil);
|
1215
|
+
rb_ivar_set(self, id_iv_quiet, bucket->quiet ? Qtrue : Qfalse);
|
1216
|
+
rb_ivar_set(self, id_iv_default_flags, ULONG2NUM(bucket->default_flags));
|
1217
|
+
rb_ivar_set(self, id_iv_default_format, bucket->default_format);
|
1218
|
+
rb_ivar_set(self, id_iv_on_error, bucket->on_error_proc);
|
1219
|
+
|
1220
|
+
buf = rb_str_buf_new2("http://");
|
1221
|
+
rb_str_buf_cat2(buf, bucket->authority);
|
1222
|
+
rb_str_buf_cat2(buf, "/pools/");
|
1223
|
+
rb_str_buf_cat2(buf, bucket->pool);
|
1224
|
+
rb_str_buf_cat2(buf, "/buckets/");
|
1225
|
+
rb_str_buf_cat2(buf, bucket->bucket);
|
1226
|
+
rb_str_buf_cat2(buf, "/");
|
1227
|
+
rb_ivar_set(self, id_iv_url, buf);
|
1228
|
+
|
1229
|
+
return self;
|
1230
|
+
}
|
1231
|
+
|
1232
|
+
static VALUE
|
1233
|
+
cb_bucket_async_p(VALUE self)
|
1234
|
+
{
|
1235
|
+
bucket_t *bucket = DATA_PTR(self);
|
1236
|
+
return bucket->async ? Qtrue : Qfalse;
|
1237
|
+
}
|
1238
|
+
|
1239
|
+
static VALUE
|
1240
|
+
cb_bucket_quiet_set(VALUE self, VALUE val)
|
1241
|
+
{
|
1242
|
+
bucket_t *bucket = DATA_PTR(self);
|
1243
|
+
VALUE new;
|
1244
|
+
|
1245
|
+
bucket->quiet = RTEST(val);
|
1246
|
+
new = bucket->quiet ? Qtrue : Qfalse;
|
1247
|
+
rb_ivar_set(self, id_iv_quiet, new);
|
1248
|
+
return new;
|
1249
|
+
}
|
1250
|
+
|
1251
|
+
static VALUE
|
1252
|
+
cb_bucket_default_flags_set(VALUE self, VALUE val)
|
1253
|
+
{
|
1254
|
+
bucket_t *bucket = DATA_PTR(self);
|
1255
|
+
|
1256
|
+
bucket->default_flags = (uint32_t)NUM2ULONG(val);
|
1257
|
+
bucket->default_format = flags_get_format(bucket->default_flags);
|
1258
|
+
rb_ivar_set(self, id_iv_default_format, bucket->default_format);
|
1259
|
+
rb_ivar_set(self, id_iv_default_flags, val);
|
1260
|
+
return val;
|
1261
|
+
}
|
1262
|
+
|
1263
|
+
static VALUE
|
1264
|
+
cb_bucket_default_format_set(VALUE self, VALUE val)
|
1265
|
+
{
|
1266
|
+
bucket_t *bucket = DATA_PTR(self);
|
1267
|
+
|
1268
|
+
if (TYPE(val) == T_FIXNUM) {
|
1269
|
+
switch (FIX2INT(val)) {
|
1270
|
+
case FMT_DOCUMENT:
|
1271
|
+
val = sym_document;
|
1272
|
+
break;
|
1273
|
+
case FMT_MARSHAL:
|
1274
|
+
val = sym_marshal;
|
1275
|
+
break;
|
1276
|
+
case FMT_PLAIN:
|
1277
|
+
val = sym_plain;
|
1278
|
+
break;
|
1279
|
+
}
|
1280
|
+
}
|
1281
|
+
if (val == sym_document || val == sym_marshal || val == sym_plain) {
|
1282
|
+
bucket->default_format = val;
|
1283
|
+
bucket->default_flags = flags_set_format(bucket->default_flags, val);
|
1284
|
+
rb_ivar_set(self, id_iv_default_format, val);
|
1285
|
+
rb_ivar_set(self, id_iv_default_flags, ULONG2NUM(bucket->default_flags));
|
1286
|
+
}
|
1287
|
+
|
1288
|
+
return val;
|
1289
|
+
}
|
1290
|
+
|
1291
|
+
static VALUE
|
1292
|
+
cb_bucket_on_error_set(VALUE self, VALUE val)
|
1293
|
+
{
|
1294
|
+
bucket_t *bucket = DATA_PTR(self);
|
1295
|
+
|
1296
|
+
if (rb_respond_to(val, id_call)) {
|
1297
|
+
bucket->on_error_proc = val;
|
1298
|
+
} else {
|
1299
|
+
bucket->on_error_proc = Qnil;
|
1300
|
+
}
|
1301
|
+
rb_ivar_set(self, id_iv_on_error, bucket->on_error_proc);
|
1302
|
+
|
1303
|
+
return bucket->on_error_proc;
|
1304
|
+
}
|
1305
|
+
|
1306
|
+
static VALUE
|
1307
|
+
cb_bucket_on_error_get(VALUE self)
|
1308
|
+
{
|
1309
|
+
bucket_t *bucket = DATA_PTR(self);
|
1310
|
+
|
1311
|
+
if (rb_block_given_p()) {
|
1312
|
+
return cb_bucket_on_error_set(self, rb_block_proc());
|
1313
|
+
} else {
|
1314
|
+
return bucket->on_error_proc;
|
1315
|
+
}
|
1316
|
+
}
|
1317
|
+
|
1318
|
+
static VALUE
|
1319
|
+
cb_bucket_delete(int argc, VALUE *argv, VALUE self)
|
1320
|
+
{
|
1321
|
+
bucket_t *bucket = DATA_PTR(self);
|
1322
|
+
context_t *ctx;
|
1323
|
+
VALUE k, c, rv, proc, exc, opts;
|
1324
|
+
char *key;
|
1325
|
+
size_t nkey;
|
1326
|
+
uint64_t cas = 0;
|
1327
|
+
libcouchbase_error_t err;
|
1328
|
+
|
1329
|
+
rb_scan_args(argc, argv, "11&", &k, &opts, &proc);
|
1330
|
+
if (!bucket->async && proc != Qnil) {
|
1331
|
+
rb_raise(rb_eArgError, "synchronous mode doesn't support callbacks");
|
1332
|
+
}
|
1333
|
+
k = unify_key(k);
|
1334
|
+
key = RSTRING_PTR(k);
|
1335
|
+
nkey = RSTRING_LEN(k);
|
1336
|
+
ctx = calloc(1, sizeof(context_t));
|
1337
|
+
ctx->quiet = bucket->quiet;
|
1338
|
+
if (ctx == NULL) {
|
1339
|
+
rb_raise(eNoMemoryError, "failed to allocate memory for context");
|
1340
|
+
}
|
1341
|
+
if (opts != Qnil) {
|
1342
|
+
if (TYPE(opts) == T_BIGNUM || TYPE(opts) == T_FIXNUM) {
|
1343
|
+
cas = NUM2ULL(opts);
|
1344
|
+
} else {
|
1345
|
+
Check_Type(opts, T_HASH);
|
1346
|
+
if ((c = rb_hash_aref(opts, sym_cas)) != Qnil) {
|
1347
|
+
cas = NUM2ULL(c);
|
1348
|
+
}
|
1349
|
+
if (RTEST(rb_funcall(opts, id_has_key_p, 1, sym_quiet))) {
|
1350
|
+
ctx->quiet = RTEST(rb_hash_aref(opts, sym_quiet));
|
1351
|
+
}
|
1352
|
+
}
|
1353
|
+
}
|
1354
|
+
ctx->proc = proc;
|
1355
|
+
rb_hash_aset(object_space, ctx->proc|1, ctx->proc);
|
1356
|
+
rv = rb_ary_new();
|
1357
|
+
ctx->rv = &rv;
|
1358
|
+
ctx->bucket = bucket;
|
1359
|
+
ctx->exception = Qnil;
|
1360
|
+
err = libcouchbase_remove(bucket->handle, (const void *)ctx,
|
1361
|
+
(const void *)key, nkey, cas);
|
1362
|
+
exc = cb_check_error(err, "failed to schedule delete request", Qnil);
|
1363
|
+
if (exc != Qnil) {
|
1364
|
+
free(ctx);
|
1365
|
+
rb_exc_raise(exc);
|
1366
|
+
}
|
1367
|
+
bucket->seqno++;
|
1368
|
+
if (bucket->async) {
|
1369
|
+
return Qnil;
|
1370
|
+
} else {
|
1371
|
+
bucket->io->run_event_loop(bucket->io);
|
1372
|
+
exc = ctx->exception;
|
1373
|
+
free(ctx);
|
1374
|
+
if (exc != Qnil) {
|
1375
|
+
rb_exc_raise(exc);
|
1376
|
+
}
|
1377
|
+
return rv;
|
1378
|
+
}
|
1379
|
+
}
|
1380
|
+
|
1381
|
+
static inline VALUE
|
1382
|
+
cb_bucket_store(libcouchbase_storage_t cmd, int argc, VALUE *argv, VALUE self)
|
1383
|
+
{
|
1384
|
+
bucket_t *bucket = DATA_PTR(self);
|
1385
|
+
context_t *ctx;
|
1386
|
+
VALUE k, v, arg, opts, rv, proc, exc, fmt;
|
1387
|
+
char *key, *bytes;
|
1388
|
+
size_t nkey, nbytes;
|
1389
|
+
uint32_t flags;
|
1390
|
+
time_t exp = 0;
|
1391
|
+
uint64_t cas = 0;
|
1392
|
+
libcouchbase_error_t err;
|
1393
|
+
|
1394
|
+
rb_scan_args(argc, argv, "21&", &k, &v, &opts, &proc);
|
1395
|
+
if (!bucket->async && proc != Qnil) {
|
1396
|
+
rb_raise(rb_eArgError, "synchronous mode doesn't support callbacks");
|
1397
|
+
}
|
1398
|
+
k = unify_key(k);
|
1399
|
+
flags = bucket->default_flags;
|
1400
|
+
if (opts != Qnil) {
|
1401
|
+
Check_Type(opts, T_HASH);
|
1402
|
+
arg = rb_hash_aref(opts, sym_flags);
|
1403
|
+
if (arg != Qnil) {
|
1404
|
+
flags = (uint32_t)NUM2ULONG(arg);
|
1405
|
+
}
|
1406
|
+
arg = rb_hash_aref(opts, sym_ttl);
|
1407
|
+
if (arg != Qnil) {
|
1408
|
+
exp = NUM2ULONG(arg);
|
1409
|
+
}
|
1410
|
+
arg = rb_hash_aref(opts, sym_cas);
|
1411
|
+
if (arg != Qnil) {
|
1412
|
+
cas = NUM2ULL(arg);
|
1413
|
+
}
|
1414
|
+
fmt = rb_hash_aref(opts, sym_format);
|
1415
|
+
if (fmt != Qnil) { /* rewrite format bits */
|
1416
|
+
flags = flags_set_format(flags, fmt);
|
1417
|
+
}
|
1418
|
+
}
|
1419
|
+
key = RSTRING_PTR(k);
|
1420
|
+
nkey = RSTRING_LEN(k);
|
1421
|
+
v = encode_value(v, flags);
|
1422
|
+
if (v == Qundef) {
|
1423
|
+
rb_raise(eValueFormatError,
|
1424
|
+
"unable to convert value for key '%s'", key);
|
1425
|
+
}
|
1426
|
+
bytes = RSTRING_PTR(v);
|
1427
|
+
nbytes = RSTRING_LEN(v);
|
1428
|
+
ctx = calloc(1, sizeof(context_t));
|
1429
|
+
if (ctx == NULL) {
|
1430
|
+
rb_raise(eNoMemoryError, "failed to allocate memory for context");
|
1431
|
+
}
|
1432
|
+
rv = Qnil;
|
1433
|
+
ctx->rv = &rv;
|
1434
|
+
ctx->bucket = bucket;
|
1435
|
+
ctx->proc = proc;
|
1436
|
+
rb_hash_aset(object_space, ctx->proc|1, ctx->proc);
|
1437
|
+
ctx->exception = Qnil;
|
1438
|
+
err = libcouchbase_store(bucket->handle, (const void *)ctx, cmd,
|
1439
|
+
(const void *)key, nkey, bytes, nbytes, flags, exp, cas);
|
1440
|
+
exc = cb_check_error(err, "failed to schedule set request", Qnil);
|
1441
|
+
if (exc != Qnil) {
|
1442
|
+
free(ctx);
|
1443
|
+
rb_exc_raise(exc);
|
1444
|
+
}
|
1445
|
+
bucket->seqno++;
|
1446
|
+
if (bucket->async) {
|
1447
|
+
return Qnil;
|
1448
|
+
} else {
|
1449
|
+
bucket->io->run_event_loop(bucket->io);
|
1450
|
+
exc = ctx->exception;
|
1451
|
+
free(ctx);
|
1452
|
+
if (exc != Qnil) {
|
1453
|
+
rb_exc_raise(exc);
|
1454
|
+
}
|
1455
|
+
if (bucket->exception != Qnil) {
|
1456
|
+
rb_exc_raise(bucket->exception);
|
1457
|
+
}
|
1458
|
+
return rv;
|
1459
|
+
}
|
1460
|
+
}
|
1461
|
+
|
1462
|
+
static inline VALUE
|
1463
|
+
cb_bucket_arithmetic(int sign, int argc, VALUE *argv, VALUE self)
|
1464
|
+
{
|
1465
|
+
bucket_t *bucket = DATA_PTR(self);
|
1466
|
+
context_t *ctx;
|
1467
|
+
VALUE k, d, arg, opts, rv, proc, exc;
|
1468
|
+
char *key;
|
1469
|
+
size_t nkey;
|
1470
|
+
time_t exp;
|
1471
|
+
uint64_t delta = 0, initial = 0;
|
1472
|
+
int create = 0;
|
1473
|
+
libcouchbase_error_t err;
|
1474
|
+
|
1475
|
+
rb_scan_args(argc, argv, "12&", &k, &d, &opts, &proc);
|
1476
|
+
if (!bucket->async && proc != Qnil) {
|
1477
|
+
rb_raise(rb_eArgError, "synchronous mode doesn't support callbacks");
|
1478
|
+
}
|
1479
|
+
k = unify_key(k);
|
1480
|
+
ctx = calloc(1, sizeof(context_t));
|
1481
|
+
if (ctx == NULL) {
|
1482
|
+
rb_raise(eNoMemoryError, "failed to allocate memory for context");
|
1483
|
+
}
|
1484
|
+
if (argc == 2 && TYPE(d) == T_HASH) {
|
1485
|
+
opts = d;
|
1486
|
+
d = Qnil;
|
1487
|
+
}
|
1488
|
+
exp = bucket->default_ttl;
|
1489
|
+
if (opts != Qnil) {
|
1490
|
+
Check_Type(opts, T_HASH);
|
1491
|
+
create = RTEST(rb_hash_aref(opts, sym_create));
|
1492
|
+
ctx->extended = RTEST(rb_hash_aref(opts, sym_extended));
|
1493
|
+
arg = rb_hash_aref(opts, sym_ttl);
|
1494
|
+
if (arg != Qnil) {
|
1495
|
+
exp = NUM2ULONG(arg);
|
1496
|
+
}
|
1497
|
+
arg = rb_hash_aref(opts, sym_initial);
|
1498
|
+
if (arg != Qnil) {
|
1499
|
+
initial = NUM2ULL(arg);
|
1500
|
+
create = 1;
|
1501
|
+
}
|
1502
|
+
}
|
1503
|
+
key = RSTRING_PTR(k);
|
1504
|
+
nkey = RSTRING_LEN(k);
|
1505
|
+
if (NIL_P(d)) {
|
1506
|
+
delta = 1 * sign;
|
1507
|
+
} else {
|
1508
|
+
delta = NUM2ULL(d) * sign;
|
1509
|
+
}
|
1510
|
+
rv = Qnil;
|
1511
|
+
ctx->rv = &rv;
|
1512
|
+
ctx->bucket = bucket;
|
1513
|
+
ctx->proc = proc;
|
1514
|
+
rb_hash_aset(object_space, ctx->proc|1, ctx->proc);
|
1515
|
+
ctx->exception = Qnil;
|
1516
|
+
ctx->arithm = sign;
|
1517
|
+
err = libcouchbase_arithmetic(bucket->handle, (const void *)ctx,
|
1518
|
+
(const void *)key, nkey, delta, exp, create, initial);
|
1519
|
+
exc = cb_check_error(err, "failed to schedule arithmetic request", k);
|
1520
|
+
if (exc != Qnil) {
|
1521
|
+
free(ctx);
|
1522
|
+
rb_exc_raise(exc);
|
1523
|
+
}
|
1524
|
+
bucket->seqno++;
|
1525
|
+
if (bucket->async) {
|
1526
|
+
return Qnil;
|
1527
|
+
} else {
|
1528
|
+
bucket->io->run_event_loop(bucket->io);
|
1529
|
+
exc = ctx->exception;
|
1530
|
+
free(ctx);
|
1531
|
+
if (exc != Qnil) {
|
1532
|
+
rb_exc_raise(exc);
|
1533
|
+
}
|
1534
|
+
return rv;
|
1535
|
+
}
|
1536
|
+
}
|
1537
|
+
|
1538
|
+
static VALUE
|
1539
|
+
cb_bucket_incr(int argc, VALUE *argv, VALUE self)
|
1540
|
+
{
|
1541
|
+
return cb_bucket_arithmetic(+1, argc, argv, self);
|
1542
|
+
}
|
1543
|
+
|
1544
|
+
static VALUE
|
1545
|
+
cb_bucket_decr(int argc, VALUE *argv, VALUE self)
|
1546
|
+
{
|
1547
|
+
return cb_bucket_arithmetic(-1, argc, argv, self);
|
1548
|
+
}
|
1549
|
+
|
1550
|
+
static VALUE
|
1551
|
+
cb_bucket_get(int argc, VALUE *argv, VALUE self)
|
1552
|
+
{
|
1553
|
+
bucket_t *bucket = DATA_PTR(self);
|
1554
|
+
context_t *ctx;
|
1555
|
+
VALUE args, rv, proc, exc, vv = Qnil, keys;
|
1556
|
+
long nn;
|
1557
|
+
libcouchbase_error_t err;
|
1558
|
+
struct key_traits *traits;
|
1559
|
+
int extended;
|
1560
|
+
|
1561
|
+
rb_scan_args(argc, argv, "0*&", &args, &proc);
|
1562
|
+
if (!bucket->async && proc != Qnil) {
|
1563
|
+
rb_raise(rb_eArgError, "synchronous mode doesn't support callbacks");
|
1564
|
+
}
|
1565
|
+
rb_funcall(args, id_flatten_bang, 0);
|
1566
|
+
traits = calloc(1, sizeof(struct key_traits));
|
1567
|
+
nn = cb_args_scan_keys(RARRAY_LEN(args), args, bucket, traits);
|
1568
|
+
ctx = calloc(1, sizeof(context_t));
|
1569
|
+
if (ctx == NULL) {
|
1570
|
+
rb_raise(eNoMemoryError, "failed to allocate memory for context");
|
1571
|
+
}
|
1572
|
+
keys = traits->keys_ary;
|
1573
|
+
ctx->proc = proc;
|
1574
|
+
rb_hash_aset(object_space, ctx->proc|1, ctx->proc);
|
1575
|
+
ctx->bucket = bucket;
|
1576
|
+
ctx->extended = traits->extended;
|
1577
|
+
ctx->quiet = traits->quiet;
|
1578
|
+
rv = rb_hash_new();
|
1579
|
+
ctx->rv = &rv;
|
1580
|
+
ctx->exception = Qnil;
|
1581
|
+
if (!bucket->async) {
|
1582
|
+
bucket->seqno = 0;
|
1583
|
+
}
|
1584
|
+
err = libcouchbase_mget(bucket->handle, (const void *)ctx,
|
1585
|
+
traits->nkeys, (const void * const *)traits->keys,
|
1586
|
+
traits->lens, (traits->explicit_ttl) ? traits->ttls : NULL);
|
1587
|
+
free(traits->keys);
|
1588
|
+
free(traits->lens);
|
1589
|
+
free(traits->ttls);
|
1590
|
+
free(traits);
|
1591
|
+
exc = cb_check_error(err, "failed to schedule get request", Qnil);
|
1592
|
+
if (exc != Qnil) {
|
1593
|
+
free(ctx);
|
1594
|
+
rb_exc_raise(exc);
|
1595
|
+
}
|
1596
|
+
bucket->seqno += nn;
|
1597
|
+
if (bucket->async) {
|
1598
|
+
return Qnil;
|
1599
|
+
} else {
|
1600
|
+
bucket->io->run_event_loop(bucket->io);
|
1601
|
+
exc = ctx->exception;
|
1602
|
+
extended = ctx->extended;
|
1603
|
+
free(ctx);
|
1604
|
+
if (exc != Qnil) {
|
1605
|
+
rb_exc_raise(exc);
|
1606
|
+
}
|
1607
|
+
if (bucket->exception != Qnil) {
|
1608
|
+
rb_exc_raise(bucket->exception);
|
1609
|
+
}
|
1610
|
+
if (nn > 1) {
|
1611
|
+
if (extended) {
|
1612
|
+
return rv; /* return as a hash {key => [value, flags, cas], ...} */
|
1613
|
+
} else {
|
1614
|
+
long ii;
|
1615
|
+
VALUE *keys_ptr, ret;
|
1616
|
+
ret = rb_ary_new();
|
1617
|
+
keys_ptr = RARRAY_PTR(keys);
|
1618
|
+
for (ii = 0; ii < nn; ii++) {
|
1619
|
+
rb_ary_push(ret, rb_hash_aref(rv, keys_ptr[ii]));
|
1620
|
+
}
|
1621
|
+
return ret; /* return as an array [value1, value2, ...] */
|
1622
|
+
}
|
1623
|
+
} else {
|
1624
|
+
rb_hash_foreach(rv, cb_first_value_i, (VALUE)&vv);
|
1625
|
+
return vv;
|
1626
|
+
}
|
1627
|
+
}
|
1628
|
+
}
|
1629
|
+
|
1630
|
+
static VALUE
|
1631
|
+
cb_bucket_touch(int argc, VALUE *argv, VALUE self)
|
1632
|
+
{
|
1633
|
+
bucket_t *bucket = DATA_PTR(self);
|
1634
|
+
context_t *ctx;
|
1635
|
+
VALUE args, rv, proc, exc;
|
1636
|
+
size_t nn;
|
1637
|
+
libcouchbase_error_t err;
|
1638
|
+
struct key_traits *traits;
|
1639
|
+
|
1640
|
+
rb_scan_args(argc, argv, "0*&", &args, &proc);
|
1641
|
+
if (!bucket->async && proc != Qnil) {
|
1642
|
+
rb_raise(rb_eArgError, "synchronous mode doesn't support callbacks");
|
1643
|
+
}
|
1644
|
+
rb_funcall(args, id_flatten_bang, 0);
|
1645
|
+
traits = calloc(1, sizeof(struct key_traits));
|
1646
|
+
nn = cb_args_scan_keys(RARRAY_LEN(args), args, bucket, traits);
|
1647
|
+
ctx = calloc(1, sizeof(context_t));
|
1648
|
+
if (ctx == NULL) {
|
1649
|
+
rb_raise(eNoMemoryError, "failed to allocate memory for context");
|
1650
|
+
}
|
1651
|
+
ctx->proc = proc;
|
1652
|
+
rb_hash_aset(object_space, ctx->proc|1, ctx->proc);
|
1653
|
+
ctx->bucket = bucket;
|
1654
|
+
rv = rb_ary_new();
|
1655
|
+
ctx->rv = &rv;
|
1656
|
+
ctx->exception = Qnil;
|
1657
|
+
if (!bucket->async) {
|
1658
|
+
bucket->seqno = 0;
|
1659
|
+
}
|
1660
|
+
err = libcouchbase_mtouch(bucket->handle, (const void *)ctx,
|
1661
|
+
traits->nkeys, (const void * const *)traits->keys,
|
1662
|
+
traits->lens, traits->ttls);
|
1663
|
+
free(traits);
|
1664
|
+
exc = cb_check_error(err, "failed to schedule touch request", Qnil);
|
1665
|
+
if (exc != Qnil) {
|
1666
|
+
free(ctx);
|
1667
|
+
rb_exc_raise(exc);
|
1668
|
+
}
|
1669
|
+
bucket->seqno += nn;
|
1670
|
+
if (bucket->async) {
|
1671
|
+
return Qnil;
|
1672
|
+
} else {
|
1673
|
+
bucket->io->run_event_loop(bucket->io);
|
1674
|
+
exc = ctx->exception;
|
1675
|
+
free(ctx);
|
1676
|
+
if (exc != Qnil) {
|
1677
|
+
rb_exc_raise(exc);
|
1678
|
+
}
|
1679
|
+
if (bucket->exception != Qnil) {
|
1680
|
+
rb_exc_raise(bucket->exception);
|
1681
|
+
}
|
1682
|
+
if (nn > 1) {
|
1683
|
+
return rv;
|
1684
|
+
} else {
|
1685
|
+
return rb_ary_pop(rv);
|
1686
|
+
}
|
1687
|
+
}
|
1688
|
+
}
|
1689
|
+
|
1690
|
+
static VALUE
|
1691
|
+
cb_bucket_flush(VALUE self)
|
1692
|
+
{
|
1693
|
+
bucket_t *bucket = DATA_PTR(self);
|
1694
|
+
context_t *ctx;
|
1695
|
+
VALUE rv, exc;
|
1696
|
+
libcouchbase_error_t err;
|
1697
|
+
|
1698
|
+
if (!bucket->async && rb_block_given_p()) {
|
1699
|
+
rb_raise(rb_eArgError, "synchronous mode doesn't support callbacks");
|
1700
|
+
}
|
1701
|
+
ctx = calloc(1, sizeof(context_t));
|
1702
|
+
if (ctx == NULL) {
|
1703
|
+
rb_raise(eNoMemoryError, "failed to allocate memory for context");
|
1704
|
+
}
|
1705
|
+
rv = Qtrue; /* optimistic by default */
|
1706
|
+
ctx->rv = &rv;
|
1707
|
+
ctx->bucket = bucket;
|
1708
|
+
ctx->exception = Qnil;
|
1709
|
+
if (rb_block_given_p()) {
|
1710
|
+
ctx->proc = rb_block_proc();
|
1711
|
+
} else {
|
1712
|
+
ctx->proc = Qnil;
|
1713
|
+
}
|
1714
|
+
rb_hash_aset(object_space, ctx->proc|1, ctx->proc);
|
1715
|
+
err = libcouchbase_flush(bucket->handle, (const void *)ctx);
|
1716
|
+
exc = cb_check_error(err, "failed to schedule flush request", Qnil);
|
1717
|
+
if (exc != Qnil) {
|
1718
|
+
free(ctx);
|
1719
|
+
rb_exc_raise(exc);
|
1720
|
+
}
|
1721
|
+
bucket->seqno++;
|
1722
|
+
if (bucket->async) {
|
1723
|
+
return Qnil;
|
1724
|
+
} else {
|
1725
|
+
bucket->io->run_event_loop(bucket->io);
|
1726
|
+
exc = ctx->exception;
|
1727
|
+
free(ctx);
|
1728
|
+
if (exc != Qnil) {
|
1729
|
+
rb_exc_raise(exc);
|
1730
|
+
}
|
1731
|
+
return rv;
|
1732
|
+
}
|
1733
|
+
}
|
1734
|
+
|
1735
|
+
static VALUE
|
1736
|
+
cb_bucket_stats(int argc, VALUE *argv, VALUE self)
|
1737
|
+
{
|
1738
|
+
bucket_t *bucket = DATA_PTR(self);
|
1739
|
+
context_t *ctx;
|
1740
|
+
VALUE rv, exc, arg, proc;
|
1741
|
+
char *key;
|
1742
|
+
size_t nkey;
|
1743
|
+
libcouchbase_error_t err;
|
1744
|
+
|
1745
|
+
rb_scan_args(argc, argv, "01&", &arg, &proc);
|
1746
|
+
if (!bucket->async && proc != Qnil) {
|
1747
|
+
rb_raise(rb_eArgError, "synchronous mode doesn't support callbacks");
|
1748
|
+
}
|
1749
|
+
|
1750
|
+
ctx = calloc(1, sizeof(context_t));
|
1751
|
+
if (ctx == NULL) {
|
1752
|
+
rb_raise(eNoMemoryError, "failed to allocate memory for context");
|
1753
|
+
}
|
1754
|
+
rv = rb_hash_new();
|
1755
|
+
ctx->rv = &rv;
|
1756
|
+
ctx->bucket = bucket;
|
1757
|
+
ctx->proc = proc;
|
1758
|
+
rb_hash_aset(object_space, ctx->proc|1, ctx->proc);
|
1759
|
+
ctx->exception = Qnil;
|
1760
|
+
if (arg != Qnil) {
|
1761
|
+
key = RSTRING_PTR(arg);
|
1762
|
+
nkey = RSTRING_LEN(arg);
|
1763
|
+
} else {
|
1764
|
+
key = NULL;
|
1765
|
+
nkey = 0;
|
1766
|
+
}
|
1767
|
+
err = libcouchbase_server_stats(bucket->handle, (const void *)ctx,
|
1768
|
+
key, nkey);
|
1769
|
+
exc = cb_check_error(err, "failed to schedule stat request", Qnil);
|
1770
|
+
if (exc != Qnil) {
|
1771
|
+
free(ctx);
|
1772
|
+
rb_exc_raise(exc);
|
1773
|
+
}
|
1774
|
+
bucket->seqno++;
|
1775
|
+
if (bucket->async) {
|
1776
|
+
return Qnil;
|
1777
|
+
} else {
|
1778
|
+
bucket->io->run_event_loop(bucket->io);
|
1779
|
+
exc = ctx->exception;
|
1780
|
+
free(ctx);
|
1781
|
+
if (exc != Qnil) {
|
1782
|
+
rb_exc_raise(exc);
|
1783
|
+
}
|
1784
|
+
if (bucket->exception != Qnil) {
|
1785
|
+
rb_exc_raise(bucket->exception);
|
1786
|
+
}
|
1787
|
+
return rv;
|
1788
|
+
}
|
1789
|
+
|
1790
|
+
return Qnil;
|
1791
|
+
}
|
1792
|
+
|
1793
|
+
static VALUE
|
1794
|
+
do_run(VALUE *args)
|
1795
|
+
{
|
1796
|
+
VALUE self = args[0], proc = args[1], exc;
|
1797
|
+
bucket_t *bucket = DATA_PTR(self);
|
1798
|
+
|
1799
|
+
bucket->seqno = 0;
|
1800
|
+
bucket->async = 1;
|
1801
|
+
cb_proc_call(proc, 1, self);
|
1802
|
+
if (bucket->seqno > 0) {
|
1803
|
+
bucket->io->run_event_loop(bucket->io);
|
1804
|
+
if (bucket->exception != Qnil) {
|
1805
|
+
exc = bucket->exception;
|
1806
|
+
bucket->exception = Qnil;
|
1807
|
+
rb_exc_raise(exc);
|
1808
|
+
}
|
1809
|
+
}
|
1810
|
+
return Qnil;
|
1811
|
+
}
|
1812
|
+
|
1813
|
+
static VALUE
|
1814
|
+
ensure_run(VALUE *args)
|
1815
|
+
{
|
1816
|
+
VALUE self = args[0];
|
1817
|
+
bucket_t *bucket = DATA_PTR(self);
|
1818
|
+
|
1819
|
+
bucket->async = 0;
|
1820
|
+
return Qnil;
|
1821
|
+
}
|
1822
|
+
|
1823
|
+
/*
|
1824
|
+
* Run the event loop.
|
1825
|
+
*
|
1826
|
+
* @yieldparam [Bucket] the bucket instance
|
1827
|
+
*
|
1828
|
+
* @example Use block to run the loop
|
1829
|
+
* c = Couchbase.new
|
1830
|
+
* c.run do
|
1831
|
+
* c.get("foo") {|ret| puts ret.value}
|
1832
|
+
* end
|
1833
|
+
*
|
1834
|
+
* @example Use lambda to run the loop
|
1835
|
+
* c = Couchbase.new
|
1836
|
+
* operations = lambda do |c|
|
1837
|
+
* c.get("foo") {|ret| puts ret.value}
|
1838
|
+
* end
|
1839
|
+
* c.run(&operations)
|
1840
|
+
*
|
1841
|
+
*/
|
1842
|
+
static VALUE
|
1843
|
+
cb_bucket_run(VALUE self)
|
1844
|
+
{
|
1845
|
+
VALUE args[2];
|
1846
|
+
|
1847
|
+
rb_need_block();
|
1848
|
+
args[0] = self;
|
1849
|
+
args[1] = rb_block_proc();
|
1850
|
+
rb_ensure(do_run, (VALUE)args, ensure_run, (VALUE)args);
|
1851
|
+
return Qnil;
|
1852
|
+
}
|
1853
|
+
|
1854
|
+
/*
|
1855
|
+
* Unconditionally set the object in the cache
|
1856
|
+
*/
|
1857
|
+
static VALUE
|
1858
|
+
cb_bucket_set(int argc, VALUE *argv, VALUE self)
|
1859
|
+
{
|
1860
|
+
return cb_bucket_store(LIBCOUCHBASE_SET, argc, argv, self);
|
1861
|
+
}
|
1862
|
+
|
1863
|
+
/*
|
1864
|
+
* Add the item to the cache, but fail if the object exists alread
|
1865
|
+
*/
|
1866
|
+
static VALUE
|
1867
|
+
cb_bucket_add(int argc, VALUE *argv, VALUE self)
|
1868
|
+
{
|
1869
|
+
return cb_bucket_store(LIBCOUCHBASE_ADD, argc, argv, self);
|
1870
|
+
}
|
1871
|
+
|
1872
|
+
/*
|
1873
|
+
* Replace the existing object in the cache
|
1874
|
+
*/
|
1875
|
+
static VALUE
|
1876
|
+
cb_bucket_replace(int argc, VALUE *argv, VALUE self)
|
1877
|
+
{
|
1878
|
+
return cb_bucket_store(LIBCOUCHBASE_REPLACE, argc, argv, self);
|
1879
|
+
}
|
1880
|
+
|
1881
|
+
/*
|
1882
|
+
* Append this object to the existing object
|
1883
|
+
*/
|
1884
|
+
static VALUE
|
1885
|
+
cb_bucket_append(int argc, VALUE *argv, VALUE self)
|
1886
|
+
{
|
1887
|
+
return cb_bucket_store(LIBCOUCHBASE_APPEND, argc, argv, self);
|
1888
|
+
}
|
1889
|
+
|
1890
|
+
/*
|
1891
|
+
* Prepend this object to the existing object
|
1892
|
+
*/
|
1893
|
+
static VALUE
|
1894
|
+
cb_bucket_prepend(int argc, VALUE *argv, VALUE self)
|
1895
|
+
{
|
1896
|
+
return cb_bucket_store(LIBCOUCHBASE_PREPEND, argc, argv, self);
|
1897
|
+
}
|
1898
|
+
|
1899
|
+
static VALUE
|
1900
|
+
cb_bucket_aset(int argc, VALUE *argv, VALUE self)
|
1901
|
+
{
|
1902
|
+
VALUE temp;
|
1903
|
+
|
1904
|
+
if (argc == 3) {
|
1905
|
+
/* swap opts and value, because value goes last for []= */
|
1906
|
+
temp = argv[2];
|
1907
|
+
argv[2] = argv[1];
|
1908
|
+
argv[1] = temp;
|
1909
|
+
}
|
1910
|
+
return cb_bucket_set(argc, argv, self);
|
1911
|
+
}
|
1912
|
+
|
1913
|
+
/*
|
1914
|
+
* Check if result of operation was successful.
|
1915
|
+
*
|
1916
|
+
* @return [Boolean] +false+ if there is an +error+ object attached,
|
1917
|
+
* +false+ otherwise.
|
1918
|
+
*/
|
1919
|
+
static VALUE
|
1920
|
+
cb_result_success_p(VALUE self)
|
1921
|
+
{
|
1922
|
+
return RTEST(rb_ivar_get(self, id_iv_error)) ? Qfalse : Qtrue;
|
1923
|
+
}
|
1924
|
+
|
1925
|
+
static VALUE
|
1926
|
+
cb_result_inspect(VALUE self)
|
1927
|
+
{
|
1928
|
+
VALUE str, attr, errno;
|
1929
|
+
char buf[100];
|
1930
|
+
|
1931
|
+
str = rb_str_buf_new2("#<");
|
1932
|
+
rb_str_buf_cat2(str, rb_obj_classname(self));
|
1933
|
+
snprintf(buf, 100, ":%p", (void *)self);
|
1934
|
+
rb_str_buf_cat2(str, buf);
|
1935
|
+
|
1936
|
+
attr = rb_ivar_get(self, id_iv_error);
|
1937
|
+
if (RTEST(attr)) {
|
1938
|
+
errno = rb_ivar_get(attr, id_iv_error);
|
1939
|
+
} else {
|
1940
|
+
errno = INT2FIX(0);
|
1941
|
+
}
|
1942
|
+
rb_str_buf_cat2(str, " error=0x");
|
1943
|
+
rb_str_append(str, rb_funcall(errno, id_to_s, 1, INT2FIX(16)));
|
1944
|
+
|
1945
|
+
attr = rb_ivar_get(self, id_iv_key);
|
1946
|
+
if (RTEST(attr)) {
|
1947
|
+
rb_str_buf_cat2(str, " key=");
|
1948
|
+
rb_str_append(str, rb_inspect(attr));
|
1949
|
+
}
|
1950
|
+
|
1951
|
+
attr = rb_ivar_get(self, id_iv_cas);
|
1952
|
+
if (RTEST(attr)) {
|
1953
|
+
rb_str_buf_cat2(str, " cas=");
|
1954
|
+
rb_str_append(str, rb_inspect(attr));
|
1955
|
+
}
|
1956
|
+
|
1957
|
+
attr = rb_ivar_get(self, id_iv_flags);
|
1958
|
+
if (RTEST(attr)) {
|
1959
|
+
rb_str_buf_cat2(str, " flags=0x");
|
1960
|
+
rb_str_append(str, rb_funcall(attr, id_to_s, 1, INT2FIX(16)));
|
1961
|
+
}
|
1962
|
+
|
1963
|
+
attr = rb_ivar_get(self, id_iv_node);
|
1964
|
+
if (RTEST(attr)) {
|
1965
|
+
rb_str_buf_cat2(str, " node=");
|
1966
|
+
rb_str_append(str, rb_inspect(attr));
|
1967
|
+
}
|
1968
|
+
rb_str_buf_cat2(str, ">");
|
1969
|
+
|
1970
|
+
return str;
|
1971
|
+
}
|
1972
|
+
|
1973
|
+
/* Ruby Extension initializer */
|
1974
|
+
void
|
1975
|
+
Init_couchbase_ext(void)
|
1976
|
+
{
|
1977
|
+
mJSON = rb_const_get(rb_cObject, rb_intern("JSON"));
|
1978
|
+
mMarshal = rb_const_get(rb_cObject, rb_intern("Marshal"));
|
1979
|
+
mCouchbase = rb_define_module("Couchbase");
|
1980
|
+
|
1981
|
+
mError = rb_define_module_under(mCouchbase, "Error");
|
1982
|
+
/* Document-class: Couchbase::Error::Base
|
1983
|
+
* The base error class */
|
1984
|
+
eBaseError = rb_define_class_under(mError, "Base", rb_eRuntimeError);
|
1985
|
+
/* Document-class: Couchbase::Error::Auth
|
1986
|
+
* Authentication error */
|
1987
|
+
eAuthError = rb_define_class_under(mError, "Auth", eBaseError);
|
1988
|
+
/* Document-class: Couchbase::Error::Busy
|
1989
|
+
* The cluster is too busy now. Try again later */
|
1990
|
+
eBusyError = rb_define_class_under(mError, "Busy", eBaseError);
|
1991
|
+
/* Document-class: Couchbase::Error::DeltaBadval
|
1992
|
+
* The given value is not a number */
|
1993
|
+
eDeltaBadvalError = rb_define_class_under(mError, "DeltaBadval", eBaseError);
|
1994
|
+
/* Document-class: Couchbase::Error::Internal
|
1995
|
+
* Internal error */
|
1996
|
+
eInternalError = rb_define_class_under(mError, "Internal", eBaseError);
|
1997
|
+
/* Document-class: Couchbase::Error::Invalid
|
1998
|
+
* Invalid arguments */
|
1999
|
+
eInvalidError = rb_define_class_under(mError, "Invalid", eBaseError);
|
2000
|
+
/* Document-class: Couchbase::Error::KeyExists
|
2001
|
+
* Key already exists */
|
2002
|
+
eKeyExistsError = rb_define_class_under(mError, "KeyExists", eBaseError);
|
2003
|
+
/* Document-class: Couchbase::Error::Libcouchbase
|
2004
|
+
* Generic error */
|
2005
|
+
eLibcouchbaseError = rb_define_class_under(mError, "Libcouchbase", eBaseError);
|
2006
|
+
/* Document-class: Couchbase::Error::Libevent
|
2007
|
+
* Problem using libevent */
|
2008
|
+
eLibeventError = rb_define_class_under(mError, "Libevent", eBaseError);
|
2009
|
+
/* Document-class: Couchbase::Error::Network
|
2010
|
+
* Network error */
|
2011
|
+
eNetworkError = rb_define_class_under(mError, "Network", eBaseError);
|
2012
|
+
/* Document-class: Couchbase::Error::NoMemory
|
2013
|
+
* Out of memory error */
|
2014
|
+
eNoMemoryError = rb_define_class_under(mError, "NoMemory", eBaseError);
|
2015
|
+
/* Document-class: Couchbase::Error::NotFound
|
2016
|
+
* No such key */
|
2017
|
+
eNotFoundError = rb_define_class_under(mError, "NotFound", eBaseError);
|
2018
|
+
/* Document-class: Couchbase::Error::NotMyVbucket
|
2019
|
+
* The vbucket is not located on this server */
|
2020
|
+
eNotMyVbucketError = rb_define_class_under(mError, "NotMyVbucket", eBaseError);
|
2021
|
+
/* Document-class: Couchbase::Error::NotStored
|
2022
|
+
* Not stored */
|
2023
|
+
eNotStoredError = rb_define_class_under(mError, "NotStored", eBaseError);
|
2024
|
+
/* Document-class: Couchbase::Error::NotSupported
|
2025
|
+
* Not supported */
|
2026
|
+
eNotSupportedError = rb_define_class_under(mError, "NotSupported", eBaseError);
|
2027
|
+
/* Document-class: Couchbase::Error::Range
|
2028
|
+
* Invalid range */
|
2029
|
+
eRangeError = rb_define_class_under(mError, "Range", eBaseError);
|
2030
|
+
/* Document-class: Couchbase::Error::TemporaryFail
|
2031
|
+
* Temporary failure. Try again later */
|
2032
|
+
eTmpFailError = rb_define_class_under(mError, "TemporaryFail", eBaseError);
|
2033
|
+
/* Document-class: Couchbase::Error::TooBig
|
2034
|
+
* Object too big */
|
2035
|
+
eTooBigError = rb_define_class_under(mError, "TooBig", eBaseError);
|
2036
|
+
/* Document-class: Couchbase::Error::UnknownCommand
|
2037
|
+
* Unknown command */
|
2038
|
+
eUnknownCommandError = rb_define_class_under(mError, "UnknownCommand", eBaseError);
|
2039
|
+
/* Document-class: Couchbase::Error::UnknownHost
|
2040
|
+
* Unknown host */
|
2041
|
+
eUnknownHostError = rb_define_class_under(mError, "UnknownHost", eBaseError);
|
2042
|
+
/* Document-class: Couchbase::Error::ValueFormat
|
2043
|
+
* Failed to decode or encode value */
|
2044
|
+
eValueFormatError = rb_define_class_under(mError, "ValueFormat", eBaseError);
|
2045
|
+
/* Document-class: Couchbase::Error::Protocol
|
2046
|
+
* Protocol error */
|
2047
|
+
eProtocolError = rb_define_class_under(mError, "Protocol", eBaseError);
|
2048
|
+
|
2049
|
+
/* Document-method: error
|
2050
|
+
* @return [Boolean] the error code from libcouchbase */
|
2051
|
+
rb_define_attr(eBaseError, "error", 1, 0);
|
2052
|
+
id_iv_error = rb_intern("@error");
|
2053
|
+
/* Document-method: key
|
2054
|
+
* @return [String] the key which generated error */
|
2055
|
+
rb_define_attr(eBaseError, "key", 1, 0);
|
2056
|
+
id_iv_key = rb_intern("@key");
|
2057
|
+
/* Document-method: cas
|
2058
|
+
* @return [Fixnum] the version of the key (+nil+ unless accessible) */
|
2059
|
+
rb_define_attr(eBaseError, "cas", 1, 0);
|
2060
|
+
id_iv_cas = rb_intern("@cas");
|
2061
|
+
/* Document-method: operation
|
2062
|
+
* @return [Symbol] the operation (+nil+ unless accessible) */
|
2063
|
+
rb_define_attr(eBaseError, "operation", 1, 0);
|
2064
|
+
id_iv_operation = rb_intern("@operation");
|
2065
|
+
|
2066
|
+
/* Document-class: Couchbase::Result
|
2067
|
+
* Protocol error */
|
2068
|
+
cResult = rb_define_class_under(mCouchbase, "Result", rb_cObject);
|
2069
|
+
rb_define_method(cResult, "inspect", cb_result_inspect, 0);
|
2070
|
+
rb_define_method(cResult, "success?", cb_result_success_p, 0);
|
2071
|
+
/* Document-method: operation
|
2072
|
+
* @return [Symbol] */
|
2073
|
+
rb_define_attr(cResult, "operation", 1, 0);
|
2074
|
+
/* Document-method: error
|
2075
|
+
* @return [Error::Base] */
|
2076
|
+
rb_define_attr(cResult, "error", 1, 0);
|
2077
|
+
/* Document-method: key
|
2078
|
+
* @return [String] */
|
2079
|
+
rb_define_attr(cResult, "key", 1, 0);
|
2080
|
+
id_iv_key = rb_intern("@key");
|
2081
|
+
/* Document-method: value
|
2082
|
+
* @return [String] */
|
2083
|
+
rb_define_attr(cResult, "value", 1, 0);
|
2084
|
+
id_iv_value = rb_intern("@value");
|
2085
|
+
/* Document-method: cas
|
2086
|
+
* @return [Fixnum] */
|
2087
|
+
rb_define_attr(cResult, "cas", 1, 0);
|
2088
|
+
id_iv_cas = rb_intern("@cas");
|
2089
|
+
/* Document-method: flags
|
2090
|
+
* @return [Fixnum] */
|
2091
|
+
rb_define_attr(cResult, "flags", 1, 0);
|
2092
|
+
id_iv_flags = rb_intern("@flags");
|
2093
|
+
/* Document-method: node
|
2094
|
+
* @return [String] */
|
2095
|
+
rb_define_attr(cResult, "node", 1, 0);
|
2096
|
+
id_iv_node = rb_intern("@node");
|
2097
|
+
|
2098
|
+
/* Document-class: Couchbase::Bucket
|
2099
|
+
* This class in charge of all stuff connected to communication with
|
2100
|
+
* Couchbase. */
|
2101
|
+
cBucket = rb_define_class_under(mCouchbase, "Bucket", rb_cObject);
|
2102
|
+
object_space = rb_hash_new();
|
2103
|
+
rb_define_const(cBucket, "OBJECT_SPACE", object_space);
|
2104
|
+
|
2105
|
+
rb_define_const(cBucket, "FMT_MASK", INT2FIX(FMT_MASK));
|
2106
|
+
rb_define_const(cBucket, "FMT_DOCUMENT", INT2FIX(FMT_DOCUMENT));
|
2107
|
+
rb_define_const(cBucket, "FMT_MARSHAL", INT2FIX(FMT_MARSHAL));
|
2108
|
+
rb_define_const(cBucket, "FMT_PLAIN", INT2FIX(FMT_PLAIN));
|
2109
|
+
|
2110
|
+
rb_define_singleton_method(cBucket, "new", cb_bucket_new, -1);
|
2111
|
+
|
2112
|
+
rb_define_method(cBucket, "initialize", cb_bucket_init, -1);
|
2113
|
+
rb_define_method(cBucket, "inspect", cb_bucket_inspect, 0);
|
2114
|
+
rb_define_method(cBucket, "seqno", cb_bucket_seqno, 0);
|
2115
|
+
|
2116
|
+
rb_define_method(cBucket, "add", cb_bucket_add, -1);
|
2117
|
+
rb_define_method(cBucket, "append", cb_bucket_append, -1);
|
2118
|
+
rb_define_method(cBucket, "prepend", cb_bucket_prepend, -1);
|
2119
|
+
rb_define_method(cBucket, "replace", cb_bucket_replace, -1);
|
2120
|
+
rb_define_method(cBucket, "set", cb_bucket_set, -1);
|
2121
|
+
rb_define_method(cBucket, "get", cb_bucket_get, -1);
|
2122
|
+
rb_define_method(cBucket, "run", cb_bucket_run, 0);
|
2123
|
+
rb_define_method(cBucket, "touch", cb_bucket_touch, -1);
|
2124
|
+
rb_define_method(cBucket, "delete", cb_bucket_delete, -1);
|
2125
|
+
rb_define_method(cBucket, "stats", cb_bucket_stats, -1);
|
2126
|
+
rb_define_method(cBucket, "flush", cb_bucket_flush, 0);
|
2127
|
+
rb_define_method(cBucket, "incr", cb_bucket_incr, -1);
|
2128
|
+
rb_define_method(cBucket, "decr", cb_bucket_decr, -1);
|
2129
|
+
|
2130
|
+
rb_define_alias(cBucket, "decrement", "decr");
|
2131
|
+
rb_define_alias(cBucket, "increment", "incr");
|
2132
|
+
|
2133
|
+
rb_define_alias(cBucket, "[]", "get");
|
2134
|
+
/* rb_define_alias(cBucket, "[]=", "set"); */
|
2135
|
+
rb_define_method(cBucket, "[]=", cb_bucket_aset, -1);
|
2136
|
+
|
2137
|
+
/* Document-method: async?
|
2138
|
+
* Flag specifying if the connection asynchronous.
|
2139
|
+
*
|
2140
|
+
* By default all operations are synchronous and block waiting for
|
2141
|
+
* results, but you can make them asynchronous and run event loop
|
2142
|
+
* explicitly. (see Bucket#run)
|
2143
|
+
*
|
2144
|
+
* @example Return value of #get operation depending on async flag
|
2145
|
+
* connection = Connection.new
|
2146
|
+
* connection.async? #=> false
|
2147
|
+
*
|
2148
|
+
* connection.run do |conn|
|
2149
|
+
* conn.async? #=> true
|
2150
|
+
* end
|
2151
|
+
*
|
2152
|
+
* @return [Boolean] */
|
2153
|
+
rb_define_method(cBucket, "async?", cb_bucket_async_p, 0);
|
2154
|
+
|
2155
|
+
/* Document-method: quiet
|
2156
|
+
* Flag specifying behaviour for operations on missing keys
|
2157
|
+
*
|
2158
|
+
* If it is +true+, the operations will silently return +nil+ or +false+
|
2159
|
+
* instead of raising Couchbase::Error::NotFoundError.
|
2160
|
+
*
|
2161
|
+
* @example Hiding cache miss (considering "miss" key is not stored)
|
2162
|
+
* connection.quiet = true
|
2163
|
+
* connection.get("miss") #=> nil
|
2164
|
+
*
|
2165
|
+
* @example Raising errors on miss (considering "miss" key is not stored)
|
2166
|
+
* connection.quiet = false
|
2167
|
+
* connection.get("miss") #=> will raise Couchbase::Error::NotFoundError
|
2168
|
+
*
|
2169
|
+
* @return [Boolean] */
|
2170
|
+
rb_define_attr(cBucket, "quiet", 1, 1);
|
2171
|
+
rb_define_method(cBucket, "quiet=", cb_bucket_quiet_set, 1);
|
2172
|
+
rb_define_alias(cBucket, "quiet?", "quiet");
|
2173
|
+
id_iv_quiet = rb_intern("@quiet");
|
2174
|
+
|
2175
|
+
/* Document-method: default_flags
|
2176
|
+
* Default flags for new values.
|
2177
|
+
*
|
2178
|
+
* The library reserves last two lower bits to store the format of the
|
2179
|
+
* value. The can be masked via FMT_MASK constant.
|
2180
|
+
*
|
2181
|
+
* @example Selecting format bits
|
2182
|
+
* connection.default_flags & Couchbase::Bucket::FMT_MASK
|
2183
|
+
*
|
2184
|
+
* @example Set user defined bits
|
2185
|
+
* connection.default_flags |= 0x6660
|
2186
|
+
*
|
2187
|
+
* @note Amending format bit will also change #default_format value
|
2188
|
+
*
|
2189
|
+
* @return [Fixnum] the effective flags */
|
2190
|
+
rb_define_attr(cBucket, "default_flags", 1, 1);
|
2191
|
+
rb_define_method(cBucket, "default_flags=", cb_bucket_default_flags_set, 1);
|
2192
|
+
id_iv_default_flags = rb_intern("@default_flags");
|
2193
|
+
|
2194
|
+
/* Document-method: default_format
|
2195
|
+
* Default format for new values.
|
2196
|
+
*
|
2197
|
+
* It uses flags field to store the format. It accepts either the Symbol
|
2198
|
+
* (+:document+, +:marshal+, +:plain+) or Fixnum (use constants
|
2199
|
+
* FMT_DOCUMENT, FMT_MARSHAL, FMT_PLAIN) and silently ignores all
|
2200
|
+
* other value.
|
2201
|
+
*
|
2202
|
+
* Here is some notes regarding how to choose the format:
|
2203
|
+
*
|
2204
|
+
* * <tt>:document</tt> (default) format supports most of ruby types
|
2205
|
+
* which could be mapped to JSON data (hashes, arrays, string,
|
2206
|
+
* numbers). Future version will be able to run map/reduce queries on
|
2207
|
+
* the values in the document form (hashes).
|
2208
|
+
*
|
2209
|
+
* * <tt>:plain</tt> format if you no need any conversions to be applied
|
2210
|
+
* to your data, but your data should be passed as String. It could be
|
2211
|
+
* useful for building custom algorithms or formats. For example
|
2212
|
+
* implement set: http://dustin.github.com/2011/02/17/memcached-set.html
|
2213
|
+
*
|
2214
|
+
* * <tt>:marshal</tt> format if you'd like to transparently serialize
|
2215
|
+
* your ruby object with standard <tt>Marshal.dump</tt> and
|
2216
|
+
* <tt>Marhal.load</tt> methods.
|
2217
|
+
*
|
2218
|
+
* @example Selecting plain format using symbol
|
2219
|
+
* connection.format = :document
|
2220
|
+
*
|
2221
|
+
* @example Selecting plain format using Fixnum constant
|
2222
|
+
* connection.format = Couchbase::Bucket::FMT_PLAIN
|
2223
|
+
*
|
2224
|
+
* @note Amending default_format will also change #default_flags value
|
2225
|
+
*
|
2226
|
+
* @return [Symbol] the effective format */
|
2227
|
+
rb_define_attr(cBucket, "default_format", 1, 1);
|
2228
|
+
rb_define_method(cBucket, "default_format=", cb_bucket_default_format_set, 1);
|
2229
|
+
id_iv_default_format = rb_intern("@default_format");
|
2230
|
+
/* Document-method: on_error
|
2231
|
+
* Error callback for asynchronous mode.
|
2232
|
+
*
|
2233
|
+
* This callback is using to deliver exceptions in asynchronous mode.
|
2234
|
+
*
|
2235
|
+
* @yieldparam [Symbol] op The operation caused the error
|
2236
|
+
* @yieldparam [String] key The key which cause the error or +nil+
|
2237
|
+
* @yieldparam [Exception] exc The exception instance
|
2238
|
+
*
|
2239
|
+
* @example Using lambda syntax
|
2240
|
+
* connection = Couchbase.new(:async => true)
|
2241
|
+
* connection.on_error = lambda {|op, key, exc| ... }
|
2242
|
+
* connection.run do |conn|
|
2243
|
+
* conn.set("foo", "bar")
|
2244
|
+
* end
|
2245
|
+
*
|
2246
|
+
* @example Using block syntax
|
2247
|
+
* connection = Couchbase.new(:async => true)
|
2248
|
+
* connection.on_error {|op, key, exc| ... }
|
2249
|
+
* ...
|
2250
|
+
*
|
2251
|
+
* @return [Proc] the effective callback */
|
2252
|
+
rb_define_attr(cBucket, "on_error", 1, 1);
|
2253
|
+
rb_define_method(cBucket, "on_error", cb_bucket_on_error_get, 0);
|
2254
|
+
rb_define_method(cBucket, "on_error=", cb_bucket_on_error_set, 1);
|
2255
|
+
id_iv_on_error = rb_intern("@on_error");
|
2256
|
+
|
2257
|
+
/* Document-method: url
|
2258
|
+
* @return [String] the address of the cluster management interface. */
|
2259
|
+
rb_define_attr(cBucket, "url", 1, 0);
|
2260
|
+
id_iv_url = rb_intern("@url");
|
2261
|
+
/* Document-method: hostname
|
2262
|
+
* @return [String] the host name of the management interface (default: "localhost") */
|
2263
|
+
rb_define_attr(cBucket, "hostname", 1, 0);
|
2264
|
+
id_iv_hostname = rb_intern("@hostname");
|
2265
|
+
/* Document-method: port
|
2266
|
+
* @return [Fixnum] the port number of the management interface (default: 8091) */
|
2267
|
+
rb_define_attr(cBucket, "port", 1, 0);
|
2268
|
+
id_iv_port = rb_intern("@port");
|
2269
|
+
/* Document-method: authority
|
2270
|
+
* @return [String] host with port. */
|
2271
|
+
rb_define_attr(cBucket, "authority", 1, 0);
|
2272
|
+
id_iv_authority = rb_intern("@authority");
|
2273
|
+
/* Document-method: bucket
|
2274
|
+
* @return [String] the bucket name */
|
2275
|
+
rb_define_attr(cBucket, "bucket", 1, 0);
|
2276
|
+
rb_define_alias(cBucket, "name", "bucket");
|
2277
|
+
id_iv_bucket = rb_intern("@bucket");
|
2278
|
+
/* Document-method: pool
|
2279
|
+
* @return [String] the pool name (usually "default") */
|
2280
|
+
rb_define_attr(cBucket, "pool", 1, 0);
|
2281
|
+
id_iv_pool = rb_intern("@pool");
|
2282
|
+
/* Document-method: username
|
2283
|
+
* @return [String] the username for protected buckets (usually matches
|
2284
|
+
* the bucket name) */
|
2285
|
+
rb_define_attr(cBucket, "username", 1, 0);
|
2286
|
+
id_iv_username = rb_intern("@username");
|
2287
|
+
/* Document-method: password
|
2288
|
+
* @return [String] the password for protected buckets */
|
2289
|
+
rb_define_attr(cBucket, "password", 1, 0);
|
2290
|
+
id_iv_password = rb_intern("@password");
|
2291
|
+
|
2292
|
+
/* Define symbols */
|
2293
|
+
id_arity = rb_intern("arity");
|
2294
|
+
id_call = rb_intern("call");
|
2295
|
+
id_load = rb_intern("load");
|
2296
|
+
id_dump = rb_intern("dump");
|
2297
|
+
id_flatten_bang = rb_intern("flatten!");
|
2298
|
+
id_has_key_p = rb_intern("has_key?");
|
2299
|
+
id_to_s = rb_intern("to_s");
|
2300
|
+
|
2301
|
+
sym_add = ID2SYM(rb_intern("add"));
|
2302
|
+
sym_append = ID2SYM(rb_intern("append"));
|
2303
|
+
sym_bucket = ID2SYM(rb_intern("bucket"));
|
2304
|
+
sym_cas = ID2SYM(rb_intern("cas"));
|
2305
|
+
sym_create = ID2SYM(rb_intern("create"));
|
2306
|
+
sym_decrement = ID2SYM(rb_intern("decrement"));
|
2307
|
+
sym_default_flags = ID2SYM(rb_intern("default_flags"));
|
2308
|
+
sym_default_format = ID2SYM(rb_intern("default_format"));
|
2309
|
+
sym_delete = ID2SYM(rb_intern("delete"));
|
2310
|
+
sym_document = ID2SYM(rb_intern("document"));
|
2311
|
+
sym_extended = ID2SYM(rb_intern("extended"));
|
2312
|
+
sym_flags = ID2SYM(rb_intern("flags"));
|
2313
|
+
sym_flush = ID2SYM(rb_intern("flush"));
|
2314
|
+
sym_format = ID2SYM(rb_intern("format"));
|
2315
|
+
sym_get = ID2SYM(rb_intern("get"));
|
2316
|
+
sym_hostname = ID2SYM(rb_intern("hostname"));
|
2317
|
+
sym_increment = ID2SYM(rb_intern("increment"));
|
2318
|
+
sym_initial = ID2SYM(rb_intern("initial"));
|
2319
|
+
sym_marshal = ID2SYM(rb_intern("marshal"));
|
2320
|
+
sym_password = ID2SYM(rb_intern("password"));
|
2321
|
+
sym_plain = ID2SYM(rb_intern("plain"));
|
2322
|
+
sym_pool = ID2SYM(rb_intern("pool"));
|
2323
|
+
sym_port = ID2SYM(rb_intern("port"));
|
2324
|
+
sym_prepend = ID2SYM(rb_intern("prepend"));
|
2325
|
+
sym_quiet = ID2SYM(rb_intern("quiet"));
|
2326
|
+
sym_replace = ID2SYM(rb_intern("replace"));
|
2327
|
+
sym_set = ID2SYM(rb_intern("set"));
|
2328
|
+
sym_stats = ID2SYM(rb_intern("stats"));
|
2329
|
+
sym_touch = ID2SYM(rb_intern("touch"));
|
2330
|
+
sym_ttl = ID2SYM(rb_intern("ttl"));
|
2331
|
+
sym_username = ID2SYM(rb_intern("username"));
|
2332
|
+
}
|