couchbase 1.3.4-x64-mingw32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/.travis.yml +22 -0
- data/.yardopts +5 -0
- data/CONTRIBUTING.markdown +75 -0
- data/Gemfile +4 -0
- data/LICENSE +201 -0
- data/Makefile +3 -0
- data/README.markdown +649 -0
- data/RELEASE_NOTES.markdown +796 -0
- data/Rakefile +20 -0
- data/couchbase.gemspec +49 -0
- data/examples/chat-em/Gemfile +7 -0
- data/examples/chat-em/README.markdown +45 -0
- data/examples/chat-em/server.rb +82 -0
- data/examples/chat-goliath-grape/Gemfile +5 -0
- data/examples/chat-goliath-grape/README.markdown +50 -0
- data/examples/chat-goliath-grape/app.rb +67 -0
- data/examples/chat-goliath-grape/config/app.rb +20 -0
- data/examples/transcoders/Gemfile +3 -0
- data/examples/transcoders/README.markdown +59 -0
- data/examples/transcoders/cb-zcat +40 -0
- data/examples/transcoders/cb-zcp +45 -0
- data/examples/transcoders/gzip_transcoder.rb +49 -0
- data/examples/transcoders/options.rb +54 -0
- data/ext/couchbase_ext/.gitignore +4 -0
- data/ext/couchbase_ext/arguments.c +956 -0
- data/ext/couchbase_ext/arithmetic.c +307 -0
- data/ext/couchbase_ext/bucket.c +1370 -0
- data/ext/couchbase_ext/context.c +65 -0
- data/ext/couchbase_ext/couchbase_ext.c +1364 -0
- data/ext/couchbase_ext/couchbase_ext.h +644 -0
- data/ext/couchbase_ext/delete.c +163 -0
- data/ext/couchbase_ext/eventmachine_plugin.c +452 -0
- data/ext/couchbase_ext/extconf.rb +168 -0
- data/ext/couchbase_ext/get.c +316 -0
- data/ext/couchbase_ext/gethrtime.c +129 -0
- data/ext/couchbase_ext/http.c +432 -0
- data/ext/couchbase_ext/multithread_plugin.c +1090 -0
- data/ext/couchbase_ext/observe.c +171 -0
- data/ext/couchbase_ext/plugin_common.c +171 -0
- data/ext/couchbase_ext/result.c +129 -0
- data/ext/couchbase_ext/stats.c +163 -0
- data/ext/couchbase_ext/store.c +542 -0
- data/ext/couchbase_ext/timer.c +192 -0
- data/ext/couchbase_ext/touch.c +186 -0
- data/ext/couchbase_ext/unlock.c +176 -0
- data/ext/couchbase_ext/utils.c +551 -0
- data/ext/couchbase_ext/version.c +142 -0
- data/lib/action_dispatch/middleware/session/couchbase_store.rb +38 -0
- data/lib/active_support/cache/couchbase_store.rb +430 -0
- data/lib/couchbase.rb +155 -0
- data/lib/couchbase/bucket.rb +457 -0
- data/lib/couchbase/cluster.rb +119 -0
- data/lib/couchbase/connection_pool.rb +58 -0
- data/lib/couchbase/constants.rb +12 -0
- data/lib/couchbase/result.rb +26 -0
- data/lib/couchbase/transcoder.rb +120 -0
- data/lib/couchbase/utils.rb +62 -0
- data/lib/couchbase/version.rb +21 -0
- data/lib/couchbase/view.rb +506 -0
- data/lib/couchbase/view_row.rb +272 -0
- data/lib/ext/multi_json_fix.rb +56 -0
- data/lib/rack/session/couchbase.rb +108 -0
- data/tasks/benchmark.rake +6 -0
- data/tasks/compile.rake +158 -0
- data/tasks/test.rake +100 -0
- data/tasks/util.rake +21 -0
- data/test/profile/.gitignore +1 -0
- data/test/profile/Gemfile +6 -0
- data/test/profile/benchmark.rb +195 -0
- data/test/setup.rb +178 -0
- data/test/test_arithmetic.rb +185 -0
- data/test/test_async.rb +316 -0
- data/test/test_bucket.rb +250 -0
- data/test/test_cas.rb +235 -0
- data/test/test_couchbase.rb +77 -0
- data/test/test_couchbase_connection_pool.rb +77 -0
- data/test/test_couchbase_rails_cache_store.rb +361 -0
- data/test/test_delete.rb +120 -0
- data/test/test_errors.rb +82 -0
- data/test/test_eventmachine.rb +70 -0
- data/test/test_format.rb +164 -0
- data/test/test_get.rb +407 -0
- data/test/test_stats.rb +57 -0
- data/test/test_store.rb +216 -0
- data/test/test_timer.rb +42 -0
- data/test/test_touch.rb +97 -0
- data/test/test_unlock.rb +119 -0
- data/test/test_utils.rb +58 -0
- data/test/test_version.rb +52 -0
- metadata +336 -0
@@ -0,0 +1,163 @@
|
|
1
|
+
/* vim: ft=c et ts=8 sts=4 sw=4 cino=
|
2
|
+
*
|
3
|
+
* Copyright 2011, 2012 Couchbase, Inc.
|
4
|
+
*
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
* you may not use this file except in compliance with the License.
|
7
|
+
* You may obtain a copy of the License at
|
8
|
+
*
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
*
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
* See the License for the specific language governing permissions and
|
15
|
+
* limitations under the License.
|
16
|
+
*/
|
17
|
+
|
18
|
+
#include "couchbase_ext.h"
|
19
|
+
|
20
|
+
void
|
21
|
+
cb_delete_callback(lcb_t handle, const void *cookie, lcb_error_t error, const lcb_remove_resp_t *resp)
|
22
|
+
{
|
23
|
+
struct cb_context_st *ctx = (struct cb_context_st *)cookie;
|
24
|
+
struct cb_bucket_st *bucket = ctx->bucket;
|
25
|
+
VALUE key, exc = Qnil, res;
|
26
|
+
|
27
|
+
ctx->nqueries--;
|
28
|
+
key = STR_NEW((const char*)resp->v.v0.key, resp->v.v0.nkey);
|
29
|
+
cb_strip_key_prefix(bucket, key);
|
30
|
+
|
31
|
+
if (error != LCB_KEY_ENOENT || !ctx->quiet) {
|
32
|
+
exc = cb_check_error(error, "failed to remove value", key);
|
33
|
+
if (exc != Qnil) {
|
34
|
+
rb_ivar_set(exc, cb_id_iv_operation, cb_sym_delete);
|
35
|
+
ctx->exception = exc;
|
36
|
+
}
|
37
|
+
}
|
38
|
+
if (bucket->async) { /* asynchronous */
|
39
|
+
if (ctx->proc != Qnil) {
|
40
|
+
res = rb_class_new_instance(0, NULL, cb_cResult);
|
41
|
+
rb_ivar_set(res, cb_id_iv_error, exc);
|
42
|
+
rb_ivar_set(res, cb_id_iv_operation, cb_sym_delete);
|
43
|
+
rb_ivar_set(res, cb_id_iv_key, key);
|
44
|
+
cb_proc_call(bucket, ctx->proc, 1, res);
|
45
|
+
}
|
46
|
+
} else { /* synchronous */
|
47
|
+
rb_hash_aset(ctx->rv, key, (error == LCB_SUCCESS) ? Qtrue : Qfalse);
|
48
|
+
}
|
49
|
+
if (ctx->nqueries == 0) {
|
50
|
+
ctx->proc = Qnil;
|
51
|
+
if (bucket->async) {
|
52
|
+
cb_context_free(ctx);
|
53
|
+
}
|
54
|
+
}
|
55
|
+
(void)handle;
|
56
|
+
}
|
57
|
+
|
58
|
+
/*
|
59
|
+
* Delete the specified key
|
60
|
+
*
|
61
|
+
* @since 1.0.0
|
62
|
+
*
|
63
|
+
* @overload delete(key, options = {})
|
64
|
+
* @param key [String, Symbol] Key used to reference the value.
|
65
|
+
* @param options [Hash] Options for operation.
|
66
|
+
* @option options [true, false] :quiet (self.quiet) If set to +true+, the
|
67
|
+
* operation won't raise error for missing key, it will return +nil+.
|
68
|
+
* Otherwise it will raise error in synchronous mode. In asynchronous
|
69
|
+
* mode this option ignored.
|
70
|
+
* @option options [Fixnum] :cas The CAS value for an object. This value
|
71
|
+
* created on the server and is guaranteed to be unique for each value of
|
72
|
+
* a given key. This value is used to provide simple optimistic
|
73
|
+
* concurrency control when multiple clients or threads try to
|
74
|
+
* update/delete an item simultaneously.
|
75
|
+
*
|
76
|
+
* @raise [Couchbase::Error::Connect] if connection closed (see {Bucket#reconnect})
|
77
|
+
* @raise [ArgumentError] when passing the block in synchronous mode
|
78
|
+
* @raise [Couchbase::Error::KeyExists] on CAS mismatch
|
79
|
+
* @raise [Couchbase::Error::NotFound] if key is missing in verbose mode
|
80
|
+
*
|
81
|
+
* @return [true, false, Hash<String, Boolean>] the result of the
|
82
|
+
* operation
|
83
|
+
*
|
84
|
+
* @example Delete the key in quiet mode (default)
|
85
|
+
* c.set("foo", "bar")
|
86
|
+
* c.delete("foo") #=> true
|
87
|
+
* c.delete("foo") #=> false
|
88
|
+
*
|
89
|
+
* @example Delete the key verbosely
|
90
|
+
* c.set("foo", "bar")
|
91
|
+
* c.delete("foo", :quiet => false) #=> true
|
92
|
+
* c.delete("foo", :quiet => true) #=> nil (default behaviour)
|
93
|
+
* c.delete("foo", :quiet => false) #=> will raise Couchbase::Error::NotFound
|
94
|
+
*
|
95
|
+
* @example Delete the key with version check
|
96
|
+
* ver = c.set("foo", "bar") #=> 5992859822302167040
|
97
|
+
* c.delete("foo", :cas => 123456) #=> will raise Couchbase::Error::KeyExists
|
98
|
+
* c.delete("foo", :cas => ver) #=> true
|
99
|
+
*/
|
100
|
+
VALUE
|
101
|
+
cb_bucket_delete(int argc, VALUE *argv, VALUE self)
|
102
|
+
{
|
103
|
+
struct cb_bucket_st *bucket = DATA_PTR(self);
|
104
|
+
struct cb_context_st *ctx;
|
105
|
+
VALUE rv, exc;
|
106
|
+
VALUE proc;
|
107
|
+
lcb_error_t err;
|
108
|
+
struct cb_params_st params;
|
109
|
+
|
110
|
+
if (!cb_bucket_connected_bang(bucket, cb_sym_delete)) {
|
111
|
+
return Qnil;
|
112
|
+
}
|
113
|
+
|
114
|
+
memset(¶ms, 0, sizeof(struct cb_params_st));
|
115
|
+
rb_scan_args(argc, argv, "0*&", ¶ms.args, &proc);
|
116
|
+
if (!bucket->async && proc != Qnil) {
|
117
|
+
rb_raise(rb_eArgError, "synchronous mode doesn't support callbacks");
|
118
|
+
}
|
119
|
+
rb_funcall(params.args, cb_id_flatten_bang, 0);
|
120
|
+
params.type = cb_cmd_remove;
|
121
|
+
params.bucket = bucket;
|
122
|
+
cb_params_build(¶ms);
|
123
|
+
|
124
|
+
ctx = cb_context_alloc_common(bucket, proc, params.cmd.remove.num);
|
125
|
+
ctx->quiet = params.cmd.remove.quiet;
|
126
|
+
err = lcb_remove(bucket->handle, (const void *)ctx,
|
127
|
+
params.cmd.remove.num, params.cmd.remove.ptr);
|
128
|
+
cb_params_destroy(¶ms);
|
129
|
+
exc = cb_check_error(err, "failed to schedule delete request", Qnil);
|
130
|
+
if (exc != Qnil) {
|
131
|
+
cb_context_free(ctx);
|
132
|
+
rb_exc_raise(exc);
|
133
|
+
}
|
134
|
+
bucket->nbytes += params.npayload;
|
135
|
+
if (bucket->async) {
|
136
|
+
cb_maybe_do_loop(bucket);
|
137
|
+
return Qnil;
|
138
|
+
} else {
|
139
|
+
if (ctx->nqueries > 0) {
|
140
|
+
/* we have some operations pending */
|
141
|
+
lcb_wait(bucket->handle);
|
142
|
+
}
|
143
|
+
exc = ctx->exception;
|
144
|
+
rv = ctx->rv;
|
145
|
+
cb_context_free(ctx);
|
146
|
+
if (exc != Qnil) {
|
147
|
+
rb_exc_raise(exc);
|
148
|
+
}
|
149
|
+
exc = bucket->exception;
|
150
|
+
if (exc != Qnil) {
|
151
|
+
bucket->exception = Qnil;
|
152
|
+
rb_exc_raise(exc);
|
153
|
+
}
|
154
|
+
if (params.cmd.remove.num > 1) {
|
155
|
+
return rv; /* return as a hash {key => true, ...} */
|
156
|
+
} else {
|
157
|
+
VALUE vv = Qnil;
|
158
|
+
rb_hash_foreach(rv, cb_first_value_i, (VALUE)&vv);
|
159
|
+
return vv;
|
160
|
+
}
|
161
|
+
return rv;
|
162
|
+
}
|
163
|
+
}
|
@@ -0,0 +1,452 @@
|
|
1
|
+
/* vim: ft=c et ts=8 sts=4 sw=4 cino=
|
2
|
+
*
|
3
|
+
* Copyright 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
|
+
#ifndef _WIN32
|
21
|
+
#ifdef BUILD_EVENTMACHINE_PLUGIN
|
22
|
+
|
23
|
+
#include <errno.h>
|
24
|
+
|
25
|
+
VALUE cb_mEm;
|
26
|
+
VALUE cb_cEmSocket;
|
27
|
+
VALUE em_cPeriodicTimer;
|
28
|
+
VALUE cb_cEmEvent;
|
29
|
+
VALUE rb_mObSpace;
|
30
|
+
ID cb_id_add_timer;
|
31
|
+
ID cb_id_cancel_timer;
|
32
|
+
ID cb_id_detach;
|
33
|
+
ID cb_id_define_finalizer;
|
34
|
+
ID cb_id_iv_event;
|
35
|
+
ID cb_id_notify_readable_p;
|
36
|
+
ID cb_id_notify_writable_p;
|
37
|
+
ID cb_id_set_notify_readable;
|
38
|
+
ID cb_id_set_notify_writable;
|
39
|
+
ID cb_id_undefine_finalizer;
|
40
|
+
ID cb_id_watch;
|
41
|
+
VALUE cb_sym_clear_holder;
|
42
|
+
VALUE cb_sym_resume;
|
43
|
+
|
44
|
+
typedef struct rb_em_event rb_em_event;
|
45
|
+
typedef struct rb_em_loop rb_em_loop;
|
46
|
+
struct rb_em_event {
|
47
|
+
lcb_socket_t socket;
|
48
|
+
void *cb_data;
|
49
|
+
void (*handler)(lcb_socket_t sock, short which, void *cb_data);
|
50
|
+
VALUE holder;
|
51
|
+
lcb_uint32_t usec;
|
52
|
+
short canceled;
|
53
|
+
short current_flags;
|
54
|
+
VALUE self;
|
55
|
+
rb_em_loop *loop;
|
56
|
+
};
|
57
|
+
|
58
|
+
struct rb_em_loop {
|
59
|
+
VALUE fiber;
|
60
|
+
struct cb_bucket_st *bucket;
|
61
|
+
};
|
62
|
+
|
63
|
+
static void
|
64
|
+
rb_em_event_mark(void *p)
|
65
|
+
{
|
66
|
+
if (p) {
|
67
|
+
rb_em_event *ev = p;
|
68
|
+
rb_gc_mark(ev->holder);
|
69
|
+
rb_gc_mark(ev->loop->bucket->self);
|
70
|
+
}
|
71
|
+
}
|
72
|
+
|
73
|
+
static void
|
74
|
+
rb_em_event_free(void *p)
|
75
|
+
{
|
76
|
+
if (p) {
|
77
|
+
rb_em_event *ev = p;
|
78
|
+
ev->self = 0;
|
79
|
+
ev->holder = 0;
|
80
|
+
ev->loop = NULL;
|
81
|
+
}
|
82
|
+
}
|
83
|
+
|
84
|
+
static void
|
85
|
+
rb_em_event_run_callback(rb_em_event *ev, short flags)
|
86
|
+
{
|
87
|
+
if (ev->loop->fiber) {
|
88
|
+
ev->current_flags = flags;
|
89
|
+
rb_fiber_resume(ev->loop->fiber, 1, &ev->self);
|
90
|
+
} else {
|
91
|
+
ev->handler(ev->socket, flags, ev->cb_data);
|
92
|
+
}
|
93
|
+
}
|
94
|
+
|
95
|
+
static VALUE
|
96
|
+
rb_em_event_call(VALUE self)
|
97
|
+
{
|
98
|
+
rb_em_event *ev;
|
99
|
+
Data_Get_Struct(self, rb_em_event, ev);
|
100
|
+
|
101
|
+
ev->holder = 0;
|
102
|
+
rb_em_event_run_callback(ev, 0);
|
103
|
+
|
104
|
+
if (!ev->canceled && !ev->holder) {
|
105
|
+
ev->holder = rb_funcall_2(em_m, cb_id_add_timer, rb_float_new((double)ev->usec / 1.0e6), self);
|
106
|
+
}
|
107
|
+
|
108
|
+
return Qnil;
|
109
|
+
}
|
110
|
+
|
111
|
+
static VALUE
|
112
|
+
rb_em_event_clear_holder(VALUE self)
|
113
|
+
{
|
114
|
+
rb_em_event *ev;
|
115
|
+
Data_Get_Struct(self, rb_em_event, ev);
|
116
|
+
|
117
|
+
ev->holder = 0;
|
118
|
+
|
119
|
+
return Qnil;
|
120
|
+
}
|
121
|
+
|
122
|
+
static void
|
123
|
+
rb_em_event_setup_finalizer(rb_em_event *ev)
|
124
|
+
{
|
125
|
+
rb_funcall_2(rb_mObSpace, cb_id_define_finalizer, ev->holder,
|
126
|
+
rb_obj_method(ev->self, cb_sym_clear_holder));
|
127
|
+
}
|
128
|
+
|
129
|
+
static void
|
130
|
+
rb_em_event_clear_finalizer(rb_em_event *ev)
|
131
|
+
{
|
132
|
+
rb_funcall_1(rb_mObSpace, cb_id_undefine_finalizer, ev->holder);
|
133
|
+
}
|
134
|
+
|
135
|
+
static VALUE
|
136
|
+
rb_em_socket_notify_readable(VALUE self)
|
137
|
+
{
|
138
|
+
VALUE event = rb_ivar_get(self, cb_id_iv_event);
|
139
|
+
rb_em_event *ev;
|
140
|
+
|
141
|
+
if (RTEST(event)) {
|
142
|
+
Data_Get_Struct(event, rb_em_event, ev);
|
143
|
+
rb_em_event_run_callback(ev, LCB_READ_EVENT);
|
144
|
+
} else {
|
145
|
+
rb_funcall_0(self, cb_id_detach);
|
146
|
+
}
|
147
|
+
|
148
|
+
return Qnil;
|
149
|
+
}
|
150
|
+
|
151
|
+
static VALUE
|
152
|
+
rb_em_socket_notify_writable(VALUE self)
|
153
|
+
{
|
154
|
+
VALUE event = rb_ivar_get(self, cb_id_iv_event);
|
155
|
+
rb_em_event *ev;
|
156
|
+
|
157
|
+
if (RTEST(event)) {
|
158
|
+
Data_Get_Struct(event, rb_em_event, ev);
|
159
|
+
rb_em_event_run_callback(ev, LCB_WRITE_EVENT);
|
160
|
+
} else {
|
161
|
+
rb_funcall_0(self, cb_id_detach);
|
162
|
+
}
|
163
|
+
|
164
|
+
return Qnil;
|
165
|
+
}
|
166
|
+
|
167
|
+
static void
|
168
|
+
cb_gc_em_loop_mark(void *p, struct cb_bucket_st *bucket)
|
169
|
+
{
|
170
|
+
rb_em_loop *loop = p;
|
171
|
+
rb_gc_mark(loop->fiber);
|
172
|
+
(void)bucket;
|
173
|
+
}
|
174
|
+
|
175
|
+
static rb_em_loop *
|
176
|
+
rb_em_loop_create(struct cb_bucket_st *bucket)
|
177
|
+
{
|
178
|
+
rb_em_loop *loop = calloc(1, sizeof(*loop));
|
179
|
+
loop->bucket = bucket;
|
180
|
+
cb_gc_protect_ptr(bucket, loop, cb_gc_em_loop_mark);
|
181
|
+
return loop;
|
182
|
+
}
|
183
|
+
|
184
|
+
static void
|
185
|
+
rb_em_loop_destroy(rb_em_loop *loop)
|
186
|
+
{
|
187
|
+
cb_gc_unprotect_ptr(loop->bucket, loop);
|
188
|
+
free(loop);
|
189
|
+
}
|
190
|
+
|
191
|
+
static void
|
192
|
+
initialize_event_machine_plugin() {
|
193
|
+
VALUE em_cConnection;
|
194
|
+
|
195
|
+
rb_mObSpace = rb_const_get(rb_cObject, rb_intern("ObjectSpace"));
|
196
|
+
|
197
|
+
em_m = rb_const_get(rb_cObject, rb_intern("EM"));
|
198
|
+
em_cConnection = rb_const_get(em_m, rb_intern("Connection"));
|
199
|
+
em_cPeriodicTimer = rb_const_get(em_m, rb_intern("PeriodicTimer"));
|
200
|
+
|
201
|
+
cb_mEm = rb_define_module_under(cb_mCouchbase, "EM");
|
202
|
+
|
203
|
+
cb_cEmEvent = rb_define_class_under(cb_mEm, "Event", rb_cObject);
|
204
|
+
rb_define_method(cb_cEmEvent, "call", rb_em_event_call, 0);
|
205
|
+
rb_define_method(cb_cEmEvent, "clear_holder", rb_em_event_clear_holder, 0);
|
206
|
+
|
207
|
+
cb_cEmSocket = rb_define_class_under(cb_mEm, "Socket", em_cConnection);
|
208
|
+
rb_define_method(cb_cEmSocket, "notify_readable", rb_em_socket_notify_readable, 0);
|
209
|
+
rb_define_method(cb_cEmSocket, "notify_writable", rb_em_socket_notify_writable, 0);
|
210
|
+
|
211
|
+
cb_id_add_timer = rb_intern("add_timer");
|
212
|
+
cb_id_cancel_timer = rb_intern("cancel_timer");
|
213
|
+
cb_id_define_finalizer = rb_intern("define_finalizer");
|
214
|
+
cb_id_detach = rb_intern("detach");
|
215
|
+
cb_id_iv_event = rb_intern("@event");
|
216
|
+
cb_id_notify_readable_p = rb_intern("notify_readable?");
|
217
|
+
cb_id_notify_writable_p = rb_intern("notify_writable?");
|
218
|
+
cb_id_set_notify_readable = rb_intern("notify_readable=");
|
219
|
+
cb_id_set_notify_writable = rb_intern("notify_writable=");
|
220
|
+
cb_id_undefine_finalizer = rb_intern("undefine_finalizer");
|
221
|
+
cb_id_watch = rb_intern("watch");
|
222
|
+
cb_sym_clear_holder = ID2SYM(rb_intern("clear_holder"));
|
223
|
+
cb_sym_resume = ID2SYM(rb_intern("resume"));
|
224
|
+
}
|
225
|
+
|
226
|
+
static void
|
227
|
+
cb_gc_em_event_mark(void *p, struct cb_bucket_st *bucket)
|
228
|
+
{
|
229
|
+
rb_em_event *ev = p;
|
230
|
+
rb_gc_mark(ev->self);
|
231
|
+
(void)bucket;
|
232
|
+
}
|
233
|
+
|
234
|
+
static void *
|
235
|
+
lcb_io_create_event(struct lcb_io_opt_st *iops)
|
236
|
+
{
|
237
|
+
rb_em_loop *loop = iops->v.v0.cookie;
|
238
|
+
rb_em_event *ev = calloc(1, sizeof(rb_em_event));
|
239
|
+
VALUE res = Data_Wrap_Struct(cb_cEmEvent, rb_em_event_mark, rb_em_event_free, ev);
|
240
|
+
cb_gc_protect_ptr(loop->bucket, ev, cb_gc_em_event_mark);
|
241
|
+
ev->self = res;
|
242
|
+
ev->loop = loop;
|
243
|
+
ev->socket = -1;
|
244
|
+
|
245
|
+
return ev;
|
246
|
+
}
|
247
|
+
|
248
|
+
static inline void
|
249
|
+
rb_em_event_dealloc(rb_em_event *ev, rb_em_loop *loop)
|
250
|
+
{
|
251
|
+
if (ev->self) {
|
252
|
+
DATA_PTR(ev->self) = 0;
|
253
|
+
}
|
254
|
+
cb_gc_unprotect_ptr(loop->bucket, ev);
|
255
|
+
free(ev);
|
256
|
+
}
|
257
|
+
|
258
|
+
static int
|
259
|
+
lcb_io_update_event(struct lcb_io_opt_st *iops,
|
260
|
+
lcb_socket_t sock,
|
261
|
+
void *event,
|
262
|
+
short flags,
|
263
|
+
void *cb_data,
|
264
|
+
void (*handler)(lcb_socket_t sock,
|
265
|
+
short which,
|
266
|
+
void *cb_data))
|
267
|
+
{
|
268
|
+
rb_em_event *ev = event;
|
269
|
+
|
270
|
+
if (ev->holder == 0) {
|
271
|
+
ev->holder = rb_funcall_2(em_m, cb_id_watch, INT2FIX(sock), cb_cEmSocket);
|
272
|
+
rb_ivar_set(ev->holder, cb_id_iv_event, ev->self);
|
273
|
+
rb_em_event_setup_finalizer(ev);
|
274
|
+
}
|
275
|
+
|
276
|
+
ev->socket = sock;
|
277
|
+
ev->cb_data = cb_data;
|
278
|
+
ev->handler = handler;
|
279
|
+
|
280
|
+
rb_funcall_1(ev->holder, cb_id_set_notify_readable, (flags & LCB_READ_EVENT) ? Qtrue : Qfalse);
|
281
|
+
rb_funcall_1(ev->holder, cb_id_set_notify_writable, (flags & LCB_WRITE_EVENT) ? Qtrue : Qfalse);
|
282
|
+
|
283
|
+
(void)iops;
|
284
|
+
return 0;
|
285
|
+
}
|
286
|
+
|
287
|
+
static void
|
288
|
+
lcb_io_delete_event(struct lcb_io_opt_st *iops,
|
289
|
+
lcb_socket_t sock,
|
290
|
+
void *event)
|
291
|
+
{
|
292
|
+
rb_em_event *ev = event;
|
293
|
+
if (ev->holder) {
|
294
|
+
rb_funcall_1(ev->holder, cb_id_set_notify_readable, Qfalse);
|
295
|
+
rb_funcall_1(ev->holder, cb_id_set_notify_writable, Qfalse);
|
296
|
+
}
|
297
|
+
(void)sock;
|
298
|
+
(void)iops;
|
299
|
+
}
|
300
|
+
|
301
|
+
static void
|
302
|
+
lcb_io_destroy_event(struct lcb_io_opt_st *iops,
|
303
|
+
void *event)
|
304
|
+
{
|
305
|
+
rb_em_loop *loop = iops->v.v0.cookie;
|
306
|
+
rb_em_event *ev = event;
|
307
|
+
if (ev->holder) {
|
308
|
+
rb_em_event_clear_finalizer(ev);
|
309
|
+
rb_ivar_set(ev->holder, cb_id_iv_event, Qfalse);
|
310
|
+
rb_funcall_0(ev->holder, cb_id_detach);
|
311
|
+
ev->holder = 0;
|
312
|
+
}
|
313
|
+
rb_em_event_dealloc(ev, loop);
|
314
|
+
}
|
315
|
+
|
316
|
+
#define lcb_io_create_timer lcb_io_create_event
|
317
|
+
|
318
|
+
static int
|
319
|
+
lcb_io_update_timer(struct lcb_io_opt_st *iops, void *timer,
|
320
|
+
lcb_uint32_t usec, void *cb_data,
|
321
|
+
void (*handler)(lcb_socket_t sock, short which, void *cb_data))
|
322
|
+
{
|
323
|
+
rb_em_event *ev = timer;
|
324
|
+
|
325
|
+
if (ev->holder) {
|
326
|
+
rb_funcall_1(em_m, cb_id_cancel_timer, ev->holder);
|
327
|
+
ev->holder = 0;
|
328
|
+
}
|
329
|
+
|
330
|
+
ev->socket = (lcb_socket_t)-1;
|
331
|
+
ev->cb_data = cb_data;
|
332
|
+
ev->handler = handler;
|
333
|
+
ev->usec = usec;
|
334
|
+
ev->canceled = 0;
|
335
|
+
ev->holder = rb_funcall_2(em_m, cb_id_add_timer, rb_float_new((double)usec / 1.0e6), ev->self);
|
336
|
+
|
337
|
+
(void)iops;
|
338
|
+
return 0;
|
339
|
+
}
|
340
|
+
|
341
|
+
static void
|
342
|
+
lcb_io_delete_timer(struct lcb_io_opt_st *iops, void *timer)
|
343
|
+
{
|
344
|
+
rb_em_event *ev = timer;
|
345
|
+
|
346
|
+
if (ev->holder) {
|
347
|
+
rb_funcall_1(em_m, cb_id_cancel_timer, ev->holder);
|
348
|
+
ev->holder = 0;
|
349
|
+
}
|
350
|
+
ev->canceled = 1;
|
351
|
+
(void)iops;
|
352
|
+
}
|
353
|
+
|
354
|
+
static void
|
355
|
+
lcb_io_destroy_timer(struct lcb_io_opt_st *iops, void *timer)
|
356
|
+
{
|
357
|
+
rb_em_loop *loop = iops->v.v0.cookie;
|
358
|
+
rb_em_event *ev = timer;
|
359
|
+
if (!ev->canceled) {
|
360
|
+
lcb_io_delete_timer(iops, timer);
|
361
|
+
}
|
362
|
+
rb_em_event_dealloc(ev, loop);
|
363
|
+
}
|
364
|
+
|
365
|
+
static void
|
366
|
+
lcb_io_run_event_loop(struct lcb_io_opt_st *iops)
|
367
|
+
{
|
368
|
+
rb_em_loop *loop = iops->v.v0.cookie;
|
369
|
+
VALUE fiber = rb_fiber_current();
|
370
|
+
VALUE event;
|
371
|
+
rb_em_event *ev;
|
372
|
+
loop->fiber = fiber;
|
373
|
+
for(;;) {
|
374
|
+
event = rb_fiber_yield(0, NULL);
|
375
|
+
if (!RTEST(event)) break;
|
376
|
+
Data_Get_Struct(event, rb_em_event, ev);
|
377
|
+
ev->handler(ev->socket, ev->current_flags, ev->cb_data);
|
378
|
+
}
|
379
|
+
}
|
380
|
+
|
381
|
+
static void
|
382
|
+
lcb_io_stop_event_loop(struct lcb_io_opt_st *iops)
|
383
|
+
{
|
384
|
+
rb_em_loop *loop = iops->v.v0.cookie;
|
385
|
+
VALUE fiber = loop->fiber;
|
386
|
+
loop->fiber = 0;
|
387
|
+
if (fiber) {
|
388
|
+
VALUE method = rb_obj_method(fiber, cb_sym_resume);
|
389
|
+
rb_funcall_1(em_m, cb_id_next_tick, method);
|
390
|
+
}
|
391
|
+
}
|
392
|
+
|
393
|
+
static void
|
394
|
+
lcb_destroy_io_opts(struct lcb_io_opt_st *iops)
|
395
|
+
{
|
396
|
+
rb_em_loop_destroy((rb_em_loop*)iops->v.v0.cookie);
|
397
|
+
}
|
398
|
+
|
399
|
+
LIBCOUCHBASE_API lcb_error_t
|
400
|
+
cb_create_ruby_em_io_opts(int version, lcb_io_opt_t *io, void *arg)
|
401
|
+
{
|
402
|
+
struct lcb_io_opt_st *ret;
|
403
|
+
rb_em_loop *loop;
|
404
|
+
struct cb_bucket_st *bucket = arg;
|
405
|
+
|
406
|
+
if (version != 0) {
|
407
|
+
return LCB_PLUGIN_VERSION_MISMATCH;
|
408
|
+
}
|
409
|
+
|
410
|
+
if (!em_m) initialize_event_machine_plugin();
|
411
|
+
|
412
|
+
ret = calloc(1, sizeof(*ret));
|
413
|
+
if (ret == NULL) {
|
414
|
+
free(ret);
|
415
|
+
return LCB_CLIENT_ENOMEM;
|
416
|
+
}
|
417
|
+
|
418
|
+
ret->version = 0;
|
419
|
+
ret->dlhandle = NULL;
|
420
|
+
ret->destructor = lcb_destroy_io_opts;
|
421
|
+
/* consider that struct isn't allocated by the library,
|
422
|
+
* `need_cleanup' flag might be set in lcb_create() */
|
423
|
+
ret->v.v0.need_cleanup = 0;
|
424
|
+
ret->v.v0.recv = cb_io_recv;
|
425
|
+
ret->v.v0.send = cb_io_send;
|
426
|
+
ret->v.v0.recvv = cb_io_recvv;
|
427
|
+
ret->v.v0.sendv = cb_io_sendv;
|
428
|
+
ret->v.v0.socket = cb_io_socket;
|
429
|
+
ret->v.v0.close = cb_io_close;
|
430
|
+
ret->v.v0.connect = cb_io_connect;
|
431
|
+
ret->v.v0.delete_event = lcb_io_delete_event;
|
432
|
+
ret->v.v0.destroy_event = lcb_io_destroy_event;
|
433
|
+
ret->v.v0.create_event = lcb_io_create_event;
|
434
|
+
ret->v.v0.update_event = lcb_io_update_event;
|
435
|
+
|
436
|
+
ret->v.v0.delete_timer = lcb_io_delete_timer;
|
437
|
+
ret->v.v0.destroy_timer = lcb_io_destroy_timer;
|
438
|
+
ret->v.v0.create_timer = lcb_io_create_timer;
|
439
|
+
ret->v.v0.update_timer = lcb_io_update_timer;
|
440
|
+
|
441
|
+
ret->v.v0.run_event_loop = lcb_io_run_event_loop;
|
442
|
+
ret->v.v0.stop_event_loop = lcb_io_stop_event_loop;
|
443
|
+
|
444
|
+
loop = rb_em_loop_create(bucket);
|
445
|
+
ret->v.v0.cookie = loop;
|
446
|
+
|
447
|
+
*io = ret;
|
448
|
+
return LCB_SUCCESS;
|
449
|
+
}
|
450
|
+
|
451
|
+
#endif
|
452
|
+
#endif
|