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
@@ -88,6 +88,7 @@ struct conn {
88
88
 
89
89
  TAILQ_HEAD(conn_tqh, conn);
90
90
 
91
+ struct context *conn_to_ctx(struct conn *conn);
91
92
  struct conn *conn_get(void *owner, bool client, bool redis);
92
93
  struct conn *conn_get_proxy(void *owner);
93
94
  void conn_put(struct conn *conn);
@@ -17,11 +17,7 @@
17
17
 
18
18
  #include <stdlib.h>
19
19
  #include <unistd.h>
20
-
21
- #include <sys/epoll.h>
22
-
23
20
  #include <nc_core.h>
24
- #include <nc_event.h>
25
21
  #include <nc_conf.h>
26
22
  #include <nc_server.h>
27
23
  #include <nc_proxy.h>
@@ -41,12 +37,10 @@ core_ctx_create(struct instance *nci)
41
37
  ctx->id = ++ctx_id;
42
38
  ctx->cf = NULL;
43
39
  ctx->stats = NULL;
40
+ ctx->evb = NULL;
44
41
  array_null(&ctx->pool);
45
- ctx->ep = -1;
46
- ctx->nevent = EVENT_SIZE_HINT;
47
42
  ctx->max_timeout = nci->stats_interval;
48
43
  ctx->timeout = ctx->max_timeout;
49
- ctx->event = NULL;
50
44
 
51
45
  /* parse and create configuration */
52
46
  ctx->cf = conf_create(nci->conf_filename);
@@ -74,8 +68,8 @@ core_ctx_create(struct instance *nci)
74
68
  }
75
69
 
76
70
  /* initialize event handling for client, proxy and server */
77
- status = event_init(ctx, EVENT_SIZE_HINT);
78
- if (status != NC_OK) {
71
+ ctx->evb = event_base_create(EVENT_SIZE, &core_core);
72
+ if (ctx->evb == NULL) {
79
73
  stats_destroy(ctx->stats);
80
74
  server_pool_deinit(&ctx->pool);
81
75
  conf_destroy(ctx->cf);
@@ -87,7 +81,7 @@ core_ctx_create(struct instance *nci)
87
81
  status = server_pool_preconnect(ctx);
88
82
  if (status != NC_OK) {
89
83
  server_pool_disconnect(ctx);
90
- event_deinit(ctx);
84
+ event_base_destroy(ctx->evb);
91
85
  stats_destroy(ctx->stats);
92
86
  server_pool_deinit(&ctx->pool);
93
87
  conf_destroy(ctx->cf);
@@ -99,7 +93,7 @@ core_ctx_create(struct instance *nci)
99
93
  status = proxy_init(ctx);
100
94
  if (status != NC_OK) {
101
95
  server_pool_disconnect(ctx);
102
- event_deinit(ctx);
96
+ event_base_destroy(ctx->evb);
103
97
  stats_destroy(ctx->stats);
104
98
  server_pool_deinit(&ctx->pool);
105
99
  conf_destroy(ctx->cf);
@@ -118,7 +112,7 @@ core_ctx_destroy(struct context *ctx)
118
112
  log_debug(LOG_VVERB, "destroy ctx %p id %"PRIu32"", ctx, ctx->id);
119
113
  proxy_deinit(ctx);
120
114
  server_pool_disconnect(ctx);
121
- event_deinit(ctx);
115
+ event_base_destroy(ctx->evb);
122
116
  stats_destroy(ctx->stats);
123
117
  server_pool_deinit(&ctx->pool);
124
118
  conf_destroy(ctx->cf);
@@ -206,9 +200,9 @@ core_close(struct context *ctx, struct conn *conn)
206
200
  conn->eof, conn->done, conn->recv_bytes, conn->send_bytes,
207
201
  conn->err ? ':' : ' ', conn->err ? strerror(conn->err) : "");
208
202
 
209
- status = event_del_conn(ctx->ep, conn);
203
+ status = event_del_conn(ctx->evb, conn);
210
204
  if (status < 0) {
211
- log_warn("event del conn e %d %c %d failed, ignored: %s", ctx->ep,
205
+ log_warn("event del conn %c %d failed, ignored: %s",
212
206
  type, conn->sd, strerror(errno));
213
207
  }
214
208
 
@@ -276,10 +270,12 @@ core_timeout(struct context *ctx)
276
270
  }
277
271
  }
278
272
 
279
- static void
280
- core_core(struct context *ctx, struct conn *conn, uint32_t events)
273
+ rstatus_t
274
+ core_core(void *arg, uint32_t events)
281
275
  {
282
276
  rstatus_t status;
277
+ struct conn *conn = arg;
278
+ struct context *ctx = conn_to_ctx(conn);
283
279
 
284
280
  log_debug(LOG_VVERB, "event %04"PRIX32" on %c %d", events,
285
281
  conn->client ? 'c' : (conn->proxy ? 'p' : 's'), conn->sd);
@@ -287,45 +283,41 @@ core_core(struct context *ctx, struct conn *conn, uint32_t events)
287
283
  conn->events = events;
288
284
 
289
285
  /* error takes precedence over read | write */
290
- if (events & EPOLLERR) {
286
+ if (events & EVENT_ERR) {
291
287
  core_error(ctx, conn);
292
- return;
288
+ return NC_ERROR;
293
289
  }
294
290
 
295
291
  /* read takes precedence over write */
296
- if (events & (EPOLLIN | EPOLLHUP)) {
292
+ if (events & EVENT_READ) {
297
293
  status = core_recv(ctx, conn);
298
294
  if (status != NC_OK || conn->done || conn->err) {
299
295
  core_close(ctx, conn);
300
- return;
296
+ return NC_ERROR;
301
297
  }
302
298
  }
303
299
 
304
- if (events & EPOLLOUT) {
300
+ if (events & EVENT_WRITE) {
305
301
  status = core_send(ctx, conn);
306
302
  if (status != NC_OK || conn->done || conn->err) {
307
303
  core_close(ctx, conn);
308
- return;
304
+ return NC_ERROR;
309
305
  }
310
306
  }
307
+
308
+ return NC_OK;
311
309
  }
312
310
 
313
311
  rstatus_t
314
312
  core_loop(struct context *ctx)
315
313
  {
316
- int i, nsd;
314
+ int nsd;
317
315
 
318
- nsd = event_wait(ctx->ep, ctx->event, ctx->nevent, ctx->timeout);
316
+ nsd = event_wait(ctx->evb, ctx->timeout);
319
317
  if (nsd < 0) {
320
318
  return nsd;
321
319
  }
322
320
 
323
- for (i = 0; i < nsd; i++) {
324
- struct epoll_event *ev = &ctx->event[i];
325
-
326
- core_core(ctx, ev->data.ptr, ev->events);
327
- }
328
-
329
321
  core_timeout(ctx);
330
322
 
331
323
  stats_swap(ctx->stats);
@@ -40,10 +40,24 @@
40
40
  # define NC_STATS 0
41
41
  #endif
42
42
 
43
+ #ifdef HAVE_EPOLL
44
+ # define NC_HAVE_EPOLL 1
45
+ #elif HAVE_KQUEUE
46
+ # define NC_HAVE_KQUEUE 1
47
+ #elif HAVE_EVENT_PORTS
48
+ # define NC_HAVE_EVENT_PORTS 1
49
+ #else
50
+ # error missing scalable I/O event notification mechanism
51
+ #endif
52
+
43
53
  #ifdef HAVE_LITTLE_ENDIAN
44
54
  # define NC_LITTLE_ENDIAN 1
45
55
  #endif
46
56
 
57
+ #ifdef HAVE_BACKTRACE
58
+ # define NC_HAVE_BACKTRACE 1
59
+ #endif
60
+
47
61
  #define NC_OK 0
48
62
  #define NC_ERROR -1
49
63
  #define NC_EAGAIN -2
@@ -65,8 +79,8 @@ struct mbuf;
65
79
  struct mhdr;
66
80
  struct conf;
67
81
  struct stats;
68
- struct epoll_event;
69
82
  struct instance;
83
+ struct event_base;
70
84
 
71
85
  #include <stddef.h>
72
86
  #include <stdint.h>
@@ -82,6 +96,7 @@ struct instance;
82
96
  #include <sys/types.h>
83
97
  #include <sys/socket.h>
84
98
  #include <sys/un.h>
99
+ #include <sys/time.h>
85
100
  #include <netinet/in.h>
86
101
 
87
102
  #include <nc_array.h>
@@ -90,6 +105,7 @@ struct instance;
90
105
  #include <nc_rbtree.h>
91
106
  #include <nc_log.h>
92
107
  #include <nc_util.h>
108
+ #include <event/nc_event.h>
93
109
  #include <nc_stats.h>
94
110
  #include <nc_mbuf.h>
95
111
  #include <nc_message.h>
@@ -101,14 +117,12 @@ struct context {
101
117
  struct stats *stats; /* stats */
102
118
 
103
119
  struct array pool; /* server_pool[] */
104
-
105
- int ep; /* epoll device */
106
- int nevent; /* # epoll event */
107
- int max_timeout; /* epoll wait max timeout in msec */
108
- int timeout; /* epoll wait timeout in msec */
109
- struct epoll_event *event; /* epoll event */
120
+ struct event_base *evb; /* event base */
121
+ int max_timeout; /* max timeout in msec */
122
+ int timeout; /* timeout in msec */
110
123
  };
111
124
 
125
+
112
126
  struct instance {
113
127
  struct context *ctx; /* active context */
114
128
  int log_level; /* log level */
@@ -126,6 +140,7 @@ struct instance {
126
140
 
127
141
  struct context *core_start(struct instance *nci);
128
142
  void core_stop(struct context *ctx);
143
+ rstatus_t core_core(void *arg, uint32_t events);
129
144
  rstatus_t core_loop(struct context *ctx);
130
145
 
131
146
  #endif
@@ -19,7 +19,6 @@
19
19
 
20
20
  #include <nc_core.h>
21
21
  #include <nc_server.h>
22
- #include <nc_event.h>
23
22
  #include <nc_proxy.h>
24
23
 
25
24
  void
@@ -163,18 +162,18 @@ proxy_listen(struct context *ctx, struct conn *p)
163
162
  return NC_ERROR;
164
163
  }
165
164
 
166
- status = event_add_conn(ctx->ep, p);
165
+ status = event_add_conn(ctx->evb, p);
167
166
  if (status < 0) {
168
- log_error("event add conn e %d p %d on addr '%.*s' failed: %s",
169
- ctx->ep, p->sd, pool->addrstr.len, pool->addrstr.data,
167
+ log_error("event add conn p %d on addr '%.*s' failed: %s",
168
+ p->sd, pool->addrstr.len, pool->addrstr.data,
170
169
  strerror(errno));
171
170
  return NC_ERROR;
172
171
  }
173
172
 
174
- status = event_del_out(ctx->ep, p);
173
+ status = event_del_out(ctx->evb, p);
175
174
  if (status < 0) {
176
- log_error("event del out e %d p %d on addr '%.*s' failed: %s",
177
- ctx->ep, p->sd, pool->addrstr.len, pool->addrstr.data,
175
+ log_error("event del out p %d on addr '%.*s' failed: %s",
176
+ p->sd, pool->addrstr.len, pool->addrstr.data,
178
177
  strerror(errno));
179
178
  return NC_ERROR;
180
179
  }
@@ -325,9 +324,9 @@ proxy_accept(struct context *ctx, struct conn *p)
325
324
  }
326
325
  }
327
326
 
328
- status = event_add_conn(ctx->ep, c);
327
+ status = event_add_conn(ctx->evb, c);
329
328
  if (status < 0) {
330
- log_error("event add conn of c %d from p %d failed: %s", c->sd, p->sd,
329
+ log_error("event add conn from p %d failed: %s", p->sd,
331
330
  strerror(errno));
332
331
  c->close(ctx, c);
333
332
  return status;
@@ -52,7 +52,9 @@
52
52
 
53
53
  #include <nc_log.h>
54
54
 
55
+ #ifndef __offsetof
55
56
  #define __offsetof(type, field) ((size_t)(&((type *)NULL)->field))
57
+ #endif
56
58
 
57
59
  /*
58
60
  * This file defines five types of data structures: singly-linked lists,
@@ -17,7 +17,6 @@
17
17
 
18
18
  #include <nc_core.h>
19
19
  #include <nc_server.h>
20
- #include <nc_event.h>
21
20
 
22
21
  struct msg *
23
22
  req_get(struct conn *conn)
@@ -413,7 +412,7 @@ req_forward_error(struct context *ctx, struct conn *conn, struct msg *msg)
413
412
  }
414
413
 
415
414
  if (req_done(conn, TAILQ_FIRST(&conn->omsg_q))) {
416
- status = event_add_out(ctx->ep, conn);
415
+ status = event_add_out(ctx->evb, conn);
417
416
  if (status != NC_OK) {
418
417
  conn->err = errno;
419
418
  }
@@ -482,7 +481,7 @@ req_forward(struct context *ctx, struct conn *c_conn, struct msg *msg)
482
481
 
483
482
  /* enqueue the message (request) into server inq */
484
483
  if (TAILQ_EMPTY(&s_conn->imsg_q)) {
485
- status = event_add_out(ctx->ep, s_conn);
484
+ status = event_add_out(ctx->evb, s_conn);
486
485
  if (status != NC_OK) {
487
486
  req_forward_error(ctx, c_conn, msg);
488
487
  s_conn->err = errno;
@@ -533,7 +532,7 @@ req_send_next(struct context *ctx, struct conn *conn)
533
532
  nmsg = TAILQ_FIRST(&conn->imsg_q);
534
533
  if (nmsg == NULL) {
535
534
  /* nothing to send as the server inq is empty */
536
- status = event_del_out(ctx->ep, conn);
535
+ status = event_del_out(ctx->evb, conn);
537
536
  if (status != NC_OK) {
538
537
  conn->err = errno;
539
538
  }
@@ -17,7 +17,6 @@
17
17
 
18
18
  #include <nc_core.h>
19
19
  #include <nc_server.h>
20
- #include <nc_event.h>
21
20
 
22
21
  struct msg *
23
22
  rsp_get(struct conn *conn)
@@ -90,7 +89,6 @@ rsp_recv_next(struct context *ctx, struct conn *conn, bool alloc)
90
89
  struct msg *msg;
91
90
 
92
91
  ASSERT(!conn->client && !conn->proxy);
93
- ASSERT(!conn->connecting);
94
92
 
95
93
  if (conn->eof) {
96
94
  msg = conn->rmsg;
@@ -157,11 +155,30 @@ rsp_filter(struct context *ctx, struct conn *conn, struct msg *msg)
157
155
 
158
156
  pmsg = TAILQ_FIRST(&conn->omsg_q);
159
157
  if (pmsg == NULL) {
160
- log_error("filter stray rsp %"PRIu64" len %"PRIu32" on s %d", msg->id,
161
- msg->mlen, conn->sd);
158
+ log_debug(LOG_ERR, "filter stray rsp %"PRIu64" len %"PRIu32" on s %d",
159
+ msg->id, msg->mlen, conn->sd);
162
160
  rsp_put(msg);
163
- errno = EINVAL;
164
- conn->err = errno;
161
+
162
+ /*
163
+ * Memcached server can respond with an error response before it has
164
+ * received the entire request. This is most commonly seen for set
165
+ * requests that exceed item_size_max. IMO, this behavior of memcached
166
+ * is incorrect. The right behavior for update requests that are over
167
+ * item_size_max would be to either:
168
+ * - close the connection Or,
169
+ * - read the entire item_size_max data and then send CLIENT_ERROR
170
+ *
171
+ * We handle this stray packet scenario in nutcracker by closing the
172
+ * server connection which would end up sending SERVER_ERROR to all
173
+ * clients that have requests pending on this server connection. The
174
+ * fix is aggresive, but not doing so would lead to clients getting
175
+ * out of sync with the server and as a result clients end up getting
176
+ * responses that don't correspond to the right request.
177
+ *
178
+ * See: https://github.com/twitter/twemproxy/issues/149
179
+ */
180
+ conn->err = EINVAL;
181
+ conn->done = 1;
165
182
  return true;
166
183
  }
167
184
  ASSERT(pmsg->peer == NULL);
@@ -222,7 +239,7 @@ rsp_forward(struct context *ctx, struct conn *s_conn, struct msg *msg)
222
239
  ASSERT(c_conn->client && !c_conn->proxy);
223
240
 
224
241
  if (req_done(c_conn, TAILQ_FIRST(&c_conn->omsg_q))) {
225
- status = event_add_out(ctx->ep, c_conn);
242
+ status = event_add_out(ctx->evb, c_conn);
226
243
  if (status != NC_OK) {
227
244
  c_conn->err = errno;
228
245
  }
@@ -267,7 +284,7 @@ rsp_send_next(struct context *ctx, struct conn *conn)
267
284
  log_debug(LOG_INFO, "c %d is done", conn->sd);
268
285
  }
269
286
 
270
- status = event_del_out(ctx->ep, conn);
287
+ status = event_del_out(ctx->evb, conn);
271
288
  if (status != NC_OK) {
272
289
  conn->err = errno;
273
290
  }
@@ -19,7 +19,6 @@
19
19
  #include <unistd.h>
20
20
 
21
21
  #include <nc_core.h>
22
- #include <nc_event.h>
23
22
  #include <nc_server.h>
24
23
  #include <nc_conf.h>
25
24
 
@@ -273,6 +272,9 @@ server_failure(struct context *ctx, struct server *server)
273
272
  if (now < 0) {
274
273
  return;
275
274
  }
275
+
276
+ stats_server_set_ts(ctx, server, server_ejected_at, now);
277
+
276
278
  next = now + pool->server_retry_timeout;
277
279
 
278
280
  log_debug(LOG_INFO, "update pool %"PRIu32" '%.*s' to delete server '%.*s' "
@@ -367,7 +369,7 @@ server_close(struct context *ctx, struct conn *conn)
367
369
  msg->err = conn->err;
368
370
 
369
371
  if (req_done(c_conn, TAILQ_FIRST(&c_conn->omsg_q))) {
370
- event_add_out(ctx->ep, msg->owner);
372
+ event_add_out(ctx->evb, msg->owner);
371
373
  }
372
374
 
373
375
  log_debug(LOG_INFO, "close s %d schedule error for req %"PRIu64" "
@@ -397,7 +399,7 @@ server_close(struct context *ctx, struct conn *conn)
397
399
  msg->err = conn->err;
398
400
 
399
401
  if (req_done(c_conn, TAILQ_FIRST(&c_conn->omsg_q))) {
400
- event_add_out(ctx->ep, msg->owner);
402
+ event_add_out(ctx->evb, msg->owner);
401
403
  }
402
404
 
403
405
  log_debug(LOG_INFO, "close s %d schedule error for req %"PRIu64" "
@@ -476,10 +478,10 @@ server_connect(struct context *ctx, struct server *server, struct conn *conn)
476
478
  }
477
479
  }
478
480
 
479
- status = event_add_conn(ctx->ep, conn);
481
+ status = event_add_conn(ctx->evb, conn);
480
482
  if (status != NC_OK) {
481
- log_error("event add conn e %d s %d for server '%.*s' failed: %s",
482
- ctx->ep, conn->sd, server->pname.len, server->pname.data,
483
+ log_error("event add conn s %d for server '%.*s' failed: %s",
484
+ conn->sd, server->pname.len, server->pname.data,
483
485
  strerror(errno));
484
486
  goto error;
485
487
  }
@@ -21,7 +21,6 @@
21
21
 
22
22
  #include <sys/types.h>
23
23
  #include <sys/socket.h>
24
- #include <sys/epoll.h>
25
24
  #include <netinet/in.h>
26
25
 
27
26
  #include <nc_core.h>
@@ -770,34 +769,27 @@ stats_send_rsp(struct stats *st)
770
769
  return NC_OK;
771
770
  }
772
771
 
773
- static void *
774
- stats_loop(void *arg)
772
+ static void
773
+ stats_loop_callback(void *arg1, void *arg2)
775
774
  {
776
- struct stats *st = arg;
777
- int n;
775
+ struct stats *st = arg1;
776
+ int n = *((int *)arg2);
778
777
 
779
- for (;;) {
780
- n = epoll_wait(st->ep, &st->event, 1, st->interval);
781
- if (n < 0) {
782
- if (errno == EINTR) {
783
- continue;
784
- }
785
- log_error("epoll wait on e %d with event m %d failed: %s",
786
- st->ep, st->sd, strerror(errno));
787
- break;
788
- }
789
-
790
- /* aggregate stats from shadow (b) -> sum (c) */
791
- stats_aggregate(st);
778
+ /* aggregate stats from shadow (b) -> sum (c) */
779
+ stats_aggregate(st);
792
780
 
793
- if (n == 0) {
794
- continue;
795
- }
796
-
797
- /* send aggregate stats sum (c) to collector */
798
- stats_send_rsp(st);
781
+ if (n == 0) {
782
+ return;
799
783
  }
800
784
 
785
+ /* send aggregate stats sum (c) to collector */
786
+ stats_send_rsp(st);
787
+ }
788
+
789
+ static void *
790
+ stats_loop(void *arg)
791
+ {
792
+ event_loop_stats(stats_loop_callback, arg);
801
793
  return NULL;
802
794
  }
803
795
 
@@ -847,7 +839,6 @@ static rstatus_t
847
839
  stats_start_aggregator(struct stats *st)
848
840
  {
849
841
  rstatus_t status;
850
- struct epoll_event ev;
851
842
 
852
843
  if (!stats_enabled) {
853
844
  return NC_OK;
@@ -858,22 +849,6 @@ stats_start_aggregator(struct stats *st)
858
849
  return status;
859
850
  }
860
851
 
861
- st->ep = epoll_create(10);
862
- if (st->ep < 0) {
863
- log_error("epoll create failed: %s", strerror(errno));
864
- return NC_ERROR;
865
- }
866
-
867
- ev.data.fd = st->sd;
868
- ev.events = EPOLLIN;
869
-
870
- status = epoll_ctl(st->ep, EPOLL_CTL_ADD, st->sd, &ev);
871
- if (status < 0) {
872
- log_error("epoll ctl on e %d sd %d failed: %s", st->ep, st->sd,
873
- strerror(errno));
874
- return NC_ERROR;
875
- }
876
-
877
852
  status = pthread_create(&st->tid, NULL, stats_loop, st);
878
853
  if (status < 0) {
879
854
  log_error("stats aggregator create failed: %s", strerror(status));
@@ -891,7 +866,6 @@ stats_stop_aggregator(struct stats *st)
891
866
  }
892
867
 
893
868
  close(st->sd);
894
- close(st->ep);
895
869
  }
896
870
 
897
871
  struct stats *
@@ -921,7 +895,6 @@ stats_create(uint16_t stats_port, char *stats_ip, int stats_interval,
921
895
  array_null(&st->sum);
922
896
 
923
897
  st->tid = (pthread_t) -1;
924
- st->ep = -1;
925
898
  st->sd = -1;
926
899
 
927
900
  string_set_text(&st->service_str, "service");
@@ -1101,6 +1074,21 @@ _stats_pool_decr_by(struct context *ctx, struct server_pool *pool,
1101
1074
  stm->name.data, stm->value.counter);
1102
1075
  }
1103
1076
 
1077
+ void
1078
+ _stats_pool_set_ts(struct context *ctx, struct server_pool *pool,
1079
+ stats_pool_field_t fidx, int64_t val)
1080
+ {
1081
+ struct stats_metric *stm;
1082
+
1083
+ stm = stats_pool_to_metric(ctx, pool, fidx);
1084
+
1085
+ ASSERT(stm->type == STATS_TIMESTAMP);
1086
+ stm->value.timestamp = val;
1087
+
1088
+ log_debug(LOG_VVVERB, "set ts field '%.*s' to %"PRId64"", stm->name.len,
1089
+ stm->name.data, stm->value.timestamp);
1090
+ }
1091
+
1104
1092
  static struct stats_metric *
1105
1093
  stats_server_to_metric(struct context *ctx, struct server *server,
1106
1094
  stats_server_field_t fidx)
@@ -1186,3 +1174,18 @@ _stats_server_decr_by(struct context *ctx, struct server *server,
1186
1174
  log_debug(LOG_VVVERB, "decr by field '%.*s' to %"PRId64"", stm->name.len,
1187
1175
  stm->name.data, stm->value.counter);
1188
1176
  }
1177
+
1178
+ void
1179
+ _stats_server_set_ts(struct context *ctx, struct server *server,
1180
+ stats_server_field_t fidx, int64_t val)
1181
+ {
1182
+ struct stats_metric *stm;
1183
+
1184
+ stm = stats_server_to_metric(ctx, server, fidx);
1185
+
1186
+ ASSERT(stm->type == STATS_TIMESTAMP);
1187
+ stm->value.timestamp = val;
1188
+
1189
+ log_debug(LOG_VVVERB, "set ts field '%.*s' to %"PRId64"", stm->name.len,
1190
+ stm->name.data, stm->value.timestamp);
1191
+ }