nutcracker 0.2.4.12 → 0.3.0.12
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 +8 -8
- data/Rakefile +1 -1
- data/ext/nutcracker/ChangeLog +10 -0
- data/ext/nutcracker/Makefile.am +2 -0
- data/ext/nutcracker/Makefile.in +101 -14
- data/ext/nutcracker/README.md +18 -1
- data/ext/nutcracker/config.h.in +18 -0
- data/ext/nutcracker/configure +196 -25
- data/ext/nutcracker/configure.ac +64 -6
- data/ext/nutcracker/extconf.rb +1 -1
- data/ext/nutcracker/man/nutcracker.8 +76 -0
- data/ext/nutcracker/notes/debug.txt +116 -16
- data/ext/nutcracker/notes/kqueue.pdf +0 -0
- data/ext/nutcracker/notes/recommendation.md +20 -0
- data/ext/nutcracker/notes/redis.md +2 -2
- data/ext/nutcracker/scripts/nutcracker.spec +1 -1
- data/ext/nutcracker/scripts/redis-check.sh +3 -1
- data/ext/nutcracker/src/Makefile.am +15 -6
- data/ext/nutcracker/src/Makefile.in +39 -36
- data/ext/nutcracker/src/event/Makefile.am +16 -0
- data/ext/nutcracker/src/event/Makefile.in +492 -0
- data/ext/nutcracker/src/event/nc_epoll.c +344 -0
- data/ext/nutcracker/src/event/nc_event.h +88 -0
- data/ext/nutcracker/src/event/nc_evport.c +420 -0
- data/ext/nutcracker/src/event/nc_kqueue.c +412 -0
- data/ext/nutcracker/src/hashkit/nc_crc32.c +19 -1
- data/ext/nutcracker/src/hashkit/nc_hashkit.h +3 -1
- data/ext/nutcracker/src/hashkit/nc_md5.c +257 -315
- data/ext/nutcracker/src/nc.c +12 -1
- data/ext/nutcracker/src/nc_connection.c +18 -1
- data/ext/nutcracker/src/nc_connection.h +1 -0
- data/ext/nutcracker/src/nc_core.c +22 -30
- data/ext/nutcracker/src/nc_core.h +22 -7
- data/ext/nutcracker/src/nc_proxy.c +8 -9
- data/ext/nutcracker/src/nc_queue.h +2 -0
- data/ext/nutcracker/src/nc_request.c +3 -4
- data/ext/nutcracker/src/nc_response.c +25 -8
- data/ext/nutcracker/src/nc_server.c +8 -6
- data/ext/nutcracker/src/nc_stats.c +46 -43
- data/ext/nutcracker/src/nc_stats.h +37 -30
- data/ext/nutcracker/src/nc_util.c +6 -1
- data/ext/nutcracker/src/proto/nc_redis.c +19 -5
- data/lib/nutcracker/version.rb +1 -1
- data/lib/nutcracker.rb +1 -1
- metadata +10 -4
- data/ext/nutcracker/src/nc_event.c +0 -214
- data/ext/nutcracker/src/nc_event.h +0 -39
@@ -0,0 +1,420 @@
|
|
1
|
+
/*
|
2
|
+
* twemproxy - A fast and lightweight proxy for memcached protocol.
|
3
|
+
* Copyright (C) 2013 Twitter, 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 <nc_core.h>
|
19
|
+
|
20
|
+
#ifdef NC_HAVE_EVENT_PORTS
|
21
|
+
|
22
|
+
#include <port.h>
|
23
|
+
#include <poll.h>
|
24
|
+
|
25
|
+
struct event_base *
|
26
|
+
event_base_create(int nevent, event_cb_t cb)
|
27
|
+
{
|
28
|
+
struct event_base *evb;
|
29
|
+
int status, evp;
|
30
|
+
port_event_t *event;
|
31
|
+
|
32
|
+
ASSERT(nevent > 0);
|
33
|
+
|
34
|
+
evp = port_create();
|
35
|
+
if (evp < 0) {
|
36
|
+
log_error("port create failed: %s", strerror(errno));
|
37
|
+
return NULL;
|
38
|
+
}
|
39
|
+
|
40
|
+
event = nc_calloc(nevent, sizeof(*event));
|
41
|
+
if (event == NULL) {
|
42
|
+
status = close(evp);
|
43
|
+
if (status < 0) {
|
44
|
+
log_error("close evp %d failed, ignored: %s", evp, strerror(errno));
|
45
|
+
}
|
46
|
+
return NULL;
|
47
|
+
}
|
48
|
+
|
49
|
+
evb = nc_alloc(sizeof(*evb));
|
50
|
+
if (evb == NULL) {
|
51
|
+
nc_free(event);
|
52
|
+
status = close(evp);
|
53
|
+
if (status < 0) {
|
54
|
+
log_error("close evp %d failed, ignored: %s", evp, strerror(errno));
|
55
|
+
}
|
56
|
+
return NULL;
|
57
|
+
}
|
58
|
+
|
59
|
+
evb->evp = evp;
|
60
|
+
evb->event = event;
|
61
|
+
evb->nevent = nevent;
|
62
|
+
evb->cb = cb;
|
63
|
+
|
64
|
+
log_debug(LOG_INFO, "evp %d with nevent %d", evb->evp, evb->nevent);
|
65
|
+
|
66
|
+
return evb;
|
67
|
+
}
|
68
|
+
|
69
|
+
void
|
70
|
+
event_base_destroy(struct event_base *evb)
|
71
|
+
{
|
72
|
+
int status;
|
73
|
+
|
74
|
+
if (evb == NULL) {
|
75
|
+
return;
|
76
|
+
}
|
77
|
+
|
78
|
+
ASSERT(evb->evp >= 0);
|
79
|
+
|
80
|
+
nc_free(evb->event);
|
81
|
+
|
82
|
+
status = close(evb->evp);
|
83
|
+
if (status < 0) {
|
84
|
+
log_error("close evp %d failed, ignored: %s", evb->evp, strerror(errno));
|
85
|
+
}
|
86
|
+
evb->evp = -1;
|
87
|
+
|
88
|
+
nc_free(evb);
|
89
|
+
}
|
90
|
+
|
91
|
+
int
|
92
|
+
event_add_in(struct event_base *evb, struct conn *c)
|
93
|
+
{
|
94
|
+
return 0;
|
95
|
+
}
|
96
|
+
|
97
|
+
int
|
98
|
+
event_del_in(struct event_base *evb, struct conn *c)
|
99
|
+
{
|
100
|
+
return 0;
|
101
|
+
}
|
102
|
+
|
103
|
+
int
|
104
|
+
event_add_out(struct event_base *evb, struct conn *c)
|
105
|
+
{
|
106
|
+
int status;
|
107
|
+
int evp = evb->evp;
|
108
|
+
|
109
|
+
ASSERT(evp > 0);
|
110
|
+
ASSERT(c != NULL);
|
111
|
+
ASSERT(c->sd > 0);
|
112
|
+
ASSERT(c->recv_active);
|
113
|
+
|
114
|
+
if (c->send_active) {
|
115
|
+
return 0;
|
116
|
+
}
|
117
|
+
|
118
|
+
status = port_associate(evp, PORT_SOURCE_FD, c->sd, POLLIN | POLLOUT, c);
|
119
|
+
if (status < 0) {
|
120
|
+
log_error("port associate on evp %d sd %d failed: %s", evp, c->sd,
|
121
|
+
strerror(errno));
|
122
|
+
} else {
|
123
|
+
c->send_active = 1;
|
124
|
+
}
|
125
|
+
|
126
|
+
return status;
|
127
|
+
}
|
128
|
+
|
129
|
+
int
|
130
|
+
event_del_out(struct event_base *evb, struct conn *c)
|
131
|
+
{
|
132
|
+
int status;
|
133
|
+
int evp = evb->evp;
|
134
|
+
|
135
|
+
ASSERT(evp > 0);
|
136
|
+
ASSERT(c != NULL);
|
137
|
+
ASSERT(c->sd > 0);
|
138
|
+
ASSERT(c->recv_active);
|
139
|
+
|
140
|
+
if (!c->send_active) {
|
141
|
+
return 0;
|
142
|
+
}
|
143
|
+
|
144
|
+
status = port_associate(evp, PORT_SOURCE_FD, c->sd, POLLIN, c);
|
145
|
+
if (status < 0) {
|
146
|
+
log_error("port associate on evp %d sd %d failed: %s", evp, c->sd,
|
147
|
+
strerror(errno));
|
148
|
+
} else {
|
149
|
+
c->send_active = 0;
|
150
|
+
}
|
151
|
+
|
152
|
+
return status;
|
153
|
+
}
|
154
|
+
|
155
|
+
int
|
156
|
+
event_add_conn(struct event_base *evb, struct conn *c)
|
157
|
+
{
|
158
|
+
int status;
|
159
|
+
int evp = evb->evp;
|
160
|
+
|
161
|
+
ASSERT(evp > 0);
|
162
|
+
ASSERT(c != NULL);
|
163
|
+
ASSERT(c->sd > 0);
|
164
|
+
ASSERT(!c->recv_active);
|
165
|
+
ASSERT(!c->send_active);
|
166
|
+
|
167
|
+
status = port_associate(evp, PORT_SOURCE_FD, c->sd, POLLIN | POLLOUT, c);
|
168
|
+
if (status < 0) {
|
169
|
+
log_error("port associate on evp %d sd %d failed: %s", evp, c->sd,
|
170
|
+
strerror(errno));
|
171
|
+
} else {
|
172
|
+
c->send_active = 1;
|
173
|
+
c->recv_active = 1;
|
174
|
+
}
|
175
|
+
|
176
|
+
return status;
|
177
|
+
}
|
178
|
+
|
179
|
+
int
|
180
|
+
event_del_conn(struct event_base *evb, struct conn *c)
|
181
|
+
{
|
182
|
+
int status;
|
183
|
+
int evp = evb->evp;
|
184
|
+
|
185
|
+
ASSERT(evp > 0);
|
186
|
+
ASSERT(c != NULL);
|
187
|
+
ASSERT(c->sd > 0);
|
188
|
+
|
189
|
+
if (!c->send_active && !c->recv_active) {
|
190
|
+
return 0;
|
191
|
+
}
|
192
|
+
|
193
|
+
/*
|
194
|
+
* Removes the association of an object with a port. The association
|
195
|
+
* is also removed if the port gets closed.
|
196
|
+
*
|
197
|
+
* On failure, we check for ENOENT errno because it is likely that we
|
198
|
+
* are deleting this connection after it was returned from the event
|
199
|
+
* loop and before we had a chance of reactivating it by calling
|
200
|
+
* port_associate() on it.
|
201
|
+
*/
|
202
|
+
status = port_dissociate(evp, PORT_SOURCE_FD, c->sd);
|
203
|
+
if (status < 0 && errno != ENOENT) {
|
204
|
+
log_error("port dissociate evp %d sd %d failed: %s", evp, c->sd,
|
205
|
+
strerror(errno));
|
206
|
+
return status;
|
207
|
+
}
|
208
|
+
|
209
|
+
c->recv_active = 0;
|
210
|
+
c->send_active = 0;
|
211
|
+
|
212
|
+
return 0;
|
213
|
+
}
|
214
|
+
|
215
|
+
static int
|
216
|
+
event_reassociate(struct event_base *evb, struct conn *c)
|
217
|
+
{
|
218
|
+
int status, events;
|
219
|
+
int evp = evb->evp;
|
220
|
+
|
221
|
+
ASSERT(evp > 0);
|
222
|
+
ASSERT(c != NULL);
|
223
|
+
ASSERT(c->sd > 0);
|
224
|
+
ASSERT(c->recv_active);
|
225
|
+
|
226
|
+
if (c->send_active) {
|
227
|
+
events = POLLIN | POLLOUT;
|
228
|
+
} else {
|
229
|
+
events = POLLIN;
|
230
|
+
}
|
231
|
+
|
232
|
+
status = port_associate(evp, PORT_SOURCE_FD, c->sd, events , c);
|
233
|
+
if (status < 0) {
|
234
|
+
log_error("port associate on evp %d sd %d failed: %s", evp, c->sd,
|
235
|
+
strerror(errno));
|
236
|
+
}
|
237
|
+
|
238
|
+
return status;
|
239
|
+
}
|
240
|
+
|
241
|
+
int
|
242
|
+
event_wait(struct event_base *evb, int timeout)
|
243
|
+
{
|
244
|
+
int evp = evb->evp;
|
245
|
+
port_event_t *event = evb->event;
|
246
|
+
int nevent = evb->nevent;
|
247
|
+
struct timespec ts, *tsp;
|
248
|
+
|
249
|
+
ASSERT(evp > 0);
|
250
|
+
ASSERT(event != NULL);
|
251
|
+
ASSERT(nevent > 0);
|
252
|
+
|
253
|
+
/* port_getn should block indefinitely if timeout < 0 */
|
254
|
+
if (timeout < 0) {
|
255
|
+
tsp = NULL;
|
256
|
+
} else {
|
257
|
+
tsp = &ts;
|
258
|
+
tsp->tv_sec = timeout / 1000LL;
|
259
|
+
tsp->tv_nsec = (timeout % 1000LL) * 1000000LL;
|
260
|
+
}
|
261
|
+
|
262
|
+
for (;;) {
|
263
|
+
int i, status;
|
264
|
+
unsigned int nreturned = 1;
|
265
|
+
|
266
|
+
/*
|
267
|
+
* port_getn() retrieves multiple events from a port. A port_getn()
|
268
|
+
* call will block until at least nreturned events is triggered. On
|
269
|
+
* a successful return event[] is populated with triggered events
|
270
|
+
* up to the maximum sized allowed by nevent. The number of entries
|
271
|
+
* actually placed in event[] is saved in nreturned, which may be
|
272
|
+
* more than what we asked for but less than nevent.
|
273
|
+
*/
|
274
|
+
status = port_getn(evp, event, nevent, &nreturned, tsp);
|
275
|
+
if (status < 0) {
|
276
|
+
if (errno == EINTR || errno == EAGAIN) {
|
277
|
+
continue;
|
278
|
+
}
|
279
|
+
|
280
|
+
/*
|
281
|
+
* ETIME - The time interval expired before the expected number
|
282
|
+
* of events have been posted to the port or nreturned is updated
|
283
|
+
* with the number of returned port_event_t structures in event[]
|
284
|
+
*/
|
285
|
+
if (errno != ETIME) {
|
286
|
+
log_error("port getn on evp %d with %d events failed: %s", evp,
|
287
|
+
nevent, strerror(errno));
|
288
|
+
return -1;
|
289
|
+
}
|
290
|
+
}
|
291
|
+
|
292
|
+
if (nreturned > 0) {
|
293
|
+
for (i = 0; i < nreturned; i++) {
|
294
|
+
port_event_t *ev = &evb->event[i];
|
295
|
+
uint32_t events = 0;
|
296
|
+
|
297
|
+
log_debug(LOG_VVERB, "port %04"PRIX32" from source %d "
|
298
|
+
"triggered on conn %p", ev->portev_events,
|
299
|
+
ev->portev_source, ev->portev_user);
|
300
|
+
|
301
|
+
if (ev->portev_events & POLLERR) {
|
302
|
+
events |= EVENT_ERR;
|
303
|
+
}
|
304
|
+
|
305
|
+
if (ev->portev_events & POLLIN) {
|
306
|
+
events |= EVENT_READ;
|
307
|
+
}
|
308
|
+
|
309
|
+
if (ev->portev_events & POLLOUT) {
|
310
|
+
events |= EVENT_WRITE;
|
311
|
+
}
|
312
|
+
|
313
|
+
if (evb->cb != NULL && events != 0) {
|
314
|
+
status = evb->cb(ev->portev_user, events);
|
315
|
+
if (status < 0) {
|
316
|
+
continue;
|
317
|
+
}
|
318
|
+
|
319
|
+
/*
|
320
|
+
* When an event for a PORT_SOURCE_FD object is retrieved,
|
321
|
+
* the object no longer has an association with the port.
|
322
|
+
* The event can be processed without the possibility that
|
323
|
+
* another thread can retrieve a subsequent event for the
|
324
|
+
* same object. After processing of the file descriptor
|
325
|
+
* is completed, the port_associate() function can be
|
326
|
+
* called to reassociate the object with the port.
|
327
|
+
*
|
328
|
+
* If the descriptor is still capable of accepting data,
|
329
|
+
* this reassociation is required for the reactivation of
|
330
|
+
* the data detection.
|
331
|
+
*/
|
332
|
+
event_reassociate(evb, ev->portev_user);
|
333
|
+
}
|
334
|
+
}
|
335
|
+
|
336
|
+
return nreturned;
|
337
|
+
}
|
338
|
+
|
339
|
+
if (timeout == -1) {
|
340
|
+
log_error("port getn on evp %d with %d events and %d timeout "
|
341
|
+
"returned no events", evp, nevent, timeout);
|
342
|
+
return -1;
|
343
|
+
}
|
344
|
+
|
345
|
+
return 0;
|
346
|
+
}
|
347
|
+
|
348
|
+
NOT_REACHED();
|
349
|
+
}
|
350
|
+
|
351
|
+
void
|
352
|
+
event_loop_stats(event_stats_cb_t cb, void *arg)
|
353
|
+
{
|
354
|
+
struct stats *st = arg;
|
355
|
+
int status, evp;
|
356
|
+
port_event_t event;
|
357
|
+
struct timespec ts, *tsp;
|
358
|
+
|
359
|
+
evp = port_create();
|
360
|
+
if (evp < 0) {
|
361
|
+
log_error("port create failed: %s", strerror(errno));
|
362
|
+
return;
|
363
|
+
}
|
364
|
+
|
365
|
+
status = port_associate(evp, PORT_SOURCE_FD, st->sd, POLLIN, NULL);
|
366
|
+
if (status < 0) {
|
367
|
+
log_error("port associate on evp %d sd %d failed: %s", evp, st->sd,
|
368
|
+
strerror(errno));
|
369
|
+
goto error;
|
370
|
+
}
|
371
|
+
|
372
|
+
/* port_getn should block indefinitely if st->interval < 0 */
|
373
|
+
if (st->interval < 0) {
|
374
|
+
tsp = NULL;
|
375
|
+
} else {
|
376
|
+
tsp = &ts;
|
377
|
+
tsp->tv_sec = st->interval / 1000LL;
|
378
|
+
tsp->tv_nsec = (st->interval % 1000LL) * 1000000LL;
|
379
|
+
}
|
380
|
+
|
381
|
+
|
382
|
+
for (;;) {
|
383
|
+
unsigned int nreturned = 1;
|
384
|
+
|
385
|
+
status = port_getn(evp, &event, 1, &nreturned, tsp);
|
386
|
+
if (status != NC_OK) {
|
387
|
+
if (errno == EINTR || errno == EAGAIN) {
|
388
|
+
continue;
|
389
|
+
}
|
390
|
+
|
391
|
+
if (errno != ETIME) {
|
392
|
+
log_error("port getn on evp %d with m %d failed: %s", evp,
|
393
|
+
st->sd, strerror(errno));
|
394
|
+
goto error;
|
395
|
+
}
|
396
|
+
}
|
397
|
+
|
398
|
+
ASSERT(nreturned <= 1);
|
399
|
+
|
400
|
+
if (nreturned == 1) {
|
401
|
+
/* re-associate monitoring descriptor with the port */
|
402
|
+
status = port_associate(evp, PORT_SOURCE_FD, st->sd, POLLIN, NULL);
|
403
|
+
if (status < 0) {
|
404
|
+
log_error("port associate on evp %d sd %d failed: %s", evp, st->sd,
|
405
|
+
strerror(errno));
|
406
|
+
}
|
407
|
+
}
|
408
|
+
|
409
|
+
cb(st, &nreturned);
|
410
|
+
}
|
411
|
+
|
412
|
+
error:
|
413
|
+
status = close(evp);
|
414
|
+
if (status < 0) {
|
415
|
+
log_error("close evp %d failed, ignored: %s", evp, strerror(errno));
|
416
|
+
}
|
417
|
+
evp = -1;
|
418
|
+
}
|
419
|
+
|
420
|
+
#endif /* NC_HAVE_EVENT_PORTS */
|