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
@@ -140,16 +140,15 @@
140
140
 
141
141
  void memcache_parse_req(struct msg *r);
142
142
  void memcache_parse_rsp(struct msg *r);
143
- void memcache_pre_splitcopy(struct mbuf *mbuf, void *arg);
144
- rstatus_t memcache_post_splitcopy(struct msg *r);
145
143
  void memcache_pre_coalesce(struct msg *r);
146
144
  void memcache_post_coalesce(struct msg *r);
145
+ rstatus_t memcache_fragment(struct msg *r, uint32_t ncontinuum, struct msg_tqh *frag_msgq);
147
146
 
148
147
  void redis_parse_req(struct msg *r);
149
148
  void redis_parse_rsp(struct msg *r);
150
- void redis_pre_splitcopy(struct mbuf *mbuf, void *arg);
151
- rstatus_t redis_post_splitcopy(struct msg *r);
152
149
  void redis_pre_coalesce(struct msg *r);
153
150
  void redis_post_coalesce(struct msg *r);
151
+ rstatus_t redis_fragment(struct msg *r, uint32_t ncontinuum, struct msg_tqh *frag_msgq);
152
+ rstatus_t redis_reply(struct msg *r);
154
153
 
155
154
  #endif
@@ -21,6 +21,25 @@
21
21
  #include <nc_core.h>
22
22
  #include <nc_proto.h>
23
23
 
24
+ /*
25
+ * Return true, if the redis command take no key, otherwise
26
+ * return false
27
+ */
28
+ static bool
29
+ redis_argz(struct msg *r)
30
+ {
31
+ switch (r->type) {
32
+ case MSG_REQ_REDIS_PING:
33
+ case MSG_REQ_REDIS_QUIT:
34
+ return true;
35
+
36
+ default:
37
+ break;
38
+ }
39
+
40
+ return false;
41
+ }
42
+
24
43
  /*
25
44
  * Return true, if the redis command accepts no arguments, otherwise
26
45
  * return false
@@ -32,6 +51,7 @@ redis_arg0(struct msg *r)
32
51
  case MSG_REQ_REDIS_EXISTS:
33
52
  case MSG_REQ_REDIS_PERSIST:
34
53
  case MSG_REQ_REDIS_PTTL:
54
+ case MSG_REQ_REDIS_SORT:
35
55
  case MSG_REQ_REDIS_TTL:
36
56
  case MSG_REQ_REDIS_TYPE:
37
57
  case MSG_REQ_REDIS_DUMP:
@@ -55,6 +75,8 @@ redis_arg0(struct msg *r)
55
75
  case MSG_REQ_REDIS_SPOP:
56
76
 
57
77
  case MSG_REQ_REDIS_ZCARD:
78
+
79
+ case MSG_REQ_REDIS_PFCOUNT:
58
80
  return true;
59
81
 
60
82
  default:
@@ -134,7 +156,9 @@ redis_arg2(struct msg *r)
134
156
  case MSG_REQ_REDIS_SMOVE:
135
157
 
136
158
  case MSG_REQ_REDIS_ZCOUNT:
159
+ case MSG_REQ_REDIS_ZLEXCOUNT:
137
160
  case MSG_REQ_REDIS_ZINCRBY:
161
+ case MSG_REQ_REDIS_ZREMRANGEBYLEX:
138
162
  case MSG_REQ_REDIS_ZREMRANGEBYRANK:
139
163
  case MSG_REQ_REDIS_ZREMRANGEBYSCORE:
140
164
 
@@ -180,6 +204,7 @@ redis_argn(struct msg *r)
180
204
  case MSG_REQ_REDIS_HDEL:
181
205
  case MSG_REQ_REDIS_HMGET:
182
206
  case MSG_REQ_REDIS_HMSET:
207
+ case MSG_REQ_REDIS_HSCAN:
183
208
 
184
209
  case MSG_REQ_REDIS_LPUSH:
185
210
  case MSG_REQ_REDIS_RPUSH:
@@ -193,6 +218,10 @@ redis_argn(struct msg *r)
193
218
  case MSG_REQ_REDIS_SUNION:
194
219
  case MSG_REQ_REDIS_SUNIONSTORE:
195
220
  case MSG_REQ_REDIS_SRANDMEMBER:
221
+ case MSG_REQ_REDIS_SSCAN:
222
+
223
+ case MSG_REQ_REDIS_PFADD:
224
+ case MSG_REQ_REDIS_PFMERGE:
196
225
 
197
226
  case MSG_REQ_REDIS_ZADD:
198
227
  case MSG_REQ_REDIS_ZINTERSTORE:
@@ -200,8 +229,10 @@ redis_argn(struct msg *r)
200
229
  case MSG_REQ_REDIS_ZRANGEBYSCORE:
201
230
  case MSG_REQ_REDIS_ZREM:
202
231
  case MSG_REQ_REDIS_ZREVRANGE:
232
+ case MSG_REQ_REDIS_ZRANGEBYLEX:
203
233
  case MSG_REQ_REDIS_ZREVRANGEBYSCORE:
204
234
  case MSG_REQ_REDIS_ZUNIONSTORE:
235
+ case MSG_REQ_REDIS_ZSCAN:
205
236
  return true;
206
237
 
207
238
  default:
@@ -230,6 +261,24 @@ redis_argx(struct msg *r)
230
261
  return false;
231
262
  }
232
263
 
264
+ /*
265
+ * Return true, if the redis command is a vector command accepting one or
266
+ * more key-value pairs, otherwise return false
267
+ */
268
+ static bool
269
+ redis_argkvx(struct msg *r)
270
+ {
271
+ switch (r->type) {
272
+ case MSG_REQ_REDIS_MSET:
273
+ return true;
274
+
275
+ default:
276
+ break;
277
+ }
278
+
279
+ return false;
280
+ }
281
+
233
282
  /*
234
283
  * Return true, if the redis command is either EVAL or EVALSHA. These commands
235
284
  * have a special format with exactly 2 arguments, followed by one or more keys,
@@ -309,7 +358,6 @@ redis_parse_req(struct msg *r)
309
358
  SW_ARGN_LEN_LF,
310
359
  SW_ARGN,
311
360
  SW_ARGN_LF,
312
- SW_FRAGMENT,
313
361
  SW_SENTINEL
314
362
  } state;
315
363
 
@@ -540,6 +588,10 @@ redis_parse_req(struct msg *r)
540
588
  r->type = MSG_REQ_REDIS_MGET;
541
589
  break;
542
590
  }
591
+ if (str4icmp(m, 'm', 's', 'e', 't')) {
592
+ r->type = MSG_REQ_REDIS_MSET;
593
+ break;
594
+ }
543
595
 
544
596
  if (str4icmp(m, 'z', 'a', 'd', 'd')) {
545
597
  r->type = MSG_REQ_REDIS_ZADD;
@@ -556,6 +608,23 @@ redis_parse_req(struct msg *r)
556
608
  break;
557
609
  }
558
610
 
611
+ if (str4icmp(m, 's', 'o', 'r', 't')) {
612
+ r->type = MSG_REQ_REDIS_SORT;
613
+ break;
614
+ }
615
+
616
+ if (str4icmp(m, 'p', 'i', 'n', 'g')) {
617
+ r->type = MSG_REQ_REDIS_PING;
618
+ r->noforward = 1;
619
+ break;
620
+ }
621
+
622
+ if (str4icmp(m, 'q', 'u', 'i', 't')) {
623
+ r->type = MSG_REQ_REDIS_QUIT;
624
+ r->quit = 1;
625
+ break;
626
+ }
627
+
559
628
  break;
560
629
 
561
630
  case 5:
@@ -579,6 +648,11 @@ redis_parse_req(struct msg *r)
579
648
  break;
580
649
  }
581
650
 
651
+ if (str5icmp(m, 'h', 's', 'c', 'a', 'n')) {
652
+ r->type = MSG_REQ_REDIS_HSCAN;
653
+ break;
654
+ }
655
+
582
656
  if (str5icmp(m, 'l', 'p', 'u', 's', 'h')) {
583
657
  r->type = MSG_REQ_REDIS_LPUSH;
584
658
  break;
@@ -619,6 +693,11 @@ redis_parse_req(struct msg *r)
619
693
  break;
620
694
  }
621
695
 
696
+ if (str5icmp(m, 's', 's', 'c', 'a', 'n')) {
697
+ r->type = MSG_REQ_REDIS_SSCAN;
698
+ break;
699
+ }
700
+
622
701
  if (str5icmp(m, 'z', 'c', 'a', 'r', 'd')) {
623
702
  r->type = MSG_REQ_REDIS_ZCARD;
624
703
  break;
@@ -629,6 +708,16 @@ redis_parse_req(struct msg *r)
629
708
  break;
630
709
  }
631
710
 
711
+ if (str5icmp(m, 'z', 's', 'c', 'a', 'n')) {
712
+ r->type = MSG_REQ_REDIS_ZSCAN;
713
+ break;
714
+ }
715
+
716
+ if (str5icmp(m, 'p', 'f', 'a', 'd', 'd')) {
717
+ r->type = MSG_REQ_REDIS_PFADD;
718
+ break;
719
+ }
720
+
632
721
  break;
633
722
 
634
723
  case 6:
@@ -780,6 +869,16 @@ redis_parse_req(struct msg *r)
780
869
  break;
781
870
  }
782
871
 
872
+ if (str7icmp(m, 'p', 'f', 'c', 'o', 'u', 'n', 't')) {
873
+ r->type = MSG_REQ_REDIS_PFCOUNT;
874
+ break;
875
+ }
876
+
877
+ if (str7icmp(m, 'p', 'f', 'm', 'e', 'r', 'g', 'e')) {
878
+ r->type = MSG_REQ_REDIS_PFMERGE;
879
+ break;
880
+ }
881
+
783
882
  break;
784
883
 
785
884
  case 8:
@@ -836,6 +935,11 @@ redis_parse_req(struct msg *r)
836
935
  break;
837
936
  }
838
937
 
938
+ if (str9icmp(m, 'z', 'l', 'e', 'x', 'c', 'o', 'u', 'n', 't')) {
939
+ r->type = MSG_REQ_REDIS_ZLEXCOUNT;
940
+ break;
941
+ }
942
+
839
943
  break;
840
944
 
841
945
  case 10:
@@ -875,6 +979,11 @@ redis_parse_req(struct msg *r)
875
979
  break;
876
980
  }
877
981
 
982
+ if (str11icmp(m, 'z', 'r', 'a', 'n', 'g', 'e', 'b', 'y', 'l', 'e', 'x')) {
983
+ r->type = MSG_REQ_REDIS_ZRANGEBYLEX;
984
+ break;
985
+ }
986
+
878
987
  break;
879
988
 
880
989
  case 12:
@@ -894,6 +1003,14 @@ redis_parse_req(struct msg *r)
894
1003
 
895
1004
  break;
896
1005
 
1006
+ case 14:
1007
+ if (str14icmp(m, 'z', 'r', 'e', 'm', 'r', 'a', 'n', 'g', 'e', 'b', 'y', 'l', 'e', 'x')) {
1008
+ r->type = MSG_REQ_REDIS_ZREMRANGEBYLEX;
1009
+ break;
1010
+ }
1011
+
1012
+ break;
1013
+
897
1014
  case 15:
898
1015
  if (str15icmp(m, 'z', 'r', 'e', 'm', 'r', 'a', 'n', 'g', 'e', 'b', 'y', 'r', 'a', 'n', 'k')) {
899
1016
  r->type = MSG_REQ_REDIS_ZREMRANGEBYRANK;
@@ -932,7 +1049,9 @@ redis_parse_req(struct msg *r)
932
1049
  case SW_REQ_TYPE_LF:
933
1050
  switch (ch) {
934
1051
  case LF:
935
- if (redis_argeval(r)) {
1052
+ if (redis_argz(r)) {
1053
+ goto done;
1054
+ } else if (redis_argeval(r)) {
936
1055
  state = SW_ARG1_LEN;
937
1056
  } else {
938
1057
  state = SW_KEY_LEN;
@@ -1005,17 +1124,23 @@ redis_parse_req(struct msg *r)
1005
1124
 
1006
1125
  if (*m != CR) {
1007
1126
  goto error;
1008
- }
1127
+ } else { /* got a key */
1128
+ struct keypos *kpos;
1009
1129
 
1010
- p = m; /* move forward by rlen bytes */
1011
- r->rlen = 0;
1012
- m = r->token;
1013
- r->token = NULL;
1130
+ p = m; /* move forward by rlen bytes */
1131
+ r->rlen = 0;
1132
+ m = r->token;
1133
+ r->token = NULL;
1014
1134
 
1015
- r->key_start = m;
1016
- r->key_end = p;
1135
+ kpos = array_push(r->keys);
1136
+ if (kpos == NULL) {
1137
+ goto enomem;
1138
+ }
1139
+ kpos->start = m;
1140
+ kpos->end = p;
1017
1141
 
1018
- state = SW_KEY_LF;
1142
+ state = SW_KEY_LF;
1143
+ }
1019
1144
 
1020
1145
  break;
1021
1146
 
@@ -1051,7 +1176,12 @@ redis_parse_req(struct msg *r)
1051
1176
  if (r->rnarg == 0) {
1052
1177
  goto done;
1053
1178
  }
1054
- state = SW_FRAGMENT;
1179
+ state = SW_KEY_LEN;
1180
+ } else if (redis_argkvx(r)) {
1181
+ if (r->rnarg == 0) {
1182
+ goto done;
1183
+ }
1184
+ state = SW_ARG1_LEN;
1055
1185
  } else if (redis_argeval(r)) {
1056
1186
  if (r->rnarg == 0) {
1057
1187
  goto done;
@@ -1069,10 +1199,6 @@ redis_parse_req(struct msg *r)
1069
1199
 
1070
1200
  break;
1071
1201
 
1072
- case SW_FRAGMENT:
1073
- r->token = p;
1074
- goto fragment;
1075
-
1076
1202
  case SW_ARG1_LEN:
1077
1203
  if (r->token == NULL) {
1078
1204
  if (ch != '$') {
@@ -1155,6 +1281,11 @@ redis_parse_req(struct msg *r)
1155
1281
  goto error;
1156
1282
  }
1157
1283
  state = SW_ARG2_LEN;
1284
+ } else if (redis_argkvx(r)) {
1285
+ if (r->rnarg == 0) {
1286
+ goto done;
1287
+ }
1288
+ state = SW_KEY_LEN;
1158
1289
  } else {
1159
1290
  goto error;
1160
1291
  }
@@ -1387,7 +1518,7 @@ redis_parse_req(struct msg *r)
1387
1518
  r->rnarg--;
1388
1519
  r->token = NULL;
1389
1520
  state = SW_ARGN_LEN_LF;
1390
- } else {
1521
+ } else {
1391
1522
  goto error;
1392
1523
  }
1393
1524
 
@@ -1468,19 +1599,6 @@ redis_parse_req(struct msg *r)
1468
1599
  r->state, r->pos - b->pos, b->last - b->pos);
1469
1600
  return;
1470
1601
 
1471
- fragment:
1472
- ASSERT(p != b->last);
1473
- ASSERT(r->token != NULL);
1474
- r->pos = r->token;
1475
- r->token = NULL;
1476
- r->state = state;
1477
- r->result = MSG_PARSE_FRAGMENT;
1478
-
1479
- log_hexdump(LOG_VERB, b->pos, mbuf_length(b), "parsed req %"PRIu64" res %d "
1480
- "type %d state %d rpos %d of %d", r->id, r->result, r->type,
1481
- r->state, r->pos - b->pos, b->last - b->pos);
1482
- return;
1483
-
1484
1602
  done:
1485
1603
  ASSERT(r->type > MSG_UNKNOWN && r->type < MSG_SENTINEL);
1486
1604
  r->pos = p + 1;
@@ -1494,6 +1612,15 @@ done:
1494
1612
  r->state, r->pos - b->pos, b->last - b->pos);
1495
1613
  return;
1496
1614
 
1615
+ enomem:
1616
+ r->result = MSG_PARSE_ERROR;
1617
+ r->state = state;
1618
+
1619
+ log_hexdump(LOG_INFO, b->pos, mbuf_length(b), "out of memory on parse req %"PRIu64" "
1620
+ "res %d type %d state %d", r->id, r->result, r->type, r->state);
1621
+
1622
+ return;
1623
+
1497
1624
  error:
1498
1625
  r->result = MSG_PARSE_ERROR;
1499
1626
  r->state = state;
@@ -1789,7 +1916,28 @@ redis_parse_rsp(struct msg *r)
1789
1916
  *
1790
1917
  * Here, we only handle a multi bulk reply element that
1791
1918
  * are either integer reply or bulk reply.
1919
+ *
1920
+ * there is a special case for sscan/hscan/zscan, these command
1921
+ * replay a nested multi-bulk with a number and a multi bulk like this:
1922
+ *
1923
+ * - mulit-bulk
1924
+ * - cursor
1925
+ * - mulit-bulk
1926
+ * - val1
1927
+ * - val2
1928
+ * - val3
1929
+ *
1930
+ * in this case, there is only one sub-multi-bulk,
1931
+ * and it's the last element of parent,
1932
+ * we can handle it like tail-recursive.
1933
+ *
1792
1934
  */
1935
+ if (ch == '*') { /* for sscan/hscan/zscan only */
1936
+ p = p - 1; /* go back by 1 byte */
1937
+ state = SW_MULTIBULK;
1938
+ break;
1939
+ }
1940
+
1793
1941
  if (ch != '$' && ch != ':') {
1794
1942
  goto error;
1795
1943
  }
@@ -1813,7 +1961,6 @@ redis_parse_rsp(struct msg *r)
1813
1961
  }
1814
1962
  r->rnarg--;
1815
1963
  r->token = NULL;
1816
-
1817
1964
  } else {
1818
1965
  goto error;
1819
1966
  }
@@ -1916,77 +2063,77 @@ error:
1916
2063
  }
1917
2064
 
1918
2065
  /*
1919
- * Pre-split copy handler invoked when the request is a multi vector -
1920
- * 'mget' or 'del' request and is about to be split into two requests
1921
- */
1922
- void
1923
- redis_pre_splitcopy(struct mbuf *mbuf, void *arg)
2066
+ * copy one bulk from src to dst
2067
+ *
2068
+ * if dst == NULL, we just eat the bulk
2069
+ *
2070
+ * */
2071
+ static rstatus_t
2072
+ redis_copy_bulk(struct msg *dst, struct msg *src)
1924
2073
  {
1925
- struct msg *r = arg;
1926
- int n;
1927
-
1928
- ASSERT(r->request);
1929
- ASSERT(r->narg > 1);
1930
- ASSERT(mbuf_empty(mbuf));
1931
-
1932
- switch (r->type) {
1933
- case MSG_REQ_REDIS_MGET:
1934
- n = nc_snprintf(mbuf->last, mbuf_size(mbuf), "*%d\r\n$4\r\nmget\r\n",
1935
- r->narg - 1);
1936
- break;
1937
-
1938
- case MSG_REQ_REDIS_DEL:
1939
- n = nc_snprintf(mbuf->last, mbuf_size(mbuf), "*%d\r\n$3\r\ndel\r\n",
1940
- r->narg - 1);
1941
- break;
1942
-
1943
- default:
1944
- n = 0;
1945
- NOT_REACHED();
2074
+ struct mbuf *mbuf, *nbuf;
2075
+ uint8_t *p;
2076
+ uint32_t len = 0;
2077
+ uint32_t bytes = 0;
2078
+ rstatus_t status;
2079
+
2080
+ for (mbuf = STAILQ_FIRST(&src->mhdr);
2081
+ mbuf && mbuf_empty(mbuf);
2082
+ mbuf = STAILQ_FIRST(&src->mhdr)) {
2083
+
2084
+ mbuf_remove(&src->mhdr, mbuf);
2085
+ mbuf_put(mbuf);
1946
2086
  }
1947
2087
 
1948
- mbuf->last += n;
1949
- }
1950
-
1951
- /*
1952
- * Post-split copy handler invoked when the request is a multi vector -
1953
- * 'mget' or 'del' request and has already been split into two requests
1954
- */
1955
- rstatus_t
1956
- redis_post_splitcopy(struct msg *r)
1957
- {
1958
- struct mbuf *hbuf, *nhbuf; /* head mbuf and new head mbuf */
1959
- struct string hstr = string("*2"); /* header string */
1960
-
1961
- ASSERT(r->request);
1962
- ASSERT(r->type == MSG_REQ_REDIS_MGET || r->type == MSG_REQ_REDIS_DEL);
1963
- ASSERT(!STAILQ_EMPTY(&r->mhdr));
1964
-
1965
- nhbuf = mbuf_get();
1966
- if (nhbuf == NULL) {
1967
- return NC_ENOMEM;
2088
+ mbuf = STAILQ_FIRST(&src->mhdr);
2089
+ if (mbuf == NULL) {
2090
+ return NC_ERROR;
1968
2091
  }
1969
2092
 
1970
- /*
1971
- * Fix the head mbuf in the head (A) msg. The fix is straightforward
1972
- * as we just need to skip over the narg token
1973
- */
1974
- hbuf = STAILQ_FIRST(&r->mhdr);
1975
- ASSERT(hbuf->pos == r->narg_start);
1976
- ASSERT(hbuf->pos < r->narg_end && r->narg_end <= hbuf->last);
1977
- hbuf->pos = r->narg_end;
1978
-
1979
- /*
1980
- * Add a new head mbuf in the head (A) msg that just contains '*2'
1981
- * token
1982
- */
1983
- STAILQ_INSERT_HEAD(&r->mhdr, nhbuf, next);
1984
- mbuf_copy(nhbuf, hstr.data, hstr.len);
2093
+ p = mbuf->pos;
2094
+ ASSERT(*p == '$');
2095
+ p++;
1985
2096
 
1986
- /* fix up the narg_start and narg_end */
1987
- r->narg_start = nhbuf->pos;
1988
- r->narg_end = nhbuf->last;
2097
+ if (p[0] == '-' && p[1] == '1') {
2098
+ len = 1 + 2 + CRLF_LEN; /* $-1\r\n */
2099
+ p = mbuf->pos + len;
2100
+ } else {
2101
+ len = 0;
2102
+ for (; p < mbuf->last && isdigit(*p); p++) {
2103
+ len = len * 10 + (uint32_t)(*p - '0');
2104
+ }
2105
+ len += CRLF_LEN * 2;
2106
+ len += (p - mbuf->pos);
2107
+ }
2108
+ bytes = len;
2109
+
2110
+ /* copy len bytes to dst */
2111
+ for (; mbuf;) {
2112
+ if (mbuf_length(mbuf) <= len) { /* steal this buf from src to dst */
2113
+ nbuf = STAILQ_NEXT(mbuf, next);
2114
+ mbuf_remove(&src->mhdr, mbuf);
2115
+ if (dst != NULL) {
2116
+ mbuf_insert(&dst->mhdr, mbuf);
2117
+ }
2118
+ len -= mbuf_length(mbuf);
2119
+ mbuf = nbuf;
2120
+ } else { /* split it */
2121
+ if (dst != NULL) {
2122
+ status = msg_append(dst, mbuf->pos, len);
2123
+ if (status != NC_OK) {
2124
+ return status;
2125
+ }
2126
+ }
2127
+ mbuf->pos += len;
2128
+ break;
2129
+ }
2130
+ }
1989
2131
 
2132
+ if (dst != NULL) {
2133
+ dst->mlen += bytes;
2134
+ }
2135
+ src->mlen -= bytes;
2136
+ log_debug(LOG_VVERB, "redis_copy_bulk copy bytes: %d", bytes);
1990
2137
  return NC_OK;
1991
2138
  }
1992
2139
 
@@ -2008,6 +2155,7 @@ redis_pre_coalesce(struct msg *r)
2008
2155
  /* do nothing, if not a response to a fragmented request */
2009
2156
  return;
2010
2157
  }
2158
+ pr->frag_owner->nfrag_done++;
2011
2159
 
2012
2160
  switch (r->type) {
2013
2161
  case MSG_RSP_REDIS_INTEGER:
@@ -2049,14 +2197,13 @@ redis_pre_coalesce(struct msg *r)
2049
2197
  r->mlen -= (uint32_t)(r->narg_end - r->narg_start);
2050
2198
  mbuf->pos = r->narg_end;
2051
2199
 
2052
- if (pr->first_fragment) {
2053
- mbuf = mbuf_get();
2054
- if (mbuf == NULL) {
2055
- pr->error = 1;
2056
- pr->err = EINVAL;
2057
- return;
2058
- }
2059
- STAILQ_INSERT_HEAD(&r->mhdr, mbuf, next);
2200
+ break;
2201
+
2202
+ case MSG_RSP_REDIS_STATUS:
2203
+ if (pr->type == MSG_REQ_REDIS_MSET) { /* MSET segments */
2204
+ mbuf = STAILQ_FIRST(&r->mhdr);
2205
+ r->mlen -= mbuf_length(mbuf);
2206
+ mbuf_rewind(mbuf);
2060
2207
  }
2061
2208
  break;
2062
2209
 
@@ -2075,6 +2222,309 @@ redis_pre_coalesce(struct msg *r)
2075
2222
  }
2076
2223
  }
2077
2224
 
2225
+ static rstatus_t
2226
+ redis_append_key(struct msg *r, uint8_t *key, uint32_t keylen)
2227
+ {
2228
+ uint32_t len;
2229
+ struct mbuf *mbuf;
2230
+ uint8_t printbuf[32];
2231
+ struct keypos *kpos;
2232
+
2233
+ /* 1. keylen */
2234
+ len = (uint32_t)nc_snprintf(printbuf, sizeof(printbuf), "$%d\r\n", keylen);
2235
+ mbuf = msg_ensure_mbuf(r, len);
2236
+ if (mbuf == NULL) {
2237
+ return NC_ENOMEM;
2238
+ }
2239
+ mbuf_copy(mbuf, printbuf, len);
2240
+ r->mlen += len;
2241
+
2242
+ /* 2. key */
2243
+ mbuf = msg_ensure_mbuf(r, keylen);
2244
+ if (mbuf == NULL) {
2245
+ return NC_ENOMEM;
2246
+ }
2247
+
2248
+ kpos = array_push(r->keys);
2249
+ if (kpos == NULL) {
2250
+ return NC_ENOMEM;
2251
+ }
2252
+
2253
+ kpos->start = mbuf->last;
2254
+ kpos->end = mbuf->last + keylen;
2255
+ mbuf_copy(mbuf, key, keylen);
2256
+ r->mlen += keylen;
2257
+
2258
+ /* 3. CRLF */
2259
+ mbuf = msg_ensure_mbuf(r, CRLF_LEN);
2260
+ if (mbuf == NULL) {
2261
+ return NC_ENOMEM;
2262
+ }
2263
+ mbuf_copy(mbuf, (uint8_t *)CRLF, CRLF_LEN);
2264
+ r->mlen += (uint32_t)CRLF_LEN;
2265
+
2266
+ return NC_OK;
2267
+ }
2268
+
2269
+ /*
2270
+ * input a msg, return a msg chain.
2271
+ * ncontinuum is the number of backend redis/memcache server
2272
+ *
2273
+ * the original msg will be fragment into at most ncontinuum fragments.
2274
+ * all the keys map to the same backend will group into one fragment.
2275
+ *
2276
+ * frag_id:
2277
+ * a unique fragment id for all fragments of the message vector. including the orig msg.
2278
+ *
2279
+ * frag_owner:
2280
+ * All fragments of the message use frag_owner point to the orig msg
2281
+ *
2282
+ * frag_seq:
2283
+ * the map from each key to it's fragment, (only in the orig msg)
2284
+ *
2285
+ * For example, a message vector with 3 keys:
2286
+ *
2287
+ * get key1 key2 key3
2288
+ *
2289
+ * suppose we have 2 backend server, and the map is:
2290
+ *
2291
+ * key1 => backend 0
2292
+ * key2 => backend 1
2293
+ * key3 => backend 0
2294
+ *
2295
+ * it will fragment like this:
2296
+ *
2297
+ * +-----------------+
2298
+ * | msg vector |
2299
+ * |(original msg) |
2300
+ * |key1, key2, key3 |
2301
+ * +-----------------+
2302
+ *
2303
+ * frag_owner
2304
+ * /--------------------------------------+
2305
+ * frag_owner / |
2306
+ * /-----------+ | /------------+ frag_owner |
2307
+ * | | | | | |
2308
+ * | v v v | |
2309
+ * +--------------------+ +---------------------+ +----+----------------+
2310
+ * | frag_id = 10 | | frag_id = 10 | | frag_id = 10 |
2311
+ * | nfrag = 3 | | nfrag = 0 | | nfrag = 0 |
2312
+ * | frag_seq = x x x | | key1, key3 | | key2 |
2313
+ * +------------|-|-|---+ +---------------------+ +---------------------+
2314
+ * | | | ^ ^ ^
2315
+ * | \ \ | | |
2316
+ * | \ ----------+ | |
2317
+ * +---\---------------+ |
2318
+ * ------------------------------------------+
2319
+ *
2320
+ */
2321
+ static rstatus_t
2322
+ redis_fragment_argx(struct msg *r, uint32_t ncontinuum, struct msg_tqh *frag_msgq,
2323
+ uint32_t key_step)
2324
+ {
2325
+ struct mbuf *mbuf;
2326
+ struct msg **sub_msgs;
2327
+ uint32_t i;
2328
+ rstatus_t status;
2329
+
2330
+ ASSERT(array_n(r->keys) == (r->narg - 1) / key_step);
2331
+
2332
+ sub_msgs = nc_zalloc(ncontinuum * sizeof(*sub_msgs));
2333
+ if (sub_msgs == NULL) {
2334
+ return NC_ENOMEM;
2335
+ }
2336
+
2337
+ ASSERT(r->frag_seq == NULL);
2338
+ r->frag_seq = nc_alloc(array_n(r->keys) * sizeof(*r->frag_seq));
2339
+ if (r->frag_seq == NULL) {
2340
+ nc_free(sub_msgs);
2341
+ return NC_ENOMEM;
2342
+ }
2343
+
2344
+ mbuf = STAILQ_FIRST(&r->mhdr);
2345
+ mbuf->pos = mbuf->start;
2346
+
2347
+ /*
2348
+ * This code is based on the assumption that '*narg\r\n$4\r\nMGET\r\n' is located
2349
+ * in a contiguous location.
2350
+ * This is always true because we have capped our MBUF_MIN_SIZE at 512 and
2351
+ * whenever we have multiple messages, we copy the tail message into a new mbuf
2352
+ */
2353
+ for (i = 0; i < 3; i++) { /* eat *narg\r\n$4\r\nMGET\r\n */
2354
+ for (; *(mbuf->pos) != '\n';) {
2355
+ mbuf->pos++;
2356
+ }
2357
+ mbuf->pos++;
2358
+ }
2359
+
2360
+ r->frag_id = msg_gen_frag_id();
2361
+ r->nfrag = 0;
2362
+ r->frag_owner = r;
2363
+
2364
+ for (i = 0; i < array_n(r->keys); i++) { /* for each key */
2365
+ struct msg *sub_msg;
2366
+ struct keypos *kpos = array_get(r->keys, i);
2367
+ uint32_t idx = msg_backend_idx(r, kpos->start, kpos->end - kpos->start);
2368
+
2369
+ if (sub_msgs[idx] == NULL) {
2370
+ sub_msgs[idx] = msg_get(r->owner, r->request, r->redis);
2371
+ if (sub_msgs[idx] == NULL) {
2372
+ nc_free(sub_msgs);
2373
+ return NC_ENOMEM;
2374
+ }
2375
+ }
2376
+ r->frag_seq[i] = sub_msg = sub_msgs[idx];
2377
+
2378
+ sub_msg->narg++;
2379
+ status = redis_append_key(sub_msg, kpos->start, kpos->end - kpos->start);
2380
+ if (status != NC_OK) {
2381
+ nc_free(sub_msgs);
2382
+ return status;
2383
+ }
2384
+
2385
+ if (key_step == 1) { /* mget,del */
2386
+ continue;
2387
+ } else { /* mset */
2388
+ status = redis_copy_bulk(NULL, r); /* eat key */
2389
+ if (status != NC_OK) {
2390
+ nc_free(sub_msgs);
2391
+ return status;
2392
+ }
2393
+
2394
+ status = redis_copy_bulk(sub_msg, r);
2395
+ if (status != NC_OK) {
2396
+ nc_free(sub_msgs);
2397
+ return status;
2398
+ }
2399
+
2400
+ sub_msg->narg++;
2401
+ }
2402
+ }
2403
+
2404
+ for (i = 0; i < ncontinuum; i++) { /* prepend mget header, and forward it */
2405
+ struct msg *sub_msg = sub_msgs[i];
2406
+ if (sub_msg == NULL) {
2407
+ continue;
2408
+ }
2409
+
2410
+ if (r->type == MSG_REQ_REDIS_MGET) {
2411
+ status = msg_prepend_format(sub_msg, "*%d\r\n$4\r\nmget\r\n",
2412
+ sub_msg->narg + 1);
2413
+ } else if (r->type == MSG_REQ_REDIS_DEL) {
2414
+ status = msg_prepend_format(sub_msg, "*%d\r\n$3\r\ndel\r\n",
2415
+ sub_msg->narg + 1);
2416
+ } else if (r->type == MSG_REQ_REDIS_MSET) {
2417
+ status = msg_prepend_format(sub_msg, "*%d\r\n$4\r\nmset\r\n",
2418
+ sub_msg->narg + 1);
2419
+ } else {
2420
+ NOT_REACHED();
2421
+ }
2422
+ if (status != NC_OK) {
2423
+ nc_free(sub_msgs);
2424
+ return status;
2425
+ }
2426
+
2427
+ sub_msg->type = r->type;
2428
+ sub_msg->frag_id = r->frag_id;
2429
+ sub_msg->frag_owner = r->frag_owner;
2430
+
2431
+ TAILQ_INSERT_TAIL(frag_msgq, sub_msg, m_tqe);
2432
+ r->nfrag++;
2433
+ }
2434
+
2435
+ nc_free(sub_msgs);
2436
+ return NC_OK;
2437
+ }
2438
+
2439
+ rstatus_t
2440
+ redis_fragment(struct msg *r, uint32_t ncontinuum, struct msg_tqh *frag_msgq)
2441
+ {
2442
+ switch (r->type) {
2443
+ case MSG_REQ_REDIS_MGET:
2444
+ case MSG_REQ_REDIS_DEL:
2445
+ return redis_fragment_argx(r, ncontinuum, frag_msgq, 1);
2446
+ case MSG_REQ_REDIS_MSET:
2447
+ return redis_fragment_argx(r, ncontinuum, frag_msgq, 2);
2448
+ default:
2449
+ return NC_OK;
2450
+ }
2451
+ }
2452
+
2453
+ rstatus_t
2454
+ redis_reply(struct msg *r)
2455
+ {
2456
+ struct msg *response = r->peer;
2457
+
2458
+ ASSERT(response != NULL);
2459
+
2460
+ switch (r->type) {
2461
+ case MSG_REQ_REDIS_PING:
2462
+ return msg_append(response, (uint8_t *)"+PONG\r\n", 7);
2463
+
2464
+ default:
2465
+ NOT_REACHED();
2466
+ return NC_ERROR;
2467
+ }
2468
+ }
2469
+
2470
+ void
2471
+ redis_post_coalesce_mset(struct msg *request)
2472
+ {
2473
+ struct msg *response = request->peer;
2474
+ rstatus_t status;
2475
+
2476
+ status = msg_append(response, (uint8_t *)"+OK\r\n", 5);
2477
+ if (status != NC_OK) {
2478
+ response->error = 1; /* mark this msg as err */
2479
+ response->err = errno;
2480
+ }
2481
+ }
2482
+
2483
+ void
2484
+ redis_post_coalesce_del(struct msg *request)
2485
+ {
2486
+ struct msg *response = request->peer;
2487
+ rstatus_t status;
2488
+
2489
+ status = msg_prepend_format(response, ":%d\r\n", request->integer);
2490
+ if (status != NC_OK) {
2491
+ response->error = 1;
2492
+ response->err = errno;
2493
+ }
2494
+ }
2495
+
2496
+ static void
2497
+ redis_post_coalesce_mget(struct msg *request)
2498
+ {
2499
+ struct msg *response = request->peer;
2500
+ struct msg *sub_msg;
2501
+ rstatus_t status;
2502
+ uint32_t i;
2503
+
2504
+ status = msg_prepend_format(response, "*%d\r\n", request->narg - 1);
2505
+ if (status != NC_OK) {
2506
+ /*
2507
+ * the fragments is still in c_conn->omsg_q, we have to discard all of them,
2508
+ * we just close the conn here
2509
+ */
2510
+ response->owner->err = 1;
2511
+ return;
2512
+ }
2513
+
2514
+ for (i = 0; i < array_n(request->keys); i++) { /* for each key */
2515
+ sub_msg = request->frag_seq[i]->peer; /* get it's peer response */
2516
+ if (sub_msg == NULL) {
2517
+ response->owner->err = 1;
2518
+ return;
2519
+ }
2520
+ status = redis_copy_bulk(response, sub_msg);
2521
+ if (status != NC_OK) {
2522
+ response->owner->err = 1;
2523
+ return;
2524
+ }
2525
+ }
2526
+ }
2527
+
2078
2528
  /*
2079
2529
  * Post-coalesce handler is invoked when the message is a response to
2080
2530
  * the fragmented multi vector request - 'mget' or 'del' and all the
@@ -2085,44 +2535,21 @@ void
2085
2535
  redis_post_coalesce(struct msg *r)
2086
2536
  {
2087
2537
  struct msg *pr = r->peer; /* peer response */
2088
- struct mbuf *mbuf;
2089
- int n;
2090
2538
 
2091
- ASSERT(r->request && r->first_fragment);
2539
+ ASSERT(!pr->request);
2540
+ ASSERT(r->request && (r->frag_owner == r));
2092
2541
  if (r->error || r->ferror) {
2093
2542
  /* do nothing, if msg is in error */
2094
2543
  return;
2095
2544
  }
2096
2545
 
2097
- ASSERT(!pr->request);
2098
-
2099
- switch (pr->type) {
2100
- case MSG_RSP_REDIS_INTEGER:
2101
- /* only redis 'del' fragmented request sends back integer reply */
2102
- ASSERT(r->type == MSG_REQ_REDIS_DEL);
2103
-
2104
- mbuf = STAILQ_FIRST(&pr->mhdr);
2105
-
2106
- ASSERT(pr->mlen == 0);
2107
- ASSERT(mbuf_empty(mbuf));
2108
-
2109
- n = nc_scnprintf(mbuf->last, mbuf_size(mbuf), ":%d\r\n", r->integer);
2110
- mbuf->last += n;
2111
- pr->mlen += (uint32_t)n;
2112
- break;
2113
-
2114
- case MSG_RSP_REDIS_MULTIBULK:
2115
- /* only redis 'mget' fragmented request sends back multi-bulk reply */
2116
- ASSERT(r->type == MSG_REQ_REDIS_MGET);
2117
-
2118
- mbuf = STAILQ_FIRST(&pr->mhdr);
2119
- ASSERT(mbuf_empty(mbuf));
2120
-
2121
- n = nc_scnprintf(mbuf->last, mbuf_size(mbuf), "*%d\r\n", r->nfrag);
2122
- mbuf->last += n;
2123
- pr->mlen += (uint32_t)n;
2124
- break;
2125
-
2546
+ switch (r->type) {
2547
+ case MSG_REQ_REDIS_MGET:
2548
+ return redis_post_coalesce_mget(r);
2549
+ case MSG_REQ_REDIS_DEL:
2550
+ return redis_post_coalesce_del(r);
2551
+ case MSG_REQ_REDIS_MSET:
2552
+ return redis_post_coalesce_mset(r);
2126
2553
  default:
2127
2554
  NOT_REACHED();
2128
2555
  }