nutcracker 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (149) hide show
  1. data/README.md +22 -0
  2. data/Rakefile +55 -0
  3. data/bin/nutcracker +2 -0
  4. data/ext/nutcracker/ChangeLog +66 -0
  5. data/ext/nutcracker/LICENSE +177 -0
  6. data/ext/nutcracker/Makefile.am +7 -0
  7. data/ext/nutcracker/Makefile.in +726 -0
  8. data/ext/nutcracker/NOTICE +124 -0
  9. data/ext/nutcracker/README.md +240 -0
  10. data/ext/nutcracker/aclocal.m4 +956 -0
  11. data/ext/nutcracker/conf/nutcracker.leaf.yml +10 -0
  12. data/ext/nutcracker/conf/nutcracker.root.yml +8 -0
  13. data/ext/nutcracker/conf/nutcracker.yml +67 -0
  14. data/ext/nutcracker/config.h.in +316 -0
  15. data/ext/nutcracker/config/config.guess +1561 -0
  16. data/ext/nutcracker/config/config.sub +1686 -0
  17. data/ext/nutcracker/config/depcomp +630 -0
  18. data/ext/nutcracker/config/install-sh +520 -0
  19. data/ext/nutcracker/config/ltmain.sh +8413 -0
  20. data/ext/nutcracker/config/missing +376 -0
  21. data/ext/nutcracker/configure +18862 -0
  22. data/ext/nutcracker/configure.ac +155 -0
  23. data/ext/nutcracker/contrib/Makefile.am +3 -0
  24. data/ext/nutcracker/contrib/Makefile.in +560 -0
  25. data/ext/nutcracker/contrib/yaml-0.1.4.tar.gz +0 -0
  26. data/ext/nutcracker/contrib/yaml-0.1.4/LICENSE +19 -0
  27. data/ext/nutcracker/contrib/yaml-0.1.4/Makefile.am +20 -0
  28. data/ext/nutcracker/contrib/yaml-0.1.4/Makefile.in +736 -0
  29. data/ext/nutcracker/contrib/yaml-0.1.4/README +27 -0
  30. data/ext/nutcracker/contrib/yaml-0.1.4/aclocal.m4 +956 -0
  31. data/ext/nutcracker/contrib/yaml-0.1.4/config.h.in +80 -0
  32. data/ext/nutcracker/contrib/yaml-0.1.4/config/config.guess +1561 -0
  33. data/ext/nutcracker/contrib/yaml-0.1.4/config/config.sub +1686 -0
  34. data/ext/nutcracker/contrib/yaml-0.1.4/config/depcomp +630 -0
  35. data/ext/nutcracker/contrib/yaml-0.1.4/config/install-sh +520 -0
  36. data/ext/nutcracker/contrib/yaml-0.1.4/config/ltmain.sh +8406 -0
  37. data/ext/nutcracker/contrib/yaml-0.1.4/config/missing +376 -0
  38. data/ext/nutcracker/contrib/yaml-0.1.4/configure +13085 -0
  39. data/ext/nutcracker/contrib/yaml-0.1.4/configure.ac +75 -0
  40. data/ext/nutcracker/contrib/yaml-0.1.4/doc/doxygen.cfg +222 -0
  41. data/ext/nutcracker/contrib/yaml-0.1.4/include/yaml.h +1971 -0
  42. data/ext/nutcracker/contrib/yaml-0.1.4/m4/libtool.m4 +7357 -0
  43. data/ext/nutcracker/contrib/yaml-0.1.4/m4/ltoptions.m4 +368 -0
  44. data/ext/nutcracker/contrib/yaml-0.1.4/m4/ltsugar.m4 +123 -0
  45. data/ext/nutcracker/contrib/yaml-0.1.4/m4/ltversion.m4 +23 -0
  46. data/ext/nutcracker/contrib/yaml-0.1.4/m4/lt~obsolete.m4 +92 -0
  47. data/ext/nutcracker/contrib/yaml-0.1.4/src/Makefile.am +4 -0
  48. data/ext/nutcracker/contrib/yaml-0.1.4/src/Makefile.in +484 -0
  49. data/ext/nutcracker/contrib/yaml-0.1.4/src/api.c +1392 -0
  50. data/ext/nutcracker/contrib/yaml-0.1.4/src/dumper.c +394 -0
  51. data/ext/nutcracker/contrib/yaml-0.1.4/src/emitter.c +2329 -0
  52. data/ext/nutcracker/contrib/yaml-0.1.4/src/loader.c +432 -0
  53. data/ext/nutcracker/contrib/yaml-0.1.4/src/parser.c +1374 -0
  54. data/ext/nutcracker/contrib/yaml-0.1.4/src/reader.c +465 -0
  55. data/ext/nutcracker/contrib/yaml-0.1.4/src/scanner.c +3570 -0
  56. data/ext/nutcracker/contrib/yaml-0.1.4/src/writer.c +141 -0
  57. data/ext/nutcracker/contrib/yaml-0.1.4/src/yaml_private.h +640 -0
  58. data/ext/nutcracker/contrib/yaml-0.1.4/tests/Makefile.am +8 -0
  59. data/ext/nutcracker/contrib/yaml-0.1.4/tests/Makefile.in +675 -0
  60. data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-deconstructor-alt.c +800 -0
  61. data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-deconstructor.c +1130 -0
  62. data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-reformatter-alt.c +217 -0
  63. data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-reformatter.c +202 -0
  64. data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-dumper.c +311 -0
  65. data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-emitter.c +327 -0
  66. data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-loader.c +63 -0
  67. data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-parser.c +63 -0
  68. data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-scanner.c +63 -0
  69. data/ext/nutcracker/contrib/yaml-0.1.4/tests/test-reader.c +354 -0
  70. data/ext/nutcracker/contrib/yaml-0.1.4/tests/test-version.c +29 -0
  71. data/ext/nutcracker/extconf.rb +5 -0
  72. data/ext/nutcracker/m4/libtool.m4 +7376 -0
  73. data/ext/nutcracker/m4/ltoptions.m4 +368 -0
  74. data/ext/nutcracker/m4/ltsugar.m4 +123 -0
  75. data/ext/nutcracker/m4/ltversion.m4 +23 -0
  76. data/ext/nutcracker/m4/lt~obsolete.m4 +92 -0
  77. data/ext/nutcracker/notes/c-styleguide.txt +425 -0
  78. data/ext/nutcracker/notes/debug.txt +96 -0
  79. data/ext/nutcracker/notes/memcache.txt +123 -0
  80. data/ext/nutcracker/notes/recommendation.md +118 -0
  81. data/ext/nutcracker/notes/redis.md +415 -0
  82. data/ext/nutcracker/notes/socket.txt +131 -0
  83. data/ext/nutcracker/scripts/multi_get.sh +26 -0
  84. data/ext/nutcracker/scripts/nutcracker.init +73 -0
  85. data/ext/nutcracker/scripts/nutcracker.spec +52 -0
  86. data/ext/nutcracker/scripts/pipelined_read.sh +23 -0
  87. data/ext/nutcracker/scripts/pipelined_write.sh +29 -0
  88. data/ext/nutcracker/scripts/populate_memcached.sh +24 -0
  89. data/ext/nutcracker/scripts/redis-check.py +23 -0
  90. data/ext/nutcracker/scripts/redis-check.sh +564 -0
  91. data/ext/nutcracker/src/Makefile.am +46 -0
  92. data/ext/nutcracker/src/Makefile.in +726 -0
  93. data/ext/nutcracker/src/hashkit/Makefile.am +22 -0
  94. data/ext/nutcracker/src/hashkit/Makefile.in +501 -0
  95. data/ext/nutcracker/src/hashkit/nc_crc32.c +105 -0
  96. data/ext/nutcracker/src/hashkit/nc_fnv.c +82 -0
  97. data/ext/nutcracker/src/hashkit/nc_hashkit.h +74 -0
  98. data/ext/nutcracker/src/hashkit/nc_hsieh.c +93 -0
  99. data/ext/nutcracker/src/hashkit/nc_jenkins.c +230 -0
  100. data/ext/nutcracker/src/hashkit/nc_ketama.c +240 -0
  101. data/ext/nutcracker/src/hashkit/nc_md5.c +379 -0
  102. data/ext/nutcracker/src/hashkit/nc_modula.c +144 -0
  103. data/ext/nutcracker/src/hashkit/nc_murmur.c +99 -0
  104. data/ext/nutcracker/src/hashkit/nc_one_at_a_time.c +51 -0
  105. data/ext/nutcracker/src/hashkit/nc_random.c +146 -0
  106. data/ext/nutcracker/src/nc.c +573 -0
  107. data/ext/nutcracker/src/nc_array.c +204 -0
  108. data/ext/nutcracker/src/nc_array.h +73 -0
  109. data/ext/nutcracker/src/nc_client.c +189 -0
  110. data/ext/nutcracker/src/nc_client.h +28 -0
  111. data/ext/nutcracker/src/nc_conf.c +1766 -0
  112. data/ext/nutcracker/src/nc_conf.h +134 -0
  113. data/ext/nutcracker/src/nc_connection.c +392 -0
  114. data/ext/nutcracker/src/nc_connection.h +99 -0
  115. data/ext/nutcracker/src/nc_core.c +334 -0
  116. data/ext/nutcracker/src/nc_core.h +131 -0
  117. data/ext/nutcracker/src/nc_event.c +214 -0
  118. data/ext/nutcracker/src/nc_event.h +39 -0
  119. data/ext/nutcracker/src/nc_log.c +254 -0
  120. data/ext/nutcracker/src/nc_log.h +120 -0
  121. data/ext/nutcracker/src/nc_mbuf.c +285 -0
  122. data/ext/nutcracker/src/nc_mbuf.h +67 -0
  123. data/ext/nutcracker/src/nc_message.c +828 -0
  124. data/ext/nutcracker/src/nc_message.h +253 -0
  125. data/ext/nutcracker/src/nc_proxy.c +359 -0
  126. data/ext/nutcracker/src/nc_proxy.h +34 -0
  127. data/ext/nutcracker/src/nc_queue.h +788 -0
  128. data/ext/nutcracker/src/nc_rbtree.c +348 -0
  129. data/ext/nutcracker/src/nc_rbtree.h +47 -0
  130. data/ext/nutcracker/src/nc_request.c +588 -0
  131. data/ext/nutcracker/src/nc_response.c +332 -0
  132. data/ext/nutcracker/src/nc_server.c +841 -0
  133. data/ext/nutcracker/src/nc_server.h +143 -0
  134. data/ext/nutcracker/src/nc_signal.c +131 -0
  135. data/ext/nutcracker/src/nc_signal.h +34 -0
  136. data/ext/nutcracker/src/nc_stats.c +1188 -0
  137. data/ext/nutcracker/src/nc_stats.h +206 -0
  138. data/ext/nutcracker/src/nc_string.c +109 -0
  139. data/ext/nutcracker/src/nc_string.h +112 -0
  140. data/ext/nutcracker/src/nc_util.c +619 -0
  141. data/ext/nutcracker/src/nc_util.h +214 -0
  142. data/ext/nutcracker/src/proto/Makefile.am +14 -0
  143. data/ext/nutcracker/src/proto/Makefile.in +482 -0
  144. data/ext/nutcracker/src/proto/nc_memcache.c +1306 -0
  145. data/ext/nutcracker/src/proto/nc_proto.h +155 -0
  146. data/ext/nutcracker/src/proto/nc_redis.c +2102 -0
  147. data/lib/nutcracker.rb +7 -0
  148. data/lib/nutcracker/version.rb +3 -0
  149. metadata +194 -0
@@ -0,0 +1,1306 @@
1
+ /*
2
+ * twemproxy - A fast and lightweight proxy for memcached protocol.
3
+ * Copyright (C) 2011 Twitter, Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ #include <ctype.h>
19
+
20
+ #include <nc_core.h>
21
+ #include <nc_proto.h>
22
+
23
+ /*
24
+ * From memcache protocol specification:
25
+ *
26
+ * Data stored by memcached is identified with the help of a key. A key
27
+ * is a text string which should uniquely identify the data for clients
28
+ * that are interested in storing and retrieving it. Currently the
29
+ * length limit of a key is set at 250 characters (of course, normally
30
+ * clients wouldn't need to use such long keys); the key must not include
31
+ * control characters or whitespace.
32
+ */
33
+ #define MEMCACHE_MAX_KEY_LENGTH 250
34
+
35
+ /*
36
+ * Return true, if the memcache command is a storage command, otherwise
37
+ * return false
38
+ */
39
+ static bool
40
+ memcache_storage(struct msg *r)
41
+ {
42
+ switch (r->type) {
43
+ case MSG_REQ_MC_SET:
44
+ case MSG_REQ_MC_CAS:
45
+ case MSG_REQ_MC_ADD:
46
+ case MSG_REQ_MC_REPLACE:
47
+ case MSG_REQ_MC_APPEND:
48
+ case MSG_REQ_MC_PREPEND:
49
+ return true;
50
+
51
+ default:
52
+ break;
53
+ }
54
+
55
+ return false;
56
+ }
57
+
58
+ /*
59
+ * Return true, if the memcache command is a cas command, otherwise
60
+ * return false
61
+ */
62
+ static bool
63
+ memcache_cas(struct msg *r)
64
+ {
65
+ if (r->type == MSG_REQ_MC_CAS) {
66
+ return true;
67
+ }
68
+
69
+ return false;
70
+ }
71
+
72
+ /*
73
+ * Return true, if the memcache command is a retrieval command, otherwise
74
+ * return false
75
+ */
76
+ static bool
77
+ memcache_retrieval(struct msg *r)
78
+ {
79
+ switch (r->type) {
80
+ case MSG_REQ_MC_GET:
81
+ case MSG_REQ_MC_GETS:
82
+ return true;
83
+
84
+ default:
85
+ break;
86
+ }
87
+
88
+ return false;
89
+ }
90
+
91
+ /*
92
+ * Return true, if the memcache command is a arithmetic command, otherwise
93
+ * return false
94
+ */
95
+ static bool
96
+ memcache_arithmetic(struct msg *r)
97
+ {
98
+ switch (r->type) {
99
+ case MSG_REQ_MC_INCR:
100
+ case MSG_REQ_MC_DECR:
101
+ return true;
102
+
103
+ default:
104
+ break;
105
+ }
106
+
107
+ return false;
108
+ }
109
+
110
+ /*
111
+ * Return true, if the memcache command is a delete command, otherwise
112
+ * return false
113
+ */
114
+ static bool
115
+ memcache_delete(struct msg *r)
116
+ {
117
+ if (r->type == MSG_REQ_MC_DELETE) {
118
+ return true;
119
+ }
120
+
121
+ return false;
122
+ }
123
+
124
+ void
125
+ memcache_parse_req(struct msg *r)
126
+ {
127
+ struct mbuf *b;
128
+ uint8_t *p, *m;
129
+ uint8_t ch;
130
+ enum {
131
+ SW_START,
132
+ SW_REQ_TYPE,
133
+ SW_SPACES_BEFORE_KEY,
134
+ SW_KEY,
135
+ SW_SPACES_BEFORE_KEYS,
136
+ SW_SPACES_BEFORE_FLAGS,
137
+ SW_FLAGS,
138
+ SW_SPACES_BEFORE_EXPIRY,
139
+ SW_EXPIRY,
140
+ SW_SPACES_BEFORE_VLEN,
141
+ SW_VLEN,
142
+ SW_SPACES_BEFORE_CAS,
143
+ SW_CAS,
144
+ SW_RUNTO_VAL,
145
+ SW_VAL,
146
+ SW_SPACES_BEFORE_NUM,
147
+ SW_NUM,
148
+ SW_RUNTO_CRLF,
149
+ SW_CRLF,
150
+ SW_NOREPLY,
151
+ SW_AFTER_NOREPLY,
152
+ SW_ALMOST_DONE,
153
+ SW_SENTINEL
154
+ } state;
155
+
156
+ state = r->state;
157
+ b = STAILQ_LAST(&r->mhdr, mbuf, next);
158
+
159
+ ASSERT(r->request);
160
+ ASSERT(!r->redis);
161
+ ASSERT(state >= SW_START && state < SW_SENTINEL);
162
+ ASSERT(b != NULL);
163
+ ASSERT(b->pos <= b->last);
164
+
165
+ /* validate the parsing maker */
166
+ ASSERT(r->pos != NULL);
167
+ ASSERT(r->pos >= b->pos && r->pos <= b->last);
168
+
169
+ for (p = r->pos; p < b->last; p++) {
170
+ ch = *p;
171
+
172
+ switch (state) {
173
+
174
+ case SW_START:
175
+ if (ch == ' ') {
176
+ break;
177
+ }
178
+
179
+ if (!islower(ch)) {
180
+ goto error;
181
+ }
182
+
183
+ /* req_start <- p; type_start <- p */
184
+ r->token = p;
185
+ state = SW_REQ_TYPE;
186
+
187
+ break;
188
+
189
+ case SW_REQ_TYPE:
190
+ if (ch == ' ' || ch == CR) {
191
+ /* type_end = p - 1 */
192
+ m = r->token;
193
+ r->token = NULL;
194
+ r->type = MSG_UNKNOWN;
195
+
196
+ switch (p - m) {
197
+
198
+ case 3:
199
+ if (str4cmp(m, 'g', 'e', 't', ' ')) {
200
+ r->type = MSG_REQ_MC_GET;
201
+ break;
202
+ }
203
+
204
+ if (str4cmp(m, 's', 'e', 't', ' ')) {
205
+ r->type = MSG_REQ_MC_SET;
206
+ break;
207
+ }
208
+
209
+ if (str4cmp(m, 'a', 'd', 'd', ' ')) {
210
+ r->type = MSG_REQ_MC_ADD;
211
+ break;
212
+ }
213
+
214
+ if (str4cmp(m, 'c', 'a', 's', ' ')) {
215
+ r->type = MSG_REQ_MC_CAS;
216
+ break;
217
+ }
218
+
219
+ break;
220
+
221
+ case 4:
222
+ if (str4cmp(m, 'g', 'e', 't', 's')) {
223
+ r->type = MSG_REQ_MC_GETS;
224
+ break;
225
+ }
226
+
227
+ if (str4cmp(m, 'i', 'n', 'c', 'r')) {
228
+ r->type = MSG_REQ_MC_INCR;
229
+ break;
230
+ }
231
+
232
+ if (str4cmp(m, 'd', 'e', 'c', 'r')) {
233
+ r->type = MSG_REQ_MC_DECR;
234
+ break;
235
+ }
236
+
237
+ if (str4cmp(m, 'q', 'u', 'i', 't')) {
238
+ r->type = MSG_REQ_MC_QUIT;
239
+ r->quit = 1;
240
+ break;
241
+ }
242
+
243
+ break;
244
+
245
+ case 6:
246
+ if (str6cmp(m, 'a', 'p', 'p', 'e', 'n', 'd')) {
247
+ r->type = MSG_REQ_MC_APPEND;
248
+ break;
249
+ }
250
+
251
+ if (str6cmp(m, 'd', 'e', 'l', 'e', 't', 'e')) {
252
+ r->type = MSG_REQ_MC_DELETE;
253
+ break;
254
+ }
255
+
256
+ break;
257
+
258
+ case 7:
259
+ if (str7cmp(m, 'p', 'r', 'e', 'p', 'e', 'n', 'd')) {
260
+ r->type = MSG_REQ_MC_PREPEND;
261
+ break;
262
+ }
263
+
264
+ if (str7cmp(m, 'r', 'e', 'p', 'l', 'a', 'c', 'e')) {
265
+ r->type = MSG_REQ_MC_REPLACE;
266
+ break;
267
+ }
268
+
269
+ break;
270
+ }
271
+
272
+ switch (r->type) {
273
+ case MSG_REQ_MC_GET:
274
+ case MSG_REQ_MC_GETS:
275
+ case MSG_REQ_MC_DELETE:
276
+ case MSG_REQ_MC_CAS:
277
+ case MSG_REQ_MC_SET:
278
+ case MSG_REQ_MC_ADD:
279
+ case MSG_REQ_MC_REPLACE:
280
+ case MSG_REQ_MC_APPEND:
281
+ case MSG_REQ_MC_PREPEND:
282
+ case MSG_REQ_MC_INCR:
283
+ case MSG_REQ_MC_DECR:
284
+ if (ch == CR) {
285
+ goto error;
286
+ }
287
+ state = SW_SPACES_BEFORE_KEY;
288
+ break;
289
+
290
+ case MSG_REQ_MC_QUIT:
291
+ p = p - 1; /* go back by 1 byte */
292
+ state = SW_CRLF;
293
+ break;
294
+
295
+ case MSG_UNKNOWN:
296
+ goto error;
297
+
298
+ default:
299
+ NOT_REACHED();
300
+ }
301
+
302
+ } else if (!islower(ch)) {
303
+ goto error;
304
+ }
305
+
306
+ break;
307
+
308
+ case SW_SPACES_BEFORE_KEY:
309
+ if (ch != ' ') {
310
+ r->token = p;
311
+ r->key_start = p;
312
+ state = SW_KEY;
313
+ }
314
+
315
+ break;
316
+
317
+ case SW_KEY:
318
+ if (ch == ' ' || ch == CR) {
319
+ if ((p - r->key_start) > MEMCACHE_MAX_KEY_LENGTH) {
320
+ log_error("parsed bad req %"PRIu64" of type %d with key "
321
+ "prefix '%.*s...' and length %d that exceeds "
322
+ "maximum key length", r->id, r->type, 16,
323
+ r->key_start, p - r->key_start);
324
+ goto error;
325
+ }
326
+ r->key_end = p;
327
+ r->token = NULL;
328
+
329
+ /* get next state */
330
+ if (memcache_storage(r)) {
331
+ state = SW_SPACES_BEFORE_FLAGS;
332
+ } else if (memcache_arithmetic(r)) {
333
+ state = SW_SPACES_BEFORE_NUM;
334
+ } else if (memcache_delete(r)) {
335
+ state = SW_RUNTO_CRLF;
336
+ } else if (memcache_retrieval(r)) {
337
+ state = SW_SPACES_BEFORE_KEYS;
338
+ } else {
339
+ state = SW_RUNTO_CRLF;
340
+ }
341
+
342
+ if (ch == CR) {
343
+ if (memcache_storage(r) || memcache_arithmetic(r)) {
344
+ goto error;
345
+ }
346
+ p = p - 1; /* go back by 1 byte */
347
+ }
348
+ }
349
+
350
+ break;
351
+
352
+ case SW_SPACES_BEFORE_KEYS:
353
+ ASSERT(memcache_retrieval(r));
354
+ switch (ch) {
355
+ case ' ':
356
+ break;
357
+
358
+ case CR:
359
+ state = SW_ALMOST_DONE;
360
+ break;
361
+
362
+ default:
363
+ r->token = p;
364
+ goto fragment;
365
+ }
366
+
367
+ break;
368
+
369
+ case SW_SPACES_BEFORE_FLAGS:
370
+ if (ch != ' ') {
371
+ if (!isdigit(ch)) {
372
+ goto error;
373
+ }
374
+ /* flags_start <- p; flags <- ch - '0' */
375
+ r->token = p;
376
+ state = SW_FLAGS;
377
+ }
378
+
379
+ break;
380
+
381
+ case SW_FLAGS:
382
+ if (isdigit(ch)) {
383
+ /* flags <- flags * 10 + (ch - '0') */
384
+ ;
385
+ } else if (ch == ' ') {
386
+ /* flags_end <- p - 1 */
387
+ r->token = NULL;
388
+ state = SW_SPACES_BEFORE_EXPIRY;
389
+ } else {
390
+ goto error;
391
+ }
392
+
393
+ break;
394
+
395
+ case SW_SPACES_BEFORE_EXPIRY:
396
+ if (ch != ' ') {
397
+ if (!isdigit(ch)) {
398
+ goto error;
399
+ }
400
+ /* expiry_start <- p; expiry <- ch - '0' */
401
+ r->token = p;
402
+ state = SW_EXPIRY;
403
+ }
404
+
405
+ break;
406
+
407
+ case SW_EXPIRY:
408
+ if (isdigit(ch)) {
409
+ /* expiry <- expiry * 10 + (ch - '0') */
410
+ ;
411
+ } else if (ch == ' ') {
412
+ /* expiry_end <- p - 1 */
413
+ r->token = NULL;
414
+ state = SW_SPACES_BEFORE_VLEN;
415
+ } else {
416
+ goto error;
417
+ }
418
+
419
+ break;
420
+
421
+ case SW_SPACES_BEFORE_VLEN:
422
+ if (ch != ' ') {
423
+ if (!isdigit(ch)) {
424
+ goto error;
425
+ }
426
+ /* vlen_start <- p */
427
+ r->token = p;
428
+ r->vlen = (uint32_t)(ch - '0');
429
+ state = SW_VLEN;
430
+ }
431
+
432
+ break;
433
+
434
+ case SW_VLEN:
435
+ if (isdigit(ch)) {
436
+ r->vlen = r->vlen * 10 + (uint32_t)(ch - '0');
437
+ } else if (memcache_cas(r)) {
438
+ if (ch != ' ') {
439
+ goto error;
440
+ }
441
+ /* vlen_end <- p - 1 */
442
+ p = p - 1; /* go back by 1 byte */
443
+ r->token = NULL;
444
+ state = SW_SPACES_BEFORE_CAS;
445
+ } else if (ch == ' ' || ch == CR) {
446
+ /* vlen_end <- p - 1 */
447
+ p = p - 1; /* go back by 1 byte */
448
+ r->token = NULL;
449
+ state = SW_RUNTO_CRLF;
450
+ } else {
451
+ goto error;
452
+ }
453
+
454
+ break;
455
+
456
+ case SW_SPACES_BEFORE_CAS:
457
+ if (ch != ' ') {
458
+ if (!isdigit(ch)) {
459
+ goto error;
460
+ }
461
+ /* cas_start <- p; cas <- ch - '0' */
462
+ r->token = p;
463
+ state = SW_CAS;
464
+ }
465
+
466
+ break;
467
+
468
+ case SW_CAS:
469
+ if (isdigit(ch)) {
470
+ /* cas <- cas * 10 + (ch - '0') */
471
+ ;
472
+ } else if (ch == ' ' || ch == CR) {
473
+ /* cas_end <- p - 1 */
474
+ p = p - 1; /* go back by 1 byte */
475
+ r->token = NULL;
476
+ state = SW_RUNTO_CRLF;
477
+ } else {
478
+ goto error;
479
+ }
480
+
481
+ break;
482
+
483
+
484
+ case SW_RUNTO_VAL:
485
+ switch (ch) {
486
+ case LF:
487
+ /* val_start <- p + 1 */
488
+ state = SW_VAL;
489
+ break;
490
+
491
+ default:
492
+ goto error;
493
+ }
494
+
495
+ break;
496
+
497
+ case SW_VAL:
498
+ m = p + r->vlen;
499
+ if (m >= b->last) {
500
+ ASSERT(r->vlen >= (uint32_t)(b->last - p));
501
+ r->vlen -= (uint32_t)(b->last - p);
502
+ m = b->last - 1;
503
+ p = m; /* move forward by vlen bytes */
504
+ break;
505
+ }
506
+ switch (*m) {
507
+ case CR:
508
+ /* val_end <- p - 1 */
509
+ p = m; /* move forward by vlen bytes */
510
+ state = SW_ALMOST_DONE;
511
+ break;
512
+
513
+ default:
514
+ goto error;
515
+ }
516
+
517
+ break;
518
+
519
+ case SW_SPACES_BEFORE_NUM:
520
+ if (ch != ' ') {
521
+ if (!isdigit(ch)) {
522
+ goto error;
523
+ }
524
+ /* num_start <- p; num <- ch - '0' */
525
+ r->token = p;
526
+ state = SW_NUM;
527
+ }
528
+
529
+ break;
530
+
531
+ case SW_NUM:
532
+ if (isdigit(ch)) {
533
+ /* num <- num * 10 + (ch - '0') */
534
+ ;
535
+ } else if (ch == ' ' || ch == CR) {
536
+ r->token = NULL;
537
+ /* num_end <- p - 1 */
538
+ p = p - 1; /* go back by 1 byte */
539
+ state = SW_RUNTO_CRLF;
540
+ } else {
541
+ goto error;
542
+ }
543
+
544
+ break;
545
+
546
+ case SW_RUNTO_CRLF:
547
+ switch (ch) {
548
+ case ' ':
549
+ break;
550
+
551
+ case 'n':
552
+ if (memcache_storage(r) || memcache_arithmetic(r) || memcache_delete(r)) {
553
+ /* noreply_start <- p */
554
+ r->token = p;
555
+ state = SW_NOREPLY;
556
+ } else {
557
+ goto error;
558
+ }
559
+
560
+ break;
561
+
562
+ case CR:
563
+ if (memcache_storage(r)) {
564
+ state = SW_RUNTO_VAL;
565
+ } else {
566
+ state = SW_ALMOST_DONE;
567
+ }
568
+
569
+ break;
570
+
571
+ default:
572
+ goto error;
573
+ }
574
+
575
+ break;
576
+
577
+ case SW_NOREPLY:
578
+ switch (ch) {
579
+ case ' ':
580
+ case CR:
581
+ m = r->token;
582
+ if (((p - m) == 7) && str7cmp(m, 'n', 'o', 'r', 'e', 'p', 'l', 'y')) {
583
+ ASSERT(memcache_storage(r) || memcache_arithmetic(r) || memcache_delete(r));
584
+ r->token = NULL;
585
+ /* noreply_end <- p - 1 */
586
+ r->noreply = 1;
587
+ state = SW_AFTER_NOREPLY;
588
+ p = p - 1; /* go back by 1 byte */
589
+ } else {
590
+ goto error;
591
+ }
592
+ }
593
+
594
+ break;
595
+
596
+ case SW_AFTER_NOREPLY:
597
+ switch (ch) {
598
+ case ' ':
599
+ break;
600
+
601
+ case CR:
602
+ if (memcache_storage(r)) {
603
+ state = SW_RUNTO_VAL;
604
+ } else {
605
+ state = SW_ALMOST_DONE;
606
+ }
607
+ break;
608
+
609
+ default:
610
+ goto error;
611
+ }
612
+
613
+ break;
614
+
615
+ case SW_CRLF:
616
+ switch (ch) {
617
+ case ' ':
618
+ break;
619
+
620
+ case CR:
621
+ state = SW_ALMOST_DONE;
622
+ break;
623
+
624
+ default:
625
+ goto error;
626
+ }
627
+
628
+ break;
629
+
630
+ case SW_ALMOST_DONE:
631
+ switch (ch) {
632
+ case LF:
633
+ /* req_end <- p */
634
+ goto done;
635
+
636
+ default:
637
+ goto error;
638
+ }
639
+
640
+ break;
641
+
642
+ case SW_SENTINEL:
643
+ default:
644
+ NOT_REACHED();
645
+ break;
646
+
647
+ }
648
+ }
649
+
650
+ /*
651
+ * At this point, buffer from b->pos to b->last has been parsed completely
652
+ * but we haven't been able to reach to any conclusion. Normally, this
653
+ * means that we have to parse again starting from the state we are in
654
+ * after more data has been read. The newly read data is either read into
655
+ * a new mbuf, if existing mbuf is full (b->last == b->end) or into the
656
+ * existing mbuf.
657
+ *
658
+ * The only exception to this is when the existing mbuf is full (b->last
659
+ * is at b->end) and token marker is set, which means that we have to
660
+ * copy the partial token into a new mbuf and parse again with more data
661
+ * read into new mbuf.
662
+ */
663
+ ASSERT(p == b->last);
664
+ r->pos = p;
665
+ r->state = state;
666
+
667
+ if (b->last == b->end && r->token != NULL) {
668
+ r->pos = r->token;
669
+ r->token = NULL;
670
+ r->result = MSG_PARSE_REPAIR;
671
+ } else {
672
+ r->result = MSG_PARSE_AGAIN;
673
+ }
674
+
675
+ log_hexdump(LOG_VERB, b->pos, mbuf_length(b), "parsed req %"PRIu64" res %d "
676
+ "type %d state %d rpos %d of %d", r->id, r->result, r->type,
677
+ r->state, r->pos - b->pos, b->last - b->pos);
678
+ return;
679
+
680
+ fragment:
681
+ ASSERT(p != b->last);
682
+ ASSERT(r->token != NULL);
683
+ r->pos = r->token;
684
+ r->token = NULL;
685
+ r->state = state;
686
+ r->result = MSG_PARSE_FRAGMENT;
687
+
688
+ log_hexdump(LOG_VERB, b->pos, mbuf_length(b), "parsed req %"PRIu64" res %d "
689
+ "type %d state %d rpos %d of %d", r->id, r->result, r->type,
690
+ r->state, r->pos - b->pos, b->last - b->pos);
691
+ return;
692
+
693
+ done:
694
+ ASSERT(r->type > MSG_UNKNOWN && r->type < MSG_SENTINEL);
695
+ r->pos = p + 1;
696
+ ASSERT(r->pos <= b->last);
697
+ r->state = SW_START;
698
+ r->result = MSG_PARSE_OK;
699
+
700
+ log_hexdump(LOG_VERB, b->pos, mbuf_length(b), "parsed req %"PRIu64" res %d "
701
+ "type %d state %d rpos %d of %d", r->id, r->result, r->type,
702
+ r->state, r->pos - b->pos, b->last - b->pos);
703
+ return;
704
+
705
+ error:
706
+ r->result = MSG_PARSE_ERROR;
707
+ r->state = state;
708
+ errno = EINVAL;
709
+
710
+ log_hexdump(LOG_INFO, b->pos, mbuf_length(b), "parsed bad req %"PRIu64" "
711
+ "res %d type %d state %d", r->id, r->result, r->type,
712
+ r->state);
713
+ }
714
+
715
+ void
716
+ memcache_parse_rsp(struct msg *r)
717
+ {
718
+ struct mbuf *b;
719
+ uint8_t *p, *m;
720
+ uint8_t ch;
721
+ enum {
722
+ SW_START,
723
+ SW_RSP_NUM,
724
+ SW_RSP_STR,
725
+ SW_SPACES_BEFORE_KEY,
726
+ SW_KEY,
727
+ SW_SPACES_BEFORE_FLAGS,
728
+ SW_FLAGS,
729
+ SW_SPACES_BEFORE_VLEN,
730
+ SW_VLEN,
731
+ SW_RUNTO_VAL,
732
+ SW_VAL,
733
+ SW_VAL_LF,
734
+ SW_END,
735
+ SW_RUNTO_CRLF,
736
+ SW_CRLF,
737
+ SW_ALMOST_DONE,
738
+ SW_SENTINEL
739
+ } state;
740
+
741
+ state = r->state;
742
+ b = STAILQ_LAST(&r->mhdr, mbuf, next);
743
+
744
+ ASSERT(!r->request);
745
+ ASSERT(!r->redis);
746
+ ASSERT(state >= SW_START && state < SW_SENTINEL);
747
+ ASSERT(b != NULL);
748
+ ASSERT(b->pos <= b->last);
749
+
750
+ /* validate the parsing marker */
751
+ ASSERT(r->pos != NULL);
752
+ ASSERT(r->pos >= b->pos && r->pos <= b->last);
753
+
754
+ for (p = r->pos; p < b->last; p++) {
755
+ ch = *p;
756
+
757
+ switch (state) {
758
+ case SW_START:
759
+ if (isdigit(ch)) {
760
+ state = SW_RSP_NUM;
761
+ } else {
762
+ state = SW_RSP_STR;
763
+ }
764
+ p = p - 1; /* go back by 1 byte */
765
+
766
+ break;
767
+
768
+ case SW_RSP_NUM:
769
+ if (r->token == NULL) {
770
+ /* rsp_start <- p; type_start <- p */
771
+ r->token = p;
772
+ }
773
+
774
+ if (isdigit(ch)) {
775
+ /* num <- num * 10 + (ch - '0') */
776
+ ;
777
+ } else if (ch == ' ' || ch == CR) {
778
+ /* type_end <- p - 1 */
779
+ r->token = NULL;
780
+ r->type = MSG_RSP_MC_NUM;
781
+ p = p - 1; /* go back by 1 byte */
782
+ state = SW_CRLF;
783
+ } else {
784
+ goto error;
785
+ }
786
+
787
+ break;
788
+
789
+ case SW_RSP_STR:
790
+ if (r->token == NULL) {
791
+ /* rsp_start <- p; type_start <- p */
792
+ r->token = p;
793
+ }
794
+
795
+ if (ch == ' ' || ch == CR) {
796
+ /* type_end <- p - 1 */
797
+ m = r->token;
798
+ r->token = NULL;
799
+ r->type = MSG_UNKNOWN;
800
+
801
+ switch (p - m) {
802
+ case 3:
803
+ if (str4cmp(m, 'E', 'N', 'D', '\r')) {
804
+ r->type = MSG_RSP_MC_END;
805
+ /* end_start <- m; end_end <- p - 1*/
806
+ r->end = m;
807
+ break;
808
+ }
809
+
810
+ break;
811
+
812
+ case 5:
813
+ if (str5cmp(m, 'V', 'A', 'L', 'U', 'E')) {
814
+ /*
815
+ * Encompasses responses for 'get', 'gets' and
816
+ * 'cas' command.
817
+ */
818
+ r->type = MSG_RSP_MC_VALUE;
819
+ break;
820
+ }
821
+
822
+ if (str5cmp(m, 'E', 'R', 'R', 'O', 'R')) {
823
+ r->type = MSG_RSP_MC_ERROR;
824
+ break;
825
+ }
826
+
827
+ break;
828
+
829
+ case 6:
830
+ if (str6cmp(m, 'S', 'T', 'O', 'R', 'E', 'D')) {
831
+ r->type = MSG_RSP_MC_STORED;
832
+ break;
833
+ }
834
+
835
+ if (str6cmp(m, 'E', 'X', 'I', 'S', 'T', 'S')) {
836
+ r->type = MSG_RSP_MC_EXISTS;
837
+ break;
838
+ }
839
+
840
+ break;
841
+
842
+ case 7:
843
+ if (str7cmp(m, 'D', 'E', 'L', 'E', 'T', 'E', 'D')) {
844
+ r->type = MSG_RSP_MC_DELETED;
845
+ break;
846
+ }
847
+
848
+ break;
849
+
850
+ case 9:
851
+ if (str9cmp(m, 'N', 'O', 'T', '_', 'F', 'O', 'U', 'N', 'D')) {
852
+ r->type = MSG_RSP_MC_NOT_FOUND;
853
+ break;
854
+ }
855
+
856
+ break;
857
+
858
+ case 10:
859
+ if (str10cmp(m, 'N', 'O', 'T', '_', 'S', 'T', 'O', 'R', 'E', 'D')) {
860
+ r->type = MSG_RSP_MC_NOT_STORED;
861
+ break;
862
+ }
863
+
864
+ break;
865
+
866
+ case 12:
867
+ if (str12cmp(m, 'C', 'L', 'I', 'E', 'N', 'T', '_', 'E', 'R', 'R', 'O', 'R')) {
868
+ r->type = MSG_RSP_MC_CLIENT_ERROR;
869
+ break;
870
+ }
871
+
872
+ if (str12cmp(m, 'S', 'E', 'R', 'V', 'E', 'R', '_', 'E', 'R', 'R', 'O', 'R')) {
873
+ r->type = MSG_RSP_MC_SERVER_ERROR;
874
+ break;
875
+ }
876
+
877
+ break;
878
+ }
879
+
880
+ switch (r->type) {
881
+ case MSG_UNKNOWN:
882
+ goto error;
883
+
884
+ case MSG_RSP_MC_STORED:
885
+ case MSG_RSP_MC_NOT_STORED:
886
+ case MSG_RSP_MC_EXISTS:
887
+ case MSG_RSP_MC_NOT_FOUND:
888
+ case MSG_RSP_MC_DELETED:
889
+ state = SW_CRLF;
890
+ break;
891
+
892
+ case MSG_RSP_MC_END:
893
+ state = SW_CRLF;
894
+ break;
895
+
896
+ case MSG_RSP_MC_VALUE:
897
+ state = SW_SPACES_BEFORE_KEY;
898
+ break;
899
+
900
+ case MSG_RSP_MC_ERROR:
901
+ state = SW_CRLF;
902
+ break;
903
+
904
+ case MSG_RSP_MC_CLIENT_ERROR:
905
+ case MSG_RSP_MC_SERVER_ERROR:
906
+ state = SW_RUNTO_CRLF;
907
+ break;
908
+
909
+ default:
910
+ NOT_REACHED();
911
+ }
912
+
913
+ p = p - 1; /* go back by 1 byte */
914
+ }
915
+
916
+ break;
917
+
918
+ case SW_SPACES_BEFORE_KEY:
919
+ if (ch != ' ') {
920
+ state = SW_KEY;
921
+ p = p - 1; /* go back by 1 byte */
922
+ }
923
+
924
+ break;
925
+
926
+ case SW_KEY:
927
+ if (r->token == NULL) {
928
+ r->token = p;
929
+ r->key_start = p;
930
+ }
931
+
932
+ if (ch == ' ') {
933
+ if ((p - r->key_start) > MEMCACHE_MAX_KEY_LENGTH) {
934
+ log_error("parsed bad req %"PRIu64" of type %d with key "
935
+ "prefix '%.*s...' and length %d that exceeds "
936
+ "maximum key length", r->id, r->type, 16,
937
+ r->key_start, p - r->key_start);
938
+ goto error;
939
+ }
940
+ r->key_end = p;
941
+ r->token = NULL;
942
+ state = SW_SPACES_BEFORE_FLAGS;
943
+ }
944
+
945
+ break;
946
+
947
+ case SW_SPACES_BEFORE_FLAGS:
948
+ if (ch != ' ') {
949
+ if (!isdigit(ch)) {
950
+ goto error;
951
+ }
952
+ state = SW_FLAGS;
953
+ p = p - 1; /* go back by 1 byte */
954
+ }
955
+
956
+ break;
957
+
958
+ case SW_FLAGS:
959
+ if (r->token == NULL) {
960
+ /* flags_start <- p */
961
+ r->token = p;
962
+ }
963
+
964
+ if (isdigit(ch)) {
965
+ /* flags <- flags * 10 + (ch - '0') */
966
+ ;
967
+ } else if (ch == ' ') {
968
+ /* flags_end <- p - 1 */
969
+ r->token = NULL;
970
+ state = SW_SPACES_BEFORE_VLEN;
971
+ } else {
972
+ goto error;
973
+ }
974
+
975
+ break;
976
+
977
+ case SW_SPACES_BEFORE_VLEN:
978
+ if (ch != ' ') {
979
+ if (!isdigit(ch)) {
980
+ goto error;
981
+ }
982
+ p = p - 1; /* go back by 1 byte */
983
+ state = SW_VLEN;
984
+ }
985
+
986
+ break;
987
+
988
+ case SW_VLEN:
989
+ if (r->token == NULL) {
990
+ /* vlen_start <- p */
991
+ r->token = p;
992
+ r->vlen = (uint32_t)(ch - '0');
993
+ } else if (isdigit(ch)) {
994
+ r->vlen = r->vlen * 10 + (uint32_t)(ch - '0');
995
+ } else if (ch == ' ' || ch == CR) {
996
+ /* vlen_end <- p - 1 */
997
+ p = p - 1; /* go back by 1 byte */
998
+ r->token = NULL;
999
+ state = SW_RUNTO_CRLF;
1000
+ } else {
1001
+ goto error;
1002
+ }
1003
+
1004
+ break;
1005
+
1006
+ case SW_RUNTO_VAL:
1007
+ switch (ch) {
1008
+ case LF:
1009
+ /* val_start <- p + 1 */
1010
+ state = SW_VAL;
1011
+ break;
1012
+
1013
+ default:
1014
+ goto error;
1015
+ }
1016
+
1017
+ break;
1018
+
1019
+ case SW_VAL:
1020
+ m = p + r->vlen;
1021
+ if (m >= b->last) {
1022
+ ASSERT(r->vlen >= (uint32_t)(b->last - p));
1023
+ r->vlen -= (uint32_t)(b->last - p);
1024
+ m = b->last - 1;
1025
+ p = m; /* move forward by vlen bytes */
1026
+ break;
1027
+ }
1028
+ switch (*m) {
1029
+ case CR:
1030
+ /* val_end <- p - 1 */
1031
+ p = m; /* move forward by vlen bytes */
1032
+ state = SW_VAL_LF;
1033
+ break;
1034
+
1035
+ default:
1036
+ goto error;
1037
+ }
1038
+
1039
+ break;
1040
+
1041
+ case SW_VAL_LF:
1042
+ switch (ch) {
1043
+ case LF:
1044
+ state = SW_END;
1045
+ break;
1046
+
1047
+ default:
1048
+ goto error;
1049
+ }
1050
+
1051
+ break;
1052
+
1053
+ case SW_END:
1054
+ if (r->token == NULL) {
1055
+ if (ch != 'E') {
1056
+ goto error;
1057
+ }
1058
+ /* end_start <- p */
1059
+ r->token = p;
1060
+ } else if (ch == CR) {
1061
+ /* end_end <- p */
1062
+ m = r->token;
1063
+ r->token = NULL;
1064
+
1065
+ switch (p - m) {
1066
+ case 3:
1067
+ if (str4cmp(m, 'E', 'N', 'D', '\r')) {
1068
+ r->end = m;
1069
+ state = SW_ALMOST_DONE;
1070
+ }
1071
+ break;
1072
+
1073
+ default:
1074
+ goto error;
1075
+ }
1076
+ }
1077
+
1078
+ break;
1079
+
1080
+ case SW_RUNTO_CRLF:
1081
+ switch (ch) {
1082
+ case CR:
1083
+ if (r->type == MSG_RSP_MC_VALUE) {
1084
+ state = SW_RUNTO_VAL;
1085
+ } else {
1086
+ state = SW_ALMOST_DONE;
1087
+ }
1088
+
1089
+ break;
1090
+
1091
+ default:
1092
+ break;
1093
+ }
1094
+
1095
+ break;
1096
+
1097
+ case SW_CRLF:
1098
+ switch (ch) {
1099
+ case ' ':
1100
+ break;
1101
+
1102
+ case CR:
1103
+ state = SW_ALMOST_DONE;
1104
+ break;
1105
+
1106
+ default:
1107
+ goto error;
1108
+ }
1109
+
1110
+ break;
1111
+
1112
+ case SW_ALMOST_DONE:
1113
+ switch (ch) {
1114
+ case LF:
1115
+ /* rsp_end <- p */
1116
+ goto done;
1117
+
1118
+ default:
1119
+ goto error;
1120
+ }
1121
+
1122
+ break;
1123
+
1124
+ case SW_SENTINEL:
1125
+ default:
1126
+ NOT_REACHED();
1127
+ break;
1128
+
1129
+ }
1130
+ }
1131
+
1132
+ ASSERT(p == b->last);
1133
+ r->pos = p;
1134
+ r->state = state;
1135
+
1136
+ if (b->last == b->end && r->token != NULL) {
1137
+ r->pos = r->token;
1138
+ r->token = NULL;
1139
+ r->result = MSG_PARSE_REPAIR;
1140
+ } else {
1141
+ r->result = MSG_PARSE_AGAIN;
1142
+ }
1143
+
1144
+ log_hexdump(LOG_VERB, b->pos, mbuf_length(b), "parsed rsp %"PRIu64" res %d "
1145
+ "type %d state %d rpos %d of %d", r->id, r->result, r->type,
1146
+ r->state, r->pos - b->pos, b->last - b->pos);
1147
+ return;
1148
+
1149
+ done:
1150
+ ASSERT(r->type > MSG_UNKNOWN && r->type < MSG_SENTINEL);
1151
+ r->pos = p + 1;
1152
+ ASSERT(r->pos <= b->last);
1153
+ r->state = SW_START;
1154
+ r->token = NULL;
1155
+ r->result = MSG_PARSE_OK;
1156
+
1157
+ log_hexdump(LOG_VERB, b->pos, mbuf_length(b), "parsed rsp %"PRIu64" res %d "
1158
+ "type %d state %d rpos %d of %d", r->id, r->result, r->type,
1159
+ r->state, r->pos - b->pos, b->last - b->pos);
1160
+ return;
1161
+
1162
+ error:
1163
+ r->result = MSG_PARSE_ERROR;
1164
+ r->state = state;
1165
+ errno = EINVAL;
1166
+
1167
+ log_hexdump(LOG_INFO, b->pos, mbuf_length(b), "parsed bad rsp %"PRIu64" "
1168
+ "res %d type %d state %d", r->id, r->result, r->type,
1169
+ r->state);
1170
+ }
1171
+
1172
+ /*
1173
+ * Pre-split copy handler invoked when the request is a multi vector -
1174
+ * 'get' or 'gets' request and is about to be split into two requests
1175
+ */
1176
+ void
1177
+ memcache_pre_splitcopy(struct mbuf *mbuf, void *arg)
1178
+ {
1179
+ struct msg *r = arg; /* request vector */
1180
+ struct string get = string("get "); /* 'get ' string */
1181
+ struct string gets = string("gets "); /* 'gets ' string */
1182
+
1183
+ ASSERT(r->request);
1184
+ ASSERT(!r->redis);
1185
+ ASSERT(mbuf_empty(mbuf));
1186
+
1187
+ switch (r->type) {
1188
+ case MSG_REQ_MC_GET:
1189
+ mbuf_copy(mbuf, get.data, get.len);
1190
+ break;
1191
+
1192
+ case MSG_REQ_MC_GETS:
1193
+ mbuf_copy(mbuf, gets.data, gets.len);
1194
+ break;
1195
+
1196
+ default:
1197
+ NOT_REACHED();
1198
+ }
1199
+ }
1200
+
1201
+ /*
1202
+ * Post-split copy handler invoked when the request is a multi vector -
1203
+ * 'get' or 'gets' request and has already been split into two requests
1204
+ */
1205
+ rstatus_t
1206
+ memcache_post_splitcopy(struct msg *r)
1207
+ {
1208
+ struct mbuf *mbuf;
1209
+ struct string crlf = string(CRLF);
1210
+
1211
+ ASSERT(r->request);
1212
+ ASSERT(!r->redis);
1213
+ ASSERT(!STAILQ_EMPTY(&r->mhdr));
1214
+
1215
+ mbuf = STAILQ_LAST(&r->mhdr, mbuf, next);
1216
+ mbuf_copy(mbuf, crlf.data, crlf.len);
1217
+
1218
+ return NC_OK;
1219
+ }
1220
+
1221
+ /*
1222
+ * Pre-coalesce handler is invoked when the message is a response to
1223
+ * the fragmented multi vector request - 'get' or 'gets' and all the
1224
+ * responses to the fragmented request vector hasn't been received
1225
+ */
1226
+ void
1227
+ memcache_pre_coalesce(struct msg *r)
1228
+ {
1229
+ struct msg *pr = r->peer; /* peer request */
1230
+ struct mbuf *mbuf;
1231
+
1232
+ ASSERT(!r->request);
1233
+ ASSERT(pr->request);
1234
+
1235
+ if (pr->frag_id == 0) {
1236
+ /* do nothing, if not a response to a fragmented request */
1237
+ return;
1238
+ }
1239
+
1240
+ switch (r->type) {
1241
+
1242
+ case MSG_RSP_MC_VALUE:
1243
+ case MSG_RSP_MC_END:
1244
+
1245
+ /*
1246
+ * Readjust responses of the fragmented message vector by not
1247
+ * including the end marker for all but the last response
1248
+ */
1249
+
1250
+ if (pr->last_fragment) {
1251
+ break;
1252
+ }
1253
+
1254
+ ASSERT(r->end != NULL);
1255
+
1256
+ for (;;) {
1257
+ mbuf = STAILQ_LAST(&r->mhdr, mbuf, next);
1258
+ ASSERT(mbuf != NULL);
1259
+
1260
+ /*
1261
+ * We cannot assert that end marker points to the last mbuf
1262
+ * Consider a scenario where end marker points to the
1263
+ * penultimate mbuf and the last mbuf only contains spaces
1264
+ * and CRLF: mhdr -> [...END] -> [\r\n]
1265
+ */
1266
+
1267
+ if (r->end >= mbuf->pos && r->end < mbuf->last) {
1268
+ /* end marker is within this mbuf */
1269
+ r->mlen -= (uint32_t)(mbuf->last - r->end);
1270
+ mbuf->last = r->end;
1271
+ break;
1272
+ }
1273
+
1274
+ /* end marker is not in this mbuf */
1275
+ r->mlen -= mbuf_length(mbuf);
1276
+ mbuf_remove(&r->mhdr, mbuf);
1277
+ mbuf_put(mbuf);
1278
+ }
1279
+
1280
+ break;
1281
+
1282
+ default:
1283
+ /*
1284
+ * Valid responses for a fragmented requests are MSG_RSP_MC_VALUE or,
1285
+ * MSG_RSP_MC_END. For an invalid response, we send out SERVER_ERRROR
1286
+ * with EINVAL errno
1287
+ */
1288
+ mbuf = STAILQ_FIRST(&r->mhdr);
1289
+ log_hexdump(LOG_ERR, mbuf->pos, mbuf_length(mbuf), "rsp fragment "
1290
+ "with unknown type %d", r->type);
1291
+ pr->error = 1;
1292
+ pr->err = EINVAL;
1293
+ break;
1294
+ }
1295
+ }
1296
+
1297
+ /*
1298
+ * Post-coalesce handler is invoked when the message is a response to
1299
+ * the fragmented multi vector request - 'get' or 'gets' and all the
1300
+ * responses to the fragmented request vector has been received and
1301
+ * the fragmented request is consider to be done
1302
+ */
1303
+ void
1304
+ memcache_post_coalesce(struct msg *r)
1305
+ {
1306
+ }