nutcracker 0.4.0.16 → 0.4.1.18

Sign up to get free protection for your applications and to get access to all the features.
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