nutcracker 0.2.4.12 → 0.3.0.12

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +8 -8
  2. data/Rakefile +1 -1
  3. data/ext/nutcracker/ChangeLog +10 -0
  4. data/ext/nutcracker/Makefile.am +2 -0
  5. data/ext/nutcracker/Makefile.in +101 -14
  6. data/ext/nutcracker/README.md +18 -1
  7. data/ext/nutcracker/config.h.in +18 -0
  8. data/ext/nutcracker/configure +196 -25
  9. data/ext/nutcracker/configure.ac +64 -6
  10. data/ext/nutcracker/extconf.rb +1 -1
  11. data/ext/nutcracker/man/nutcracker.8 +76 -0
  12. data/ext/nutcracker/notes/debug.txt +116 -16
  13. data/ext/nutcracker/notes/kqueue.pdf +0 -0
  14. data/ext/nutcracker/notes/recommendation.md +20 -0
  15. data/ext/nutcracker/notes/redis.md +2 -2
  16. data/ext/nutcracker/scripts/nutcracker.spec +1 -1
  17. data/ext/nutcracker/scripts/redis-check.sh +3 -1
  18. data/ext/nutcracker/src/Makefile.am +15 -6
  19. data/ext/nutcracker/src/Makefile.in +39 -36
  20. data/ext/nutcracker/src/event/Makefile.am +16 -0
  21. data/ext/nutcracker/src/event/Makefile.in +492 -0
  22. data/ext/nutcracker/src/event/nc_epoll.c +344 -0
  23. data/ext/nutcracker/src/event/nc_event.h +88 -0
  24. data/ext/nutcracker/src/event/nc_evport.c +420 -0
  25. data/ext/nutcracker/src/event/nc_kqueue.c +412 -0
  26. data/ext/nutcracker/src/hashkit/nc_crc32.c +19 -1
  27. data/ext/nutcracker/src/hashkit/nc_hashkit.h +3 -1
  28. data/ext/nutcracker/src/hashkit/nc_md5.c +257 -315
  29. data/ext/nutcracker/src/nc.c +12 -1
  30. data/ext/nutcracker/src/nc_connection.c +18 -1
  31. data/ext/nutcracker/src/nc_connection.h +1 -0
  32. data/ext/nutcracker/src/nc_core.c +22 -30
  33. data/ext/nutcracker/src/nc_core.h +22 -7
  34. data/ext/nutcracker/src/nc_proxy.c +8 -9
  35. data/ext/nutcracker/src/nc_queue.h +2 -0
  36. data/ext/nutcracker/src/nc_request.c +3 -4
  37. data/ext/nutcracker/src/nc_response.c +25 -8
  38. data/ext/nutcracker/src/nc_server.c +8 -6
  39. data/ext/nutcracker/src/nc_stats.c +46 -43
  40. data/ext/nutcracker/src/nc_stats.h +37 -30
  41. data/ext/nutcracker/src/nc_util.c +6 -1
  42. data/ext/nutcracker/src/proto/nc_redis.c +19 -5
  43. data/lib/nutcracker/version.rb +1 -1
  44. data/lib/nutcracker.rb +1 -1
  45. metadata +10 -4
  46. data/ext/nutcracker/src/nc_event.c +0 -214
  47. 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 */