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.
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 */