nutcracker 0.3.0.12 → 0.4.0.13

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 (107) hide show
  1. checksums.yaml +5 -13
  2. data/README.md +3 -3
  3. data/Rakefile +12 -10
  4. data/ext/nutcracker/Makefile.in +215 -162
  5. data/ext/nutcracker/README.md +16 -4
  6. data/ext/nutcracker/aclocal.m4 +432 -254
  7. data/ext/nutcracker/{contrib/yaml-0.1.4/configure → autom4te.cache/output.0} +11367 -4545
  8. data/ext/nutcracker/autom4te.cache/output.1 +19907 -0
  9. data/ext/nutcracker/autom4te.cache/output.2 +19907 -0
  10. data/ext/nutcracker/autom4te.cache/requests +518 -0
  11. data/ext/nutcracker/autom4te.cache/traces.0 +2715 -0
  12. data/ext/nutcracker/autom4te.cache/traces.1 +967 -0
  13. data/ext/nutcracker/autom4te.cache/traces.2 +2715 -0
  14. data/ext/nutcracker/config/compile +347 -0
  15. data/ext/nutcracker/config/config.guess +116 -78
  16. data/ext/nutcracker/config/config.sub +65 -45
  17. data/ext/nutcracker/config/depcomp +295 -192
  18. data/ext/nutcracker/config/install-sh +7 -7
  19. data/ext/nutcracker/config/ltmain.sh +15 -20
  20. data/ext/nutcracker/config/missing +149 -265
  21. data/ext/nutcracker/configure +493 -367
  22. data/ext/nutcracker/contrib/Makefile.in +158 -116
  23. data/ext/nutcracker/extconf.rb +0 -1
  24. data/ext/nutcracker/m4/libtool.m4 +4 -23
  25. data/ext/nutcracker/m4/ltoptions.m4 +0 -0
  26. data/ext/nutcracker/m4/ltsugar.m4 +0 -0
  27. data/ext/nutcracker/m4/ltversion.m4 +0 -0
  28. data/ext/nutcracker/m4/lt~obsolete.m4 +0 -0
  29. data/ext/nutcracker/notes/recommendation.md +1 -1
  30. data/ext/nutcracker/notes/redis.md +35 -3
  31. data/ext/nutcracker/scripts/benchmark-mget.py +43 -0
  32. data/ext/nutcracker/scripts/nutcracker.spec +61 -3
  33. data/ext/nutcracker/scripts/redis-check.sh +43 -0
  34. data/ext/nutcracker/src/Makefile.in +205 -142
  35. data/ext/nutcracker/src/event/Makefile.in +164 -66
  36. data/ext/nutcracker/src/hashkit/Makefile.in +164 -66
  37. data/ext/nutcracker/src/nc_conf.c +2 -0
  38. data/ext/nutcracker/src/nc_connection.c +31 -0
  39. data/ext/nutcracker/src/nc_connection.h +3 -0
  40. data/ext/nutcracker/src/nc_core.c +38 -2
  41. data/ext/nutcracker/src/nc_core.h +11 -0
  42. data/ext/nutcracker/src/nc_log.c +90 -12
  43. data/ext/nutcracker/src/nc_log.h +11 -0
  44. data/ext/nutcracker/src/nc_mbuf.h +1 -1
  45. data/ext/nutcracker/src/nc_message.c +162 -116
  46. data/ext/nutcracker/src/nc_message.h +161 -129
  47. data/ext/nutcracker/src/nc_proxy.c +34 -4
  48. data/ext/nutcracker/src/nc_request.c +158 -32
  49. data/ext/nutcracker/src/nc_server.c +59 -5
  50. data/ext/nutcracker/src/nc_server.h +1 -0
  51. data/ext/nutcracker/src/nc_signal.c +2 -2
  52. data/ext/nutcracker/src/nc_stats.c +21 -0
  53. data/ext/nutcracker/src/nc_stats.h +28 -26
  54. data/ext/nutcracker/src/nc_string.c +176 -1
  55. data/ext/nutcracker/src/nc_string.h +26 -0
  56. data/ext/nutcracker/src/nc_util.c +12 -0
  57. data/ext/nutcracker/src/nc_util.h +1 -0
  58. data/ext/nutcracker/src/proto/Makefile.in +164 -66
  59. data/ext/nutcracker/src/proto/nc_memcache.c +279 -88
  60. data/ext/nutcracker/src/proto/nc_proto.h +3 -4
  61. data/ext/nutcracker/src/proto/nc_redis.c +561 -134
  62. data/lib/nutcracker/version.rb +1 -1
  63. metadata +31 -67
  64. data/ext/nutcracker/contrib/yaml-0.1.4/LICENSE +0 -19
  65. data/ext/nutcracker/contrib/yaml-0.1.4/Makefile.am +0 -20
  66. data/ext/nutcracker/contrib/yaml-0.1.4/Makefile.in +0 -736
  67. data/ext/nutcracker/contrib/yaml-0.1.4/README +0 -27
  68. data/ext/nutcracker/contrib/yaml-0.1.4/aclocal.m4 +0 -956
  69. data/ext/nutcracker/contrib/yaml-0.1.4/config.h.in +0 -80
  70. data/ext/nutcracker/contrib/yaml-0.1.4/config/config.guess +0 -1561
  71. data/ext/nutcracker/contrib/yaml-0.1.4/config/config.sub +0 -1686
  72. data/ext/nutcracker/contrib/yaml-0.1.4/config/depcomp +0 -630
  73. data/ext/nutcracker/contrib/yaml-0.1.4/config/install-sh +0 -520
  74. data/ext/nutcracker/contrib/yaml-0.1.4/config/ltmain.sh +0 -8406
  75. data/ext/nutcracker/contrib/yaml-0.1.4/config/missing +0 -376
  76. data/ext/nutcracker/contrib/yaml-0.1.4/configure.ac +0 -75
  77. data/ext/nutcracker/contrib/yaml-0.1.4/doc/doxygen.cfg +0 -222
  78. data/ext/nutcracker/contrib/yaml-0.1.4/include/yaml.h +0 -1971
  79. data/ext/nutcracker/contrib/yaml-0.1.4/m4/libtool.m4 +0 -7357
  80. data/ext/nutcracker/contrib/yaml-0.1.4/m4/ltoptions.m4 +0 -368
  81. data/ext/nutcracker/contrib/yaml-0.1.4/m4/ltsugar.m4 +0 -123
  82. data/ext/nutcracker/contrib/yaml-0.1.4/m4/ltversion.m4 +0 -23
  83. data/ext/nutcracker/contrib/yaml-0.1.4/m4/lt~obsolete.m4 +0 -92
  84. data/ext/nutcracker/contrib/yaml-0.1.4/src/Makefile.am +0 -4
  85. data/ext/nutcracker/contrib/yaml-0.1.4/src/Makefile.in +0 -484
  86. data/ext/nutcracker/contrib/yaml-0.1.4/src/api.c +0 -1392
  87. data/ext/nutcracker/contrib/yaml-0.1.4/src/dumper.c +0 -394
  88. data/ext/nutcracker/contrib/yaml-0.1.4/src/emitter.c +0 -2329
  89. data/ext/nutcracker/contrib/yaml-0.1.4/src/loader.c +0 -432
  90. data/ext/nutcracker/contrib/yaml-0.1.4/src/parser.c +0 -1374
  91. data/ext/nutcracker/contrib/yaml-0.1.4/src/reader.c +0 -465
  92. data/ext/nutcracker/contrib/yaml-0.1.4/src/scanner.c +0 -3570
  93. data/ext/nutcracker/contrib/yaml-0.1.4/src/writer.c +0 -141
  94. data/ext/nutcracker/contrib/yaml-0.1.4/src/yaml_private.h +0 -640
  95. data/ext/nutcracker/contrib/yaml-0.1.4/tests/Makefile.am +0 -8
  96. data/ext/nutcracker/contrib/yaml-0.1.4/tests/Makefile.in +0 -675
  97. data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-deconstructor-alt.c +0 -800
  98. data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-deconstructor.c +0 -1130
  99. data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-reformatter-alt.c +0 -217
  100. data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-reformatter.c +0 -202
  101. data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-dumper.c +0 -311
  102. data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-emitter.c +0 -327
  103. data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-loader.c +0 -63
  104. data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-parser.c +0 -63
  105. data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-scanner.c +0 -63
  106. data/ext/nutcracker/contrib/yaml-0.1.4/tests/test-reader.c +0 -354
  107. data/ext/nutcracker/contrib/yaml-0.1.4/tests/test-version.c +0 -29
@@ -1557,6 +1557,8 @@ conf_add_server(struct conf *cf, struct command *cmd, void *conf)
1557
1557
  field->weight = nc_atoi(weight, weightlen);
1558
1558
  if (field->weight < 0) {
1559
1559
  return "has an invalid weight in \"hostname:port:weight [name]\" format string";
1560
+ } else if (field->weight == 0) {
1561
+ return "has a zero weight in \"hostname:port:weight [name]\" format string";
1560
1562
  }
1561
1563
 
1562
1564
  if (value->data[0] != '/') {
@@ -83,6 +83,9 @@
83
83
 
84
84
  static uint32_t nfree_connq; /* # free conn q */
85
85
  static struct conn_tqh free_connq; /* free conn q */
86
+ static uint64_t ntotal_conn; /* total # connections counter from start */
87
+ static uint32_t ncurr_conn; /* current # connections */
88
+ static uint32_t ncurr_cconn; /* current # client connections */
86
89
 
87
90
  /*
88
91
  * Return the context associated with this connection.
@@ -154,6 +157,9 @@ _conn_get(void)
154
157
  conn->done = 0;
155
158
  conn->redis = 0;
156
159
 
160
+ ntotal_conn++;
161
+ ncurr_conn++;
162
+
157
163
  return conn;
158
164
  }
159
165
 
@@ -195,6 +201,8 @@ conn_get(void *owner, bool client, bool redis)
195
201
  conn->dequeue_inq = NULL;
196
202
  conn->enqueue_outq = req_client_enqueue_omsgq;
197
203
  conn->dequeue_outq = req_client_dequeue_omsgq;
204
+
205
+ ncurr_cconn++;
198
206
  } else {
199
207
  /*
200
208
  * server receives a response, possibly parsing it, and sends a
@@ -285,6 +293,11 @@ conn_put(struct conn *conn)
285
293
 
286
294
  nfree_connq++;
287
295
  TAILQ_INSERT_HEAD(&free_connq, conn, conn_tqe);
296
+
297
+ if (conn->client) {
298
+ ncurr_cconn--;
299
+ }
300
+ ncurr_conn--;
288
301
  }
289
302
 
290
303
  void
@@ -407,3 +420,21 @@ conn_sendv(struct conn *conn, struct array *sendv, size_t nsend)
407
420
 
408
421
  return NC_ERROR;
409
422
  }
423
+
424
+ uint32_t
425
+ conn_ncurr_conn(void)
426
+ {
427
+ return ncurr_conn;
428
+ }
429
+
430
+ uint64_t
431
+ conn_ntotal_conn(void)
432
+ {
433
+ return ntotal_conn;
434
+ }
435
+
436
+ uint32_t
437
+ conn_ncurr_cconn(void)
438
+ {
439
+ return ncurr_cconn;
440
+ }
@@ -96,5 +96,8 @@ ssize_t conn_recv(struct conn *conn, void *buf, size_t size);
96
96
  ssize_t conn_sendv(struct conn *conn, struct array *sendv, size_t nsend);
97
97
  void conn_init(void);
98
98
  void conn_deinit(void);
99
+ uint32_t conn_ncurr_conn(void);
100
+ uint64_t conn_ntotal_conn(void);
101
+ uint32_t conn_ncurr_cconn(void);
99
102
 
100
103
  #endif
@@ -24,6 +24,27 @@
24
24
 
25
25
  static uint32_t ctx_id; /* context generation */
26
26
 
27
+ static rstatus_t
28
+ core_calc_connections(struct context *ctx)
29
+ {
30
+ int status;
31
+ struct rlimit limit;
32
+
33
+ status = getrlimit(RLIMIT_NOFILE, &limit);
34
+ if (status < 0) {
35
+ log_error("getrlimit failed: %s", strerror(errno));
36
+ return NC_ERROR;
37
+ }
38
+
39
+ ctx->max_nfd = (uint32_t)limit.rlim_cur;
40
+ ctx->max_ncconn = ctx->max_nfd - ctx->max_nsconn - RESERVED_FDS;
41
+ log_debug(LOG_NOTICE, "max fds %"PRIu32" max client conns %"PRIu32" "
42
+ "max server conns %"PRIu32"", ctx->max_nfd, ctx->max_ncconn,
43
+ ctx->max_nsconn);
44
+
45
+ return NC_OK;
46
+ }
47
+
27
48
  static struct context *
28
49
  core_ctx_create(struct instance *nci)
29
50
  {
@@ -41,6 +62,9 @@ core_ctx_create(struct instance *nci)
41
62
  array_null(&ctx->pool);
42
63
  ctx->max_timeout = nci->stats_interval;
43
64
  ctx->timeout = ctx->max_timeout;
65
+ ctx->max_nfd = 0;
66
+ ctx->max_ncconn = 0;
67
+ ctx->max_nsconn = 0;
44
68
 
45
69
  /* parse and create configuration */
46
70
  ctx->cf = conf_create(nci->conf_filename);
@@ -57,6 +81,18 @@ core_ctx_create(struct instance *nci)
57
81
  return NULL;
58
82
  }
59
83
 
84
+ /*
85
+ * Get rlimit and calculate max client connections after we have
86
+ * calculated max server connections
87
+ */
88
+ status = core_calc_connections(ctx);
89
+ if (status != NC_OK) {
90
+ server_pool_deinit(&ctx->pool);
91
+ conf_destroy(ctx->cf);
92
+ nc_free(ctx);
93
+ return NULL;
94
+ }
95
+
60
96
  /* create stats per server pool */
61
97
  ctx->stats = stats_create(nci->stats_port, nci->stats_addr, nci->stats_interval,
62
98
  nci->hostname, &ctx->pool);
@@ -172,9 +208,9 @@ core_send(struct context *ctx, struct conn *conn)
172
208
 
173
209
  status = conn->send(ctx, conn);
174
210
  if (status != NC_OK) {
175
- log_debug(LOG_INFO, "send on %c %d failed: %s",
211
+ log_debug(LOG_INFO, "send on %c %d failed: status: %d errno: %d %s",
176
212
  conn->client ? 'c' : (conn->proxy ? 'p' : 's'), conn->sd,
177
- strerror(errno));
213
+ status, errno, strerror(errno));
178
214
  }
179
215
 
180
216
  return status;
@@ -63,6 +63,9 @@
63
63
  #define NC_EAGAIN -2
64
64
  #define NC_ENOMEM -3
65
65
 
66
+ /* reserved fds for std streams, log, stats fd, epoll etc. */
67
+ #define RESERVED_FDS 32
68
+
66
69
  typedef int rstatus_t; /* return type */
67
70
  typedef int err_t; /* error type */
68
71
 
@@ -87,6 +90,8 @@ struct event_base;
87
90
  #include <stdbool.h>
88
91
  #include <inttypes.h>
89
92
  #include <string.h>
93
+ #include <stdio.h>
94
+ #include <ctype.h>
90
95
  #include <errno.h>
91
96
  #include <limits.h>
92
97
  #include <time.h>
@@ -97,6 +102,7 @@ struct event_base;
97
102
  #include <sys/socket.h>
98
103
  #include <sys/un.h>
99
104
  #include <sys/time.h>
105
+ #include <sys/resource.h>
100
106
  #include <netinet/in.h>
101
107
 
102
108
  #include <nc_array.h>
@@ -110,6 +116,7 @@ struct event_base;
110
116
  #include <nc_mbuf.h>
111
117
  #include <nc_message.h>
112
118
  #include <nc_connection.h>
119
+ #include <nc_server.h>
113
120
 
114
121
  struct context {
115
122
  uint32_t id; /* unique context id */
@@ -120,6 +127,10 @@ struct context {
120
127
  struct event_base *evb; /* event base */
121
128
  int max_timeout; /* max timeout in msec */
122
129
  int timeout; /* timeout in msec */
130
+
131
+ uint32_t max_nfd; /* max # files */
132
+ uint32_t max_ncconn; /* max # client connections */
133
+ uint32_t max_nsconn; /* max # server connections */
123
134
  };
124
135
 
125
136
 
@@ -68,7 +68,7 @@ log_reopen(void)
68
68
  close(l->fd);
69
69
  l->fd = open(l->name, O_WRONLY | O_APPEND | O_CREAT, 0644);
70
70
  if (l->fd < 0) {
71
- log_stderr("reopening log file '%s' failed, ignored: %s", l->name,
71
+ log_stderr_safe("reopening log file '%s' failed, ignored: %s", l->name,
72
72
  strerror(errno));
73
73
  }
74
74
  }
@@ -81,7 +81,7 @@ log_level_up(void)
81
81
 
82
82
  if (l->level < LOG_PVERB) {
83
83
  l->level++;
84
- loga("up log level to %d", l->level);
84
+ log_safe("up log level to %d", l->level);
85
85
  }
86
86
  }
87
87
 
@@ -92,7 +92,7 @@ log_level_down(void)
92
92
 
93
93
  if (l->level > LOG_EMERG) {
94
94
  l->level--;
95
- loga("down log level to %d", l->level);
95
+ log_safe("down log level to %d", l->level);
96
96
  }
97
97
  }
98
98
 
@@ -105,6 +105,17 @@ log_level_set(int level)
105
105
  loga("set log level to %d", l->level);
106
106
  }
107
107
 
108
+ void
109
+ log_stacktrace(void)
110
+ {
111
+ struct logger *l = &logger;
112
+
113
+ if (l->fd < 0) {
114
+ return;
115
+ }
116
+ nc_stacktrace_fd(l->fd);
117
+ }
118
+
108
119
  int
109
120
  log_loggable(int level)
110
121
  {
@@ -122,11 +133,10 @@ _log(const char *file, int line, int panic, const char *fmt, ...)
122
133
  {
123
134
  struct logger *l = &logger;
124
135
  int len, size, errno_save;
125
- char buf[LOG_MAX_LEN], *timestr;
136
+ char buf[LOG_MAX_LEN];
126
137
  va_list args;
127
- struct tm *local;
128
- time_t t;
129
138
  ssize_t n;
139
+ struct timeval tv;
130
140
 
131
141
  if (l->fd < 0) {
132
142
  return;
@@ -136,12 +146,11 @@ _log(const char *file, int line, int panic, const char *fmt, ...)
136
146
  len = 0; /* length of output buffer */
137
147
  size = LOG_MAX_LEN; /* size of output buffer */
138
148
 
139
- t = time(NULL);
140
- local = localtime(&t);
141
- timestr = asctime(local);
142
-
143
- len += nc_scnprintf(buf + len, size - len, "[%.*s] %s:%d ",
144
- strlen(timestr) - 1, timestr, file, line);
149
+ gettimeofday(&tv, NULL);
150
+ buf[len++] = '[';
151
+ len += nc_strftime(buf + len, size - len, "%Y-%m-%d %H:%M:%S.", localtime(&tv.tv_sec));
152
+ len += nc_scnprintf(buf + len, size - len, "%03ld", tv.tv_usec/1000);
153
+ len += nc_scnprintf(buf + len, size - len, "] %s:%d ", file, line);
145
154
 
146
155
  va_start(args, fmt);
147
156
  len += nc_vscnprintf(buf + len, size - len, fmt, args);
@@ -250,5 +259,74 @@ _log_hexdump(const char *file, int line, char *data, int datalen,
250
259
  l->nerror++;
251
260
  }
252
261
 
262
+ if (len >= size - 1) {
263
+ n = nc_write(l->fd, "\n", 1);
264
+ if (n < 0) {
265
+ l->nerror++;
266
+ }
267
+ }
268
+
269
+ errno = errno_save;
270
+ }
271
+
272
+ void
273
+ _log_safe(const char *fmt, ...)
274
+ {
275
+ struct logger *l = &logger;
276
+ int len, size, errno_save;
277
+ char buf[LOG_MAX_LEN];
278
+ va_list args;
279
+ ssize_t n;
280
+
281
+ if (l->fd < 0) {
282
+ return;
283
+ }
284
+
285
+ errno_save = errno;
286
+ len = 0; /* length of output buffer */
287
+ size = LOG_MAX_LEN; /* size of output buffer */
288
+
289
+ len += nc_safe_snprintf(buf + len, size - len, "[.......................] ");
290
+
291
+ va_start(args, fmt);
292
+ len += nc_safe_vsnprintf(buf + len, size - len, fmt, args);
293
+ va_end(args);
294
+
295
+ buf[len++] = '\n';
296
+
297
+ n = nc_write(l->fd, buf, len);
298
+ if (n < 0) {
299
+ l->nerror++;
300
+ }
301
+
302
+ errno = errno_save;
303
+ }
304
+
305
+ void
306
+ _log_stderr_safe(const char *fmt, ...)
307
+ {
308
+ struct logger *l = &logger;
309
+ int len, size, errno_save;
310
+ char buf[LOG_MAX_LEN];
311
+ va_list args;
312
+ ssize_t n;
313
+
314
+ errno_save = errno;
315
+ len = 0; /* length of output buffer */
316
+ size = LOG_MAX_LEN; /* size of output buffer */
317
+
318
+ len += nc_safe_snprintf(buf + len, size - len, "[.......................] ");
319
+
320
+ va_start(args, fmt);
321
+ len += nc_safe_vsnprintf(buf + len, size - len, fmt, args);
322
+ va_end(args);
323
+
324
+ buf[len++] = '\n';
325
+
326
+ n = nc_write(STDERR_FILENO, buf, len);
327
+ if (n < 0) {
328
+ l->nerror++;
329
+ }
330
+
253
331
  errno = errno_save;
254
332
  }
@@ -78,6 +78,14 @@ struct logger {
78
78
  _log_stderr(__VA_ARGS__); \
79
79
  } while (0)
80
80
 
81
+ #define log_safe(...) do { \
82
+ _log_safe(__VA_ARGS__); \
83
+ } while (0)
84
+
85
+ #define log_stderr_safe(...) do { \
86
+ _log_stderr_safe(__VA_ARGS__); \
87
+ } while (0)
88
+
81
89
  #define loga(...) do { \
82
90
  _log(__FILE__, __LINE__, 0, __VA_ARGS__); \
83
91
  } while (0)
@@ -111,10 +119,13 @@ void log_deinit(void);
111
119
  void log_level_up(void);
112
120
  void log_level_down(void);
113
121
  void log_level_set(int level);
122
+ void log_stacktrace(void);
114
123
  void log_reopen(void);
115
124
  int log_loggable(int level);
116
125
  void _log(const char *file, int line, int panic, const char *fmt, ...);
117
126
  void _log_stderr(const char *fmt, ...);
127
+ void _log_safe(const char *fmt, ...);
128
+ void _log_stderr_safe(const char *fmt, ...);
118
129
  void _log_hexdump(const char *file, int line, char *data, int datalen, const char *fmt, ...);
119
130
 
120
131
  #endif
@@ -35,7 +35,7 @@ STAILQ_HEAD(mhdr, mbuf);
35
35
 
36
36
  #define MBUF_MAGIC 0xdeadbeef
37
37
  #define MBUF_MIN_SIZE 512
38
- #define MBUF_MAX_SIZE 65536
38
+ #define MBUF_MAX_SIZE 16777216
39
39
  #define MBUF_SIZE 16384
40
40
  #define MBUF_HSIZE sizeof(struct mbuf)
41
41
 
@@ -116,6 +116,13 @@ static struct msg_tqh free_msgq; /* free msg q */
116
116
  static struct rbtree tmo_rbt; /* timeout rbtree */
117
117
  static struct rbnode tmo_rbs; /* timeout rbtree sentinel */
118
118
 
119
+ #define DEFINE_ACTION(_name) string(#_name),
120
+ static struct string msg_type_strings[] = {
121
+ MSG_TYPE_CODEC( DEFINE_ACTION )
122
+ null_string
123
+ };
124
+ #undef DEFINE_ACTION
125
+
119
126
  static struct msg *
120
127
  msg_from_rbe(struct rbnode *node)
121
128
  {
@@ -212,6 +219,7 @@ done:
212
219
 
213
220
  STAILQ_INIT(&msg->mhdr);
214
221
  msg->mlen = 0;
222
+ msg->start_ts = 0;
215
223
 
216
224
  msg->state = 0;
217
225
  msg->pos = NULL;
@@ -220,21 +228,26 @@ done:
220
228
  msg->parser = NULL;
221
229
  msg->result = MSG_PARSE_OK;
222
230
 
223
- msg->pre_splitcopy = NULL;
224
- msg->post_splitcopy = NULL;
231
+ msg->fragment = NULL;
232
+ msg->reply = NULL;
225
233
  msg->pre_coalesce = NULL;
226
234
  msg->post_coalesce = NULL;
227
235
 
228
236
  msg->type = MSG_UNKNOWN;
229
237
 
230
- msg->key_start = NULL;
231
- msg->key_end = NULL;
238
+ msg->keys = array_create(1, sizeof(struct keypos));
239
+ if (msg->keys == NULL) {
240
+ nc_free(msg);
241
+ return NULL;
242
+ }
232
243
 
233
244
  msg->vlen = 0;
234
245
  msg->end = NULL;
235
246
 
236
247
  msg->frag_owner = NULL;
248
+ msg->frag_seq = NULL;
237
249
  msg->nfrag = 0;
250
+ msg->nfrag_done = 0;
238
251
  msg->frag_id = 0;
239
252
 
240
253
  msg->narg_start = NULL;
@@ -250,10 +263,9 @@ done:
250
263
  msg->request = 0;
251
264
  msg->quit = 0;
252
265
  msg->noreply = 0;
266
+ msg->noforward = 0;
253
267
  msg->done = 0;
254
268
  msg->fdone = 0;
255
- msg->first_fragment = 0;
256
- msg->last_fragment = 0;
257
269
  msg->swallow = 0;
258
270
  msg->redis = 0;
259
271
 
@@ -280,8 +292,8 @@ msg_get(struct conn *conn, bool request, bool redis)
280
292
  } else {
281
293
  msg->parser = redis_parse_rsp;
282
294
  }
283
- msg->pre_splitcopy = redis_pre_splitcopy;
284
- msg->post_splitcopy = redis_post_splitcopy;
295
+ msg->fragment = redis_fragment;
296
+ msg->reply = redis_reply;
285
297
  msg->pre_coalesce = redis_pre_coalesce;
286
298
  msg->post_coalesce = redis_post_coalesce;
287
299
  } else {
@@ -290,12 +302,15 @@ msg_get(struct conn *conn, bool request, bool redis)
290
302
  } else {
291
303
  msg->parser = memcache_parse_rsp;
292
304
  }
293
- msg->pre_splitcopy = memcache_pre_splitcopy;
294
- msg->post_splitcopy = memcache_post_splitcopy;
305
+ msg->fragment = memcache_fragment;
295
306
  msg->pre_coalesce = memcache_pre_coalesce;
296
307
  msg->post_coalesce = memcache_post_coalesce;
297
308
  }
298
309
 
310
+ if (log_loggable(LOG_NOTICE) != 0) {
311
+ msg->start_ts = nc_usec_now();
312
+ }
313
+
299
314
  log_debug(LOG_VVERB, "get msg %p id %"PRIu64" request %d owner sd %d",
300
315
  msg, msg->id, msg->request, conn->sd);
301
316
 
@@ -356,15 +371,30 @@ msg_put(struct msg *msg)
356
371
  mbuf_put(mbuf);
357
372
  }
358
373
 
374
+ if (msg->frag_seq) {
375
+ nc_free(msg->frag_seq);
376
+ msg->frag_seq = NULL;
377
+ }
378
+
379
+ if (msg->keys) {
380
+ msg->keys->nelem = 0; /* a hack here */
381
+ array_destroy(msg->keys);
382
+ msg->keys = NULL;
383
+ }
384
+
359
385
  nfree_msgq++;
360
386
  TAILQ_INSERT_HEAD(&free_msgq, msg, m_tqe);
361
387
  }
362
388
 
363
389
  void
364
- msg_dump(struct msg *msg)
390
+ msg_dump(struct msg *msg, int level)
365
391
  {
366
392
  struct mbuf *mbuf;
367
393
 
394
+ if (log_loggable(level) == 0) {
395
+ return;
396
+ }
397
+
368
398
  loga("msg dump id %"PRIu64" request %d len %"PRIu32" type %d done %d "
369
399
  "error %d (err %d)", msg->id, msg->request, msg->mlen, msg->type,
370
400
  msg->done, msg->error, msg->err);
@@ -377,7 +407,7 @@ msg_dump(struct msg *msg)
377
407
  q = mbuf->last;
378
408
  len = q - p;
379
409
 
380
- loga_hexdump(p, len, "mbuf with %ld bytes of data", len);
410
+ loga_hexdump(p, len, "mbuf [%p] with %ld bytes of data", p, len);
381
411
  }
382
412
  }
383
413
 
@@ -406,12 +436,122 @@ msg_deinit(void)
406
436
  ASSERT(nfree_msgq == 0);
407
437
  }
408
438
 
439
+ struct string *
440
+ msg_type_string(msg_type_t type)
441
+ {
442
+ return &msg_type_strings[type];
443
+ }
444
+
409
445
  bool
410
446
  msg_empty(struct msg *msg)
411
447
  {
412
448
  return msg->mlen == 0 ? true : false;
413
449
  }
414
450
 
451
+ uint32_t
452
+ msg_backend_idx(struct msg *msg, uint8_t *key, uint32_t keylen)
453
+ {
454
+ struct conn *conn = msg->owner;
455
+ struct server_pool *pool = conn->owner;
456
+
457
+ return server_pool_idx(pool, key, keylen);
458
+ }
459
+
460
+ struct mbuf *
461
+ msg_ensure_mbuf(struct msg *msg, size_t len)
462
+ {
463
+ struct mbuf *mbuf;
464
+
465
+ if (STAILQ_EMPTY(&msg->mhdr) ||
466
+ mbuf_size(STAILQ_LAST(&msg->mhdr, mbuf, next)) < len) {
467
+ mbuf = mbuf_get();
468
+ if (mbuf == NULL) {
469
+ return NULL;
470
+ }
471
+ mbuf_insert(&msg->mhdr, mbuf);
472
+ } else {
473
+ mbuf = STAILQ_LAST(&msg->mhdr, mbuf, next);
474
+ }
475
+ return mbuf;
476
+ }
477
+
478
+ /*
479
+ * append small(small than a mbuf) content into msg
480
+ */
481
+ rstatus_t
482
+ msg_append(struct msg *msg, uint8_t *pos, size_t n)
483
+ {
484
+ struct mbuf *mbuf;
485
+
486
+ ASSERT(n <= mbuf_data_size());
487
+
488
+ mbuf = msg_ensure_mbuf(msg, n);
489
+ if (mbuf == NULL) {
490
+ return NC_ENOMEM;
491
+ }
492
+
493
+ ASSERT(n <= mbuf_size(mbuf));
494
+
495
+ mbuf_copy(mbuf, pos, n);
496
+ msg->mlen += (uint32_t)n;
497
+ return NC_OK;
498
+ }
499
+
500
+ /*
501
+ * prepend small(small than a mbuf) content into msg
502
+ */
503
+ rstatus_t
504
+ msg_prepend(struct msg *msg, uint8_t *pos, size_t n)
505
+ {
506
+ struct mbuf *mbuf;
507
+
508
+ mbuf = mbuf_get();
509
+ if (mbuf == NULL) {
510
+ return NC_ENOMEM;
511
+ }
512
+
513
+ ASSERT(n <= mbuf_size(mbuf));
514
+
515
+ mbuf_copy(mbuf, pos, n);
516
+ msg->mlen += (uint32_t)n;
517
+
518
+ STAILQ_INSERT_HEAD(&msg->mhdr, mbuf, next);
519
+ return NC_OK;
520
+ }
521
+
522
+ /*
523
+ * prepend small(small than a mbuf) content into msg
524
+ */
525
+ rstatus_t
526
+ msg_prepend_format(struct msg *msg, const char *fmt, ...)
527
+ {
528
+ struct mbuf *mbuf;
529
+ int32_t n;
530
+ va_list args;
531
+
532
+ mbuf = mbuf_get();
533
+ if (mbuf == NULL) {
534
+ return NC_ENOMEM;
535
+ }
536
+
537
+ va_start(args, fmt);
538
+ n = nc_vscnprintf(mbuf->last, mbuf_size(mbuf), fmt, args);
539
+ va_end(args);
540
+
541
+ mbuf->last += n;
542
+ msg->mlen += (uint32_t)n;
543
+
544
+ ASSERT(mbuf_size(mbuf) >= 0);
545
+ STAILQ_INSERT_HEAD(&msg->mhdr, mbuf, next);
546
+ return NC_OK;
547
+ }
548
+
549
+ inline uint64_t
550
+ msg_gen_frag_id(void)
551
+ {
552
+ return ++frag_id;
553
+ }
554
+
415
555
  static rstatus_t
416
556
  msg_parsed(struct context *ctx, struct conn *conn, struct msg *msg)
417
557
  {
@@ -453,101 +593,6 @@ msg_parsed(struct context *ctx, struct conn *conn, struct msg *msg)
453
593
  return NC_OK;
454
594
  }
455
595
 
456
- static rstatus_t
457
- msg_fragment(struct context *ctx, struct conn *conn, struct msg *msg)
458
- {
459
- rstatus_t status; /* return status */
460
- struct msg *nmsg; /* new message */
461
- struct mbuf *nbuf; /* new mbuf */
462
-
463
- ASSERT(conn->client && !conn->proxy);
464
- ASSERT(msg->request);
465
-
466
- nbuf = mbuf_split(&msg->mhdr, msg->pos, msg->pre_splitcopy, msg);
467
- if (nbuf == NULL) {
468
- return NC_ENOMEM;
469
- }
470
-
471
- status = msg->post_splitcopy(msg);
472
- if (status != NC_OK) {
473
- mbuf_put(nbuf);
474
- return status;
475
- }
476
-
477
- nmsg = msg_get(msg->owner, msg->request, msg->redis);
478
- if (nmsg == NULL) {
479
- mbuf_put(nbuf);
480
- return NC_ENOMEM;
481
- }
482
- mbuf_insert(&nmsg->mhdr, nbuf);
483
- nmsg->pos = nbuf->pos;
484
-
485
- /* update length of current (msg) and new message (nmsg) */
486
- nmsg->mlen = mbuf_length(nbuf);
487
- msg->mlen -= nmsg->mlen;
488
-
489
- /*
490
- * Attach unique fragment id to all fragments of the message vector. All
491
- * fragments of the message, including the first fragment point to the
492
- * first fragment through the frag_owner pointer. The first_fragment and
493
- * last_fragment identify first and last fragment respectively.
494
- *
495
- * For example, a message vector given below is split into 3 fragments:
496
- * 'get key1 key2 key3\r\n'
497
- * Or,
498
- * '*4\r\n$4\r\nmget\r\n$4\r\nkey1\r\n$4\r\nkey2\r\n$4\r\nkey3\r\n'
499
- *
500
- * +--------------+
501
- * | msg vector |
502
- * |(original msg)|
503
- * +--------------+
504
- *
505
- * frag_owner frag_owner
506
- * /-----------+ /------------+
507
- * | | | |
508
- * | v v |
509
- * +--------------------+ +---------------------+
510
- * | frag_id = 10 | | frag_id = 10 |
511
- * | first_fragment = 1 | | first_fragment = 0 |
512
- * | last_fragment = 0 | | last_fragment = 0 |
513
- * | nfrag = 3 | | nfrag = 0 |
514
- * +--------------------+ +---------------------+
515
- * ^
516
- * | frag_owner
517
- * \-------------+
518
- * |
519
- * |
520
- * +---------------------+
521
- * | frag_id = 10 |
522
- * | first_fragment = 0 |
523
- * | last_fragment = 1 |
524
- * | nfrag = 0 |
525
- * +---------------------+
526
- *
527
- *
528
- */
529
- if (msg->frag_id == 0) {
530
- msg->frag_id = ++frag_id;
531
- msg->first_fragment = 1;
532
- msg->nfrag = 1;
533
- msg->frag_owner = msg;
534
- }
535
- nmsg->frag_id = msg->frag_id;
536
- msg->last_fragment = 0;
537
- nmsg->last_fragment = 1;
538
- nmsg->frag_owner = msg->frag_owner;
539
- msg->frag_owner->nfrag++;
540
-
541
- stats_pool_incr(ctx, conn->owner, fragments);
542
-
543
- log_debug(LOG_VERB, "fragment msg into %"PRIu64" and %"PRIu64" frag id "
544
- "%"PRIu64"", msg->id, nmsg->id, msg->frag_id);
545
-
546
- conn->recv_done(ctx, conn, msg, nmsg);
547
-
548
- return NC_OK;
549
- }
550
-
551
596
  static rstatus_t
552
597
  msg_repair(struct context *ctx, struct conn *conn, struct msg *msg)
553
598
  {
@@ -581,10 +626,6 @@ msg_parse(struct context *ctx, struct conn *conn, struct msg *msg)
581
626
  status = msg_parsed(ctx, conn, msg);
582
627
  break;
583
628
 
584
- case MSG_PARSE_FRAGMENT:
585
- status = msg_fragment(ctx, conn, msg);
586
- break;
587
-
588
629
  case MSG_PARSE_REPAIR:
589
630
  status = msg_repair(ctx, conn, msg);
590
631
  break;
@@ -742,11 +783,16 @@ msg_send_chain(struct context *ctx, struct conn *conn, struct msg *msg)
742
783
  }
743
784
  }
744
785
 
745
- ASSERT(!TAILQ_EMPTY(&send_msgq) && nsend != 0);
746
-
786
+ /*
787
+ * (nsend == 0) is possible in redis multi-del
788
+ * see PR: https://github.com/twitter/twemproxy/pull/225
789
+ */
747
790
  conn->smsg = NULL;
748
-
749
- n = conn_sendv(conn, &sendv, nsend);
791
+ if (!TAILQ_EMPTY(&send_msgq) && nsend != 0) {
792
+ n = conn_sendv(conn, &sendv, nsend);
793
+ } else {
794
+ n = 0;
795
+ }
750
796
 
751
797
  nsent = n > 0 ? (size_t)n : 0;
752
798
 
@@ -794,7 +840,7 @@ msg_send_chain(struct context *ctx, struct conn *conn, struct msg *msg)
794
840
 
795
841
  ASSERT(TAILQ_EMPTY(&send_msgq));
796
842
 
797
- if (n > 0) {
843
+ if (n >= 0) {
798
844
  return NC_OK;
799
845
  }
800
846