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,1090 @@
|
|
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
|
+
|
21
|
+
#ifndef _WIN32
|
22
|
+
|
23
|
+
#ifndef HAVE_RB_THREAD_BLOCKING_REGION
|
24
|
+
#include <rubysig.h>
|
25
|
+
#endif
|
26
|
+
#include <errno.h>
|
27
|
+
#ifdef HAVE_POLL
|
28
|
+
#include <poll.h>
|
29
|
+
#endif
|
30
|
+
|
31
|
+
/* events sorted array */
|
32
|
+
typedef struct rb_mt_event rb_mt_event;
|
33
|
+
struct rb_mt_event {
|
34
|
+
void *cb_data;
|
35
|
+
void (*handler)(lcb_socket_t sock, short which, void *cb_data);
|
36
|
+
lcb_socket_t socket;
|
37
|
+
int loop_index;
|
38
|
+
short flags;
|
39
|
+
short actual_flags;
|
40
|
+
short inserted;
|
41
|
+
rb_mt_event *next;
|
42
|
+
};
|
43
|
+
|
44
|
+
typedef struct rb_mt_socket_list rb_mt_socket_list;
|
45
|
+
struct rb_mt_socket_list {
|
46
|
+
lcb_socket_t socket;
|
47
|
+
short flags;
|
48
|
+
rb_mt_event *first;
|
49
|
+
};
|
50
|
+
|
51
|
+
typedef struct rb_mt_events rb_mt_events;
|
52
|
+
struct rb_mt_events {
|
53
|
+
uint32_t capa;
|
54
|
+
uint32_t count;
|
55
|
+
rb_mt_socket_list *sockets;
|
56
|
+
};
|
57
|
+
|
58
|
+
static int
|
59
|
+
events_init(rb_mt_events *events)
|
60
|
+
{
|
61
|
+
rb_mt_socket_list *new_socks = malloc(4 * sizeof(*new_socks));
|
62
|
+
if (new_socks == NULL) {
|
63
|
+
return 0;
|
64
|
+
}
|
65
|
+
events->capa = 4;
|
66
|
+
events->count = 0;
|
67
|
+
events->sockets = new_socks;
|
68
|
+
return 1;
|
69
|
+
}
|
70
|
+
|
71
|
+
static void
|
72
|
+
events_finalize(rb_mt_events *events)
|
73
|
+
{
|
74
|
+
if (events->sockets) {
|
75
|
+
uint32_t i;
|
76
|
+
for(i = 0; i < events->count; i++) {
|
77
|
+
rb_mt_socket_list *list = &events->sockets[i];
|
78
|
+
while(list->first) {
|
79
|
+
rb_mt_event *next = list->first->next;
|
80
|
+
free(list->first);
|
81
|
+
list->first = next;
|
82
|
+
}
|
83
|
+
}
|
84
|
+
free(events->sockets);
|
85
|
+
events->sockets = NULL;
|
86
|
+
}
|
87
|
+
events->capa = 0;
|
88
|
+
events->count = 0;
|
89
|
+
}
|
90
|
+
|
91
|
+
static uint32_t
|
92
|
+
events_index(rb_mt_events *events, lcb_socket_t socket)
|
93
|
+
{
|
94
|
+
uint32_t m, l = 0, r = events->count;
|
95
|
+
while(l < r) {
|
96
|
+
m = l + (r - l) / 2;
|
97
|
+
if (events->sockets[m].socket >= socket) {
|
98
|
+
r = m;
|
99
|
+
} else {
|
100
|
+
l = m + 1;
|
101
|
+
}
|
102
|
+
}
|
103
|
+
return l;
|
104
|
+
}
|
105
|
+
|
106
|
+
static void
|
107
|
+
events_insert(rb_mt_events *events, rb_mt_event *event)
|
108
|
+
{
|
109
|
+
uint32_t i = events_index(events, event->socket);
|
110
|
+
rb_mt_socket_list *list = &events->sockets[i];
|
111
|
+
if (i == events->count || list->socket != event->socket) {
|
112
|
+
if (events->capa == events->count) {
|
113
|
+
uint32_t new_capa = events->capa << 1;
|
114
|
+
rb_mt_socket_list *new_socks = realloc(events->sockets, new_capa * sizeof(*new_socks));
|
115
|
+
if (new_socks == NULL) {
|
116
|
+
rb_raise(cb_eClientNoMemoryError, "failed to allocate memory for events array");
|
117
|
+
}
|
118
|
+
events->sockets = new_socks;
|
119
|
+
events->capa = new_capa;
|
120
|
+
list = &events->sockets[i];
|
121
|
+
}
|
122
|
+
if (i < events->count) {
|
123
|
+
MEMMOVE(events->sockets+i+1, events->sockets+i, rb_mt_socket_list, events->count - i);
|
124
|
+
}
|
125
|
+
events->count++;
|
126
|
+
list->socket = event->socket;
|
127
|
+
list->flags = event->flags;
|
128
|
+
list->first = event;
|
129
|
+
event->next = NULL;
|
130
|
+
} else {
|
131
|
+
list->flags |= event->flags;
|
132
|
+
event->next = list->first;
|
133
|
+
list->first = event;
|
134
|
+
}
|
135
|
+
event->inserted = 1;
|
136
|
+
}
|
137
|
+
|
138
|
+
static void
|
139
|
+
event_list_fix_flags(rb_mt_socket_list *list)
|
140
|
+
{
|
141
|
+
short flags = 0;
|
142
|
+
rb_mt_event *event = list->first;
|
143
|
+
while (event) {
|
144
|
+
flags |= event->flags;
|
145
|
+
event = event->next;
|
146
|
+
}
|
147
|
+
list->flags = flags;
|
148
|
+
}
|
149
|
+
|
150
|
+
static void
|
151
|
+
events_remove(rb_mt_events *events, rb_mt_event *event)
|
152
|
+
{
|
153
|
+
uint32_t i = events_index(events, event->socket);
|
154
|
+
rb_mt_socket_list *list = &events->sockets[i];
|
155
|
+
rb_mt_event **next;
|
156
|
+
if (list->socket != event->socket) {
|
157
|
+
rb_raise(rb_eIndexError, "There is no socket in event loop");
|
158
|
+
}
|
159
|
+
next = &list->first;
|
160
|
+
for(;;) {
|
161
|
+
if (*next == NULL) {
|
162
|
+
rb_raise(rb_eIndexError, "There is no event in event loop");
|
163
|
+
}
|
164
|
+
if (*next == event) {
|
165
|
+
*next = event->next;
|
166
|
+
event->next = NULL;
|
167
|
+
event->inserted = 0;
|
168
|
+
break;
|
169
|
+
}
|
170
|
+
next = &event->next;
|
171
|
+
}
|
172
|
+
if (list->first == NULL) {
|
173
|
+
MEMMOVE(events->sockets + i, events->sockets + i + 1, rb_mt_socket_list, events->count - i - 1);
|
174
|
+
events->count--;
|
175
|
+
} else {
|
176
|
+
event_list_fix_flags(list);
|
177
|
+
}
|
178
|
+
}
|
179
|
+
|
180
|
+
static void
|
181
|
+
events_fix_flags(rb_mt_events *events, lcb_socket_t socket)
|
182
|
+
{
|
183
|
+
uint32_t i = events_index(events, socket);
|
184
|
+
rb_mt_socket_list *list = &events->sockets[i];
|
185
|
+
if (list->socket != socket) {
|
186
|
+
rb_raise(rb_eIndexError, "There is no socket in event loop");
|
187
|
+
}
|
188
|
+
event_list_fix_flags(list);
|
189
|
+
}
|
190
|
+
|
191
|
+
static inline lcb_socket_t
|
192
|
+
events_max_fd(rb_mt_events *events)
|
193
|
+
{
|
194
|
+
if (events->count) {
|
195
|
+
return events->sockets[events->count - 1].socket;
|
196
|
+
} else {
|
197
|
+
return -1;
|
198
|
+
}
|
199
|
+
}
|
200
|
+
|
201
|
+
/* events sorted array end */
|
202
|
+
|
203
|
+
/* timers heap */
|
204
|
+
typedef struct rb_mt_timer rb_mt_timer;
|
205
|
+
struct rb_mt_timer {
|
206
|
+
void *cb_data;
|
207
|
+
void (*handler)(lcb_socket_t sock, short which, void *cb_data);
|
208
|
+
int index;
|
209
|
+
hrtime_t ts;
|
210
|
+
hrtime_t period;
|
211
|
+
};
|
212
|
+
|
213
|
+
typedef struct rb_mt_timers rb_mt_timers;
|
214
|
+
struct rb_mt_timers {
|
215
|
+
uint32_t capa;
|
216
|
+
uint32_t count;
|
217
|
+
rb_mt_timer **timers;
|
218
|
+
};
|
219
|
+
|
220
|
+
static int
|
221
|
+
timers_init(rb_mt_timers *timers)
|
222
|
+
{
|
223
|
+
rb_mt_timer **new_timers = malloc(4 * sizeof(*new_timers));
|
224
|
+
if (new_timers == NULL) {
|
225
|
+
return 0;
|
226
|
+
}
|
227
|
+
timers->capa = 4;
|
228
|
+
timers->count = 0;
|
229
|
+
timers->timers = new_timers;
|
230
|
+
return 1;
|
231
|
+
}
|
232
|
+
|
233
|
+
static void
|
234
|
+
timers_finalize(rb_mt_timers *timers)
|
235
|
+
{
|
236
|
+
if (timers->timers) {
|
237
|
+
uint32_t i;
|
238
|
+
for(i = 0; i < timers->count; i++) {
|
239
|
+
free(timers->timers[i]);
|
240
|
+
}
|
241
|
+
free(timers->timers);
|
242
|
+
timers->timers = NULL;
|
243
|
+
}
|
244
|
+
timers->count = 0;
|
245
|
+
timers->capa = 0;
|
246
|
+
}
|
247
|
+
|
248
|
+
#define tms_at(_timers, at) (_timers)->timers[(at)]
|
249
|
+
#define tms_ts_at(timers, at) tms_at((timers), (at))->ts
|
250
|
+
|
251
|
+
static void
|
252
|
+
timers_move_last(rb_mt_timers *timers, uint32_t to)
|
253
|
+
{
|
254
|
+
if (to < timers->count - 1) {
|
255
|
+
rb_mt_timer *last = tms_at(timers, timers->count - 1);
|
256
|
+
tms_at(timers, to) = last;
|
257
|
+
last->index = to;
|
258
|
+
}
|
259
|
+
timers->count--;
|
260
|
+
}
|
261
|
+
|
262
|
+
static inline void
|
263
|
+
timers_swap(rb_mt_timers *timers, uint32_t i, uint32_t j)
|
264
|
+
{
|
265
|
+
rb_mt_timer *itmp = tms_at(timers, j);
|
266
|
+
rb_mt_timer *jtmp = tms_at(timers, i);
|
267
|
+
tms_at(timers, i) = itmp;
|
268
|
+
tms_at(timers, j) = jtmp;
|
269
|
+
itmp->index = i;
|
270
|
+
jtmp->index = j;
|
271
|
+
}
|
272
|
+
|
273
|
+
static void timers_heapify_up(rb_mt_timers *timers, uint32_t pos);
|
274
|
+
|
275
|
+
static void
|
276
|
+
timers_insert(rb_mt_timers *timers, rb_mt_timer *timer)
|
277
|
+
{
|
278
|
+
if (timers->count == timers->capa) {
|
279
|
+
rb_mt_timer **new_timers;
|
280
|
+
size_t new_capa = timers->capa << 1;
|
281
|
+
new_timers = realloc(timers->timers, new_capa * sizeof(rb_mt_timer*));
|
282
|
+
if (new_timers == NULL) {
|
283
|
+
rb_raise(cb_eClientNoMemoryError, "failed to allocate memory for timers heap");
|
284
|
+
}
|
285
|
+
timers->timers = new_timers;
|
286
|
+
timers->capa = new_capa;
|
287
|
+
}
|
288
|
+
tms_at(timers, timers->count) = timer;
|
289
|
+
timer->index = timers->count;
|
290
|
+
timers->count++;
|
291
|
+
timers_heapify_up(timers, timer->index);
|
292
|
+
}
|
293
|
+
|
294
|
+
static void
|
295
|
+
timers_heapify_up(rb_mt_timers *timers, uint32_t pos)
|
296
|
+
{
|
297
|
+
hrtime_t cur_ts = tms_ts_at(timers, pos);
|
298
|
+
uint32_t higher = (pos - 1) / 2;
|
299
|
+
while (pos && tms_ts_at(timers, higher) > cur_ts) {
|
300
|
+
timers_swap(timers, higher, pos);
|
301
|
+
pos = higher;
|
302
|
+
higher = (pos - 1) / 2;
|
303
|
+
}
|
304
|
+
}
|
305
|
+
|
306
|
+
static void
|
307
|
+
timers_heapify_down(rb_mt_timers *timers, uint32_t pos)
|
308
|
+
{
|
309
|
+
uint32_t count = timers->count;
|
310
|
+
uint32_t middle = (timers->count - 2) / 2;
|
311
|
+
hrtime_t cur_ts = tms_ts_at(timers, pos);
|
312
|
+
if (count == 1) return;
|
313
|
+
while (pos <= middle) {
|
314
|
+
uint32_t min_pos = pos;
|
315
|
+
hrtime_t ch_ts, min_ts = cur_ts;
|
316
|
+
|
317
|
+
if ((ch_ts = tms_ts_at(timers, pos * 2 + 1)) < min_ts) {
|
318
|
+
min_pos = pos * 2 + 1;
|
319
|
+
min_ts = ch_ts;
|
320
|
+
}
|
321
|
+
|
322
|
+
if (pos * 2 + 2 < count && tms_ts_at(timers, pos * 2 + 2) < min_ts) {
|
323
|
+
min_pos = pos * 2 + 2;
|
324
|
+
}
|
325
|
+
|
326
|
+
if (min_pos == pos) break;
|
327
|
+
timers_swap(timers, pos, min_pos);
|
328
|
+
pos = min_pos;
|
329
|
+
}
|
330
|
+
}
|
331
|
+
|
332
|
+
static void
|
333
|
+
timers_heapify_item(rb_mt_timers *timers, uint32_t pos)
|
334
|
+
{
|
335
|
+
if (pos && tms_ts_at(timers, pos) < tms_ts_at(timers, (pos - 1) / 2)) {
|
336
|
+
timers_heapify_up(timers, pos);
|
337
|
+
} else {
|
338
|
+
timers_heapify_down(timers, pos);
|
339
|
+
}
|
340
|
+
}
|
341
|
+
|
342
|
+
static inline hrtime_t
|
343
|
+
timers_minimum(rb_mt_timers *timers)
|
344
|
+
{
|
345
|
+
if (timers->count) {
|
346
|
+
return tms_ts_at(timers, 0);
|
347
|
+
} else {
|
348
|
+
return 0;
|
349
|
+
}
|
350
|
+
}
|
351
|
+
|
352
|
+
static inline rb_mt_timer *
|
353
|
+
timers_first(rb_mt_timers *timers)
|
354
|
+
{
|
355
|
+
if (timers->count) {
|
356
|
+
return tms_at(timers, 0);
|
357
|
+
} else {
|
358
|
+
return 0;
|
359
|
+
}
|
360
|
+
}
|
361
|
+
|
362
|
+
static void
|
363
|
+
timers_remove_timer(rb_mt_timers *timers, rb_mt_timer *timer)
|
364
|
+
{
|
365
|
+
uint32_t at = timer->index;
|
366
|
+
timer->index = -1;
|
367
|
+
if (at < timers->count - 1) {
|
368
|
+
timers_move_last(timers, at);
|
369
|
+
timers_heapify_item(timers, at);
|
370
|
+
} else {
|
371
|
+
timers->count--;
|
372
|
+
}
|
373
|
+
}
|
374
|
+
|
375
|
+
static void
|
376
|
+
timers_run(rb_mt_timers *timers, hrtime_t now)
|
377
|
+
{
|
378
|
+
hrtime_t next_time = timers_minimum(timers);
|
379
|
+
while (next_time && next_time < now) {
|
380
|
+
rb_mt_timer *first = timers_first(timers);
|
381
|
+
|
382
|
+
first->ts = now + first->period;
|
383
|
+
timers_heapify_item(timers, 0);
|
384
|
+
|
385
|
+
first->handler(-1, 0, first->cb_data);
|
386
|
+
|
387
|
+
next_time = timers_minimum(timers);
|
388
|
+
}
|
389
|
+
}
|
390
|
+
/* timers heap end */
|
391
|
+
|
392
|
+
/* callbacks array */
|
393
|
+
typedef struct rb_mt_callbacks rb_mt_callbacks;
|
394
|
+
struct rb_mt_callbacks {
|
395
|
+
uint32_t capa;
|
396
|
+
uint32_t count;
|
397
|
+
rb_mt_event **events;
|
398
|
+
};
|
399
|
+
|
400
|
+
static int
|
401
|
+
callbacks_init(rb_mt_callbacks *callbacks)
|
402
|
+
{
|
403
|
+
rb_mt_event **new_events = calloc(4, sizeof(*new_events));
|
404
|
+
if (new_events == NULL) {
|
405
|
+
return 0;
|
406
|
+
}
|
407
|
+
callbacks->events = new_events;
|
408
|
+
callbacks->capa = 4;
|
409
|
+
callbacks->count = 0;
|
410
|
+
return 1;
|
411
|
+
}
|
412
|
+
|
413
|
+
static void
|
414
|
+
callbacks_finalize(rb_mt_callbacks *callbacks)
|
415
|
+
{
|
416
|
+
if (callbacks->events) {
|
417
|
+
free(callbacks->events);
|
418
|
+
callbacks->events = NULL;
|
419
|
+
}
|
420
|
+
callbacks->capa = 0;
|
421
|
+
callbacks->count = 0;
|
422
|
+
}
|
423
|
+
|
424
|
+
static void
|
425
|
+
callbacks_push(rb_mt_callbacks *callbacks, rb_mt_event *event)
|
426
|
+
{
|
427
|
+
if (callbacks->count == callbacks->capa) {
|
428
|
+
uint32_t new_capa = callbacks->capa << 1;
|
429
|
+
rb_mt_event **new_events = realloc(callbacks->events, new_capa * sizeof(*new_events));
|
430
|
+
if (new_events == NULL) {
|
431
|
+
rb_raise(cb_eClientNoMemoryError, "failed to allocate memory for callbacks array");
|
432
|
+
}
|
433
|
+
callbacks->capa = new_capa;
|
434
|
+
callbacks->events = new_events;
|
435
|
+
}
|
436
|
+
event->loop_index = callbacks->count;
|
437
|
+
callbacks->events[callbacks->count] = event;
|
438
|
+
callbacks->count++;
|
439
|
+
}
|
440
|
+
|
441
|
+
static void
|
442
|
+
callbacks_remove(rb_mt_callbacks *callbacks, rb_mt_event *event)
|
443
|
+
{
|
444
|
+
int i = event->loop_index;
|
445
|
+
if (i >= 0) {
|
446
|
+
if (callbacks->events[i] != event) {
|
447
|
+
rb_raise(rb_eIndexError, "callback index belongs to different callback");
|
448
|
+
}
|
449
|
+
event->loop_index = -1;
|
450
|
+
callbacks->events[i] = NULL;
|
451
|
+
}
|
452
|
+
}
|
453
|
+
|
454
|
+
static void
|
455
|
+
callbacks_run(rb_mt_callbacks *callbacks)
|
456
|
+
{
|
457
|
+
uint32_t i;
|
458
|
+
for(i = 0; i < callbacks->count; i++) {
|
459
|
+
rb_mt_event *cb = callbacks->events[i];
|
460
|
+
if (cb) {
|
461
|
+
cb->loop_index = -1;
|
462
|
+
callbacks->events[i] = NULL;
|
463
|
+
cb->handler(cb->socket, cb->actual_flags, cb->cb_data);
|
464
|
+
}
|
465
|
+
}
|
466
|
+
callbacks->count = 0;
|
467
|
+
}
|
468
|
+
|
469
|
+
static void
|
470
|
+
callbacks_clean(rb_mt_callbacks *callbacks)
|
471
|
+
{
|
472
|
+
uint32_t i;
|
473
|
+
for(i = 0; i < callbacks->count; i++) {
|
474
|
+
if (callbacks->events[i]) {
|
475
|
+
callbacks->events[i]->loop_index = -1;
|
476
|
+
callbacks->events[i] = NULL;
|
477
|
+
}
|
478
|
+
}
|
479
|
+
callbacks->count = 0;
|
480
|
+
}
|
481
|
+
/* callbacks array end */
|
482
|
+
|
483
|
+
typedef struct rb_mt_loop rb_mt_loop;
|
484
|
+
struct rb_mt_loop {
|
485
|
+
rb_mt_events events;
|
486
|
+
rb_mt_timers timers;
|
487
|
+
rb_mt_callbacks callbacks;
|
488
|
+
short run;
|
489
|
+
};
|
490
|
+
|
491
|
+
static rb_mt_loop*
|
492
|
+
loop_create()
|
493
|
+
{
|
494
|
+
rb_mt_loop *loop = calloc(1, sizeof(*loop));
|
495
|
+
if (loop == NULL) return NULL;
|
496
|
+
if (!events_init(&loop->events)) goto free_loop;
|
497
|
+
if (!timers_init(&loop->timers)) goto free_events;
|
498
|
+
if (!callbacks_init(&loop->callbacks)) goto free_timers;
|
499
|
+
return loop;
|
500
|
+
|
501
|
+
free_timers:
|
502
|
+
timers_finalize(&loop->timers);
|
503
|
+
free_events:
|
504
|
+
events_finalize(&loop->events);
|
505
|
+
free_loop:
|
506
|
+
free(loop);
|
507
|
+
return NULL;
|
508
|
+
}
|
509
|
+
|
510
|
+
static void
|
511
|
+
loop_destroy(rb_mt_loop *loop)
|
512
|
+
{
|
513
|
+
events_finalize(&loop->events);
|
514
|
+
timers_finalize(&loop->timers);
|
515
|
+
callbacks_finalize(&loop->callbacks);
|
516
|
+
free(loop);
|
517
|
+
}
|
518
|
+
|
519
|
+
static void
|
520
|
+
loop_remove_event(rb_mt_loop *loop, rb_mt_event *event)
|
521
|
+
{
|
522
|
+
if (event->inserted) {
|
523
|
+
events_remove(&loop->events, event);
|
524
|
+
}
|
525
|
+
callbacks_remove(&loop->callbacks, event);
|
526
|
+
}
|
527
|
+
|
528
|
+
static void
|
529
|
+
loop_enque_events(rb_mt_callbacks *callbacks, rb_mt_event *sock, short flags)
|
530
|
+
{
|
531
|
+
while (sock) {
|
532
|
+
short actual = sock->flags & flags;
|
533
|
+
if (actual) {
|
534
|
+
sock->actual_flags = actual;
|
535
|
+
callbacks_push(callbacks, (rb_mt_event*)sock);
|
536
|
+
}
|
537
|
+
sock = sock->next;
|
538
|
+
}
|
539
|
+
}
|
540
|
+
|
541
|
+
/* loop select implementation */
|
542
|
+
#ifndef HAVE_RB_THREAD_FD_SELECT
|
543
|
+
typedef fd_set rb_fdset_t;
|
544
|
+
#define rb_fd_init FD_ZERO
|
545
|
+
#define rb_fd_set FD_SET
|
546
|
+
#define rb_fd_isset FD_ISSET
|
547
|
+
#define rb_fd_term(set) (void)0
|
548
|
+
#define rb_thread_fd_select rb_thread_select
|
549
|
+
#endif
|
550
|
+
|
551
|
+
typedef struct loop_select_arg {
|
552
|
+
rb_mt_loop *loop;
|
553
|
+
rb_fdset_t in, out, exc;
|
554
|
+
} ls_arg;
|
555
|
+
|
556
|
+
static void
|
557
|
+
ls_arg_free(void *p) {
|
558
|
+
ls_arg *args = p;
|
559
|
+
if (args) {
|
560
|
+
rb_fd_term(&args->in);
|
561
|
+
rb_fd_term(&args->out);
|
562
|
+
xfree(args);
|
563
|
+
}
|
564
|
+
}
|
565
|
+
|
566
|
+
static VALUE
|
567
|
+
ls_arg_alloc(ls_arg **args)
|
568
|
+
{
|
569
|
+
return Data_Make_Struct(rb_cObject, ls_arg, 0, ls_arg_free, *args);
|
570
|
+
}
|
571
|
+
|
572
|
+
static VALUE
|
573
|
+
loop_run_select(VALUE argp)
|
574
|
+
{
|
575
|
+
ls_arg *args = (ls_arg*) argp;
|
576
|
+
rb_mt_loop *loop = args->loop;
|
577
|
+
rb_fdset_t *in = NULL, *out = NULL, *exc = NULL;
|
578
|
+
struct timeval timeout;
|
579
|
+
struct timeval *timeoutp = NULL;
|
580
|
+
int result, max = 0;
|
581
|
+
hrtime_t now, next_time;
|
582
|
+
|
583
|
+
next_time = timers_minimum(&loop->timers);
|
584
|
+
if (next_time) {
|
585
|
+
now = gethrtime();
|
586
|
+
if (next_time <= now) {
|
587
|
+
timeout.tv_sec = 0;
|
588
|
+
timeout.tv_usec = 0;
|
589
|
+
} else {
|
590
|
+
hrtime_t hrto = (next_time - now) / 1000;
|
591
|
+
timeout.tv_sec = (long)(hrto / 1000000);
|
592
|
+
timeout.tv_usec = (long)(hrto % 1000000);
|
593
|
+
}
|
594
|
+
timeoutp = &timeout;
|
595
|
+
}
|
596
|
+
|
597
|
+
if (loop->events.count) {
|
598
|
+
uint32_t i;
|
599
|
+
rb_fd_init(&args->in);
|
600
|
+
rb_fd_init(&args->out);
|
601
|
+
rb_fd_init(&args->exc);
|
602
|
+
for(i = 0; i < loop->events.count; i++) {
|
603
|
+
rb_mt_socket_list *list = &loop->events.sockets[i];
|
604
|
+
if (list->flags != 0) {
|
605
|
+
if (list->flags & LCB_READ_EVENT) {
|
606
|
+
in = &args->in;
|
607
|
+
rb_fd_set(list->socket, in);
|
608
|
+
}
|
609
|
+
if (list->flags & LCB_WRITE_EVENT) {
|
610
|
+
out = &args->out;
|
611
|
+
rb_fd_set(list->socket, out);
|
612
|
+
}
|
613
|
+
exc = &args->exc;
|
614
|
+
rb_fd_set(list->socket, exc);
|
615
|
+
}
|
616
|
+
}
|
617
|
+
max = events_max_fd(&loop->events) + 1;
|
618
|
+
}
|
619
|
+
|
620
|
+
result = rb_thread_fd_select(max, in, out, exc, timeoutp);
|
621
|
+
|
622
|
+
if (result < 0) {
|
623
|
+
rb_sys_fail("rb_thread_fd_select");
|
624
|
+
}
|
625
|
+
/* fix current time so that socket callbacks will not cause timers timeouts */
|
626
|
+
if (next_time) {
|
627
|
+
now = gethrtime();
|
628
|
+
}
|
629
|
+
|
630
|
+
if (result > 0) {
|
631
|
+
uint32_t i;
|
632
|
+
for(i = 0; i < loop->events.count && result; i++) {
|
633
|
+
rb_mt_socket_list *list = loop->events.sockets + i;
|
634
|
+
rb_mt_event *sock = list->first;
|
635
|
+
short flags = 0;
|
636
|
+
if (in && rb_fd_isset(list->socket, in)) {
|
637
|
+
flags |= LCB_READ_EVENT;
|
638
|
+
result--;
|
639
|
+
}
|
640
|
+
if (out && rb_fd_isset(list->socket, out)) {
|
641
|
+
flags |= LCB_WRITE_EVENT;
|
642
|
+
result--;
|
643
|
+
}
|
644
|
+
if (exc && rb_fd_isset(list->socket, exc)) {
|
645
|
+
flags = LCB_ERROR_EVENT | LCB_WRITE_EVENT;
|
646
|
+
result--;
|
647
|
+
}
|
648
|
+
if (flags) {
|
649
|
+
loop_enque_events(&loop->callbacks, sock, flags);
|
650
|
+
}
|
651
|
+
}
|
652
|
+
callbacks_run(&loop->callbacks);
|
653
|
+
}
|
654
|
+
|
655
|
+
if (next_time) {
|
656
|
+
timers_run(&loop->timers, now);
|
657
|
+
}
|
658
|
+
if (loop->events.count == 0 && loop->timers.count == 0) {
|
659
|
+
loop->run = 0;
|
660
|
+
}
|
661
|
+
return Qnil;
|
662
|
+
}
|
663
|
+
|
664
|
+
static VALUE
|
665
|
+
loop_select_cleanup(VALUE argp)
|
666
|
+
{
|
667
|
+
ls_arg *args = DATA_PTR(argp);
|
668
|
+
if (args) {
|
669
|
+
callbacks_clean(&args->loop->callbacks);
|
670
|
+
ls_arg_free(args);
|
671
|
+
DATA_PTR(argp) = 0;
|
672
|
+
}
|
673
|
+
return Qnil;
|
674
|
+
}
|
675
|
+
/* loop select implementaion end */
|
676
|
+
|
677
|
+
/* loop poll implementation */
|
678
|
+
#ifdef HAVE_POLL
|
679
|
+
/* code influenced by ruby's source and cool.io */
|
680
|
+
#define POLLIN_SET (POLLIN | POLLHUP | POLLERR)
|
681
|
+
#define POLLOUT_SET (POLLOUT | POLLHUP | POLLERR)
|
682
|
+
#define HRTIME_INFINITY ((hrtime_t)~0)
|
683
|
+
|
684
|
+
#ifdef HAVE_PPOLL
|
685
|
+
static int
|
686
|
+
xpoll(struct pollfd *fds, nfds_t nfds, hrtime_t timeout)
|
687
|
+
{
|
688
|
+
if (timeout != HRTIME_INFINITY) {
|
689
|
+
struct timespec ts;
|
690
|
+
ts.tv_sec = (long)(timeout / (1000 * 1000 * 1000));
|
691
|
+
ts.tv_nsec = (long)(timeout % (1000 * 1000 * 1000));
|
692
|
+
return ppoll(fds, nfds, &ts, NULL);
|
693
|
+
}
|
694
|
+
return ppoll(fds, nfds, NULL, NULL);
|
695
|
+
}
|
696
|
+
#else
|
697
|
+
#define TIMEOUT_MAX ((hrtime_t)(((unsigned int)~0) >> 1))
|
698
|
+
static int
|
699
|
+
xpoll(struct pollfd *fds, nfds_t nfds, hrtime_t timeout)
|
700
|
+
{
|
701
|
+
int ts = -1;
|
702
|
+
if (timeout != HRTIME_INFINITY) {
|
703
|
+
timeout = (timeout + 999999) / (1000 * 1000);
|
704
|
+
if (timeout <= TIMEOUT_MAX) {
|
705
|
+
ts = (int)timeout;
|
706
|
+
}
|
707
|
+
}
|
708
|
+
return poll(fds, nfds, ts);
|
709
|
+
}
|
710
|
+
#endif
|
711
|
+
|
712
|
+
typedef struct poll_args lp_arg;
|
713
|
+
struct poll_args {
|
714
|
+
rb_mt_loop *loop;
|
715
|
+
struct pollfd *fds;
|
716
|
+
nfds_t nfd;
|
717
|
+
hrtime_t ts;
|
718
|
+
int result;
|
719
|
+
int lerrno;
|
720
|
+
};
|
721
|
+
|
722
|
+
static void
|
723
|
+
lp_arg_free(void *p)
|
724
|
+
{
|
725
|
+
lp_arg *args = p;
|
726
|
+
if (args) {
|
727
|
+
if (args->fds) {
|
728
|
+
free(args->fds);
|
729
|
+
}
|
730
|
+
xfree(args);
|
731
|
+
}
|
732
|
+
}
|
733
|
+
|
734
|
+
static VALUE
|
735
|
+
lp_arg_alloc(lp_arg **args)
|
736
|
+
{
|
737
|
+
return Data_Make_Struct(rb_cObject, lp_arg, 0, lp_arg_free, *args);
|
738
|
+
}
|
739
|
+
|
740
|
+
#if defined(HAVE_RB_THREAD_BLOCKING_REGION) || defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL)
|
741
|
+
static VALUE
|
742
|
+
loop_blocking_poll(void *argp)
|
743
|
+
{
|
744
|
+
lp_arg *args = argp;
|
745
|
+
args->result = xpoll(args->fds, args->nfd, args->ts);
|
746
|
+
if (args->result < 0) args->lerrno = errno;
|
747
|
+
return Qnil;
|
748
|
+
}
|
749
|
+
#endif
|
750
|
+
|
751
|
+
static VALUE
|
752
|
+
loop_run_poll(VALUE argp)
|
753
|
+
{
|
754
|
+
lp_arg *args = (lp_arg*)argp;
|
755
|
+
rb_mt_loop *loop = args->loop;
|
756
|
+
hrtime_t now, next_time;
|
757
|
+
|
758
|
+
if (loop->events.count) {
|
759
|
+
uint32_t i;
|
760
|
+
args->fds = calloc(loop->events.count, sizeof(struct pollfd));
|
761
|
+
if (args->fds == NULL) {
|
762
|
+
rb_raise(cb_eClientNoMemoryError, "failed to allocate memory for pollfd");
|
763
|
+
}
|
764
|
+
for(i = 0; i < loop->events.count; i++) {
|
765
|
+
rb_mt_socket_list *list = &loop->events.sockets[i];
|
766
|
+
args->fds[i].fd = list->socket;
|
767
|
+
args->fds[i].events =
|
768
|
+
(list->flags & LCB_READ_EVENT ? POLLIN : 0) |
|
769
|
+
(list->flags & LCB_WRITE_EVENT ? POLLOUT : 0);
|
770
|
+
}
|
771
|
+
args->nfd = loop->events.count;
|
772
|
+
}
|
773
|
+
|
774
|
+
retry:
|
775
|
+
next_time = timers_minimum(&loop->timers);
|
776
|
+
if (next_time) {
|
777
|
+
now = gethrtime();
|
778
|
+
args->ts = next_time <= now ? 0 : next_time - now;
|
779
|
+
} else {
|
780
|
+
args->ts = HRTIME_INFINITY;
|
781
|
+
}
|
782
|
+
|
783
|
+
|
784
|
+
#if defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL)
|
785
|
+
rb_thread_call_without_gvl((void *(*)(void*))loop_blocking_poll, args, RUBY_UBF_IO, 0);
|
786
|
+
#elif defined(HAVE_RB_THREAD_BLOCKING_REGION)
|
787
|
+
rb_thread_blocking_region(loop_blocking_poll, args, RUBY_UBF_PROCESS, NULL);
|
788
|
+
#else
|
789
|
+
if (rb_thread_alone()) {
|
790
|
+
TRAP_BEG;
|
791
|
+
args->result = xpoll(args->fds, args->nfd, args->ts);
|
792
|
+
if (args->result < 0) args->lerrno = errno;
|
793
|
+
TRAP_END;
|
794
|
+
} else {
|
795
|
+
/* 5 millisecond pause */
|
796
|
+
hrtime_t mini_pause = 5000000;
|
797
|
+
int exact = 0;
|
798
|
+
if (args->ts != HRTIME_INFINITY && args->ts < mini_pause) {
|
799
|
+
mini_pause = args->ts;
|
800
|
+
exact = 1;
|
801
|
+
}
|
802
|
+
TRAP_BEG;
|
803
|
+
args->result = xpoll(args->fds, args->nfd, mini_pause);
|
804
|
+
if (args->result < 0) args->lerrno = errno;
|
805
|
+
TRAP_END;
|
806
|
+
if (args->result == 0 && !exact) {
|
807
|
+
args->result = -1;
|
808
|
+
args->lerrno = EINTR;
|
809
|
+
}
|
810
|
+
}
|
811
|
+
#endif
|
812
|
+
|
813
|
+
if (args->result < 0) {
|
814
|
+
errno = args->lerrno;
|
815
|
+
switch (errno) {
|
816
|
+
case EINTR:
|
817
|
+
#ifdef ERESTART
|
818
|
+
case ERESTART:
|
819
|
+
#endif
|
820
|
+
#ifndef HAVE_RB_THREAD_BLOCKING_REGION
|
821
|
+
rb_thread_schedule();
|
822
|
+
#endif
|
823
|
+
goto retry;
|
824
|
+
}
|
825
|
+
rb_sys_fail("poll");
|
826
|
+
return Qnil;
|
827
|
+
}
|
828
|
+
|
829
|
+
if (next_time) {
|
830
|
+
now = gethrtime();
|
831
|
+
}
|
832
|
+
|
833
|
+
if (args->result > 0) {
|
834
|
+
uint32_t cnt = args->result;
|
835
|
+
uint32_t fd_n = 0, ev_n = 0;
|
836
|
+
while (cnt && fd_n < args->nfd && ev_n < loop->events.count) {
|
837
|
+
struct pollfd *res = args->fds + fd_n;
|
838
|
+
rb_mt_socket_list *list = loop->events.sockets + ev_n;
|
839
|
+
rb_mt_event *sock = list->first;
|
840
|
+
|
841
|
+
/* if plugin used correctly, this checks are noop */
|
842
|
+
if (res->fd < list->socket) {
|
843
|
+
fd_n++;
|
844
|
+
continue;
|
845
|
+
} else if (res->fd > list->socket) {
|
846
|
+
ev_n++;
|
847
|
+
continue;
|
848
|
+
}
|
849
|
+
|
850
|
+
if (res->revents) {
|
851
|
+
short flags =
|
852
|
+
((res->revents & POLLIN_SET) ? LCB_READ_EVENT : 0) |
|
853
|
+
((res->revents & POLLOUT_SET) ? LCB_WRITE_EVENT : 0);
|
854
|
+
cnt--;
|
855
|
+
loop_enque_events(&loop->callbacks, sock, flags);
|
856
|
+
}
|
857
|
+
fd_n++;
|
858
|
+
ev_n++;
|
859
|
+
}
|
860
|
+
callbacks_run(&loop->callbacks);
|
861
|
+
}
|
862
|
+
|
863
|
+
if (next_time) {
|
864
|
+
timers_run(&loop->timers, now);
|
865
|
+
}
|
866
|
+
if (loop->events.count == 0 && loop->timers.count == 0) {
|
867
|
+
loop->run = 0;
|
868
|
+
}
|
869
|
+
return Qnil;
|
870
|
+
}
|
871
|
+
|
872
|
+
static VALUE
|
873
|
+
loop_poll_cleanup(VALUE argp)
|
874
|
+
{
|
875
|
+
lp_arg *args = DATA_PTR(argp);
|
876
|
+
if (args) {
|
877
|
+
callbacks_clean(&args->loop->callbacks);
|
878
|
+
lp_arg_free(args);
|
879
|
+
DATA_PTR(argp) = 0;
|
880
|
+
}
|
881
|
+
return Qnil;
|
882
|
+
}
|
883
|
+
#endif
|
884
|
+
/* loop poll implementation end */
|
885
|
+
|
886
|
+
static void
|
887
|
+
loop_run(rb_mt_loop *loop)
|
888
|
+
{
|
889
|
+
|
890
|
+
loop->run = 1;
|
891
|
+
|
892
|
+
while(loop->run) {
|
893
|
+
#ifdef HAVE_POLL
|
894
|
+
/* prefer use of poll when it gives some benefits, but use rb_thread_fd_select when it is sufficient */
|
895
|
+
lcb_socket_t max = events_max_fd(&loop->events);
|
896
|
+
int use_poll = max >= 128;
|
897
|
+
if (use_poll) {
|
898
|
+
lp_arg *args;
|
899
|
+
VALUE argp = lp_arg_alloc(&args);
|
900
|
+
args->loop = loop;
|
901
|
+
rb_ensure(loop_run_poll, (VALUE)args, loop_poll_cleanup, argp);
|
902
|
+
} else
|
903
|
+
#endif
|
904
|
+
{
|
905
|
+
ls_arg *args;
|
906
|
+
VALUE argp = ls_arg_alloc(&args);
|
907
|
+
args->loop = loop;
|
908
|
+
rb_ensure(loop_run_select, (VALUE)args, loop_select_cleanup, argp);
|
909
|
+
}
|
910
|
+
}
|
911
|
+
}
|
912
|
+
|
913
|
+
static void *
|
914
|
+
lcb_io_create_event(struct lcb_io_opt_st *iops)
|
915
|
+
{
|
916
|
+
rb_mt_event *event = calloc(1, sizeof(*event));
|
917
|
+
(void)iops;
|
918
|
+
event->loop_index = -1;
|
919
|
+
return event;
|
920
|
+
}
|
921
|
+
|
922
|
+
static int
|
923
|
+
lcb_io_update_event(struct lcb_io_opt_st *iops,
|
924
|
+
lcb_socket_t sock,
|
925
|
+
void *eventp,
|
926
|
+
short flags,
|
927
|
+
void *cb_data,
|
928
|
+
void (*handler)(lcb_socket_t sock,
|
929
|
+
short which,
|
930
|
+
void *cb_data))
|
931
|
+
{
|
932
|
+
rb_mt_loop *loop = iops->v.v0.cookie;
|
933
|
+
rb_mt_event *event = eventp;
|
934
|
+
short old_flags = event->flags;
|
935
|
+
|
936
|
+
if (event->inserted && old_flags == flags &&
|
937
|
+
cb_data == event->cb_data && handler == event->handler)
|
938
|
+
{
|
939
|
+
return 0;
|
940
|
+
}
|
941
|
+
loop_remove_event(loop, event);
|
942
|
+
event->flags = flags;
|
943
|
+
event->cb_data = cb_data;
|
944
|
+
event->handler = handler;
|
945
|
+
event->socket = sock;
|
946
|
+
if (!event->inserted) {
|
947
|
+
events_insert(&loop->events, event);
|
948
|
+
}
|
949
|
+
if ((old_flags & flags) != old_flags) {
|
950
|
+
events_fix_flags(&loop->events, sock);
|
951
|
+
}
|
952
|
+
return 0;
|
953
|
+
}
|
954
|
+
|
955
|
+
static void
|
956
|
+
lcb_io_delete_event(struct lcb_io_opt_st *iops,
|
957
|
+
lcb_socket_t sock,
|
958
|
+
void *event)
|
959
|
+
{
|
960
|
+
loop_remove_event((rb_mt_loop*)iops->v.v0.cookie, (rb_mt_event*)event);
|
961
|
+
(void)sock;
|
962
|
+
}
|
963
|
+
|
964
|
+
static void
|
965
|
+
lcb_io_destroy_event(struct lcb_io_opt_st *iops,
|
966
|
+
void *event)
|
967
|
+
{
|
968
|
+
lcb_io_delete_event(iops, -1, event);
|
969
|
+
free(event);
|
970
|
+
}
|
971
|
+
|
972
|
+
static void *
|
973
|
+
lcb_io_create_timer(struct lcb_io_opt_st *iops)
|
974
|
+
{
|
975
|
+
rb_mt_timer *timer = calloc(1, sizeof(*timer));
|
976
|
+
timer->index = -1;
|
977
|
+
(void)iops;
|
978
|
+
return timer;
|
979
|
+
}
|
980
|
+
|
981
|
+
static int
|
982
|
+
lcb_io_update_timer(struct lcb_io_opt_st *iops, void *event,
|
983
|
+
lcb_uint32_t usec, void *cb_data,
|
984
|
+
void (*handler)(lcb_socket_t sock, short which, void *cb_data))
|
985
|
+
{
|
986
|
+
rb_mt_loop *loop = iops->v.v0.cookie;
|
987
|
+
rb_mt_timer *timer = event;
|
988
|
+
|
989
|
+
timer->period = usec * (hrtime_t)1000;
|
990
|
+
timer->ts = gethrtime() + timer->period;
|
991
|
+
timer->cb_data = cb_data;
|
992
|
+
timer->handler = handler;
|
993
|
+
if (timer->index != -1) {
|
994
|
+
timers_heapify_item(&loop->timers, timer->index);
|
995
|
+
} else {
|
996
|
+
timers_insert(&loop->timers, timer);
|
997
|
+
}
|
998
|
+
return 0;
|
999
|
+
}
|
1000
|
+
|
1001
|
+
static void
|
1002
|
+
lcb_io_delete_timer(struct lcb_io_opt_st *iops, void *event)
|
1003
|
+
{
|
1004
|
+
rb_mt_loop *loop = iops->v.v0.cookie;
|
1005
|
+
rb_mt_timer *timer = event;
|
1006
|
+
if (timer->index != -1) {
|
1007
|
+
timers_remove_timer(&loop->timers, timer);
|
1008
|
+
}
|
1009
|
+
}
|
1010
|
+
|
1011
|
+
static void
|
1012
|
+
lcb_io_destroy_timer(struct lcb_io_opt_st *iops, void *timer)
|
1013
|
+
{
|
1014
|
+
lcb_io_delete_timer(iops, timer);
|
1015
|
+
free(timer);
|
1016
|
+
}
|
1017
|
+
|
1018
|
+
static void
|
1019
|
+
lcb_io_stop_event_loop(struct lcb_io_opt_st *iops)
|
1020
|
+
{
|
1021
|
+
rb_mt_loop *loop = iops->v.v0.cookie;
|
1022
|
+
loop->run = 0;
|
1023
|
+
}
|
1024
|
+
|
1025
|
+
static void
|
1026
|
+
lcb_io_run_event_loop(struct lcb_io_opt_st *iops)
|
1027
|
+
{
|
1028
|
+
rb_mt_loop *loop = iops->v.v0.cookie;
|
1029
|
+
loop_run(loop);
|
1030
|
+
}
|
1031
|
+
|
1032
|
+
static void
|
1033
|
+
lcb_destroy_io_opts(struct lcb_io_opt_st *iops)
|
1034
|
+
{
|
1035
|
+
rb_mt_loop *loop = iops->v.v0.cookie;
|
1036
|
+
loop_destroy(loop);
|
1037
|
+
free(iops);
|
1038
|
+
}
|
1039
|
+
|
1040
|
+
LIBCOUCHBASE_API lcb_error_t
|
1041
|
+
cb_create_ruby_mt_io_opts(int version, lcb_io_opt_t *io, void *arg)
|
1042
|
+
{
|
1043
|
+
struct lcb_io_opt_st *ret;
|
1044
|
+
rb_mt_loop *loop;
|
1045
|
+
(void)arg;
|
1046
|
+
if (version != 0) {
|
1047
|
+
return LCB_PLUGIN_VERSION_MISMATCH;
|
1048
|
+
}
|
1049
|
+
ret = calloc(1, sizeof(*ret));
|
1050
|
+
if (ret == NULL) {
|
1051
|
+
free(ret);
|
1052
|
+
return LCB_CLIENT_ENOMEM;
|
1053
|
+
}
|
1054
|
+
|
1055
|
+
ret->version = 0;
|
1056
|
+
ret->dlhandle = NULL;
|
1057
|
+
ret->destructor = lcb_destroy_io_opts;
|
1058
|
+
/* consider that struct isn't allocated by the library,
|
1059
|
+
* `need_cleanup' flag might be set in lcb_create() */
|
1060
|
+
ret->v.v0.need_cleanup = 0;
|
1061
|
+
ret->v.v0.recv = cb_io_recv;
|
1062
|
+
ret->v.v0.send = cb_io_send;
|
1063
|
+
ret->v.v0.recvv = cb_io_recvv;
|
1064
|
+
ret->v.v0.sendv = cb_io_sendv;
|
1065
|
+
ret->v.v0.socket = cb_io_socket;
|
1066
|
+
ret->v.v0.close = cb_io_close;
|
1067
|
+
ret->v.v0.connect = cb_io_connect;
|
1068
|
+
ret->v.v0.delete_event = lcb_io_delete_event;
|
1069
|
+
ret->v.v0.destroy_event = lcb_io_destroy_event;
|
1070
|
+
ret->v.v0.create_event = lcb_io_create_event;
|
1071
|
+
ret->v.v0.update_event = lcb_io_update_event;
|
1072
|
+
|
1073
|
+
ret->v.v0.delete_timer = lcb_io_delete_timer;
|
1074
|
+
ret->v.v0.destroy_timer = lcb_io_destroy_timer;
|
1075
|
+
ret->v.v0.create_timer = lcb_io_create_timer;
|
1076
|
+
ret->v.v0.update_timer = lcb_io_update_timer;
|
1077
|
+
|
1078
|
+
ret->v.v0.run_event_loop = lcb_io_run_event_loop;
|
1079
|
+
ret->v.v0.stop_event_loop = lcb_io_stop_event_loop;
|
1080
|
+
|
1081
|
+
loop = loop_create();
|
1082
|
+
if (loop == NULL) {
|
1083
|
+
free(ret);
|
1084
|
+
return LCB_CLIENT_ENOMEM;
|
1085
|
+
}
|
1086
|
+
ret->v.v0.cookie = loop;
|
1087
|
+
*io = ret;
|
1088
|
+
return LCB_SUCCESS;
|
1089
|
+
}
|
1090
|
+
#endif /* _WIN32 */
|