couchbase 1.1.5 → 1.2.0.beta
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -1
- data/.travis.yml +12 -1
- data/HISTORY.markdown +112 -1
- data/README.markdown +149 -6
- data/couchbase.gemspec +5 -1
- data/ext/couchbase_ext/.gitignore +4 -0
- data/ext/couchbase_ext/arguments.c +973 -0
- data/ext/couchbase_ext/arithmetic.c +322 -0
- data/ext/couchbase_ext/bucket.c +1092 -0
- data/ext/couchbase_ext/couchbase_ext.c +618 -3247
- data/ext/couchbase_ext/couchbase_ext.h +519 -0
- data/ext/couchbase_ext/delete.c +167 -0
- data/ext/couchbase_ext/extconf.rb +24 -5
- data/ext/couchbase_ext/get.c +301 -0
- data/ext/couchbase_ext/gethrtime.c +124 -0
- data/ext/couchbase_ext/http.c +402 -0
- data/ext/couchbase_ext/observe.c +174 -0
- data/ext/couchbase_ext/result.c +126 -0
- data/ext/couchbase_ext/stats.c +169 -0
- data/ext/couchbase_ext/store.c +522 -0
- data/ext/couchbase_ext/timer.c +192 -0
- data/ext/couchbase_ext/touch.c +190 -0
- data/ext/couchbase_ext/unlock.c +180 -0
- data/ext/couchbase_ext/utils.c +471 -0
- data/ext/couchbase_ext/version.c +147 -0
- data/lib/action_dispatch/middleware/session/couchbase_store.rb +38 -0
- data/lib/active_support/cache/couchbase_store.rb +356 -0
- data/lib/couchbase.rb +24 -3
- data/lib/couchbase/bucket.rb +372 -9
- data/lib/couchbase/result.rb +26 -0
- data/lib/couchbase/utils.rb +59 -0
- data/lib/couchbase/version.rb +1 -1
- data/lib/couchbase/view.rb +305 -0
- data/lib/couchbase/view_row.rb +230 -0
- data/lib/ext/multi_json_fix.rb +47 -0
- data/lib/rack/session/couchbase.rb +104 -0
- data/tasks/compile.rake +5 -14
- data/test/setup.rb +6 -2
- data/test/test_arithmetic.rb +32 -2
- data/test/test_async.rb +18 -4
- data/test/test_bucket.rb +11 -1
- data/test/test_cas.rb +13 -3
- data/test/test_couchbase_rails_cache_store.rb +294 -0
- data/test/test_delete.rb +60 -3
- data/test/test_format.rb +28 -17
- data/test/test_get.rb +91 -14
- data/test/test_store.rb +31 -1
- data/test/{test_flush.rb → test_timer.rb} +11 -18
- data/test/test_touch.rb +33 -5
- data/test/test_unlock.rb +120 -0
- data/test/test_utils.rb +26 -0
- metadata +101 -8
@@ -0,0 +1,174 @@
|
|
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
|
+
observe_callback(lcb_t handle, const void *cookie, lcb_error_t error, const lcb_observe_resp_t *resp)
|
22
|
+
{
|
23
|
+
struct context_st *ctx = (struct context_st *)cookie;
|
24
|
+
struct bucket_st *bucket = ctx->bucket;
|
25
|
+
VALUE key, res, *rv = ctx->rv;
|
26
|
+
|
27
|
+
if (resp->v.v0.key) {
|
28
|
+
key = STR_NEW((const char*)resp->v.v0.key, resp->v.v0.nkey);
|
29
|
+
ctx->exception = cb_check_error(error, "failed to execute observe request", key);
|
30
|
+
if (ctx->exception) {
|
31
|
+
cb_gc_protect(bucket, ctx->exception);
|
32
|
+
}
|
33
|
+
res = rb_class_new_instance(0, NULL, cResult);
|
34
|
+
rb_ivar_set(res, id_iv_completed, Qfalse);
|
35
|
+
rb_ivar_set(res, id_iv_error, ctx->exception);
|
36
|
+
rb_ivar_set(res, id_iv_operation, sym_observe);
|
37
|
+
rb_ivar_set(res, id_iv_key, key);
|
38
|
+
rb_ivar_set(res, id_iv_cas, ULL2NUM(resp->v.v0.cas));
|
39
|
+
rb_ivar_set(res, id_iv_from_master, resp->v.v0.from_master ? Qtrue : Qfalse);
|
40
|
+
rb_ivar_set(res, id_iv_time_to_persist, ULONG2NUM(resp->v.v0.ttp));
|
41
|
+
rb_ivar_set(res, id_iv_time_to_replicate, ULONG2NUM(resp->v.v0.ttr));
|
42
|
+
switch (resp->v.v0.status) {
|
43
|
+
case LCB_OBSERVE_FOUND:
|
44
|
+
rb_ivar_set(res, id_iv_status, sym_found);
|
45
|
+
break;
|
46
|
+
case LCB_OBSERVE_PERSISTED:
|
47
|
+
rb_ivar_set(res, id_iv_status, sym_persisted);
|
48
|
+
break;
|
49
|
+
case LCB_OBSERVE_NOT_FOUND:
|
50
|
+
rb_ivar_set(res, id_iv_status, sym_not_found);
|
51
|
+
break;
|
52
|
+
default:
|
53
|
+
rb_ivar_set(res, id_iv_status, Qnil);
|
54
|
+
}
|
55
|
+
if (bucket->async) { /* asynchronous */
|
56
|
+
if (ctx->proc != Qnil) {
|
57
|
+
cb_proc_call(ctx->proc, 1, res);
|
58
|
+
}
|
59
|
+
} else { /* synchronous */
|
60
|
+
if (NIL_P(ctx->exception)) {
|
61
|
+
VALUE stats = rb_hash_aref(*rv, key);
|
62
|
+
if (NIL_P(stats)) {
|
63
|
+
stats = rb_ary_new();
|
64
|
+
rb_hash_aset(*rv, key, stats);
|
65
|
+
}
|
66
|
+
rb_ary_push(stats, res);
|
67
|
+
}
|
68
|
+
}
|
69
|
+
} else {
|
70
|
+
if (bucket->async && ctx->proc != Qnil) {
|
71
|
+
res = rb_class_new_instance(0, NULL, cResult);
|
72
|
+
rb_ivar_set(res, id_iv_completed, Qtrue);
|
73
|
+
cb_proc_call(ctx->proc, 1, res);
|
74
|
+
}
|
75
|
+
ctx->nqueries--;
|
76
|
+
cb_gc_unprotect(bucket, ctx->proc);
|
77
|
+
}
|
78
|
+
(void)handle;
|
79
|
+
}
|
80
|
+
|
81
|
+
/*
|
82
|
+
* Observe key state
|
83
|
+
*
|
84
|
+
* @since 1.2.0.dp6
|
85
|
+
*
|
86
|
+
* @overload observe(*keys, options = {})
|
87
|
+
* @param keys [String, Symbol, Array] One or several keys to fetch
|
88
|
+
* @param options [Hash] Options for operation.
|
89
|
+
*
|
90
|
+
* @yieldparam ret [Result] the result of operation in asynchronous mode
|
91
|
+
* (valid attributes: +error+, +status+, +operation+, +key+, +cas+,
|
92
|
+
* +from_master+, +time_to_persist+, +time_to_replicate+).
|
93
|
+
*
|
94
|
+
* @return [Hash<String, Array<Result>>, Array<Result>] the state of the
|
95
|
+
* keys on all nodes. If the +keys+ argument was String or Symbol, this
|
96
|
+
* method will return just array of results (result per each node),
|
97
|
+
* otherwise it will return hash map.
|
98
|
+
*
|
99
|
+
* @example Observe single key
|
100
|
+
* c.observe("foo")
|
101
|
+
* #=> [#<Couchbase::Result:0x00000001650df0 ...>, ...]
|
102
|
+
*
|
103
|
+
* @example Observe multiple keys
|
104
|
+
* keys = ["foo", "bar"]
|
105
|
+
* stats = c.observe(keys)
|
106
|
+
* stats.size #=> 2
|
107
|
+
* stats["foo"] #=> [#<Couchbase::Result:0x00000001650df0 ...>, ...]
|
108
|
+
*/
|
109
|
+
|
110
|
+
VALUE
|
111
|
+
cb_bucket_observe(int argc, VALUE *argv, VALUE self)
|
112
|
+
{
|
113
|
+
struct bucket_st *bucket = DATA_PTR(self);
|
114
|
+
struct context_st *ctx;
|
115
|
+
VALUE args, rv, proc, exc;
|
116
|
+
lcb_error_t err;
|
117
|
+
struct params_st params;
|
118
|
+
|
119
|
+
if (bucket->handle == NULL) {
|
120
|
+
rb_raise(eConnectError, "closed connection");
|
121
|
+
}
|
122
|
+
rb_scan_args(argc, argv, "0*&", &args, &proc);
|
123
|
+
if (!bucket->async && proc != Qnil) {
|
124
|
+
rb_raise(rb_eArgError, "synchronous mode doesn't support callbacks");
|
125
|
+
}
|
126
|
+
memset(¶ms, 0, sizeof(struct params_st));
|
127
|
+
params.type = cmd_observe;
|
128
|
+
params.bucket = bucket;
|
129
|
+
cb_params_build(¶ms, RARRAY_LEN(args), args);
|
130
|
+
ctx = xcalloc(1, sizeof(struct context_st));
|
131
|
+
if (ctx == NULL) {
|
132
|
+
rb_raise(eClientNoMemoryError, "failed to allocate memory for context");
|
133
|
+
}
|
134
|
+
ctx->proc = cb_gc_protect(bucket, proc);
|
135
|
+
ctx->bucket = bucket;
|
136
|
+
rv = rb_hash_new();
|
137
|
+
ctx->rv = &rv;
|
138
|
+
ctx->exception = Qnil;
|
139
|
+
ctx->nqueries = params.cmd.observe.num;
|
140
|
+
err = lcb_observe(bucket->handle, (const void *)ctx,
|
141
|
+
params.cmd.observe.num, params.cmd.observe.ptr);
|
142
|
+
cb_params_destroy(¶ms);
|
143
|
+
exc = cb_check_error(err, "failed to schedule observe request", Qnil);
|
144
|
+
if (exc != Qnil) {
|
145
|
+
xfree(ctx);
|
146
|
+
rb_exc_raise(exc);
|
147
|
+
}
|
148
|
+
bucket->nbytes += params.npayload;
|
149
|
+
if (bucket->async) {
|
150
|
+
maybe_do_loop(bucket);
|
151
|
+
return Qnil;
|
152
|
+
} else {
|
153
|
+
if (ctx->nqueries > 0) {
|
154
|
+
/* we have some operations pending */
|
155
|
+
lcb_wait(bucket->handle);
|
156
|
+
}
|
157
|
+
exc = ctx->exception;
|
158
|
+
xfree(ctx);
|
159
|
+
if (exc != Qnil) {
|
160
|
+
cb_gc_unprotect(bucket, exc);
|
161
|
+
rb_exc_raise(exc);
|
162
|
+
}
|
163
|
+
if (bucket->exception != Qnil) {
|
164
|
+
rb_exc_raise(bucket->exception);
|
165
|
+
}
|
166
|
+
if (params.cmd.observe.num > 1 || params.cmd.observe.array) {
|
167
|
+
return rv; /* return as a hash {key => {}, ...} */
|
168
|
+
} else {
|
169
|
+
VALUE vv = Qnil;
|
170
|
+
rb_hash_foreach(rv, cb_first_value_i, (VALUE)&vv);
|
171
|
+
return vv; /* return first value */
|
172
|
+
}
|
173
|
+
}
|
174
|
+
}
|
@@ -0,0 +1,126 @@
|
|
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
|
+
/*
|
21
|
+
* Check if result of operation was successful.
|
22
|
+
*
|
23
|
+
* @since 1.0.0
|
24
|
+
*
|
25
|
+
* @return [true, false] +false+ if there is an +error+ object attached,
|
26
|
+
* +false+ otherwise.
|
27
|
+
*/
|
28
|
+
VALUE
|
29
|
+
cb_result_success_p(VALUE self)
|
30
|
+
{
|
31
|
+
return RTEST(rb_ivar_get(self, id_iv_error)) ? Qfalse : Qtrue;
|
32
|
+
}
|
33
|
+
|
34
|
+
/*
|
35
|
+
* Returns a string containing a human-readable representation of the Result.
|
36
|
+
*
|
37
|
+
* @since 1.0.0
|
38
|
+
*
|
39
|
+
* @return [String]
|
40
|
+
*/
|
41
|
+
VALUE
|
42
|
+
cb_result_inspect(VALUE self)
|
43
|
+
{
|
44
|
+
VALUE str, attr, error;
|
45
|
+
char buf[100];
|
46
|
+
|
47
|
+
str = rb_str_buf_new2("#<");
|
48
|
+
rb_str_buf_cat2(str, rb_obj_classname(self));
|
49
|
+
snprintf(buf, 100, ":%p", (void *)self);
|
50
|
+
rb_str_buf_cat2(str, buf);
|
51
|
+
|
52
|
+
attr = rb_ivar_get(self, id_iv_error);
|
53
|
+
if (RTEST(attr)) {
|
54
|
+
error = rb_ivar_get(attr, id_iv_error);
|
55
|
+
} else {
|
56
|
+
error = INT2FIX(0);
|
57
|
+
}
|
58
|
+
rb_str_buf_cat2(str, " error=0x");
|
59
|
+
rb_str_append(str, rb_funcall(error, id_to_s, 1, INT2FIX(16)));
|
60
|
+
|
61
|
+
attr = rb_ivar_get(self, id_iv_operation);
|
62
|
+
if (RTEST(attr)) {
|
63
|
+
rb_str_buf_cat2(str, " operation=");
|
64
|
+
rb_str_append(str, rb_inspect(attr));
|
65
|
+
}
|
66
|
+
|
67
|
+
attr = rb_ivar_get(self, id_iv_key);
|
68
|
+
if (RTEST(attr)) {
|
69
|
+
rb_str_buf_cat2(str, " key=");
|
70
|
+
rb_str_append(str, rb_inspect(attr));
|
71
|
+
}
|
72
|
+
|
73
|
+
attr = rb_ivar_get(self, id_iv_status);
|
74
|
+
if (RTEST(attr)) {
|
75
|
+
rb_str_buf_cat2(str, " status=");
|
76
|
+
rb_str_append(str, rb_inspect(attr));
|
77
|
+
}
|
78
|
+
|
79
|
+
attr = rb_ivar_get(self, id_iv_cas);
|
80
|
+
if (RTEST(attr)) {
|
81
|
+
rb_str_buf_cat2(str, " cas=");
|
82
|
+
rb_str_append(str, rb_inspect(attr));
|
83
|
+
}
|
84
|
+
|
85
|
+
attr = rb_ivar_get(self, id_iv_flags);
|
86
|
+
if (RTEST(attr)) {
|
87
|
+
rb_str_buf_cat2(str, " flags=0x");
|
88
|
+
rb_str_append(str, rb_funcall(attr, id_to_s, 1, INT2FIX(16)));
|
89
|
+
}
|
90
|
+
|
91
|
+
attr = rb_ivar_get(self, id_iv_node);
|
92
|
+
if (RTEST(attr)) {
|
93
|
+
rb_str_buf_cat2(str, " node=");
|
94
|
+
rb_str_append(str, rb_inspect(attr));
|
95
|
+
}
|
96
|
+
|
97
|
+
attr = rb_ivar_get(self, id_iv_from_master);
|
98
|
+
if (attr != Qnil) {
|
99
|
+
rb_str_buf_cat2(str, " from_master=");
|
100
|
+
rb_str_append(str, rb_inspect(attr));
|
101
|
+
}
|
102
|
+
|
103
|
+
attr = rb_ivar_get(self, id_iv_time_to_persist);
|
104
|
+
if (RTEST(attr)) {
|
105
|
+
rb_str_buf_cat2(str, " time_to_persist=");
|
106
|
+
rb_str_append(str, rb_inspect(attr));
|
107
|
+
}
|
108
|
+
|
109
|
+
attr = rb_ivar_get(self, id_iv_time_to_replicate);
|
110
|
+
if (RTEST(attr)) {
|
111
|
+
rb_str_buf_cat2(str, " time_to_replicate=");
|
112
|
+
rb_str_append(str, rb_inspect(attr));
|
113
|
+
}
|
114
|
+
|
115
|
+
attr = rb_ivar_get(self, id_iv_headers);
|
116
|
+
if (RTEST(attr)) {
|
117
|
+
rb_str_buf_cat2(str, " headers=");
|
118
|
+
rb_str_append(str, rb_inspect(attr));
|
119
|
+
}
|
120
|
+
|
121
|
+
rb_str_buf_cat2(str, ">");
|
122
|
+
|
123
|
+
return str;
|
124
|
+
}
|
125
|
+
|
126
|
+
|
@@ -0,0 +1,169 @@
|
|
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
|
+
stat_callback(lcb_t handle, const void *cookie, lcb_error_t error, const lcb_server_stat_resp_t *resp)
|
22
|
+
{
|
23
|
+
struct context_st *ctx = (struct context_st *)cookie;
|
24
|
+
struct bucket_st *bucket = ctx->bucket;
|
25
|
+
VALUE stats, node, key, val, *rv = ctx->rv, 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, id_iv_operation, sym_stats);
|
31
|
+
if (NIL_P(ctx->exception)) {
|
32
|
+
ctx->exception = cb_gc_protect(bucket, exc);
|
33
|
+
}
|
34
|
+
}
|
35
|
+
if (node != Qnil) {
|
36
|
+
key = STR_NEW((const char*)resp->v.v0.key, resp->v.v0.nkey);
|
37
|
+
val = STR_NEW((const char*)resp->v.v0.bytes, resp->v.v0.nbytes);
|
38
|
+
if (bucket->async) { /* asynchronous */
|
39
|
+
if (ctx->proc != Qnil) {
|
40
|
+
res = rb_class_new_instance(0, NULL, cResult);
|
41
|
+
rb_ivar_set(res, id_iv_error, exc);
|
42
|
+
rb_ivar_set(res, id_iv_operation, sym_stats);
|
43
|
+
rb_ivar_set(res, id_iv_node, node);
|
44
|
+
rb_ivar_set(res, id_iv_key, key);
|
45
|
+
rb_ivar_set(res, id_iv_value, val);
|
46
|
+
cb_proc_call(ctx->proc, 1, res);
|
47
|
+
}
|
48
|
+
} else { /* synchronous */
|
49
|
+
if (NIL_P(exc)) {
|
50
|
+
stats = rb_hash_aref(*rv, key);
|
51
|
+
if (NIL_P(stats)) {
|
52
|
+
stats = rb_hash_new();
|
53
|
+
rb_hash_aset(*rv, key, stats);
|
54
|
+
}
|
55
|
+
rb_hash_aset(stats, node, val);
|
56
|
+
}
|
57
|
+
}
|
58
|
+
} else {
|
59
|
+
ctx->nqueries--;
|
60
|
+
cb_gc_unprotect(bucket, ctx->proc);
|
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 bucket_st *bucket = DATA_PTR(self);
|
111
|
+
struct context_st *ctx;
|
112
|
+
VALUE rv, exc, args, proc;
|
113
|
+
lcb_error_t err;
|
114
|
+
struct params_st params;
|
115
|
+
|
116
|
+
if (bucket->handle == NULL) {
|
117
|
+
rb_raise(eConnectError, "closed connection");
|
118
|
+
}
|
119
|
+
rb_scan_args(argc, argv, "0*&", &args, &proc);
|
120
|
+
if (!bucket->async && proc != Qnil) {
|
121
|
+
rb_raise(rb_eArgError, "synchronous mode doesn't support callbacks");
|
122
|
+
}
|
123
|
+
memset(¶ms, 0, sizeof(struct params_st));
|
124
|
+
params.type = cmd_stats;
|
125
|
+
params.bucket = bucket;
|
126
|
+
cb_params_build(¶ms, RARRAY_LEN(args), args);
|
127
|
+
ctx = xcalloc(1, sizeof(struct context_st));
|
128
|
+
if (ctx == NULL) {
|
129
|
+
rb_raise(eClientNoMemoryError, "failed to allocate memory for context");
|
130
|
+
}
|
131
|
+
rv = rb_hash_new();
|
132
|
+
ctx->rv = &rv;
|
133
|
+
ctx->bucket = bucket;
|
134
|
+
ctx->proc = cb_gc_protect(bucket, proc);
|
135
|
+
ctx->exception = Qnil;
|
136
|
+
ctx->nqueries = params.cmd.stats.num;
|
137
|
+
err = lcb_server_stats(bucket->handle, (const void *)ctx,
|
138
|
+
params.cmd.stats.num, params.cmd.stats.ptr);
|
139
|
+
exc = cb_check_error(err, "failed to schedule stat request", Qnil);
|
140
|
+
cb_params_destroy(¶ms);
|
141
|
+
if (exc != Qnil) {
|
142
|
+
xfree(ctx);
|
143
|
+
rb_exc_raise(exc);
|
144
|
+
}
|
145
|
+
bucket->nbytes += params.npayload;
|
146
|
+
if (bucket->async) {
|
147
|
+
maybe_do_loop(bucket);
|
148
|
+
return Qnil;
|
149
|
+
} else {
|
150
|
+
if (ctx->nqueries > 0) {
|
151
|
+
/* we have some operations pending */
|
152
|
+
lcb_wait(bucket->handle);
|
153
|
+
}
|
154
|
+
exc = ctx->exception;
|
155
|
+
xfree(ctx);
|
156
|
+
if (exc != Qnil) {
|
157
|
+
cb_gc_unprotect(bucket, exc);
|
158
|
+
rb_exc_raise(exc);
|
159
|
+
}
|
160
|
+
if (bucket->exception != Qnil) {
|
161
|
+
rb_exc_raise(bucket->exception);
|
162
|
+
}
|
163
|
+
return rv;
|
164
|
+
}
|
165
|
+
|
166
|
+
return Qnil;
|
167
|
+
}
|
168
|
+
|
169
|
+
|