nutcracker 0.4.0.16 → 0.4.1.18

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 (121) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +3 -3
  3. data/ext/nutcracker/ChangeLog +33 -8
  4. data/ext/nutcracker/Makefile.in +34 -21
  5. data/ext/nutcracker/README.md +61 -26
  6. data/ext/nutcracker/aclocal.m4 +34 -31
  7. data/ext/nutcracker/autom4te.cache/output.0 +1875 -1330
  8. data/ext/nutcracker/autom4te.cache/output.1 +1875 -1330
  9. data/ext/nutcracker/autom4te.cache/requests +232 -451
  10. data/ext/nutcracker/autom4te.cache/traces.0 +2256 -2129
  11. data/ext/nutcracker/autom4te.cache/traces.1 +73 -59
  12. data/ext/nutcracker/config.h.in +1 -2
  13. data/ext/nutcracker/config.h.in~ +333 -0
  14. data/ext/nutcracker/config/compile +1 -1
  15. data/ext/nutcracker/config/config.guess +13 -160
  16. data/ext/nutcracker/config/config.sub +25 -11
  17. data/ext/nutcracker/config/depcomp +1 -1
  18. data/ext/nutcracker/config/install-sh +170 -196
  19. data/ext/nutcracker/config/ltmain.sh +3509 -2018
  20. data/ext/nutcracker/config/missing +1 -1
  21. data/ext/nutcracker/configure +1874 -1329
  22. data/ext/nutcracker/configure.ac +3 -2
  23. data/ext/nutcracker/contrib/Makefile.in +18 -5
  24. data/ext/nutcracker/contrib/yaml-0.1.4/LICENSE +19 -0
  25. data/ext/nutcracker/contrib/yaml-0.1.4/Makefile.am +20 -0
  26. data/ext/nutcracker/contrib/yaml-0.1.4/Makefile.in +832 -0
  27. data/ext/nutcracker/contrib/yaml-0.1.4/README +27 -0
  28. data/ext/nutcracker/contrib/yaml-0.1.4/aclocal.m4 +1157 -0
  29. data/ext/nutcracker/contrib/yaml-0.1.4/autom4te.cache/output.0 +13342 -0
  30. data/ext/nutcracker/contrib/yaml-0.1.4/autom4te.cache/output.1 +14611 -0
  31. data/ext/nutcracker/{autom4te.cache → contrib/yaml-0.1.4/autom4te.cache}/output.2 +3465 -8761
  32. data/ext/nutcracker/contrib/yaml-0.1.4/autom4te.cache/requests +516 -0
  33. data/ext/nutcracker/{autom4te.cache/traces.2 → contrib/yaml-0.1.4/autom4te.cache/traces.0} +662 -698
  34. data/ext/nutcracker/contrib/yaml-0.1.4/autom4te.cache/traces.1 +577 -0
  35. data/ext/nutcracker/contrib/yaml-0.1.4/autom4te.cache/traces.2 +2721 -0
  36. data/ext/nutcracker/contrib/yaml-0.1.4/config.h.in +79 -0
  37. data/ext/nutcracker/contrib/yaml-0.1.4/config.h.in~ +80 -0
  38. data/ext/nutcracker/contrib/yaml-0.1.4/config/compile +347 -0
  39. data/ext/nutcracker/contrib/yaml-0.1.4/config/config.guess +1421 -0
  40. data/ext/nutcracker/contrib/yaml-0.1.4/config/config.sub +1807 -0
  41. data/ext/nutcracker/contrib/yaml-0.1.4/config/depcomp +791 -0
  42. data/ext/nutcracker/contrib/yaml-0.1.4/config/install-sh +501 -0
  43. data/ext/nutcracker/contrib/yaml-0.1.4/config/ltmain.sh +11147 -0
  44. data/ext/nutcracker/contrib/yaml-0.1.4/config/missing +215 -0
  45. data/ext/nutcracker/contrib/yaml-0.1.4/config/test-driver +148 -0
  46. data/ext/nutcracker/contrib/yaml-0.1.4/configure +14611 -0
  47. data/ext/nutcracker/contrib/yaml-0.1.4/configure.ac +75 -0
  48. data/ext/nutcracker/contrib/yaml-0.1.4/doc/doxygen.cfg +222 -0
  49. data/ext/nutcracker/contrib/yaml-0.1.4/include/yaml.h +1971 -0
  50. data/ext/nutcracker/contrib/yaml-0.1.4/m4/libtool.m4 +8369 -0
  51. data/ext/nutcracker/contrib/yaml-0.1.4/m4/ltoptions.m4 +437 -0
  52. data/ext/nutcracker/contrib/yaml-0.1.4/m4/ltsugar.m4 +124 -0
  53. data/ext/nutcracker/contrib/yaml-0.1.4/m4/ltversion.m4 +23 -0
  54. data/ext/nutcracker/contrib/yaml-0.1.4/m4/lt~obsolete.m4 +99 -0
  55. data/ext/nutcracker/contrib/yaml-0.1.4/src/Makefile.am +4 -0
  56. data/ext/nutcracker/contrib/yaml-0.1.4/src/Makefile.in +600 -0
  57. data/ext/nutcracker/contrib/yaml-0.1.4/src/api.c +1392 -0
  58. data/ext/nutcracker/contrib/yaml-0.1.4/src/dumper.c +394 -0
  59. data/ext/nutcracker/contrib/yaml-0.1.4/src/emitter.c +2329 -0
  60. data/ext/nutcracker/contrib/yaml-0.1.4/src/loader.c +432 -0
  61. data/ext/nutcracker/contrib/yaml-0.1.4/src/parser.c +1374 -0
  62. data/ext/nutcracker/contrib/yaml-0.1.4/src/reader.c +465 -0
  63. data/ext/nutcracker/contrib/yaml-0.1.4/src/scanner.c +3570 -0
  64. data/ext/nutcracker/contrib/yaml-0.1.4/src/writer.c +141 -0
  65. data/ext/nutcracker/contrib/yaml-0.1.4/src/yaml_private.h +640 -0
  66. data/ext/nutcracker/contrib/yaml-0.1.4/tests/Makefile.am +8 -0
  67. data/ext/nutcracker/contrib/yaml-0.1.4/tests/Makefile.in +1083 -0
  68. data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-deconstructor-alt.c +800 -0
  69. data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-deconstructor.c +1130 -0
  70. data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-reformatter-alt.c +217 -0
  71. data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-reformatter.c +202 -0
  72. data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-dumper.c +311 -0
  73. data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-emitter.c +327 -0
  74. data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-loader.c +63 -0
  75. data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-parser.c +63 -0
  76. data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-scanner.c +63 -0
  77. data/ext/nutcracker/contrib/yaml-0.1.4/tests/test-reader.c +354 -0
  78. data/ext/nutcracker/contrib/yaml-0.1.4/tests/test-version.c +29 -0
  79. data/ext/nutcracker/m4/libtool.m4 +1474 -1087
  80. data/ext/nutcracker/m4/ltoptions.m4 +90 -37
  81. data/ext/nutcracker/m4/ltsugar.m4 +4 -3
  82. data/ext/nutcracker/m4/ltversion.m4 +6 -6
  83. data/ext/nutcracker/m4/lt~obsolete.m4 +4 -3
  84. data/ext/nutcracker/man/nutcracker.8 +1 -1
  85. data/ext/nutcracker/notes/memcache.md +162 -0
  86. data/ext/nutcracker/notes/recommendation.md +10 -5
  87. data/ext/nutcracker/notes/redis.md +23 -9
  88. data/ext/nutcracker/scripts/nutcracker.init +10 -0
  89. data/ext/nutcracker/scripts/nutcracker.init.debian +83 -0
  90. data/ext/nutcracker/scripts/nutcracker.spec +36 -2
  91. data/ext/nutcracker/scripts/redis-check.sh +4 -0
  92. data/ext/nutcracker/src/Makefile.am +6 -1
  93. data/ext/nutcracker/src/Makefile.in +26 -12
  94. data/ext/nutcracker/src/event/Makefile.in +19 -6
  95. data/ext/nutcracker/src/hashkit/Makefile.in +19 -6
  96. data/ext/nutcracker/src/hashkit/nc_jenkins.c +1 -1
  97. data/ext/nutcracker/src/hashkit/nc_ketama.c +3 -3
  98. data/ext/nutcracker/src/nc.c +1 -1
  99. data/ext/nutcracker/src/nc_conf.c +67 -19
  100. data/ext/nutcracker/src/nc_conf.h +9 -4
  101. data/ext/nutcracker/src/nc_connection.c +35 -2
  102. data/ext/nutcracker/src/nc_connection.h +53 -47
  103. data/ext/nutcracker/src/nc_core.c +8 -1
  104. data/ext/nutcracker/src/nc_message.c +23 -7
  105. data/ext/nutcracker/src/nc_message.h +24 -1
  106. data/ext/nutcracker/src/nc_proxy.c +14 -3
  107. data/ext/nutcracker/src/nc_rbtree.c +1 -5
  108. data/ext/nutcracker/src/nc_request.c +58 -10
  109. data/ext/nutcracker/src/nc_response.c +27 -4
  110. data/ext/nutcracker/src/nc_server.c +33 -5
  111. data/ext/nutcracker/src/nc_server.h +10 -9
  112. data/ext/nutcracker/src/nc_string.h +17 -0
  113. data/ext/nutcracker/src/nc_util.c +5 -1
  114. data/ext/nutcracker/src/proto/Makefile.in +19 -6
  115. data/ext/nutcracker/src/proto/nc_memcache.c +76 -12
  116. data/ext/nutcracker/src/proto/nc_proto.h +9 -0
  117. data/ext/nutcracker/src/proto/nc_redis.c +400 -18
  118. data/lib/nutcracker.rb +1 -1
  119. data/lib/nutcracker/version.rb +1 -1
  120. metadata +61 -6
  121. data/ext/nutcracker/notes/memcache.txt +0 -123
@@ -311,7 +311,14 @@ core_core(void *arg, uint32_t events)
311
311
  {
312
312
  rstatus_t status;
313
313
  struct conn *conn = arg;
314
- struct context *ctx = conn_to_ctx(conn);
314
+ struct context *ctx;
315
+
316
+ if (conn->owner == NULL) {
317
+ log_warn("conn is already unrefed!");
318
+ return NC_OK;
319
+ }
320
+
321
+ ctx = conn_to_ctx(conn);
315
322
 
316
323
  log_debug(LOG_VVERB, "event %04"PRIX32" on %c %d", events,
317
324
  conn->client ? 'c' : (conn->proxy ? 'p' : 's'), conn->sd);
@@ -226,6 +226,7 @@ done:
226
226
  msg->token = NULL;
227
227
 
228
228
  msg->parser = NULL;
229
+ msg->add_auth = NULL;
229
230
  msg->result = MSG_PARSE_OK;
230
231
 
231
232
  msg->fragment = NULL;
@@ -292,8 +293,10 @@ msg_get(struct conn *conn, bool request, bool redis)
292
293
  } else {
293
294
  msg->parser = redis_parse_rsp;
294
295
  }
296
+ msg->add_auth = redis_add_auth;
295
297
  msg->fragment = redis_fragment;
296
298
  msg->reply = redis_reply;
299
+ msg->failure = redis_failure;
297
300
  msg->pre_coalesce = redis_pre_coalesce;
298
301
  msg->post_coalesce = redis_post_coalesce;
299
302
  } else {
@@ -302,7 +305,9 @@ msg_get(struct conn *conn, bool request, bool redis)
302
305
  } else {
303
306
  msg->parser = memcache_parse_rsp;
304
307
  }
308
+ msg->add_auth = memcache_add_auth;
305
309
  msg->fragment = memcache_fragment;
310
+ msg->failure = memcache_failure;
306
311
  msg->pre_coalesce = memcache_pre_coalesce;
307
312
  msg->post_coalesce = memcache_post_coalesce;
308
313
  }
@@ -472,11 +477,13 @@ msg_ensure_mbuf(struct msg *msg, size_t len)
472
477
  } else {
473
478
  mbuf = STAILQ_LAST(&msg->mhdr, mbuf, next);
474
479
  }
480
+
475
481
  return mbuf;
476
482
  }
477
483
 
478
484
  /*
479
- * append small(small than a mbuf) content into msg
485
+ * Append n bytes of data, with n <= mbuf_size(mbuf)
486
+ * into mbuf
480
487
  */
481
488
  rstatus_t
482
489
  msg_append(struct msg *msg, uint8_t *pos, size_t n)
@@ -494,11 +501,13 @@ msg_append(struct msg *msg, uint8_t *pos, size_t n)
494
501
 
495
502
  mbuf_copy(mbuf, pos, n);
496
503
  msg->mlen += (uint32_t)n;
504
+
497
505
  return NC_OK;
498
506
  }
499
507
 
500
508
  /*
501
- * prepend small(small than a mbuf) content into msg
509
+ * Prepend n bytes of data, with n <= mbuf_size(mbuf)
510
+ * into mbuf
502
511
  */
503
512
  rstatus_t
504
513
  msg_prepend(struct msg *msg, uint8_t *pos, size_t n)
@@ -516,17 +525,20 @@ msg_prepend(struct msg *msg, uint8_t *pos, size_t n)
516
525
  msg->mlen += (uint32_t)n;
517
526
 
518
527
  STAILQ_INSERT_HEAD(&msg->mhdr, mbuf, next);
528
+
519
529
  return NC_OK;
520
530
  }
521
531
 
522
532
  /*
523
- * prepend small(small than a mbuf) content into msg
533
+ * Prepend a formatted string into msg. Returns an error if the formatted
534
+ * string does not fit in a single mbuf.
524
535
  */
525
536
  rstatus_t
526
537
  msg_prepend_format(struct msg *msg, const char *fmt, ...)
527
538
  {
528
539
  struct mbuf *mbuf;
529
- int32_t n;
540
+ int n;
541
+ uint32_t size;
530
542
  va_list args;
531
543
 
532
544
  mbuf = mbuf_get();
@@ -534,15 +546,19 @@ msg_prepend_format(struct msg *msg, const char *fmt, ...)
534
546
  return NC_ENOMEM;
535
547
  }
536
548
 
549
+ size = mbuf_size(mbuf);
550
+
537
551
  va_start(args, fmt);
538
- n = nc_vscnprintf(mbuf->last, mbuf_size(mbuf), fmt, args);
552
+ n = nc_vsnprintf(mbuf->last, size, fmt, args);
539
553
  va_end(args);
554
+ if (n <= 0 || n >= (int)size) {
555
+ return NC_ERROR;
556
+ }
540
557
 
541
558
  mbuf->last += n;
542
559
  msg->mlen += (uint32_t)n;
543
-
544
- ASSERT(mbuf_size(mbuf) >= 0);
545
560
  STAILQ_INSERT_HEAD(&msg->mhdr, mbuf, next);
561
+
546
562
  return NC_OK;
547
563
  }
548
564
 
@@ -21,9 +21,11 @@
21
21
  #include <nc_core.h>
22
22
 
23
23
  typedef void (*msg_parse_t)(struct msg *);
24
+ typedef rstatus_t (*msg_add_auth_t)(struct context *ctx, struct conn *c_conn, struct conn *s_conn);
24
25
  typedef rstatus_t (*msg_fragment_t)(struct msg *, uint32_t, struct msg_tqh *);
25
26
  typedef void (*msg_coalesce_t)(struct msg *r);
26
27
  typedef rstatus_t (*msg_reply_t)(struct msg *r);
28
+ typedef bool (*msg_failure_t)(struct msg *r);
27
29
 
28
30
  typedef enum msg_parse_result {
29
31
  MSG_PARSE_OK, /* parsing ok */
@@ -45,6 +47,7 @@ typedef enum msg_parse_result {
45
47
  ACTION( REQ_MC_PREPEND ) \
46
48
  ACTION( REQ_MC_INCR ) /* memcache arithmetic request */ \
47
49
  ACTION( REQ_MC_DECR ) \
50
+ ACTION( REQ_MC_TOUCH ) /* memcache touch request */ \
48
51
  ACTION( REQ_MC_QUIT ) /* memcache quit request */ \
49
52
  ACTION( RSP_MC_NUM ) /* memcache arithmetic response */ \
50
53
  ACTION( RSP_MC_STORED ) /* memcache cas and storage response */ \
@@ -54,6 +57,7 @@ typedef enum msg_parse_result {
54
57
  ACTION( RSP_MC_END ) \
55
58
  ACTION( RSP_MC_VALUE ) \
56
59
  ACTION( RSP_MC_DELETED ) /* memcache delete response */ \
60
+ ACTION( RSP_MC_TOUCHED ) /* memcache touch response */ \
57
61
  ACTION( RSP_MC_ERROR ) /* memcache error responses */ \
58
62
  ACTION( RSP_MC_CLIENT_ERROR ) \
59
63
  ACTION( RSP_MC_SERVER_ERROR ) \
@@ -160,8 +164,23 @@ typedef enum msg_parse_result {
160
164
  ACTION( REQ_REDIS_EVALSHA ) \
161
165
  ACTION( REQ_REDIS_PING ) /* redis requests - ping/quit */ \
162
166
  ACTION( REQ_REDIS_QUIT) \
167
+ ACTION( REQ_REDIS_AUTH) \
168
+ ACTION( REQ_REDIS_SELECT) /* only during init */ \
163
169
  ACTION( RSP_REDIS_STATUS ) /* redis response */ \
164
170
  ACTION( RSP_REDIS_ERROR ) \
171
+ ACTION( RSP_REDIS_ERROR_ERR ) \
172
+ ACTION( RSP_REDIS_ERROR_OOM ) \
173
+ ACTION( RSP_REDIS_ERROR_BUSY ) \
174
+ ACTION( RSP_REDIS_ERROR_NOAUTH ) \
175
+ ACTION( RSP_REDIS_ERROR_LOADING ) \
176
+ ACTION( RSP_REDIS_ERROR_BUSYKEY ) \
177
+ ACTION( RSP_REDIS_ERROR_MISCONF ) \
178
+ ACTION( RSP_REDIS_ERROR_NOSCRIPT ) \
179
+ ACTION( RSP_REDIS_ERROR_READONLY ) \
180
+ ACTION( RSP_REDIS_ERROR_WRONGTYPE ) \
181
+ ACTION( RSP_REDIS_ERROR_EXECABORT ) \
182
+ ACTION( RSP_REDIS_ERROR_MASTERDOWN ) \
183
+ ACTION( RSP_REDIS_ERROR_NOREPLICAS ) \
165
184
  ACTION( RSP_REDIS_INTEGER ) \
166
185
  ACTION( RSP_REDIS_BULK ) \
167
186
  ACTION( RSP_REDIS_MULTIBULK ) \
@@ -202,7 +221,10 @@ struct msg {
202
221
  msg_parse_result_t result; /* message parsing result */
203
222
 
204
223
  msg_fragment_t fragment; /* message fragment */
205
- msg_reply_t reply; /* gen message reply (example: ping) */
224
+ msg_reply_t reply; /* generate message reply (example: ping) */
225
+ msg_add_auth_t add_auth; /* add auth message when we forward msg */
226
+ msg_failure_t failure; /* transient failure response? */
227
+
206
228
  msg_coalesce_t pre_coalesce; /* message pre-coalesce */
207
229
  msg_coalesce_t post_coalesce; /* message post-coalesce */
208
230
 
@@ -267,6 +289,7 @@ void req_put(struct msg *msg);
267
289
  bool req_done(struct conn *conn, struct msg *msg);
268
290
  bool req_error(struct conn *conn, struct msg *msg);
269
291
  void req_server_enqueue_imsgq(struct context *ctx, struct conn *conn, struct msg *msg);
292
+ void req_server_enqueue_imsgq_head(struct context *ctx, struct conn *conn, struct msg *msg);
270
293
  void req_server_dequeue_imsgq(struct context *ctx, struct conn *conn, struct msg *msg);
271
294
  void req_client_enqueue_omsgq(struct context *ctx, struct conn *conn, struct msg *msg);
272
295
  void req_server_enqueue_omsgq(struct context *ctx, struct conn *conn, struct msg *msg);
@@ -15,6 +15,7 @@
15
15
  * limitations under the License.
16
16
  */
17
17
 
18
+ #include <sys/stat.h>
18
19
  #include <sys/un.h>
19
20
 
20
21
  #include <nc_core.h>
@@ -29,9 +30,9 @@ proxy_ref(struct conn *conn, void *owner)
29
30
  ASSERT(!conn->client && conn->proxy);
30
31
  ASSERT(conn->owner == NULL);
31
32
 
32
- conn->family = pool->family;
33
- conn->addrlen = pool->addrlen;
34
- conn->addr = pool->addr;
33
+ conn->family = pool->info.family;
34
+ conn->addrlen = pool->info.addrlen;
35
+ conn->addr = (struct sockaddr *)&pool->info.addr;
35
36
 
36
37
  pool->p_conn = conn;
37
38
 
@@ -148,6 +149,16 @@ proxy_listen(struct context *ctx, struct conn *p)
148
149
  return NC_ERROR;
149
150
  }
150
151
 
152
+ if (p->family == AF_UNIX && pool->perm) {
153
+ struct sockaddr_un *un = (struct sockaddr_un *)p->addr;
154
+ status = chmod(un->sun_path, pool->perm);
155
+ if (status < 0) {
156
+ log_error("chmod on p %d on addr '%.*s' failed: %s", p->sd,
157
+ pool->addrstr.len, pool->addrstr.data, strerror(errno));
158
+ return NC_ERROR;
159
+ }
160
+ }
161
+
151
162
  status = listen(p->sd, pool->backlog);
152
163
  if (status < 0) {
153
164
  log_error("listen on p %d on addr '%.*s' failed: %s", p->sd,
@@ -218,11 +218,7 @@ rbtree_delete(struct rbtree *tree, struct rbnode *node)
218
218
  subst = node;
219
219
  } else {
220
220
  subst = rbtree_node_min(node->right, sentinel);
221
- if (subst->left != sentinel) {
222
- temp = subst->left;
223
- } else {
224
- temp = subst->right;
225
- }
221
+ temp = subst->right;
226
222
  }
227
223
 
228
224
  if (subst == *root) {
@@ -303,7 +303,7 @@ req_server_enqueue_imsgq(struct context *ctx, struct conn *conn, struct msg *msg
303
303
  * or the message is dequeued from the server out_q
304
304
  *
305
305
  * noreply request are free from timeouts because client is not intrested
306
- * in the reponse anyway!
306
+ * in the response anyway!
307
307
  */
308
308
  if (!msg->noreply) {
309
309
  msg_tmo_insert(msg, conn);
@@ -315,6 +315,30 @@ req_server_enqueue_imsgq(struct context *ctx, struct conn *conn, struct msg *msg
315
315
  stats_server_incr_by(ctx, conn->owner, in_queue_bytes, msg->mlen);
316
316
  }
317
317
 
318
+ void
319
+ req_server_enqueue_imsgq_head(struct context *ctx, struct conn *conn, struct msg *msg)
320
+ {
321
+ ASSERT(msg->request);
322
+ ASSERT(!conn->client && !conn->proxy);
323
+
324
+ /*
325
+ * timeout clock starts ticking the instant the message is enqueued into
326
+ * the server in_q; the clock continues to tick until it either expires
327
+ * or the message is dequeued from the server out_q
328
+ *
329
+ * noreply request are free from timeouts because client is not intrested
330
+ * in the reponse anyway!
331
+ */
332
+ if (!msg->noreply) {
333
+ msg_tmo_insert(msg, conn);
334
+ }
335
+
336
+ TAILQ_INSERT_HEAD(&conn->imsg_q, msg, s_tqe);
337
+
338
+ stats_server_incr(ctx, conn->owner, in_queue);
339
+ stats_server_incr_by(ctx, conn->owner, in_queue_bytes, msg->mlen);
340
+ }
341
+
318
342
  void
319
343
  req_server_dequeue_imsgq(struct context *ctx, struct conn *conn, struct msg *msg)
320
344
  {
@@ -429,20 +453,21 @@ req_recv_next(struct context *ctx, struct conn *conn, bool alloc)
429
453
  static rstatus_t
430
454
  req_make_reply(struct context *ctx, struct conn *conn, struct msg *req)
431
455
  {
432
- struct msg *msg;
456
+ struct msg *rsp;
433
457
 
434
- msg = msg_get(conn, true, conn->redis); /* replay */
435
- if (msg == NULL) {
458
+ rsp = msg_get(conn, false, conn->redis); /* replay */
459
+ if (rsp == NULL) {
436
460
  conn->err = errno;
437
461
  return NC_ENOMEM;
438
462
  }
439
463
 
440
- req->peer = msg;
441
- msg->peer = req;
442
- msg->request = 0;
464
+ req->peer = rsp;
465
+ rsp->peer = req;
466
+ rsp->request = 0;
443
467
 
444
468
  req->done = 1;
445
469
  conn->enqueue_outq(ctx, conn, req);
470
+
446
471
  return NC_OK;
447
472
  }
448
473
 
@@ -460,19 +485,32 @@ req_filter(struct context *ctx, struct conn *conn, struct msg *msg)
460
485
  }
461
486
 
462
487
  /*
463
- * Handle "quit\r\n", which is the protocol way of doing a
464
- * passive close
488
+ * Handle "quit\r\n" (memcache) or "*1\r\n$4\r\nquit\r\n" (redis), which
489
+ * is the protocol way of doing a passive close. The connection is closed
490
+ * as soon as all pending replies have been written to the client.
465
491
  */
466
492
  if (msg->quit) {
467
- ASSERT(conn->rmsg == NULL);
468
493
  log_debug(LOG_INFO, "filter quit req %"PRIu64" from c %d", msg->id,
469
494
  conn->sd);
495
+ if (conn->rmsg != NULL) {
496
+ log_debug(LOG_INFO, "discard invalid req %"PRIu64" len %"PRIu32" "
497
+ "from c %d sent after quit req", conn->rmsg->id,
498
+ conn->rmsg->mlen, conn->sd);
499
+ }
470
500
  conn->eof = 1;
471
501
  conn->recv_ready = 0;
472
502
  req_put(msg);
473
503
  return true;
474
504
  }
475
505
 
506
+ /*
507
+ * If this conn is not authenticated, we will mark it as noforward,
508
+ * and handle it in the redis_reply handler.
509
+ */
510
+ if (!conn_authenticated(conn)) {
511
+ msg->noforward = 1;
512
+ }
513
+
476
514
  return false;
477
515
  }
478
516
 
@@ -554,6 +592,16 @@ req_forward(struct context *ctx, struct conn *c_conn, struct msg *msg)
554
592
  return;
555
593
  }
556
594
  }
595
+
596
+ if (!conn_authenticated(s_conn)) {
597
+ status = msg->add_auth(ctx, c_conn, s_conn);
598
+ if (status != NC_OK) {
599
+ req_forward_error(ctx, c_conn, msg);
600
+ s_conn->err = errno;
601
+ return;
602
+ }
603
+ }
604
+
557
605
  s_conn->enqueue_inq(ctx, s_conn, msg);
558
606
 
559
607
  req_forward_stats(ctx, s_conn->owner, msg);
@@ -171,7 +171,7 @@ rsp_filter(struct context *ctx, struct conn *conn, struct msg *msg)
171
171
  * We handle this stray packet scenario in nutcracker by closing the
172
172
  * server connection which would end up sending SERVER_ERROR to all
173
173
  * clients that have requests pending on this server connection. The
174
- * fix is aggresive, but not doing so would lead to clients getting
174
+ * fix is aggressive, but not doing so would lead to clients getting
175
175
  * out of sync with the server and as a result clients end up getting
176
176
  * responses that don't correspond to the right request.
177
177
  *
@@ -184,7 +184,28 @@ rsp_filter(struct context *ctx, struct conn *conn, struct msg *msg)
184
184
  ASSERT(pmsg->peer == NULL);
185
185
  ASSERT(pmsg->request && !pmsg->done);
186
186
 
187
+ /*
188
+ * If the response from a server suggests a protocol level transient
189
+ * failure, close the server connection and send back a generic error
190
+ * response to the client.
191
+ *
192
+ * If auto_eject_host is enabled, this will also update the failure_count
193
+ * and eject the server if it exceeds the failure_limit
194
+ */
195
+ if (msg->failure(msg)) {
196
+ log_debug(LOG_INFO, "server failure rsp %"PRIu64" len %"PRIu32" "
197
+ "type %d on s %d", msg->id, msg->mlen, msg->type, conn->sd);
198
+ rsp_put(msg);
199
+
200
+ conn->err = EINVAL;
201
+ conn->done = 1;
202
+
203
+ return true;
204
+ }
205
+
187
206
  if (pmsg->swallow) {
207
+ conn->swallow_msg(conn, pmsg, msg);
208
+
188
209
  conn->dequeue_outq(ctx, conn, pmsg);
189
210
  pmsg->done = 1;
190
211
 
@@ -201,12 +222,12 @@ rsp_filter(struct context *ctx, struct conn *conn, struct msg *msg)
201
222
  }
202
223
 
203
224
  static void
204
- rsp_forward_stats(struct context *ctx, struct server *server, struct msg *msg)
225
+ rsp_forward_stats(struct context *ctx, struct server *server, struct msg *msg, uint32_t msgsize)
205
226
  {
206
227
  ASSERT(!msg->request);
207
228
 
208
229
  stats_server_incr(ctx, server, responses);
209
- stats_server_incr_by(ctx, server, response_bytes, msg->mlen);
230
+ stats_server_incr_by(ctx, server, response_bytes, msgsize);
210
231
  }
211
232
 
212
233
  static void
@@ -215,8 +236,10 @@ rsp_forward(struct context *ctx, struct conn *s_conn, struct msg *msg)
215
236
  rstatus_t status;
216
237
  struct msg *pmsg;
217
238
  struct conn *c_conn;
239
+ uint32_t msgsize;
218
240
 
219
241
  ASSERT(!s_conn->client && !s_conn->proxy);
242
+ msgsize = msg->mlen;
220
243
 
221
244
  /* response from server implies that server is ok and heartbeating */
222
245
  server_ok(ctx, s_conn);
@@ -245,7 +268,7 @@ rsp_forward(struct context *ctx, struct conn *s_conn, struct msg *msg)
245
268
  }
246
269
  }
247
270
 
248
- rsp_forward_stats(ctx, s_conn->owner, msg);
271
+ rsp_forward_stats(ctx, s_conn->owner, msg, msgsize);
249
272
  }
250
273
 
251
274
  void
@@ -22,6 +22,23 @@
22
22
  #include <nc_server.h>
23
23
  #include <nc_conf.h>
24
24
 
25
+ static void
26
+ server_resolve(struct server *server, struct conn *conn)
27
+ {
28
+ rstatus_t status;
29
+
30
+ status = nc_resolve(&server->addrstr, server->port, &server->info);
31
+ if (status != NC_OK) {
32
+ conn->err = EHOSTDOWN;
33
+ conn->done = 1;
34
+ return;
35
+ }
36
+
37
+ conn->family = server->info.family;
38
+ conn->addrlen = server->info.addrlen;
39
+ conn->addr = (struct sockaddr *)&server->info.addr;
40
+ }
41
+
25
42
  void
26
43
  server_ref(struct conn *conn, void *owner)
27
44
  {
@@ -30,9 +47,7 @@ server_ref(struct conn *conn, void *owner)
30
47
  ASSERT(!conn->client && !conn->proxy);
31
48
  ASSERT(conn->owner == NULL);
32
49
 
33
- conn->family = server->family;
34
- conn->addrlen = server->addrlen;
35
- conn->addr = server->addr;
50
+ server_resolve(server, conn);
36
51
 
37
52
  server->ns_conn_q++;
38
53
  TAILQ_INSERT_TAIL(&server->s_conn_q, conn, conn_tqe);
@@ -338,6 +353,8 @@ server_close(struct context *ctx, struct conn *conn)
338
353
  server_close_stats(ctx, conn->owner, conn->err, conn->eof,
339
354
  conn->connected);
340
355
 
356
+ conn->connected = false;
357
+
341
358
  if (conn->sd < 0) {
342
359
  server_failure(ctx, conn->owner);
343
360
  conn->unref(conn);
@@ -452,6 +469,12 @@ server_connect(struct context *ctx, struct server *server, struct conn *conn)
452
469
 
453
470
  ASSERT(!conn->client && !conn->proxy);
454
471
 
472
+ if (conn->err) {
473
+ ASSERT(conn->done && conn->sd < 0);
474
+ errno = conn->err;
475
+ return NC_ERROR;
476
+ }
477
+
455
478
  if (conn->sd > 0) {
456
479
  /* already connected on server connection */
457
480
  return NC_OK;
@@ -535,6 +558,8 @@ server_connected(struct context *ctx, struct conn *conn)
535
558
  conn->connecting = 0;
536
559
  conn->connected = 1;
537
560
 
561
+ conn->post_connect(ctx, conn, server);
562
+
538
563
  log_debug(LOG_INFO, "connected on s %d to server '%.*s'", conn->sd,
539
564
  server->pname.len, server->pname.data);
540
565
  }
@@ -605,12 +630,15 @@ static uint32_t
605
630
  server_pool_hash(struct server_pool *pool, uint8_t *key, uint32_t keylen)
606
631
  {
607
632
  ASSERT(array_n(&pool->server) != 0);
633
+ ASSERT(key != NULL);
608
634
 
609
635
  if (array_n(&pool->server) == 1) {
610
636
  return 0;
611
637
  }
612
638
 
613
- ASSERT(key != NULL && keylen != 0);
639
+ if (keylen == 0) {
640
+ return 0;
641
+ }
614
642
 
615
643
  return pool->key_hash((char *)key, keylen);
616
644
  }
@@ -621,7 +649,7 @@ server_pool_idx(struct server_pool *pool, uint8_t *key, uint32_t keylen)
621
649
  uint32_t hash, idx;
622
650
 
623
651
  ASSERT(array_n(&pool->server) != 0);
624
- ASSERT(key != NULL && keylen != 0);
652
+ ASSERT(key != NULL);
625
653
 
626
654
  /*
627
655
  * If hash_tag: is configured for this server pool, we use the part of