couchbase 1.2.1 → 1.2.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +50 -5
- data/RELEASE_NOTES.markdown +256 -145
- data/couchbase.gemspec +2 -4
- data/examples/chat-em/Gemfile +7 -0
- data/examples/chat-em/README.markdown +45 -0
- data/examples/chat-em/server.rb +82 -0
- data/ext/couchbase_ext/arguments.c +18 -17
- data/ext/couchbase_ext/arithmetic.c +17 -25
- data/ext/couchbase_ext/bucket.c +227 -32
- data/ext/couchbase_ext/context.c +64 -0
- data/ext/couchbase_ext/couchbase_ext.c +106 -14
- data/ext/couchbase_ext/couchbase_ext.h +81 -12
- data/ext/couchbase_ext/delete.c +18 -25
- data/ext/couchbase_ext/eventmachine_plugin.c +452 -0
- data/ext/couchbase_ext/extconf.rb +2 -0
- data/ext/couchbase_ext/get.c +18 -31
- data/ext/couchbase_ext/http.c +40 -31
- data/ext/couchbase_ext/multithread_plugin.c +38 -201
- data/ext/couchbase_ext/observe.c +17 -25
- data/ext/couchbase_ext/plugin_common.c +171 -0
- data/ext/couchbase_ext/result.c +18 -12
- data/ext/couchbase_ext/stats.c +17 -25
- data/ext/couchbase_ext/store.c +43 -47
- data/ext/couchbase_ext/touch.c +18 -25
- data/ext/couchbase_ext/unlock.c +18 -25
- data/ext/couchbase_ext/utils.c +23 -8
- data/ext/couchbase_ext/version.c +16 -24
- data/lib/couchbase.rb +1 -0
- data/lib/couchbase/bucket.rb +1 -1
- data/lib/couchbase/constants.rb +12 -0
- data/lib/couchbase/version.rb +1 -1
- data/lib/couchbase/view.rb +210 -60
- data/lib/couchbase/view_row.rb +103 -61
- data/tasks/compile.rake +1 -1
- data/test/test_async.rb +63 -0
- data/test/test_eventmachine.rb +70 -0
- metadata +143 -174
- data/tasks/doc.rake +0 -27
@@ -131,6 +131,7 @@ have_header("mach/mach_time.h")
|
|
131
131
|
have_header("stdint.h") or die("Failed to locate stdint.h")
|
132
132
|
have_header("sys/time.h")
|
133
133
|
have_header("fcntl.h")
|
134
|
+
have_type("st_index_t")
|
134
135
|
have_func("clock_gettime")
|
135
136
|
have_func("gettimeofday")
|
136
137
|
have_func("QueryPerformanceCounter")
|
@@ -139,6 +140,7 @@ have_func("rb_thread_fd_select")
|
|
139
140
|
have_func("rb_thread_blocking_region")
|
140
141
|
have_func("poll", "poll.h")
|
141
142
|
have_func("ppoll", "poll.h")
|
143
|
+
have_func("rb_fiber_yield")
|
142
144
|
define("_GNU_SOURCE")
|
143
145
|
create_header("couchbase_config.h")
|
144
146
|
create_makefile("couchbase_ext")
|
data/ext/couchbase_ext/get.c
CHANGED
@@ -22,7 +22,7 @@ cb_get_callback(lcb_t handle, const void *cookie, lcb_error_t error, const lcb_g
|
|
22
22
|
{
|
23
23
|
struct cb_context_st *ctx = (struct cb_context_st *)cookie;
|
24
24
|
struct cb_bucket_st *bucket = ctx->bucket;
|
25
|
-
VALUE key, val, flags, cas,
|
25
|
+
VALUE key, val, flags, cas, exc = Qnil, res;
|
26
26
|
|
27
27
|
ctx->nqueries--;
|
28
28
|
key = STR_NEW((const char*)resp->v.v0.key, resp->v.v0.nkey);
|
@@ -32,7 +32,7 @@ cb_get_callback(lcb_t handle, const void *cookie, lcb_error_t error, const lcb_g
|
|
32
32
|
exc = cb_check_error(error, "failed to get value", key);
|
33
33
|
if (exc != Qnil) {
|
34
34
|
rb_ivar_set(exc, cb_id_iv_operation, cb_sym_get);
|
35
|
-
ctx->exception =
|
35
|
+
ctx->exception = exc;
|
36
36
|
}
|
37
37
|
}
|
38
38
|
|
@@ -46,14 +46,10 @@ cb_get_callback(lcb_t handle, const void *cookie, lcb_error_t error, const lcb_g
|
|
46
46
|
VALUE exc_str = rb_funcall(val, cb_id_to_s, 0);
|
47
47
|
VALUE msg = rb_funcall(rb_mKernel, cb_id_sprintf, 3,
|
48
48
|
rb_str_new2("unable to convert value for key '%s': %s"), key, exc_str);
|
49
|
-
if (ctx->exception != Qnil) {
|
50
|
-
cb_gc_unprotect(bucket, ctx->exception);
|
51
|
-
}
|
52
49
|
ctx->exception = rb_exc_new3(cb_eValueFormatError, msg);
|
53
50
|
rb_ivar_set(ctx->exception, cb_id_iv_operation, cb_sym_get);
|
54
51
|
rb_ivar_set(ctx->exception, cb_id_iv_key, key);
|
55
52
|
rb_ivar_set(ctx->exception, cb_id_iv_inner_exception, val);
|
56
|
-
cb_gc_protect(bucket, ctx->exception);
|
57
53
|
val = raw;
|
58
54
|
}
|
59
55
|
} else if (cb_flags_get_format(resp->v.v0.flags) == cb_sym_plain) {
|
@@ -73,17 +69,17 @@ cb_get_callback(lcb_t handle, const void *cookie, lcb_error_t error, const lcb_g
|
|
73
69
|
} else { /* synchronous */
|
74
70
|
if (NIL_P(exc) && error != LCB_KEY_ENOENT) {
|
75
71
|
if (ctx->extended) {
|
76
|
-
rb_hash_aset(
|
72
|
+
rb_hash_aset(ctx->rv, key, rb_ary_new3(3, val, flags, cas));
|
77
73
|
} else {
|
78
|
-
rb_hash_aset(
|
74
|
+
rb_hash_aset(ctx->rv, key, val);
|
79
75
|
}
|
80
76
|
}
|
81
77
|
}
|
82
78
|
|
83
79
|
if (ctx->nqueries == 0) {
|
84
|
-
|
80
|
+
ctx->proc = Qnil;
|
85
81
|
if (bucket->async) {
|
86
|
-
|
82
|
+
cb_context_free(ctx);
|
87
83
|
}
|
88
84
|
}
|
89
85
|
(void)handle;
|
@@ -222,36 +218,28 @@ cb_bucket_get(int argc, VALUE *argv, VALUE self)
|
|
222
218
|
{
|
223
219
|
struct cb_bucket_st *bucket = DATA_PTR(self);
|
224
220
|
struct cb_context_st *ctx;
|
225
|
-
VALUE
|
221
|
+
VALUE rv, proc, exc;
|
226
222
|
size_t ii;
|
227
223
|
lcb_error_t err = LCB_SUCCESS;
|
228
224
|
struct cb_params_st params;
|
229
225
|
|
230
|
-
if (bucket
|
231
|
-
|
226
|
+
if (!cb_bucket_connected_bang(bucket, cb_sym_get)) {
|
227
|
+
return Qnil;
|
232
228
|
}
|
233
|
-
|
229
|
+
|
230
|
+
memset(¶ms, 0, sizeof(struct cb_params_st));
|
231
|
+
rb_scan_args(argc, argv, "0*&", ¶ms.args, &proc);
|
234
232
|
if (!bucket->async && proc != Qnil) {
|
235
233
|
rb_raise(rb_eArgError, "synchronous mode doesn't support callbacks");
|
236
234
|
}
|
237
|
-
memset(¶ms, 0, sizeof(struct cb_params_st));
|
238
235
|
params.type = cb_cmd_get;
|
239
236
|
params.bucket = bucket;
|
240
|
-
params.cmd.get.keys_ary =
|
241
|
-
cb_params_build(¶ms
|
242
|
-
ctx =
|
243
|
-
if (ctx == NULL) {
|
244
|
-
rb_raise(cb_eClientNoMemoryError, "failed to allocate memory for context");
|
245
|
-
}
|
237
|
+
params.cmd.get.keys_ary = rb_ary_new();
|
238
|
+
cb_params_build(¶ms);
|
239
|
+
ctx = cb_context_alloc_common(bucket, proc, params.cmd.get.num);
|
246
240
|
ctx->extended = params.cmd.get.extended;
|
247
241
|
ctx->quiet = params.cmd.get.quiet;
|
248
242
|
ctx->force_format = params.cmd.get.forced_format;
|
249
|
-
ctx->proc = cb_gc_protect(bucket, proc);
|
250
|
-
ctx->bucket = bucket;
|
251
|
-
rv = rb_hash_new();
|
252
|
-
ctx->rv = &rv;
|
253
|
-
ctx->exception = Qnil;
|
254
|
-
ctx->nqueries = params.cmd.get.num;
|
255
243
|
if (params.cmd.get.replica) {
|
256
244
|
err = lcb_get_replica(bucket->handle, (const void *)ctx,
|
257
245
|
params.cmd.get.num, params.cmd.get.ptr_gr);
|
@@ -260,10 +248,9 @@ cb_bucket_get(int argc, VALUE *argv, VALUE self)
|
|
260
248
|
params.cmd.get.num, params.cmd.get.ptr);
|
261
249
|
}
|
262
250
|
cb_params_destroy(¶ms);
|
263
|
-
cb_gc_unprotect(bucket, params.cmd.get.keys_ary);
|
264
251
|
exc = cb_check_error(err, "failed to schedule get request", Qnil);
|
265
252
|
if (exc != Qnil) {
|
266
|
-
|
253
|
+
cb_context_free(ctx);
|
267
254
|
rb_exc_raise(exc);
|
268
255
|
}
|
269
256
|
bucket->nbytes += params.npayload;
|
@@ -276,9 +263,9 @@ cb_bucket_get(int argc, VALUE *argv, VALUE self)
|
|
276
263
|
lcb_wait(bucket->handle);
|
277
264
|
}
|
278
265
|
exc = ctx->exception;
|
279
|
-
|
266
|
+
rv = ctx->rv;
|
267
|
+
cb_context_free(ctx);
|
280
268
|
if (exc != Qnil) {
|
281
|
-
cb_gc_unprotect(bucket, exc);
|
282
269
|
rb_exc_raise(exc);
|
283
270
|
}
|
284
271
|
exc = bucket->exception;
|
data/ext/couchbase_ext/http.c
CHANGED
@@ -22,24 +22,35 @@ cb_http_complete_callback(lcb_http_request_t request, lcb_t handle, const void *
|
|
22
22
|
{
|
23
23
|
struct cb_context_st *ctx = (struct cb_context_st *)cookie;
|
24
24
|
struct cb_bucket_st *bucket = ctx->bucket;
|
25
|
-
VALUE
|
25
|
+
VALUE key, val, res, exc;
|
26
26
|
lcb_http_status_t status;
|
27
27
|
|
28
28
|
ctx->request->completed = 1;
|
29
|
+
|
30
|
+
if (bucket->destroying) {
|
31
|
+
cb_context_free(ctx);
|
32
|
+
return;
|
33
|
+
}
|
34
|
+
|
29
35
|
key = STR_NEW((const char*)resp->v.v0.path, resp->v.v0.npath);
|
30
36
|
val = resp->v.v0.nbytes ? STR_NEW((const char*)resp->v.v0.bytes, resp->v.v0.nbytes) : Qnil;
|
31
|
-
exc =
|
32
|
-
if (exc
|
33
|
-
|
37
|
+
exc = ctx->exception;
|
38
|
+
if (!RTEST(exc)) {
|
39
|
+
exc = cb_check_error_with_status(error, "failed to execute HTTP request", key, resp->v.v0.status);
|
40
|
+
if (exc != Qnil && val != Qnil) {
|
34
41
|
rb_ivar_set(exc, cb_id_iv_body, val);
|
35
42
|
}
|
36
|
-
|
37
|
-
|
43
|
+
}
|
44
|
+
if (RTEST(exc)) {
|
45
|
+
if (rb_obj_is_kind_of(exc, cb_eHTTPError)) {
|
46
|
+
rb_funcall(exc, cb_id_parse_body_bang, 0);
|
47
|
+
}
|
48
|
+
ctx->exception = exc;
|
38
49
|
}
|
39
50
|
status = resp->v.v0.status;
|
40
51
|
if (resp->v.v0.headers) {
|
41
52
|
cb_build_headers(ctx, resp->v.v0.headers);
|
42
|
-
|
53
|
+
ctx->headers_val = Qnil;
|
43
54
|
}
|
44
55
|
if (ctx->extended) {
|
45
56
|
res = rb_class_new_instance(0, NULL, cb_cResult);
|
@@ -55,10 +66,13 @@ cb_http_complete_callback(lcb_http_request_t request, lcb_t handle, const void *
|
|
55
66
|
}
|
56
67
|
if (ctx->proc != Qnil) {
|
57
68
|
cb_proc_call(bucket, ctx->proc, 1, res);
|
58
|
-
|
69
|
+
ctx->proc = Qnil;
|
59
70
|
}
|
60
71
|
if (!bucket->async && ctx->exception == Qnil) {
|
61
|
-
|
72
|
+
ctx->rv = res;
|
73
|
+
}
|
74
|
+
if (bucket->async) {
|
75
|
+
cb_context_free(ctx);
|
62
76
|
}
|
63
77
|
(void)handle;
|
64
78
|
(void)request;
|
@@ -81,14 +95,11 @@ cb_http_data_callback(lcb_http_request_t request, lcb_t handle, const void *cook
|
|
81
95
|
if (ctx->exception != Qnil) {
|
82
96
|
VALUE body_str = rb_ivar_get(ctx->exception, cb_id_iv_body);
|
83
97
|
if (NIL_P(body_str)) {
|
84
|
-
cb_gc_protect(bucket, ctx->exception);
|
85
98
|
rb_ivar_set(ctx->exception, cb_id_iv_body, val);
|
86
99
|
} else {
|
87
100
|
rb_str_concat(body_str, val);
|
88
101
|
}
|
89
|
-
|
90
|
-
lcb_cancel_http_request(bucket->handle, request);
|
91
|
-
}
|
102
|
+
return;
|
92
103
|
}
|
93
104
|
}
|
94
105
|
if (resp->v.v0.headers) {
|
@@ -97,7 +108,7 @@ cb_http_data_callback(lcb_http_request_t request, lcb_t handle, const void *cook
|
|
97
108
|
if (ctx->proc != Qnil) {
|
98
109
|
if (ctx->extended) {
|
99
110
|
res = rb_class_new_instance(0, NULL, cb_cResult);
|
100
|
-
rb_ivar_set(res, cb_id_iv_error,
|
111
|
+
rb_ivar_set(res, cb_id_iv_error, Qnil);
|
101
112
|
rb_ivar_set(res, cb_id_iv_status, status ? INT2FIX(status) : Qnil);
|
102
113
|
rb_ivar_set(res, cb_id_iv_operation, cb_sym_http_request);
|
103
114
|
rb_ivar_set(res, cb_id_iv_key, key);
|
@@ -110,6 +121,7 @@ cb_http_data_callback(lcb_http_request_t request, lcb_t handle, const void *cook
|
|
110
121
|
cb_proc_call(bucket, ctx->proc, 1, res);
|
111
122
|
}
|
112
123
|
(void)handle;
|
124
|
+
(void)request;
|
113
125
|
}
|
114
126
|
|
115
127
|
void
|
@@ -278,27 +290,25 @@ cb_http_request_perform(VALUE self)
|
|
278
290
|
struct cb_context_st *ctx;
|
279
291
|
VALUE rv, exc;
|
280
292
|
lcb_error_t err;
|
281
|
-
struct cb_bucket_st *bucket;
|
293
|
+
struct cb_bucket_st *bucket = req->bucket;
|
282
294
|
|
283
|
-
|
284
|
-
|
285
|
-
rb_raise(cb_eClientNoMemoryError, "failed to allocate memory");
|
295
|
+
if (!cb_bucket_connected_bang(bucket, cb_sym_http_request)) {
|
296
|
+
return Qnil;
|
286
297
|
}
|
287
|
-
|
288
|
-
ctx
|
289
|
-
ctx->
|
290
|
-
ctx->proc = rb_block_given_p() ?
|
298
|
+
|
299
|
+
ctx = cb_context_alloc(bucket);
|
300
|
+
ctx->rv = Qnil;
|
301
|
+
ctx->proc = rb_block_given_p() ? rb_block_proc() : req->on_body_callback;
|
291
302
|
ctx->extended = req->extended;
|
292
303
|
ctx->request = req;
|
293
|
-
ctx->headers_val =
|
294
|
-
ctx->exception = Qnil;
|
304
|
+
ctx->headers_val = rb_hash_new();
|
295
305
|
|
296
306
|
err = lcb_make_http_request(bucket->handle, (const void *)ctx,
|
297
307
|
req->type, &req->cmd, &req->request);
|
298
308
|
exc = cb_check_error(err, "failed to schedule document request",
|
299
309
|
STR_NEW(req->cmd.v.v0.path, req->cmd.v.v0.npath));
|
300
310
|
if (exc != Qnil) {
|
301
|
-
|
311
|
+
lcb_cancel_http_request(bucket->handle, req->request);
|
302
312
|
rb_exc_raise(exc);
|
303
313
|
}
|
304
314
|
req->running = 1;
|
@@ -308,10 +318,10 @@ cb_http_request_perform(VALUE self)
|
|
308
318
|
} else {
|
309
319
|
lcb_wait(bucket->handle);
|
310
320
|
if (req->completed) {
|
321
|
+
rv = ctx->rv;
|
311
322
|
exc = ctx->exception;
|
312
|
-
|
323
|
+
cb_context_free(ctx);
|
313
324
|
if (exc != Qnil) {
|
314
|
-
cb_gc_unprotect(bucket, exc);
|
315
325
|
rb_exc_raise(exc);
|
316
326
|
}
|
317
327
|
return rv;
|
@@ -333,7 +343,7 @@ cb_http_request_pause(VALUE self)
|
|
333
343
|
VALUE
|
334
344
|
cb_http_request_continue(VALUE self)
|
335
345
|
{
|
336
|
-
VALUE exc,
|
346
|
+
VALUE exc, rv;
|
337
347
|
struct cb_http_request_st *req = DATA_PTR(self);
|
338
348
|
|
339
349
|
if (req->running) {
|
@@ -341,12 +351,11 @@ cb_http_request_continue(VALUE self)
|
|
341
351
|
if (req->completed) {
|
342
352
|
exc = req->ctx->exception;
|
343
353
|
rv = req->ctx->rv;
|
344
|
-
|
354
|
+
cb_context_free(req->ctx);
|
345
355
|
if (exc != Qnil) {
|
346
|
-
cb_gc_unprotect(req->bucket, exc);
|
347
356
|
rb_exc_raise(exc);
|
348
357
|
}
|
349
|
-
return
|
358
|
+
return rv;
|
350
359
|
}
|
351
360
|
} else {
|
352
361
|
cb_http_request_perform(self);
|
@@ -24,149 +24,9 @@
|
|
24
24
|
#include <rubysig.h>
|
25
25
|
#endif
|
26
26
|
#include <errno.h>
|
27
|
-
#include <sys/types.h>
|
28
|
-
#include <sys/socket.h>
|
29
|
-
#include <unistd.h>
|
30
|
-
#ifdef HAVE_FCNTL_H
|
31
|
-
#include <fcntl.h>
|
32
|
-
#endif
|
33
27
|
#ifdef HAVE_POLL
|
34
28
|
#include <poll.h>
|
35
29
|
#endif
|
36
|
-
#define INVALID_SOCKET (-1)
|
37
|
-
|
38
|
-
/* Copied from libev plugin */
|
39
|
-
static lcb_ssize_t
|
40
|
-
lcb_io_recv(struct lcb_io_opt_st *iops, lcb_socket_t sock,
|
41
|
-
void *buffer, lcb_size_t len, int flags)
|
42
|
-
{
|
43
|
-
lcb_ssize_t ret = recv(sock, buffer, len, flags);
|
44
|
-
if (ret < 0) {
|
45
|
-
iops->v.v0.error = errno;
|
46
|
-
}
|
47
|
-
return ret;
|
48
|
-
}
|
49
|
-
|
50
|
-
static lcb_ssize_t
|
51
|
-
lcb_io_recvv(struct lcb_io_opt_st *iops, lcb_socket_t sock,
|
52
|
-
struct lcb_iovec_st *iov, lcb_size_t niov)
|
53
|
-
{
|
54
|
-
struct msghdr msg;
|
55
|
-
struct iovec vec[2];
|
56
|
-
lcb_ssize_t ret;
|
57
|
-
|
58
|
-
if (niov != 2) {
|
59
|
-
return -1;
|
60
|
-
}
|
61
|
-
memset(&msg, 0, sizeof(msg));
|
62
|
-
msg.msg_iov = vec;
|
63
|
-
msg.msg_iovlen = iov[1].iov_len ? (lcb_size_t)2 : (lcb_size_t)1;
|
64
|
-
msg.msg_iov[0].iov_base = iov[0].iov_base;
|
65
|
-
msg.msg_iov[0].iov_len = iov[0].iov_len;
|
66
|
-
msg.msg_iov[1].iov_base = iov[1].iov_base;
|
67
|
-
msg.msg_iov[1].iov_len = iov[1].iov_len;
|
68
|
-
ret = recvmsg(sock, &msg, 0);
|
69
|
-
|
70
|
-
if (ret < 0) {
|
71
|
-
iops->v.v0.error = errno;
|
72
|
-
}
|
73
|
-
|
74
|
-
return ret;
|
75
|
-
}
|
76
|
-
|
77
|
-
static lcb_ssize_t
|
78
|
-
lcb_io_send(struct lcb_io_opt_st *iops, lcb_socket_t sock,
|
79
|
-
const void *msg, lcb_size_t len, int flags)
|
80
|
-
{
|
81
|
-
lcb_ssize_t ret = send(sock, msg, len, flags);
|
82
|
-
if (ret < 0) {
|
83
|
-
iops->v.v0.error = errno;
|
84
|
-
}
|
85
|
-
return ret;
|
86
|
-
}
|
87
|
-
|
88
|
-
static lcb_ssize_t
|
89
|
-
lcb_io_sendv(struct lcb_io_opt_st *iops, lcb_socket_t sock,
|
90
|
-
struct lcb_iovec_st *iov, lcb_size_t niov)
|
91
|
-
{
|
92
|
-
struct msghdr msg;
|
93
|
-
struct iovec vec[2];
|
94
|
-
lcb_ssize_t ret;
|
95
|
-
|
96
|
-
if (niov != 2) {
|
97
|
-
return -1;
|
98
|
-
}
|
99
|
-
memset(&msg, 0, sizeof(msg));
|
100
|
-
msg.msg_iov = vec;
|
101
|
-
msg.msg_iovlen = iov[1].iov_len ? (lcb_size_t)2 : (lcb_size_t)1;
|
102
|
-
msg.msg_iov[0].iov_base = iov[0].iov_base;
|
103
|
-
msg.msg_iov[0].iov_len = iov[0].iov_len;
|
104
|
-
msg.msg_iov[1].iov_base = iov[1].iov_base;
|
105
|
-
msg.msg_iov[1].iov_len = iov[1].iov_len;
|
106
|
-
ret = sendmsg(sock, &msg, 0);
|
107
|
-
|
108
|
-
if (ret < 0) {
|
109
|
-
iops->v.v0.error = errno;
|
110
|
-
}
|
111
|
-
return ret;
|
112
|
-
}
|
113
|
-
|
114
|
-
static int
|
115
|
-
make_socket_nonblocking(lcb_socket_t sock)
|
116
|
-
{
|
117
|
-
int flags;
|
118
|
-
if ((flags = fcntl(sock, F_GETFL, NULL)) < 0) {
|
119
|
-
return -1;
|
120
|
-
}
|
121
|
-
if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1) {
|
122
|
-
return -1;
|
123
|
-
}
|
124
|
-
|
125
|
-
return 0;
|
126
|
-
}
|
127
|
-
|
128
|
-
static int
|
129
|
-
close_socket(lcb_socket_t sock)
|
130
|
-
{
|
131
|
-
return close(sock);
|
132
|
-
}
|
133
|
-
|
134
|
-
static lcb_socket_t
|
135
|
-
lcb_io_socket(struct lcb_io_opt_st *iops, int domain, int type,
|
136
|
-
int protocol)
|
137
|
-
{
|
138
|
-
lcb_socket_t sock = socket(domain, type, protocol);
|
139
|
-
if (sock == INVALID_SOCKET) {
|
140
|
-
iops->v.v0.error = errno;
|
141
|
-
} else {
|
142
|
-
if (make_socket_nonblocking(sock) != 0) {
|
143
|
-
int error = errno;
|
144
|
-
iops->v.v0.close(iops, sock);
|
145
|
-
iops->v.v0.error = error;
|
146
|
-
sock = INVALID_SOCKET;
|
147
|
-
}
|
148
|
-
}
|
149
|
-
|
150
|
-
return sock;
|
151
|
-
}
|
152
|
-
|
153
|
-
static void
|
154
|
-
lcb_io_close(struct lcb_io_opt_st *iops, lcb_socket_t sock)
|
155
|
-
{
|
156
|
-
close_socket(sock);
|
157
|
-
(void)iops;
|
158
|
-
}
|
159
|
-
|
160
|
-
static int
|
161
|
-
lcb_io_connect(struct lcb_io_opt_st *iops, lcb_socket_t sock,
|
162
|
-
const struct sockaddr *name, unsigned int namelen)
|
163
|
-
{
|
164
|
-
int ret = connect(sock, name, (socklen_t)namelen);
|
165
|
-
if (ret < 0) {
|
166
|
-
iops->v.v0.error = errno;
|
167
|
-
}
|
168
|
-
return ret;
|
169
|
-
}
|
170
30
|
|
171
31
|
/* events sorted array */
|
172
32
|
typedef struct rb_mt_event rb_mt_event;
|
@@ -807,45 +667,33 @@ loop_select_cleanup(VALUE argp)
|
|
807
667
|
/* code influenced by ruby's source and cool.io */
|
808
668
|
#define POLLIN_SET (POLLIN | POLLHUP | POLLERR)
|
809
669
|
#define POLLOUT_SET (POLLOUT | POLLHUP | POLLERR)
|
670
|
+
#define HRTIME_INFINITY ((hrtime_t)~0)
|
810
671
|
|
811
|
-
#
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
672
|
+
#ifdef HAVE_PPOLL
|
673
|
+
static int
|
674
|
+
xpoll(struct pollfd *fds, nfds_t nfds, hrtime_t timeout)
|
675
|
+
{
|
676
|
+
if (timeout != HRTIME_INFINITY) {
|
677
|
+
struct timespec ts;
|
678
|
+
ts.tv_sec = (long)(timeout / (1000 * 1000 * 1000));
|
679
|
+
ts.tv_nsec = (long)(timeout % (1000 * 1000 * 1000));
|
680
|
+
return ppoll(fds, nfds, &ts, NULL);
|
681
|
+
}
|
682
|
+
return ppoll(fds, nfds, NULL, NULL);
|
683
|
+
}
|
818
684
|
#else
|
819
|
-
#
|
820
|
-
#endif
|
821
|
-
#define TIMET_MAX (~(time_t)0 <= 0 ? (time_t)((~(unsigned_time_t)0) >> 1) : (time_t)(~(unsigned_time_t)0))
|
685
|
+
#define TIMEOUT_MAX ((hrtime_t)(((unsigned int)~0) >> 1))
|
822
686
|
static int
|
823
|
-
|
824
|
-
const struct timespec *ts, const sigset_t *sigmask)
|
687
|
+
xpoll(struct pollfd *fds, nfds_t nfds, hrtime_t timeout)
|
825
688
|
{
|
826
|
-
int
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
if (ts->tv_sec > TIMET_MAX/1000) {
|
832
|
-
timeout_ms = -1;
|
833
|
-
} else {
|
834
|
-
tmp = ts->tv_sec * 1000;
|
835
|
-
tmp2 = (ts->tv_nsec + 999999) / (1000 * 1000);
|
836
|
-
if (TIMET_MAX - tmp < tmp2) {
|
837
|
-
timeout_ms = -1;
|
838
|
-
} else {
|
839
|
-
timeout_ms = tmp + tmp2;
|
840
|
-
}
|
689
|
+
int ts = -1;
|
690
|
+
if (timeout != HRTIME_INFINITY) {
|
691
|
+
timeout = (timeout + 999999) / (1000 * 1000);
|
692
|
+
if (timeout <= TIMEOUT_MAX) {
|
693
|
+
ts = (int)timeout;
|
841
694
|
}
|
842
|
-
} else {
|
843
|
-
timeout_ms = -1;
|
844
695
|
}
|
845
|
-
|
846
|
-
(void)sigmask;
|
847
|
-
|
848
|
-
return poll(fds, nfds, timeout_ms);
|
696
|
+
return poll(fds, nfds, ts);
|
849
697
|
}
|
850
698
|
#endif
|
851
699
|
|
@@ -854,7 +702,7 @@ struct poll_args {
|
|
854
702
|
rb_mt_loop *loop;
|
855
703
|
struct pollfd *fds;
|
856
704
|
nfds_t nfd;
|
857
|
-
|
705
|
+
hrtime_t ts;
|
858
706
|
int result;
|
859
707
|
int lerrno;
|
860
708
|
};
|
@@ -882,7 +730,7 @@ lp_arg_alloc(lp_arg **args)
|
|
882
730
|
loop_blocking_poll(void *argp)
|
883
731
|
{
|
884
732
|
lp_arg *args = argp;
|
885
|
-
args->result =
|
733
|
+
args->result = xpoll(args->fds, args->nfd, args->ts);
|
886
734
|
if (args->result < 0) args->lerrno = errno;
|
887
735
|
return Qnil;
|
888
736
|
}
|
@@ -893,7 +741,6 @@ loop_run_poll(VALUE argp)
|
|
893
741
|
{
|
894
742
|
lp_arg *args = (lp_arg*)argp;
|
895
743
|
rb_mt_loop *loop = args->loop;
|
896
|
-
struct timespec ts;
|
897
744
|
hrtime_t now, next_time;
|
898
745
|
|
899
746
|
if (loop->events.count) {
|
@@ -916,17 +763,9 @@ retry:
|
|
916
763
|
next_time = timers_minimum(&loop->timers);
|
917
764
|
if (next_time) {
|
918
765
|
now = gethrtime();
|
919
|
-
|
920
|
-
ts.tv_sec = 0;
|
921
|
-
ts.tv_nsec = 0;
|
922
|
-
} else {
|
923
|
-
hrtime_t hrto = next_time - now;
|
924
|
-
ts.tv_sec = (long)(hrto / 1000000000);
|
925
|
-
ts.tv_nsec = (long)(hrto % 1000000000);
|
926
|
-
}
|
927
|
-
args->ts = &ts;
|
766
|
+
args->ts = next_time <= now ? 0 : next_time - now;
|
928
767
|
} else {
|
929
|
-
args->ts =
|
768
|
+
args->ts = HRTIME_INFINITY;
|
930
769
|
}
|
931
770
|
|
932
771
|
#ifdef HAVE_RB_THREAD_BLOCKING_REGION
|
@@ -934,21 +773,19 @@ retry:
|
|
934
773
|
#else
|
935
774
|
if (rb_thread_alone()) {
|
936
775
|
TRAP_BEG;
|
937
|
-
args->result =
|
776
|
+
args->result = xpoll(args->fds, args->nfd, args->ts);
|
938
777
|
if (args->result < 0) args->lerrno = errno;
|
939
778
|
TRAP_END;
|
940
779
|
} else {
|
941
|
-
struct timespec mini_pause;
|
942
|
-
int exact = 0;
|
943
|
-
mini_pause.tv_sec = 0;
|
944
780
|
/* 5 millisecond pause */
|
945
|
-
mini_pause
|
946
|
-
|
947
|
-
|
781
|
+
hrtime_t mini_pause = 5000000;
|
782
|
+
int exact = 0;
|
783
|
+
if (args->ts != HRTIME_INFINITY && args->ts < mini_pause) {
|
784
|
+
mini_pause = args->ts;
|
948
785
|
exact = 1;
|
949
786
|
}
|
950
787
|
TRAP_BEG;
|
951
|
-
args->result =
|
788
|
+
args->result = xpoll(args->fds, args->nfd, mini_pause);
|
952
789
|
if (args->result < 0) args->lerrno = errno;
|
953
790
|
TRAP_END;
|
954
791
|
if (args->result == 0 && !exact) {
|
@@ -1206,13 +1043,13 @@ cb_create_ruby_mt_io_opts(int version, lcb_io_opt_t *io, void *arg)
|
|
1206
1043
|
/* consider that struct isn't allocated by the library,
|
1207
1044
|
* `need_cleanup' flag might be set in lcb_create() */
|
1208
1045
|
ret->v.v0.need_cleanup = 0;
|
1209
|
-
ret->v.v0.recv =
|
1210
|
-
ret->v.v0.send =
|
1211
|
-
ret->v.v0.recvv =
|
1212
|
-
ret->v.v0.sendv =
|
1213
|
-
ret->v.v0.socket =
|
1214
|
-
ret->v.v0.close =
|
1215
|
-
ret->v.v0.connect =
|
1046
|
+
ret->v.v0.recv = cb_io_recv;
|
1047
|
+
ret->v.v0.send = cb_io_send;
|
1048
|
+
ret->v.v0.recvv = cb_io_recvv;
|
1049
|
+
ret->v.v0.sendv = cb_io_sendv;
|
1050
|
+
ret->v.v0.socket = cb_io_socket;
|
1051
|
+
ret->v.v0.close = cb_io_close;
|
1052
|
+
ret->v.v0.connect = cb_io_connect;
|
1216
1053
|
ret->v.v0.delete_event = lcb_io_delete_event;
|
1217
1054
|
ret->v.v0.destroy_event = lcb_io_destroy_event;
|
1218
1055
|
ret->v.v0.create_event = lcb_io_create_event;
|