nutcracker 0.3.0.12 → 0.4.0.13

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