nutcracker 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +22 -0
- data/Rakefile +55 -0
- data/bin/nutcracker +2 -0
- data/ext/nutcracker/ChangeLog +66 -0
- data/ext/nutcracker/LICENSE +177 -0
- data/ext/nutcracker/Makefile.am +7 -0
- data/ext/nutcracker/Makefile.in +726 -0
- data/ext/nutcracker/NOTICE +124 -0
- data/ext/nutcracker/README.md +240 -0
- data/ext/nutcracker/aclocal.m4 +956 -0
- data/ext/nutcracker/conf/nutcracker.leaf.yml +10 -0
- data/ext/nutcracker/conf/nutcracker.root.yml +8 -0
- data/ext/nutcracker/conf/nutcracker.yml +67 -0
- data/ext/nutcracker/config.h.in +316 -0
- data/ext/nutcracker/config/config.guess +1561 -0
- data/ext/nutcracker/config/config.sub +1686 -0
- data/ext/nutcracker/config/depcomp +630 -0
- data/ext/nutcracker/config/install-sh +520 -0
- data/ext/nutcracker/config/ltmain.sh +8413 -0
- data/ext/nutcracker/config/missing +376 -0
- data/ext/nutcracker/configure +18862 -0
- data/ext/nutcracker/configure.ac +155 -0
- data/ext/nutcracker/contrib/Makefile.am +3 -0
- data/ext/nutcracker/contrib/Makefile.in +560 -0
- data/ext/nutcracker/contrib/yaml-0.1.4.tar.gz +0 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/LICENSE +19 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/Makefile.am +20 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/Makefile.in +736 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/README +27 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/aclocal.m4 +956 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/config.h.in +80 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/config/config.guess +1561 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/config/config.sub +1686 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/config/depcomp +630 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/config/install-sh +520 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/config/ltmain.sh +8406 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/config/missing +376 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/configure +13085 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/configure.ac +75 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/doc/doxygen.cfg +222 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/include/yaml.h +1971 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/m4/libtool.m4 +7357 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/m4/ltoptions.m4 +368 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/m4/ltsugar.m4 +123 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/m4/ltversion.m4 +23 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/m4/lt~obsolete.m4 +92 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/src/Makefile.am +4 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/src/Makefile.in +484 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/src/api.c +1392 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/src/dumper.c +394 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/src/emitter.c +2329 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/src/loader.c +432 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/src/parser.c +1374 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/src/reader.c +465 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/src/scanner.c +3570 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/src/writer.c +141 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/src/yaml_private.h +640 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/Makefile.am +8 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/Makefile.in +675 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-deconstructor-alt.c +800 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-deconstructor.c +1130 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-reformatter-alt.c +217 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-reformatter.c +202 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-dumper.c +311 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-emitter.c +327 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-loader.c +63 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-parser.c +63 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-scanner.c +63 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/test-reader.c +354 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/test-version.c +29 -0
- data/ext/nutcracker/extconf.rb +5 -0
- data/ext/nutcracker/m4/libtool.m4 +7376 -0
- data/ext/nutcracker/m4/ltoptions.m4 +368 -0
- data/ext/nutcracker/m4/ltsugar.m4 +123 -0
- data/ext/nutcracker/m4/ltversion.m4 +23 -0
- data/ext/nutcracker/m4/lt~obsolete.m4 +92 -0
- data/ext/nutcracker/notes/c-styleguide.txt +425 -0
- data/ext/nutcracker/notes/debug.txt +96 -0
- data/ext/nutcracker/notes/memcache.txt +123 -0
- data/ext/nutcracker/notes/recommendation.md +118 -0
- data/ext/nutcracker/notes/redis.md +415 -0
- data/ext/nutcracker/notes/socket.txt +131 -0
- data/ext/nutcracker/scripts/multi_get.sh +26 -0
- data/ext/nutcracker/scripts/nutcracker.init +73 -0
- data/ext/nutcracker/scripts/nutcracker.spec +52 -0
- data/ext/nutcracker/scripts/pipelined_read.sh +23 -0
- data/ext/nutcracker/scripts/pipelined_write.sh +29 -0
- data/ext/nutcracker/scripts/populate_memcached.sh +24 -0
- data/ext/nutcracker/scripts/redis-check.py +23 -0
- data/ext/nutcracker/scripts/redis-check.sh +564 -0
- data/ext/nutcracker/src/Makefile.am +46 -0
- data/ext/nutcracker/src/Makefile.in +726 -0
- data/ext/nutcracker/src/hashkit/Makefile.am +22 -0
- data/ext/nutcracker/src/hashkit/Makefile.in +501 -0
- data/ext/nutcracker/src/hashkit/nc_crc32.c +105 -0
- data/ext/nutcracker/src/hashkit/nc_fnv.c +82 -0
- data/ext/nutcracker/src/hashkit/nc_hashkit.h +74 -0
- data/ext/nutcracker/src/hashkit/nc_hsieh.c +93 -0
- data/ext/nutcracker/src/hashkit/nc_jenkins.c +230 -0
- data/ext/nutcracker/src/hashkit/nc_ketama.c +240 -0
- data/ext/nutcracker/src/hashkit/nc_md5.c +379 -0
- data/ext/nutcracker/src/hashkit/nc_modula.c +144 -0
- data/ext/nutcracker/src/hashkit/nc_murmur.c +99 -0
- data/ext/nutcracker/src/hashkit/nc_one_at_a_time.c +51 -0
- data/ext/nutcracker/src/hashkit/nc_random.c +146 -0
- data/ext/nutcracker/src/nc.c +573 -0
- data/ext/nutcracker/src/nc_array.c +204 -0
- data/ext/nutcracker/src/nc_array.h +73 -0
- data/ext/nutcracker/src/nc_client.c +189 -0
- data/ext/nutcracker/src/nc_client.h +28 -0
- data/ext/nutcracker/src/nc_conf.c +1766 -0
- data/ext/nutcracker/src/nc_conf.h +134 -0
- data/ext/nutcracker/src/nc_connection.c +392 -0
- data/ext/nutcracker/src/nc_connection.h +99 -0
- data/ext/nutcracker/src/nc_core.c +334 -0
- data/ext/nutcracker/src/nc_core.h +131 -0
- data/ext/nutcracker/src/nc_event.c +214 -0
- data/ext/nutcracker/src/nc_event.h +39 -0
- data/ext/nutcracker/src/nc_log.c +254 -0
- data/ext/nutcracker/src/nc_log.h +120 -0
- data/ext/nutcracker/src/nc_mbuf.c +285 -0
- data/ext/nutcracker/src/nc_mbuf.h +67 -0
- data/ext/nutcracker/src/nc_message.c +828 -0
- data/ext/nutcracker/src/nc_message.h +253 -0
- data/ext/nutcracker/src/nc_proxy.c +359 -0
- data/ext/nutcracker/src/nc_proxy.h +34 -0
- data/ext/nutcracker/src/nc_queue.h +788 -0
- data/ext/nutcracker/src/nc_rbtree.c +348 -0
- data/ext/nutcracker/src/nc_rbtree.h +47 -0
- data/ext/nutcracker/src/nc_request.c +588 -0
- data/ext/nutcracker/src/nc_response.c +332 -0
- data/ext/nutcracker/src/nc_server.c +841 -0
- data/ext/nutcracker/src/nc_server.h +143 -0
- data/ext/nutcracker/src/nc_signal.c +131 -0
- data/ext/nutcracker/src/nc_signal.h +34 -0
- data/ext/nutcracker/src/nc_stats.c +1188 -0
- data/ext/nutcracker/src/nc_stats.h +206 -0
- data/ext/nutcracker/src/nc_string.c +109 -0
- data/ext/nutcracker/src/nc_string.h +112 -0
- data/ext/nutcracker/src/nc_util.c +619 -0
- data/ext/nutcracker/src/nc_util.h +214 -0
- data/ext/nutcracker/src/proto/Makefile.am +14 -0
- data/ext/nutcracker/src/proto/Makefile.in +482 -0
- data/ext/nutcracker/src/proto/nc_memcache.c +1306 -0
- data/ext/nutcracker/src/proto/nc_proto.h +155 -0
- data/ext/nutcracker/src/proto/nc_redis.c +2102 -0
- data/lib/nutcracker.rb +7 -0
- data/lib/nutcracker/version.rb +3 -0
- metadata +194 -0
|
@@ -0,0 +1,155 @@
|
|
|
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
|
+
#ifndef _NC_PROTO_H_
|
|
19
|
+
#define _NC_PROTO_H_
|
|
20
|
+
|
|
21
|
+
#include <nc_core.h>
|
|
22
|
+
|
|
23
|
+
#ifdef NC_LITTLE_ENDIAN
|
|
24
|
+
|
|
25
|
+
#define str4cmp(m, c0, c1, c2, c3) \
|
|
26
|
+
(*(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0))
|
|
27
|
+
|
|
28
|
+
#define str5cmp(m, c0, c1, c2, c3, c4) \
|
|
29
|
+
(str4cmp(m, c0, c1, c2, c3) && (m[4] == c4))
|
|
30
|
+
|
|
31
|
+
#define str6cmp(m, c0, c1, c2, c3, c4, c5) \
|
|
32
|
+
(str4cmp(m, c0, c1, c2, c3) && \
|
|
33
|
+
(((uint32_t *) m)[1] & 0xffff) == ((c5 << 8) | c4))
|
|
34
|
+
|
|
35
|
+
#define str7cmp(m, c0, c1, c2, c3, c4, c5, c6) \
|
|
36
|
+
(str6cmp(m, c0, c1, c2, c3, c4, c5) && (m[6] == c6))
|
|
37
|
+
|
|
38
|
+
#define str8cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) \
|
|
39
|
+
(str4cmp(m, c0, c1, c2, c3) && \
|
|
40
|
+
(((uint32_t *) m)[1] == ((c7 << 24) | (c6 << 16) | (c5 << 8) | c4)))
|
|
41
|
+
|
|
42
|
+
#define str9cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8) \
|
|
43
|
+
(str8cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) && m[8] == c8)
|
|
44
|
+
|
|
45
|
+
#define str10cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9) \
|
|
46
|
+
(str8cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) && \
|
|
47
|
+
(((uint32_t *) m)[2] & 0xffff) == ((c9 << 8) | c8))
|
|
48
|
+
|
|
49
|
+
#define str11cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10) \
|
|
50
|
+
(str10cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9) && (m[10] == c10))
|
|
51
|
+
|
|
52
|
+
#define str12cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11) \
|
|
53
|
+
(str8cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) && \
|
|
54
|
+
(((uint32_t *) m)[2] == ((c11 << 24) | (c10 << 16) | (c9 << 8) | c8)))
|
|
55
|
+
|
|
56
|
+
#else
|
|
57
|
+
|
|
58
|
+
#define str4cmp(m, c0, c1, c2, c3) \
|
|
59
|
+
(m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3)
|
|
60
|
+
|
|
61
|
+
#define str5cmp(m, c0, c1, c2, c3, c4) \
|
|
62
|
+
(str4cmp(m, c0, c1, c2, c3) && (m[4] == c4))
|
|
63
|
+
|
|
64
|
+
#define str6cmp(m, c0, c1, c2, c3, c4, c5) \
|
|
65
|
+
(str5cmp(m, c0, c1, c2, c3, c4) && m[5] == c5)
|
|
66
|
+
|
|
67
|
+
#define str7cmp(m, c0, c1, c2, c3, c4, c5, c6) \
|
|
68
|
+
(str6cmp(m, c0, c1, c2, c3, c4, c5) && m[6] == c6)
|
|
69
|
+
|
|
70
|
+
#define str8cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) \
|
|
71
|
+
(str7cmp(m, c0, c1, c2, c3, c4, c5, c6) && m[7] == c7)
|
|
72
|
+
|
|
73
|
+
#define str9cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8) \
|
|
74
|
+
(str8cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) && m[8] == c8)
|
|
75
|
+
|
|
76
|
+
#define str10cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9) \
|
|
77
|
+
(str9cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8) && m[9] == c9)
|
|
78
|
+
|
|
79
|
+
#define str11cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10) \
|
|
80
|
+
(str10cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9) && m[10] == c10)
|
|
81
|
+
|
|
82
|
+
#define str12cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11) \
|
|
83
|
+
(str11cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10) && m[11] == c11)
|
|
84
|
+
|
|
85
|
+
#endif
|
|
86
|
+
|
|
87
|
+
#define str3icmp(m, c0, c1, c2) \
|
|
88
|
+
((m[0] == c0 || m[0] == (c0 ^ 0x20)) && \
|
|
89
|
+
(m[1] == c1 || m[1] == (c1 ^ 0x20)) && \
|
|
90
|
+
(m[2] == c2 || m[2] == (c2 ^ 0x20)))
|
|
91
|
+
|
|
92
|
+
#define str4icmp(m, c0, c1, c2, c3) \
|
|
93
|
+
(str3icmp(m, c0, c1, c2) && (m[3] == c3 || m[3] == (c3 ^ 0x20)))
|
|
94
|
+
|
|
95
|
+
#define str5icmp(m, c0, c1, c2, c3, c4) \
|
|
96
|
+
(str4icmp(m, c0, c1, c2, c3) && (m[4] == c4 || m[4] == (c4 ^ 0x20)))
|
|
97
|
+
|
|
98
|
+
#define str6icmp(m, c0, c1, c2, c3, c4, c5) \
|
|
99
|
+
(str5icmp(m, c0, c1, c2, c3, c4) && (m[5] == c5 || m[5] == (c5 ^ 0x20)))
|
|
100
|
+
|
|
101
|
+
#define str7icmp(m, c0, c1, c2, c3, c4, c5, c6) \
|
|
102
|
+
(str6icmp(m, c0, c1, c2, c3, c4, c5) && \
|
|
103
|
+
(m[6] == c6 || m[6] == (c6 ^ 0x20)))
|
|
104
|
+
|
|
105
|
+
#define str8icmp(m, c0, c1, c2, c3, c4, c5, c6, c7) \
|
|
106
|
+
(str7icmp(m, c0, c1, c2, c3, c4, c5, c6) && \
|
|
107
|
+
(m[7] == c7 || m[7] == (c7 ^ 0x20)))
|
|
108
|
+
|
|
109
|
+
#define str9icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8) \
|
|
110
|
+
(str8icmp(m, c0, c1, c2, c3, c4, c5, c6, c7) && \
|
|
111
|
+
(m[8] == c8 || m[8] == (c8 ^ 0x20)))
|
|
112
|
+
|
|
113
|
+
#define str10icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9) \
|
|
114
|
+
(str9icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8) && \
|
|
115
|
+
(m[9] == c9 || m[9] == (c9 ^ 0x20)))
|
|
116
|
+
|
|
117
|
+
#define str11icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10) \
|
|
118
|
+
(str10icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9) && \
|
|
119
|
+
(m[10] == c10 || m[10] == (c10 ^ 0x20)))
|
|
120
|
+
|
|
121
|
+
#define str12icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11) \
|
|
122
|
+
(str11icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10) && \
|
|
123
|
+
(m[11] == c11 || m[11] == (c11 ^ 0x20)))
|
|
124
|
+
|
|
125
|
+
#define str13icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12) \
|
|
126
|
+
(str12icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11) && \
|
|
127
|
+
(m[12] == c12 || m[12] == (c12 ^ 0x20)))
|
|
128
|
+
|
|
129
|
+
#define str14icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13) \
|
|
130
|
+
(str13icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12) && \
|
|
131
|
+
(m[13] == c13 || m[13] == (c13 ^ 0x20)))
|
|
132
|
+
|
|
133
|
+
#define str15icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14) \
|
|
134
|
+
(str14icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13) && \
|
|
135
|
+
(m[14] == c14 || m[14] == (c14 ^ 0x20)))
|
|
136
|
+
|
|
137
|
+
#define str16icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15) \
|
|
138
|
+
(str15icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14) && \
|
|
139
|
+
(m[15] == c15 || m[15] == (c15 ^ 0x20)))
|
|
140
|
+
|
|
141
|
+
void memcache_parse_req(struct msg *r);
|
|
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
|
+
void memcache_pre_coalesce(struct msg *r);
|
|
146
|
+
void memcache_post_coalesce(struct msg *r);
|
|
147
|
+
|
|
148
|
+
void redis_parse_req(struct msg *r);
|
|
149
|
+
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
|
+
void redis_pre_coalesce(struct msg *r);
|
|
153
|
+
void redis_post_coalesce(struct msg *r);
|
|
154
|
+
|
|
155
|
+
#endif
|
|
@@ -0,0 +1,2102 @@
|
|
|
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 <stdio.h>
|
|
19
|
+
#include <ctype.h>
|
|
20
|
+
|
|
21
|
+
#include <nc_core.h>
|
|
22
|
+
#include <nc_proto.h>
|
|
23
|
+
|
|
24
|
+
/*
|
|
25
|
+
* Return true, if the redis command accepts no arguments, otherwise
|
|
26
|
+
* return false
|
|
27
|
+
*/
|
|
28
|
+
static bool
|
|
29
|
+
redis_arg0(struct msg *r)
|
|
30
|
+
{
|
|
31
|
+
switch (r->type) {
|
|
32
|
+
case MSG_REQ_REDIS_EXISTS:
|
|
33
|
+
case MSG_REQ_REDIS_PERSIST:
|
|
34
|
+
case MSG_REQ_REDIS_PTTL:
|
|
35
|
+
case MSG_REQ_REDIS_TTL:
|
|
36
|
+
case MSG_REQ_REDIS_TYPE:
|
|
37
|
+
|
|
38
|
+
case MSG_REQ_REDIS_DECR:
|
|
39
|
+
case MSG_REQ_REDIS_GET:
|
|
40
|
+
case MSG_REQ_REDIS_INCR:
|
|
41
|
+
case MSG_REQ_REDIS_STRLEN:
|
|
42
|
+
|
|
43
|
+
case MSG_REQ_REDIS_HGETALL:
|
|
44
|
+
case MSG_REQ_REDIS_HKEYS:
|
|
45
|
+
case MSG_REQ_REDIS_HLEN:
|
|
46
|
+
case MSG_REQ_REDIS_HVALS:
|
|
47
|
+
|
|
48
|
+
case MSG_REQ_REDIS_LLEN:
|
|
49
|
+
case MSG_REQ_REDIS_LPOP:
|
|
50
|
+
case MSG_REQ_REDIS_RPOP:
|
|
51
|
+
|
|
52
|
+
case MSG_REQ_REDIS_SCARD:
|
|
53
|
+
case MSG_REQ_REDIS_SMEMBERS:
|
|
54
|
+
case MSG_REQ_REDIS_SPOP:
|
|
55
|
+
case MSG_REQ_REDIS_SRANDMEMBER:
|
|
56
|
+
|
|
57
|
+
case MSG_REQ_REDIS_ZCARD:
|
|
58
|
+
return true;
|
|
59
|
+
|
|
60
|
+
default:
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/*
|
|
68
|
+
* Return true, if the redis command accepts exactly 1 argument, otherwise
|
|
69
|
+
* return false
|
|
70
|
+
*/
|
|
71
|
+
static bool
|
|
72
|
+
redis_arg1(struct msg *r)
|
|
73
|
+
{
|
|
74
|
+
switch (r->type) {
|
|
75
|
+
case MSG_REQ_REDIS_EXPIRE:
|
|
76
|
+
case MSG_REQ_REDIS_EXPIREAT:
|
|
77
|
+
case MSG_REQ_REDIS_PEXPIRE:
|
|
78
|
+
case MSG_REQ_REDIS_PEXPIREAT:
|
|
79
|
+
|
|
80
|
+
case MSG_REQ_REDIS_APPEND:
|
|
81
|
+
case MSG_REQ_REDIS_DECRBY:
|
|
82
|
+
case MSG_REQ_REDIS_GETBIT:
|
|
83
|
+
case MSG_REQ_REDIS_GETSET:
|
|
84
|
+
case MSG_REQ_REDIS_INCRBY:
|
|
85
|
+
case MSG_REQ_REDIS_INCRBYFLOAT:
|
|
86
|
+
case MSG_REQ_REDIS_SET:
|
|
87
|
+
case MSG_REQ_REDIS_SETNX:
|
|
88
|
+
|
|
89
|
+
case MSG_REQ_REDIS_HEXISTS:
|
|
90
|
+
case MSG_REQ_REDIS_HGET:
|
|
91
|
+
|
|
92
|
+
case MSG_REQ_REDIS_LINDEX:
|
|
93
|
+
case MSG_REQ_REDIS_LPUSHX:
|
|
94
|
+
case MSG_REQ_REDIS_RPOPLPUSH:
|
|
95
|
+
case MSG_REQ_REDIS_RPUSHX:
|
|
96
|
+
|
|
97
|
+
case MSG_REQ_REDIS_SISMEMBER:
|
|
98
|
+
|
|
99
|
+
case MSG_REQ_REDIS_ZRANK:
|
|
100
|
+
case MSG_REQ_REDIS_ZREVRANK:
|
|
101
|
+
case MSG_REQ_REDIS_ZSCORE:
|
|
102
|
+
return true;
|
|
103
|
+
|
|
104
|
+
default:
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/*
|
|
112
|
+
* Return true, if the redis command accepts exactly 2 arguments, otherwise
|
|
113
|
+
* return false
|
|
114
|
+
*/
|
|
115
|
+
static bool
|
|
116
|
+
redis_arg2(struct msg *r)
|
|
117
|
+
{
|
|
118
|
+
switch (r->type) {
|
|
119
|
+
case MSG_REQ_REDIS_GETRANGE:
|
|
120
|
+
case MSG_REQ_REDIS_PSETEX:
|
|
121
|
+
case MSG_REQ_REDIS_SETBIT:
|
|
122
|
+
case MSG_REQ_REDIS_SETEX:
|
|
123
|
+
case MSG_REQ_REDIS_SETRANGE:
|
|
124
|
+
|
|
125
|
+
case MSG_REQ_REDIS_HINCRBY:
|
|
126
|
+
case MSG_REQ_REDIS_HINCRBYFLOAT:
|
|
127
|
+
case MSG_REQ_REDIS_HSET:
|
|
128
|
+
case MSG_REQ_REDIS_HSETNX:
|
|
129
|
+
|
|
130
|
+
case MSG_REQ_REDIS_LRANGE:
|
|
131
|
+
case MSG_REQ_REDIS_LREM:
|
|
132
|
+
case MSG_REQ_REDIS_LSET:
|
|
133
|
+
case MSG_REQ_REDIS_LTRIM:
|
|
134
|
+
|
|
135
|
+
case MSG_REQ_REDIS_SMOVE:
|
|
136
|
+
|
|
137
|
+
case MSG_REQ_REDIS_ZCOUNT:
|
|
138
|
+
case MSG_REQ_REDIS_ZINCRBY:
|
|
139
|
+
case MSG_REQ_REDIS_ZREMRANGEBYRANK:
|
|
140
|
+
case MSG_REQ_REDIS_ZREMRANGEBYSCORE:
|
|
141
|
+
return true;
|
|
142
|
+
|
|
143
|
+
default:
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/*
|
|
151
|
+
* Return true, if the redis command accepts exactly 3 arguments, otherwise
|
|
152
|
+
* return false
|
|
153
|
+
*/
|
|
154
|
+
static bool
|
|
155
|
+
redis_arg3(struct msg *r)
|
|
156
|
+
{
|
|
157
|
+
switch (r->type) {
|
|
158
|
+
case MSG_REQ_REDIS_LINSERT:
|
|
159
|
+
return true;
|
|
160
|
+
|
|
161
|
+
default:
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/*
|
|
169
|
+
* Return true, if the redis command accepts 0 or more arguments, otherwise
|
|
170
|
+
* return false
|
|
171
|
+
*/
|
|
172
|
+
static bool
|
|
173
|
+
redis_argn(struct msg *r)
|
|
174
|
+
{
|
|
175
|
+
switch (r->type) {
|
|
176
|
+
case MSG_REQ_REDIS_BITCOUNT:
|
|
177
|
+
|
|
178
|
+
case MSG_REQ_REDIS_HDEL:
|
|
179
|
+
case MSG_REQ_REDIS_HMGET:
|
|
180
|
+
case MSG_REQ_REDIS_HMSET:
|
|
181
|
+
|
|
182
|
+
case MSG_REQ_REDIS_LPUSH:
|
|
183
|
+
case MSG_REQ_REDIS_RPUSH:
|
|
184
|
+
|
|
185
|
+
case MSG_REQ_REDIS_SADD:
|
|
186
|
+
case MSG_REQ_REDIS_SDIFF:
|
|
187
|
+
case MSG_REQ_REDIS_SDIFFSTORE:
|
|
188
|
+
case MSG_REQ_REDIS_SINTER:
|
|
189
|
+
case MSG_REQ_REDIS_SINTERSTORE:
|
|
190
|
+
case MSG_REQ_REDIS_SREM:
|
|
191
|
+
case MSG_REQ_REDIS_SUNION:
|
|
192
|
+
case MSG_REQ_REDIS_SUNIONSTORE:
|
|
193
|
+
|
|
194
|
+
case MSG_REQ_REDIS_ZADD:
|
|
195
|
+
case MSG_REQ_REDIS_ZINTERSTORE:
|
|
196
|
+
case MSG_REQ_REDIS_ZRANGE:
|
|
197
|
+
case MSG_REQ_REDIS_ZRANGEBYSCORE:
|
|
198
|
+
case MSG_REQ_REDIS_ZREM:
|
|
199
|
+
case MSG_REQ_REDIS_ZREVRANGE:
|
|
200
|
+
case MSG_REQ_REDIS_ZREVRANGEBYSCORE:
|
|
201
|
+
case MSG_REQ_REDIS_ZUNIONSTORE:
|
|
202
|
+
return true;
|
|
203
|
+
|
|
204
|
+
default:
|
|
205
|
+
break;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/*
|
|
212
|
+
* Return true, if the redis command is a vector command accepting one or
|
|
213
|
+
* more keys, otherwise return false
|
|
214
|
+
*/
|
|
215
|
+
static bool
|
|
216
|
+
redis_argx(struct msg *r)
|
|
217
|
+
{
|
|
218
|
+
switch (r->type) {
|
|
219
|
+
case MSG_REQ_REDIS_MGET:
|
|
220
|
+
case MSG_REQ_REDIS_DEL:
|
|
221
|
+
return true;
|
|
222
|
+
|
|
223
|
+
default:
|
|
224
|
+
break;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return false;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/*
|
|
231
|
+
* Return true, if the redis command is either EVAL or EVALSHA. These commands
|
|
232
|
+
* have a special format with exactly 2 arguments, followed by one or more keys,
|
|
233
|
+
* followed by zero or more arguments (the documentation online seems to suggest
|
|
234
|
+
* that at least one argument is required, but that shouldn't be the case).
|
|
235
|
+
*/
|
|
236
|
+
static bool
|
|
237
|
+
redis_argeval(struct msg *r)
|
|
238
|
+
{
|
|
239
|
+
switch (r->type) {
|
|
240
|
+
case MSG_REQ_REDIS_EVAL:
|
|
241
|
+
case MSG_REQ_REDIS_EVALSHA:
|
|
242
|
+
return true;
|
|
243
|
+
|
|
244
|
+
default:
|
|
245
|
+
break;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return false;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/*
|
|
252
|
+
* Reference: http://redis.io/topics/protocol
|
|
253
|
+
*
|
|
254
|
+
* Redis >= 1.2 uses the unified protocol to send requests to the Redis
|
|
255
|
+
* server. In the unified protocol all the arguments sent to the server
|
|
256
|
+
* are binary safe and every request has the following general form:
|
|
257
|
+
*
|
|
258
|
+
* *<number of arguments> CR LF
|
|
259
|
+
* $<number of bytes of argument 1> CR LF
|
|
260
|
+
* <argument data> CR LF
|
|
261
|
+
* ...
|
|
262
|
+
* $<number of bytes of argument N> CR LF
|
|
263
|
+
* <argument data> CR LF
|
|
264
|
+
*
|
|
265
|
+
* Before the unified request protocol, redis protocol for requests supported
|
|
266
|
+
* the following commands
|
|
267
|
+
* 1). Inline commands: simple commands where arguments are just space
|
|
268
|
+
* separated strings. No binary safeness is possible.
|
|
269
|
+
* 2). Bulk commands: bulk commands are exactly like inline commands, but
|
|
270
|
+
* the last argument is handled in a special way in order to allow for
|
|
271
|
+
* a binary-safe last argument.
|
|
272
|
+
*
|
|
273
|
+
* Nutcracker only supports the Redis unified protocol for requests.
|
|
274
|
+
*/
|
|
275
|
+
void
|
|
276
|
+
redis_parse_req(struct msg *r)
|
|
277
|
+
{
|
|
278
|
+
struct mbuf *b;
|
|
279
|
+
uint8_t *p, *m;
|
|
280
|
+
uint8_t ch;
|
|
281
|
+
enum {
|
|
282
|
+
SW_START,
|
|
283
|
+
SW_NARG,
|
|
284
|
+
SW_NARG_LF,
|
|
285
|
+
SW_REQ_TYPE_LEN,
|
|
286
|
+
SW_REQ_TYPE_LEN_LF,
|
|
287
|
+
SW_REQ_TYPE,
|
|
288
|
+
SW_REQ_TYPE_LF,
|
|
289
|
+
SW_KEY_LEN,
|
|
290
|
+
SW_KEY_LEN_LF,
|
|
291
|
+
SW_KEY,
|
|
292
|
+
SW_KEY_LF,
|
|
293
|
+
SW_ARG1_LEN,
|
|
294
|
+
SW_ARG1_LEN_LF,
|
|
295
|
+
SW_ARG1,
|
|
296
|
+
SW_ARG1_LF,
|
|
297
|
+
SW_ARG2_LEN,
|
|
298
|
+
SW_ARG2_LEN_LF,
|
|
299
|
+
SW_ARG2,
|
|
300
|
+
SW_ARG2_LF,
|
|
301
|
+
SW_ARG3_LEN,
|
|
302
|
+
SW_ARG3_LEN_LF,
|
|
303
|
+
SW_ARG3,
|
|
304
|
+
SW_ARG3_LF,
|
|
305
|
+
SW_ARGN_LEN,
|
|
306
|
+
SW_ARGN_LEN_LF,
|
|
307
|
+
SW_ARGN,
|
|
308
|
+
SW_ARGN_LF,
|
|
309
|
+
SW_FRAGMENT,
|
|
310
|
+
SW_SENTINEL
|
|
311
|
+
} state;
|
|
312
|
+
|
|
313
|
+
state = r->state;
|
|
314
|
+
b = STAILQ_LAST(&r->mhdr, mbuf, next);
|
|
315
|
+
|
|
316
|
+
ASSERT(r->request);
|
|
317
|
+
ASSERT(state >= SW_START && state < SW_SENTINEL);
|
|
318
|
+
ASSERT(b != NULL);
|
|
319
|
+
ASSERT(b->pos <= b->last);
|
|
320
|
+
|
|
321
|
+
/* validate the parsing maker */
|
|
322
|
+
ASSERT(r->pos != NULL);
|
|
323
|
+
ASSERT(r->pos >= b->pos && r->pos <= b->last);
|
|
324
|
+
|
|
325
|
+
for (p = r->pos; p < b->last; p++) {
|
|
326
|
+
ch = *p;
|
|
327
|
+
|
|
328
|
+
switch (state) {
|
|
329
|
+
|
|
330
|
+
case SW_START:
|
|
331
|
+
case SW_NARG:
|
|
332
|
+
if (r->token == NULL) {
|
|
333
|
+
if (ch != '*') {
|
|
334
|
+
goto error;
|
|
335
|
+
}
|
|
336
|
+
r->token = p;
|
|
337
|
+
/* req_start <- p */
|
|
338
|
+
r->narg_start = p;
|
|
339
|
+
r->rnarg = 0;
|
|
340
|
+
state = SW_NARG;
|
|
341
|
+
} else if (isdigit(ch)) {
|
|
342
|
+
r->rnarg = r->rnarg * 10 + (uint32_t)(ch - '0');
|
|
343
|
+
} else if (ch == CR) {
|
|
344
|
+
if (r->rnarg == 0) {
|
|
345
|
+
goto error;
|
|
346
|
+
}
|
|
347
|
+
r->narg = r->rnarg;
|
|
348
|
+
r->narg_end = p;
|
|
349
|
+
r->token = NULL;
|
|
350
|
+
state = SW_NARG_LF;
|
|
351
|
+
} else {
|
|
352
|
+
goto error;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
break;
|
|
356
|
+
|
|
357
|
+
case SW_NARG_LF:
|
|
358
|
+
switch (ch) {
|
|
359
|
+
case LF:
|
|
360
|
+
state = SW_REQ_TYPE_LEN;
|
|
361
|
+
break;
|
|
362
|
+
|
|
363
|
+
default:
|
|
364
|
+
goto error;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
break;
|
|
368
|
+
|
|
369
|
+
case SW_REQ_TYPE_LEN:
|
|
370
|
+
if (r->token == NULL) {
|
|
371
|
+
if (ch != '$') {
|
|
372
|
+
goto error;
|
|
373
|
+
}
|
|
374
|
+
r->token = p;
|
|
375
|
+
r->rlen = 0;
|
|
376
|
+
} else if (isdigit(ch)) {
|
|
377
|
+
r->rlen = r->rlen * 10 + (uint32_t)(ch - '0');
|
|
378
|
+
} else if (ch == CR) {
|
|
379
|
+
if (r->rlen == 0 || r->rnarg == 0) {
|
|
380
|
+
goto error;
|
|
381
|
+
}
|
|
382
|
+
r->rnarg--;
|
|
383
|
+
r->token = NULL;
|
|
384
|
+
state = SW_REQ_TYPE_LEN_LF;
|
|
385
|
+
} else {
|
|
386
|
+
goto error;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
break;
|
|
390
|
+
|
|
391
|
+
case SW_REQ_TYPE_LEN_LF:
|
|
392
|
+
switch (ch) {
|
|
393
|
+
case LF:
|
|
394
|
+
state = SW_REQ_TYPE;
|
|
395
|
+
break;
|
|
396
|
+
|
|
397
|
+
default:
|
|
398
|
+
goto error;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
break;
|
|
402
|
+
|
|
403
|
+
case SW_REQ_TYPE:
|
|
404
|
+
if (r->token == NULL) {
|
|
405
|
+
r->token = p;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
m = r->token + r->rlen;
|
|
409
|
+
if (m >= b->last) {
|
|
410
|
+
m = b->last - 1;
|
|
411
|
+
p = m;
|
|
412
|
+
break;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
if (*m != CR) {
|
|
416
|
+
goto error;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
p = m; /* move forward by rlen bytes */
|
|
420
|
+
r->rlen = 0;
|
|
421
|
+
m = r->token;
|
|
422
|
+
r->token = NULL;
|
|
423
|
+
r->type = MSG_UNKNOWN;
|
|
424
|
+
|
|
425
|
+
switch (p - m) {
|
|
426
|
+
|
|
427
|
+
case 3:
|
|
428
|
+
if (str3icmp(m, 'g', 'e', 't')) {
|
|
429
|
+
r->type = MSG_REQ_REDIS_GET;
|
|
430
|
+
break;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
if (str3icmp(m, 's', 'e', 't')) {
|
|
434
|
+
r->type = MSG_REQ_REDIS_SET;
|
|
435
|
+
break;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
if (str3icmp(m, 't', 't', 'l')) {
|
|
439
|
+
r->type = MSG_REQ_REDIS_TTL;
|
|
440
|
+
break;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
if (str3icmp(m, 'd', 'e', 'l')) {
|
|
444
|
+
r->type = MSG_REQ_REDIS_DEL;
|
|
445
|
+
break;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
break;
|
|
449
|
+
|
|
450
|
+
case 4:
|
|
451
|
+
if (str4icmp(m, 'p', 't', 't', 'l')) {
|
|
452
|
+
r->type = MSG_REQ_REDIS_PTTL;
|
|
453
|
+
break;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
if (str4icmp(m, 'd', 'e', 'c', 'r')) {
|
|
457
|
+
r->type = MSG_REQ_REDIS_DECR;
|
|
458
|
+
break;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
if (str4icmp(m, 'h', 'd', 'e', 'l')) {
|
|
462
|
+
r->type = MSG_REQ_REDIS_HDEL;
|
|
463
|
+
break;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
if (str4icmp(m, 'h', 'g', 'e', 't')) {
|
|
467
|
+
r->type = MSG_REQ_REDIS_HGET;
|
|
468
|
+
break;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
if (str4icmp(m, 'h', 'l', 'e', 'n')) {
|
|
472
|
+
r->type = MSG_REQ_REDIS_HLEN;
|
|
473
|
+
break;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
if (str4icmp(m, 'h', 's', 'e', 't')) {
|
|
477
|
+
r->type = MSG_REQ_REDIS_HSET;
|
|
478
|
+
break;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
if (str4icmp(m, 'i', 'n', 'c', 'r')) {
|
|
482
|
+
r->type = MSG_REQ_REDIS_INCR;
|
|
483
|
+
break;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
if (str4icmp(m, 'l', 'l', 'e', 'n')) {
|
|
487
|
+
r->type = MSG_REQ_REDIS_LLEN;
|
|
488
|
+
break;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
if (str4icmp(m, 'l', 'p', 'o', 'p')) {
|
|
492
|
+
r->type = MSG_REQ_REDIS_LPOP;
|
|
493
|
+
break;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
if (str4icmp(m, 'l', 'r', 'e', 'm')) {
|
|
497
|
+
r->type = MSG_REQ_REDIS_LREM;
|
|
498
|
+
break;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
if (str4icmp(m, 'l', 's', 'e', 't')) {
|
|
502
|
+
r->type = MSG_REQ_REDIS_LSET;
|
|
503
|
+
break;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
if (str4icmp(m, 'r', 'p', 'o', 'p')) {
|
|
507
|
+
r->type = MSG_REQ_REDIS_RPOP;
|
|
508
|
+
break;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
if (str4icmp(m, 's', 'a', 'd', 'd')) {
|
|
512
|
+
r->type = MSG_REQ_REDIS_SADD;
|
|
513
|
+
break;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
if (str4icmp(m, 's', 'p', 'o', 'p')) {
|
|
517
|
+
r->type = MSG_REQ_REDIS_SPOP;
|
|
518
|
+
break;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
if (str4icmp(m, 's', 'r', 'e', 'm')) {
|
|
522
|
+
r->type = MSG_REQ_REDIS_SREM;
|
|
523
|
+
break;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
if (str4icmp(m, 't', 'y', 'p', 'e')) {
|
|
527
|
+
r->type = MSG_REQ_REDIS_TYPE;
|
|
528
|
+
break;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
if (str4icmp(m, 'm', 'g', 'e', 't')) {
|
|
532
|
+
r->type = MSG_REQ_REDIS_MGET;
|
|
533
|
+
break;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
if (str4icmp(m, 'z', 'a', 'd', 'd')) {
|
|
537
|
+
r->type = MSG_REQ_REDIS_ZADD;
|
|
538
|
+
break;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
if (str4icmp(m, 'z', 'r', 'e', 'm')) {
|
|
542
|
+
r->type = MSG_REQ_REDIS_ZREM;
|
|
543
|
+
break;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
if (str4icmp(m, 'e', 'v', 'a', 'l')) {
|
|
547
|
+
r->type = MSG_REQ_REDIS_EVAL;
|
|
548
|
+
break;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
break;
|
|
552
|
+
|
|
553
|
+
case 5:
|
|
554
|
+
if (str5icmp(m, 'h', 'k', 'e', 'y', 's')) {
|
|
555
|
+
r->type = MSG_REQ_REDIS_HKEYS;
|
|
556
|
+
break;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
if (str5icmp(m, 'h', 'm', 'g', 'e', 't')) {
|
|
560
|
+
r->type = MSG_REQ_REDIS_HMGET;
|
|
561
|
+
break;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
if (str5icmp(m, 'h', 'm', 's', 'e', 't')) {
|
|
565
|
+
r->type = MSG_REQ_REDIS_HMSET;
|
|
566
|
+
break;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
if (str5icmp(m, 'h', 'v', 'a', 'l', 's')) {
|
|
570
|
+
r->type = MSG_REQ_REDIS_HVALS;
|
|
571
|
+
break;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
if (str5icmp(m, 'l', 'p', 'u', 's', 'h')) {
|
|
575
|
+
r->type = MSG_REQ_REDIS_LPUSH;
|
|
576
|
+
break;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
if (str5icmp(m, 'l', 't', 'r', 'i', 'm')) {
|
|
580
|
+
r->type = MSG_REQ_REDIS_LTRIM;
|
|
581
|
+
break;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
if (str5icmp(m, 'r', 'p', 'u', 's', 'h')) {
|
|
585
|
+
r->type = MSG_REQ_REDIS_RPUSH;
|
|
586
|
+
break;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
if (str5icmp(m, 's', 'c', 'a', 'r', 'd')) {
|
|
590
|
+
r->type = MSG_REQ_REDIS_SCARD;
|
|
591
|
+
break;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
if (str5icmp(m, 's', 'd', 'i', 'f', 'f')) {
|
|
595
|
+
r->type = MSG_REQ_REDIS_SDIFF;
|
|
596
|
+
break;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
if (str5icmp(m, 's', 'e', 't', 'e', 'x')) {
|
|
600
|
+
r->type = MSG_REQ_REDIS_SETEX;
|
|
601
|
+
break;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
if (str5icmp(m, 's', 'e', 't', 'n', 'x')) {
|
|
605
|
+
r->type = MSG_REQ_REDIS_SETNX;
|
|
606
|
+
break;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
if (str5icmp(m, 's', 'm', 'o', 'v', 'e')) {
|
|
610
|
+
r->type = MSG_REQ_REDIS_SMOVE;
|
|
611
|
+
break;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
if (str5icmp(m, 'z', 'c', 'a', 'r', 'd')) {
|
|
615
|
+
r->type = MSG_REQ_REDIS_ZCARD;
|
|
616
|
+
break;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
if (str5icmp(m, 'z', 'r', 'a', 'n', 'k')) {
|
|
620
|
+
r->type = MSG_REQ_REDIS_ZRANK;
|
|
621
|
+
break;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
break;
|
|
625
|
+
|
|
626
|
+
case 6:
|
|
627
|
+
if (str6icmp(m, 'a', 'p', 'p', 'e', 'n', 'd')) {
|
|
628
|
+
r->type = MSG_REQ_REDIS_APPEND;
|
|
629
|
+
break;
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
if (str6icmp(m, 'd', 'e', 'c', 'r', 'b', 'y')) {
|
|
633
|
+
r->type = MSG_REQ_REDIS_DECRBY;
|
|
634
|
+
break;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
if (str6icmp(m, 'e', 'x', 'i', 's', 't', 's')) {
|
|
638
|
+
r->type = MSG_REQ_REDIS_EXISTS;
|
|
639
|
+
break;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
if (str6icmp(m, 'e', 'x', 'p', 'i', 'r', 'e')) {
|
|
643
|
+
r->type = MSG_REQ_REDIS_EXPIRE;
|
|
644
|
+
break;
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
if (str6icmp(m, 'g', 'e', 't', 'b', 'i', 't')) {
|
|
648
|
+
r->type = MSG_REQ_REDIS_GETBIT;
|
|
649
|
+
break;
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
if (str6icmp(m, 'g', 'e', 't', 's', 'e', 't')) {
|
|
653
|
+
r->type = MSG_REQ_REDIS_GETSET;
|
|
654
|
+
break;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
if (str6icmp(m, 'p', 's', 'e', 't', 'e', 'x')) {
|
|
658
|
+
r->type = MSG_REQ_REDIS_PSETEX;
|
|
659
|
+
break;
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
if (str6icmp(m, 'h', 's', 'e', 't', 'n', 'x')) {
|
|
663
|
+
r->type = MSG_REQ_REDIS_HSETNX;
|
|
664
|
+
break;
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
if (str6icmp(m, 'i', 'n', 'c', 'r', 'b', 'y')) {
|
|
668
|
+
r->type = MSG_REQ_REDIS_INCRBY;
|
|
669
|
+
break;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
if (str6icmp(m, 'l', 'i', 'n', 'd', 'e', 'x')) {
|
|
673
|
+
r->type = MSG_REQ_REDIS_LINDEX;
|
|
674
|
+
break;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
if (str6icmp(m, 'l', 'p', 'u', 's', 'h', 'x')) {
|
|
678
|
+
r->type = MSG_REQ_REDIS_LPUSHX;
|
|
679
|
+
break;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
if (str6icmp(m, 'l', 'r', 'a', 'n', 'g', 'e')) {
|
|
683
|
+
r->type = MSG_REQ_REDIS_LRANGE;
|
|
684
|
+
break;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
if (str6icmp(m, 'r', 'p', 'u', 's', 'h', 'x')) {
|
|
688
|
+
r->type = MSG_REQ_REDIS_RPUSHX;
|
|
689
|
+
break;
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
if (str6icmp(m, 's', 'e', 't', 'b', 'i', 't')) {
|
|
693
|
+
r->type = MSG_REQ_REDIS_SETBIT;
|
|
694
|
+
break;
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
if (str6icmp(m, 's', 'i', 'n', 't', 'e', 'r')) {
|
|
698
|
+
r->type = MSG_REQ_REDIS_SINTER;
|
|
699
|
+
break;
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
if (str6icmp(m, 's', 't', 'r', 'l', 'e', 'n')) {
|
|
703
|
+
r->type = MSG_REQ_REDIS_STRLEN;
|
|
704
|
+
break;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
if (str6icmp(m, 's', 'u', 'n', 'i', 'o', 'n')) {
|
|
708
|
+
r->type = MSG_REQ_REDIS_SUNION;
|
|
709
|
+
break;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
if (str6icmp(m, 'z', 'c', 'o', 'u', 'n', 't')) {
|
|
713
|
+
r->type = MSG_REQ_REDIS_ZCOUNT;
|
|
714
|
+
break;
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
if (str6icmp(m, 'z', 'r', 'a', 'n', 'g', 'e')) {
|
|
718
|
+
r->type = MSG_REQ_REDIS_ZRANGE;
|
|
719
|
+
break;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
if (str6icmp(m, 'z', 's', 'c', 'o', 'r', 'e')) {
|
|
723
|
+
r->type = MSG_REQ_REDIS_ZSCORE;
|
|
724
|
+
break;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
break;
|
|
728
|
+
|
|
729
|
+
case 7:
|
|
730
|
+
if (str7icmp(m, 'p', 'e', 'r', 's', 'i', 's', 't')) {
|
|
731
|
+
r->type = MSG_REQ_REDIS_PERSIST;
|
|
732
|
+
break;
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
if (str7icmp(m, 'p', 'e', 'x', 'p', 'i', 'r', 'e')) {
|
|
736
|
+
r->type = MSG_REQ_REDIS_PEXPIRE;
|
|
737
|
+
break;
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
if (str7icmp(m, 'h', 'e', 'x', 'i', 's', 't', 's')) {
|
|
741
|
+
r->type = MSG_REQ_REDIS_HEXISTS;
|
|
742
|
+
break;
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
if (str7icmp(m, 'h', 'g', 'e', 't', 'a', 'l', 'l')) {
|
|
746
|
+
r->type = MSG_REQ_REDIS_HGETALL;
|
|
747
|
+
break;
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
if (str7icmp(m, 'h', 'i', 'n', 'c', 'r', 'b', 'y')) {
|
|
751
|
+
r->type = MSG_REQ_REDIS_HINCRBY;
|
|
752
|
+
break;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
if (str7icmp(m, 'l', 'i', 'n', 's', 'e', 'r', 't')) {
|
|
756
|
+
r->type = MSG_REQ_REDIS_LINSERT;
|
|
757
|
+
break;
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
if (str7icmp(m, 'z', 'i', 'n', 'c', 'r', 'b', 'y')) {
|
|
761
|
+
r->type = MSG_REQ_REDIS_ZINCRBY;
|
|
762
|
+
break;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
if (str7icmp(m, 'e', 'v', 'a', 'l', 's', 'h', 'a')) {
|
|
766
|
+
r->type = MSG_REQ_REDIS_EVALSHA;
|
|
767
|
+
break;
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
break;
|
|
771
|
+
|
|
772
|
+
case 8:
|
|
773
|
+
if (str8icmp(m, 'e', 'x', 'p', 'i', 'r', 'e', 'a', 't')) {
|
|
774
|
+
r->type = MSG_REQ_REDIS_EXPIREAT;
|
|
775
|
+
break;
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
if (str8icmp(m, 'b', 'i', 't', 'c', 'o', 'u', 'n', 't')) {
|
|
779
|
+
r->type = MSG_REQ_REDIS_BITCOUNT;
|
|
780
|
+
break;
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
if (str8icmp(m, 'g', 'e', 't', 'r', 'a', 'n', 'g', 'e')) {
|
|
784
|
+
r->type = MSG_REQ_REDIS_GETRANGE;
|
|
785
|
+
break;
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
if (str8icmp(m, 's', 'e', 't', 'r', 'a', 'n', 'g', 'e')) {
|
|
789
|
+
r->type = MSG_REQ_REDIS_SETRANGE;
|
|
790
|
+
break;
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
if (str8icmp(m, 's', 'm', 'e', 'm', 'b', 'e', 'r', 's')) {
|
|
794
|
+
r->type = MSG_REQ_REDIS_SMEMBERS;
|
|
795
|
+
break;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
if (str8icmp(m, 'z', 'r', 'e', 'v', 'r', 'a', 'n', 'k')) {
|
|
799
|
+
r->type = MSG_REQ_REDIS_ZREVRANK;
|
|
800
|
+
break;
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
break;
|
|
804
|
+
|
|
805
|
+
case 9:
|
|
806
|
+
if (str9icmp(m, 'p', 'e', 'x', 'p', 'i', 'r', 'e', 'a', 't')) {
|
|
807
|
+
r->type = MSG_REQ_REDIS_PEXPIREAT;
|
|
808
|
+
break;
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
if (str9icmp(m, 'r', 'p', 'o', 'p', 'l', 'p', 'u', 's', 'h')) {
|
|
812
|
+
r->type = MSG_REQ_REDIS_RPOPLPUSH;
|
|
813
|
+
break;
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
if (str9icmp(m, 's', 'i', 's', 'm', 'e', 'm', 'b', 'e', 'r')) {
|
|
817
|
+
r->type = MSG_REQ_REDIS_SISMEMBER;
|
|
818
|
+
break;
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
if (str9icmp(m, 'z', 'r', 'e', 'v', 'r', 'a', 'n', 'g', 'e')) {
|
|
822
|
+
r->type = MSG_REQ_REDIS_ZREVRANGE;
|
|
823
|
+
break;
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
break;
|
|
827
|
+
|
|
828
|
+
case 10:
|
|
829
|
+
if (str10icmp(m, 's', 'd', 'i', 'f', 'f', 's', 't', 'o', 'r', 'e')) {
|
|
830
|
+
r->type = MSG_REQ_REDIS_SDIFFSTORE;
|
|
831
|
+
break;
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
case 11:
|
|
835
|
+
if (str11icmp(m, 'i', 'n', 'c', 'r', 'b', 'y', 'f', 'l', 'o', 'a', 't')) {
|
|
836
|
+
r->type = MSG_REQ_REDIS_INCRBYFLOAT;
|
|
837
|
+
break;
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
if (str11icmp(m, 's', 'i', 'n', 't', 'e', 'r', 's', 't', 'o', 'r', 'e')) {
|
|
841
|
+
r->type = MSG_REQ_REDIS_SINTERSTORE;
|
|
842
|
+
break;
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
if (str11icmp(m, 's', 'r', 'a', 'n', 'd', 'm', 'e', 'm', 'b', 'e', 'r')) {
|
|
846
|
+
r->type = MSG_REQ_REDIS_SRANDMEMBER;
|
|
847
|
+
break;
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
if (str11icmp(m, 's', 'u', 'n', 'i', 'o', 'n', 's', 't', 'o', 'r', 'e')) {
|
|
851
|
+
r->type = MSG_REQ_REDIS_SUNIONSTORE;
|
|
852
|
+
break;
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
if (str11icmp(m, 'z', 'i', 'n', 't', 'e', 'r', 's', 't', 'o', 'r', 'e')) {
|
|
856
|
+
r->type = MSG_REQ_REDIS_ZINTERSTORE;
|
|
857
|
+
break;
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
if (str11icmp(m, 'z', 'u', 'n', 'i', 'o', 'n', 's', 't', 'o', 'r', 'e')) {
|
|
861
|
+
r->type = MSG_REQ_REDIS_ZUNIONSTORE;
|
|
862
|
+
break;
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
break;
|
|
866
|
+
|
|
867
|
+
case 12:
|
|
868
|
+
if (str12icmp(m, 'h', 'i', 'n', 'c', 'r', 'b', 'y', 'f', 'l', 'o', 'a', 't')) {
|
|
869
|
+
r->type = MSG_REQ_REDIS_HINCRBYFLOAT;
|
|
870
|
+
break;
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
|
|
874
|
+
break;
|
|
875
|
+
|
|
876
|
+
case 13:
|
|
877
|
+
if (str13icmp(m, 'z', 'r', 'a', 'n', 'g', 'e', 'b', 'y', 's', 'c', 'o', 'r', 'e')) {
|
|
878
|
+
r->type = MSG_REQ_REDIS_ZRANGEBYSCORE;
|
|
879
|
+
break;
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
break;
|
|
883
|
+
|
|
884
|
+
case 15:
|
|
885
|
+
if (str15icmp(m, 'z', 'r', 'e', 'm', 'r', 'a', 'n', 'g', 'e', 'b', 'y', 'r', 'a', 'n', 'k')) {
|
|
886
|
+
r->type = MSG_REQ_REDIS_ZREMRANGEBYRANK;
|
|
887
|
+
break;
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
break;
|
|
891
|
+
|
|
892
|
+
case 16:
|
|
893
|
+
if (str16icmp(m, 'z', 'r', 'e', 'm', 'r', 'a', 'n', 'g', 'e', 'b', 'y', 's', 'c', 'o', 'r', 'e')) {
|
|
894
|
+
r->type = MSG_REQ_REDIS_ZREMRANGEBYSCORE;
|
|
895
|
+
break;
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
if (str16icmp(m, 'z', 'r', 'e', 'v', 'r', 'a', 'n', 'g', 'e', 'b', 'y', 's', 'c', 'o', 'r', 'e')) {
|
|
899
|
+
r->type = MSG_REQ_REDIS_ZREVRANGEBYSCORE;
|
|
900
|
+
break;
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
break;
|
|
904
|
+
|
|
905
|
+
default:
|
|
906
|
+
break;
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
if (r->type == MSG_UNKNOWN) {
|
|
910
|
+
log_error("parsed unsupported command '%.*s'", p - m, m);
|
|
911
|
+
goto error;
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
log_debug(LOG_VERB, "parsed command '%.*s'", p - m, m);
|
|
915
|
+
|
|
916
|
+
state = SW_REQ_TYPE_LF;
|
|
917
|
+
break;
|
|
918
|
+
|
|
919
|
+
case SW_REQ_TYPE_LF:
|
|
920
|
+
switch (ch) {
|
|
921
|
+
case LF:
|
|
922
|
+
if (redis_argeval(r)) {
|
|
923
|
+
state = SW_ARG1_LEN;
|
|
924
|
+
} else {
|
|
925
|
+
state = SW_KEY_LEN;
|
|
926
|
+
}
|
|
927
|
+
break;
|
|
928
|
+
|
|
929
|
+
default:
|
|
930
|
+
goto error;
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
break;
|
|
934
|
+
|
|
935
|
+
case SW_KEY_LEN:
|
|
936
|
+
if (r->token == NULL) {
|
|
937
|
+
if (ch != '$') {
|
|
938
|
+
goto error;
|
|
939
|
+
}
|
|
940
|
+
r->token = p;
|
|
941
|
+
r->rlen = 0;
|
|
942
|
+
} else if (isdigit(ch)) {
|
|
943
|
+
r->rlen = r->rlen * 10 + (uint32_t)(ch - '0');
|
|
944
|
+
} else if (ch == CR) {
|
|
945
|
+
if (r->rlen == 0) {
|
|
946
|
+
log_error("parsed bad req %"PRIu64" of type %d with empty "
|
|
947
|
+
"key", r->id, r->type);
|
|
948
|
+
goto error;
|
|
949
|
+
}
|
|
950
|
+
if (r->rlen > mbuf_data_size()) {
|
|
951
|
+
log_error("parsed bad req %"PRIu64" of type %d with key "
|
|
952
|
+
"length %d that exceeds maximum redis key "
|
|
953
|
+
"length of %d", r->id, r->type, r->rlen,
|
|
954
|
+
mbuf_data_size());
|
|
955
|
+
goto error;
|
|
956
|
+
}
|
|
957
|
+
if (r->rnarg == 0) {
|
|
958
|
+
goto error;
|
|
959
|
+
}
|
|
960
|
+
r->rnarg--;
|
|
961
|
+
r->token = NULL;
|
|
962
|
+
state = SW_KEY_LEN_LF;
|
|
963
|
+
} else {
|
|
964
|
+
goto error;
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
break;
|
|
968
|
+
|
|
969
|
+
case SW_KEY_LEN_LF:
|
|
970
|
+
switch (ch) {
|
|
971
|
+
case LF:
|
|
972
|
+
state = SW_KEY;
|
|
973
|
+
break;
|
|
974
|
+
|
|
975
|
+
default:
|
|
976
|
+
goto error;
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
break;
|
|
980
|
+
|
|
981
|
+
case SW_KEY:
|
|
982
|
+
if (r->token == NULL) {
|
|
983
|
+
r->token = p;
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
m = r->token + r->rlen;
|
|
987
|
+
if (m >= b->last) {
|
|
988
|
+
m = b->last - 1;
|
|
989
|
+
p = m;
|
|
990
|
+
break;
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
if (*m != CR) {
|
|
994
|
+
goto error;
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
p = m; /* move forward by rlen bytes */
|
|
998
|
+
r->rlen = 0;
|
|
999
|
+
m = r->token;
|
|
1000
|
+
r->token = NULL;
|
|
1001
|
+
|
|
1002
|
+
r->key_start = m;
|
|
1003
|
+
r->key_end = p;
|
|
1004
|
+
|
|
1005
|
+
state = SW_KEY_LF;
|
|
1006
|
+
|
|
1007
|
+
break;
|
|
1008
|
+
|
|
1009
|
+
case SW_KEY_LF:
|
|
1010
|
+
switch (ch) {
|
|
1011
|
+
case LF:
|
|
1012
|
+
if (redis_arg0(r)) {
|
|
1013
|
+
if (r->rnarg != 0) {
|
|
1014
|
+
goto error;
|
|
1015
|
+
}
|
|
1016
|
+
goto done;
|
|
1017
|
+
} else if (redis_arg1(r)) {
|
|
1018
|
+
if (r->rnarg != 1) {
|
|
1019
|
+
goto error;
|
|
1020
|
+
}
|
|
1021
|
+
state = SW_ARG1_LEN;
|
|
1022
|
+
} else if (redis_arg2(r)) {
|
|
1023
|
+
if (r->rnarg != 2) {
|
|
1024
|
+
goto error;
|
|
1025
|
+
}
|
|
1026
|
+
state = SW_ARG1_LEN;
|
|
1027
|
+
} else if (redis_arg3(r)) {
|
|
1028
|
+
if (r->rnarg != 3) {
|
|
1029
|
+
goto error;
|
|
1030
|
+
}
|
|
1031
|
+
state = SW_ARG1_LEN;
|
|
1032
|
+
} else if (redis_argn(r)) {
|
|
1033
|
+
if (r->rnarg == 0) {
|
|
1034
|
+
goto done;
|
|
1035
|
+
}
|
|
1036
|
+
state = SW_ARG1_LEN;
|
|
1037
|
+
} else if (redis_argx(r)) {
|
|
1038
|
+
if (r->rnarg == 0) {
|
|
1039
|
+
goto done;
|
|
1040
|
+
}
|
|
1041
|
+
state = SW_FRAGMENT;
|
|
1042
|
+
} else if (redis_argeval(r)) {
|
|
1043
|
+
if (r->rnarg == 0) {
|
|
1044
|
+
goto done;
|
|
1045
|
+
}
|
|
1046
|
+
state = SW_ARGN_LEN;
|
|
1047
|
+
} else {
|
|
1048
|
+
goto error;
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
break;
|
|
1052
|
+
|
|
1053
|
+
default:
|
|
1054
|
+
goto error;
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
break;
|
|
1058
|
+
|
|
1059
|
+
case SW_FRAGMENT:
|
|
1060
|
+
r->token = p;
|
|
1061
|
+
goto fragment;
|
|
1062
|
+
|
|
1063
|
+
case SW_ARG1_LEN:
|
|
1064
|
+
if (r->token == NULL) {
|
|
1065
|
+
if (ch != '$') {
|
|
1066
|
+
goto error;
|
|
1067
|
+
}
|
|
1068
|
+
r->rlen = 0;
|
|
1069
|
+
r->token = p;
|
|
1070
|
+
} else if (isdigit(ch)) {
|
|
1071
|
+
r->rlen = r->rlen * 10 + (uint32_t)(ch - '0');
|
|
1072
|
+
} else if (ch == CR) {
|
|
1073
|
+
if ((p - r->token) <= 1 || r->rnarg == 0) {
|
|
1074
|
+
goto error;
|
|
1075
|
+
}
|
|
1076
|
+
r->rnarg--;
|
|
1077
|
+
r->token = NULL;
|
|
1078
|
+
state = SW_ARG1_LEN_LF;
|
|
1079
|
+
} else {
|
|
1080
|
+
goto error;
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
break;
|
|
1084
|
+
|
|
1085
|
+
case SW_ARG1_LEN_LF:
|
|
1086
|
+
switch (ch) {
|
|
1087
|
+
case LF:
|
|
1088
|
+
state = SW_ARG1;
|
|
1089
|
+
break;
|
|
1090
|
+
|
|
1091
|
+
default:
|
|
1092
|
+
goto error;
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
break;
|
|
1096
|
+
|
|
1097
|
+
case SW_ARG1:
|
|
1098
|
+
m = p + r->rlen;
|
|
1099
|
+
if (m >= b->last) {
|
|
1100
|
+
r->rlen -= (uint32_t)(b->last - p);
|
|
1101
|
+
m = b->last - 1;
|
|
1102
|
+
p = m;
|
|
1103
|
+
break;
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
if (*m != CR) {
|
|
1107
|
+
goto error;
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
p = m; /* move forward by rlen bytes */
|
|
1111
|
+
r->rlen = 0;
|
|
1112
|
+
|
|
1113
|
+
state = SW_ARG1_LF;
|
|
1114
|
+
|
|
1115
|
+
break;
|
|
1116
|
+
|
|
1117
|
+
case SW_ARG1_LF:
|
|
1118
|
+
switch (ch) {
|
|
1119
|
+
case LF:
|
|
1120
|
+
if (redis_arg1(r)) {
|
|
1121
|
+
if (r->rnarg != 0) {
|
|
1122
|
+
goto error;
|
|
1123
|
+
}
|
|
1124
|
+
goto done;
|
|
1125
|
+
} else if (redis_arg2(r)) {
|
|
1126
|
+
if (r->rnarg != 1) {
|
|
1127
|
+
goto error;
|
|
1128
|
+
}
|
|
1129
|
+
state = SW_ARG2_LEN;
|
|
1130
|
+
} else if (redis_arg3(r)) {
|
|
1131
|
+
if (r->rnarg != 2) {
|
|
1132
|
+
goto error;
|
|
1133
|
+
}
|
|
1134
|
+
state = SW_ARG2_LEN;
|
|
1135
|
+
} else if (redis_argn(r)) {
|
|
1136
|
+
if (r->rnarg == 0) {
|
|
1137
|
+
goto done;
|
|
1138
|
+
}
|
|
1139
|
+
state = SW_ARGN_LEN;
|
|
1140
|
+
} else if (redis_argeval(r)) {
|
|
1141
|
+
if (r->rnarg < 2) {
|
|
1142
|
+
goto error;
|
|
1143
|
+
}
|
|
1144
|
+
state = SW_ARG2_LEN;
|
|
1145
|
+
} else {
|
|
1146
|
+
goto error;
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
break;
|
|
1150
|
+
|
|
1151
|
+
default:
|
|
1152
|
+
goto error;
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
break;
|
|
1156
|
+
|
|
1157
|
+
case SW_ARG2_LEN:
|
|
1158
|
+
if (r->token == NULL) {
|
|
1159
|
+
if (ch != '$') {
|
|
1160
|
+
goto error;
|
|
1161
|
+
}
|
|
1162
|
+
r->rlen = 0;
|
|
1163
|
+
r->token = p;
|
|
1164
|
+
} else if (isdigit(ch)) {
|
|
1165
|
+
r->rlen = r->rlen * 10 + (uint32_t)(ch - '0');
|
|
1166
|
+
} else if (ch == CR) {
|
|
1167
|
+
if ((p - r->token) <= 1 || r->rnarg == 0) {
|
|
1168
|
+
goto error;
|
|
1169
|
+
}
|
|
1170
|
+
r->rnarg--;
|
|
1171
|
+
r->token = NULL;
|
|
1172
|
+
state = SW_ARG2_LEN_LF;
|
|
1173
|
+
} else {
|
|
1174
|
+
goto error;
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
break;
|
|
1178
|
+
|
|
1179
|
+
case SW_ARG2_LEN_LF:
|
|
1180
|
+
switch (ch) {
|
|
1181
|
+
case LF:
|
|
1182
|
+
state = SW_ARG2;
|
|
1183
|
+
break;
|
|
1184
|
+
|
|
1185
|
+
default:
|
|
1186
|
+
goto error;
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
break;
|
|
1190
|
+
|
|
1191
|
+
case SW_ARG2:
|
|
1192
|
+
if (r->token == NULL && redis_argeval(r)) {
|
|
1193
|
+
/*
|
|
1194
|
+
* For EVAL/EVALSHA, ARG2 represents the # key/arg pairs which must
|
|
1195
|
+
* be tokenized and stored in contiguous memory.
|
|
1196
|
+
*/
|
|
1197
|
+
r->token = p;
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
m = p + r->rlen;
|
|
1201
|
+
if (m >= b->last) {
|
|
1202
|
+
r->rlen -= (uint32_t)(b->last - p);
|
|
1203
|
+
m = b->last - 1;
|
|
1204
|
+
p = m;
|
|
1205
|
+
break;
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
if (*m != CR) {
|
|
1209
|
+
goto error;
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
p = m; /* move forward by rlen bytes */
|
|
1213
|
+
r->rlen = 0;
|
|
1214
|
+
|
|
1215
|
+
if (redis_argeval(r)) {
|
|
1216
|
+
uint32_t nkey;
|
|
1217
|
+
uint8_t *chp;
|
|
1218
|
+
|
|
1219
|
+
/*
|
|
1220
|
+
* For EVAL/EVALSHA, we need to find the integer value of this
|
|
1221
|
+
* argument. It tells us the number of keys in the script, and
|
|
1222
|
+
* we need to error out if number of keys is 0. At this point,
|
|
1223
|
+
* both p and m point to the end of the argument and r->token
|
|
1224
|
+
* points to the start.
|
|
1225
|
+
*/
|
|
1226
|
+
if (p - r->token < 1) {
|
|
1227
|
+
goto error;
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
for (nkey = 0, chp = r->token; chp < p; chp++) {
|
|
1231
|
+
if (isdigit(*chp)) {
|
|
1232
|
+
nkey = nkey * 10 + (uint32_t)(*chp - '0');
|
|
1233
|
+
} else {
|
|
1234
|
+
goto error;
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
if (nkey == 0) {
|
|
1238
|
+
goto error;
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
r->token = NULL;
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
state = SW_ARG2_LF;
|
|
1245
|
+
|
|
1246
|
+
break;
|
|
1247
|
+
|
|
1248
|
+
case SW_ARG2_LF:
|
|
1249
|
+
switch (ch) {
|
|
1250
|
+
case LF:
|
|
1251
|
+
if (redis_arg2(r)) {
|
|
1252
|
+
if (r->rnarg != 0) {
|
|
1253
|
+
goto error;
|
|
1254
|
+
}
|
|
1255
|
+
goto done;
|
|
1256
|
+
} else if (redis_arg3(r)) {
|
|
1257
|
+
if (r->rnarg != 1) {
|
|
1258
|
+
goto error;
|
|
1259
|
+
}
|
|
1260
|
+
state = SW_ARG3_LEN;
|
|
1261
|
+
} else if (redis_argn(r)) {
|
|
1262
|
+
if (r->rnarg == 0) {
|
|
1263
|
+
goto done;
|
|
1264
|
+
}
|
|
1265
|
+
state = SW_ARGN_LEN;
|
|
1266
|
+
} else if (redis_argeval(r)) {
|
|
1267
|
+
if (r->rnarg < 1) {
|
|
1268
|
+
goto error;
|
|
1269
|
+
}
|
|
1270
|
+
state = SW_KEY_LEN;
|
|
1271
|
+
} else {
|
|
1272
|
+
goto error;
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
break;
|
|
1276
|
+
|
|
1277
|
+
default:
|
|
1278
|
+
goto error;
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
break;
|
|
1282
|
+
|
|
1283
|
+
case SW_ARG3_LEN:
|
|
1284
|
+
if (r->token == NULL) {
|
|
1285
|
+
if (ch != '$') {
|
|
1286
|
+
goto error;
|
|
1287
|
+
}
|
|
1288
|
+
r->rlen = 0;
|
|
1289
|
+
r->token = p;
|
|
1290
|
+
} else if (isdigit(ch)) {
|
|
1291
|
+
r->rlen = r->rlen * 10 + (uint32_t)(ch - '0');
|
|
1292
|
+
} else if (ch == CR) {
|
|
1293
|
+
if ((p - r->token) <= 1 || r->rnarg == 0) {
|
|
1294
|
+
goto error;
|
|
1295
|
+
}
|
|
1296
|
+
r->rnarg--;
|
|
1297
|
+
r->token = NULL;
|
|
1298
|
+
state = SW_ARG3_LEN_LF;
|
|
1299
|
+
} else {
|
|
1300
|
+
goto error;
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
break;
|
|
1304
|
+
|
|
1305
|
+
case SW_ARG3_LEN_LF:
|
|
1306
|
+
switch (ch) {
|
|
1307
|
+
case LF:
|
|
1308
|
+
state = SW_ARG3;
|
|
1309
|
+
break;
|
|
1310
|
+
|
|
1311
|
+
default:
|
|
1312
|
+
goto error;
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
break;
|
|
1316
|
+
|
|
1317
|
+
case SW_ARG3:
|
|
1318
|
+
m = p + r->rlen;
|
|
1319
|
+
if (m >= b->last) {
|
|
1320
|
+
r->rlen -= (uint32_t)(b->last - p);
|
|
1321
|
+
m = b->last - 1;
|
|
1322
|
+
p = m;
|
|
1323
|
+
break;
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
if (*m != CR) {
|
|
1327
|
+
goto error;
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
p = m; /* move forward by rlen bytes */
|
|
1331
|
+
r->rlen = 0;
|
|
1332
|
+
state = SW_ARG3_LF;
|
|
1333
|
+
|
|
1334
|
+
break;
|
|
1335
|
+
|
|
1336
|
+
case SW_ARG3_LF:
|
|
1337
|
+
switch (ch) {
|
|
1338
|
+
case LF:
|
|
1339
|
+
if (redis_arg3(r)) {
|
|
1340
|
+
if (r->rnarg != 0) {
|
|
1341
|
+
goto error;
|
|
1342
|
+
}
|
|
1343
|
+
goto done;
|
|
1344
|
+
} else if (redis_argn(r)) {
|
|
1345
|
+
if (r->rnarg == 0) {
|
|
1346
|
+
goto done;
|
|
1347
|
+
}
|
|
1348
|
+
state = SW_ARGN_LEN;
|
|
1349
|
+
} else {
|
|
1350
|
+
goto error;
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1353
|
+
break;
|
|
1354
|
+
|
|
1355
|
+
default:
|
|
1356
|
+
goto error;
|
|
1357
|
+
}
|
|
1358
|
+
|
|
1359
|
+
break;
|
|
1360
|
+
|
|
1361
|
+
case SW_ARGN_LEN:
|
|
1362
|
+
if (r->token == NULL) {
|
|
1363
|
+
if (ch != '$') {
|
|
1364
|
+
goto error;
|
|
1365
|
+
}
|
|
1366
|
+
r->rlen = 0;
|
|
1367
|
+
r->token = p;
|
|
1368
|
+
} else if (isdigit(ch)) {
|
|
1369
|
+
r->rlen = r->rlen * 10 + (uint32_t)(ch - '0');
|
|
1370
|
+
} else if (ch == CR) {
|
|
1371
|
+
if ((p - r->token) <= 1 || r->rnarg == 0) {
|
|
1372
|
+
goto error;
|
|
1373
|
+
}
|
|
1374
|
+
r->rnarg--;
|
|
1375
|
+
r->token = NULL;
|
|
1376
|
+
state = SW_ARGN_LEN_LF;
|
|
1377
|
+
} else {
|
|
1378
|
+
goto error;
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1381
|
+
break;
|
|
1382
|
+
|
|
1383
|
+
case SW_ARGN_LEN_LF:
|
|
1384
|
+
switch (ch) {
|
|
1385
|
+
case LF:
|
|
1386
|
+
state = SW_ARGN;
|
|
1387
|
+
break;
|
|
1388
|
+
|
|
1389
|
+
default:
|
|
1390
|
+
goto error;
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1393
|
+
break;
|
|
1394
|
+
|
|
1395
|
+
case SW_ARGN:
|
|
1396
|
+
m = p + r->rlen;
|
|
1397
|
+
if (m >= b->last) {
|
|
1398
|
+
r->rlen -= (uint32_t)(b->last - p);
|
|
1399
|
+
m = b->last - 1;
|
|
1400
|
+
p = m;
|
|
1401
|
+
break;
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
if (*m != CR) {
|
|
1405
|
+
goto error;
|
|
1406
|
+
}
|
|
1407
|
+
|
|
1408
|
+
p = m; /* move forward by rlen bytes */
|
|
1409
|
+
r->rlen = 0;
|
|
1410
|
+
state = SW_ARGN_LF;
|
|
1411
|
+
|
|
1412
|
+
break;
|
|
1413
|
+
|
|
1414
|
+
case SW_ARGN_LF:
|
|
1415
|
+
switch (ch) {
|
|
1416
|
+
case LF:
|
|
1417
|
+
if (redis_argn(r) || redis_argeval(r)) {
|
|
1418
|
+
if (r->rnarg == 0) {
|
|
1419
|
+
goto done;
|
|
1420
|
+
}
|
|
1421
|
+
state = SW_ARGN_LEN;
|
|
1422
|
+
} else {
|
|
1423
|
+
goto error;
|
|
1424
|
+
}
|
|
1425
|
+
|
|
1426
|
+
break;
|
|
1427
|
+
|
|
1428
|
+
default:
|
|
1429
|
+
goto error;
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1432
|
+
break;
|
|
1433
|
+
|
|
1434
|
+
case SW_SENTINEL:
|
|
1435
|
+
default:
|
|
1436
|
+
NOT_REACHED();
|
|
1437
|
+
break;
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1441
|
+
ASSERT(p == b->last);
|
|
1442
|
+
r->pos = p;
|
|
1443
|
+
r->state = state;
|
|
1444
|
+
|
|
1445
|
+
if (b->last == b->end && r->token != NULL) {
|
|
1446
|
+
r->pos = r->token;
|
|
1447
|
+
r->token = NULL;
|
|
1448
|
+
r->result = MSG_PARSE_REPAIR;
|
|
1449
|
+
} else {
|
|
1450
|
+
r->result = MSG_PARSE_AGAIN;
|
|
1451
|
+
}
|
|
1452
|
+
|
|
1453
|
+
log_hexdump(LOG_VERB, b->pos, mbuf_length(b), "parsed req %"PRIu64" res %d "
|
|
1454
|
+
"type %d state %d rpos %d of %d", r->id, r->result, r->type,
|
|
1455
|
+
r->state, r->pos - b->pos, b->last - b->pos);
|
|
1456
|
+
return;
|
|
1457
|
+
|
|
1458
|
+
fragment:
|
|
1459
|
+
ASSERT(p != b->last);
|
|
1460
|
+
ASSERT(r->token != NULL);
|
|
1461
|
+
r->pos = r->token;
|
|
1462
|
+
r->token = NULL;
|
|
1463
|
+
r->state = state;
|
|
1464
|
+
r->result = MSG_PARSE_FRAGMENT;
|
|
1465
|
+
|
|
1466
|
+
log_hexdump(LOG_VERB, b->pos, mbuf_length(b), "parsed req %"PRIu64" res %d "
|
|
1467
|
+
"type %d state %d rpos %d of %d", r->id, r->result, r->type,
|
|
1468
|
+
r->state, r->pos - b->pos, b->last - b->pos);
|
|
1469
|
+
return;
|
|
1470
|
+
|
|
1471
|
+
done:
|
|
1472
|
+
ASSERT(r->type > MSG_UNKNOWN && r->type < MSG_SENTINEL);
|
|
1473
|
+
r->pos = p + 1;
|
|
1474
|
+
ASSERT(r->pos <= b->last);
|
|
1475
|
+
r->state = SW_START;
|
|
1476
|
+
r->token = NULL;
|
|
1477
|
+
r->result = MSG_PARSE_OK;
|
|
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
|
+
error:
|
|
1485
|
+
r->result = MSG_PARSE_ERROR;
|
|
1486
|
+
r->state = state;
|
|
1487
|
+
errno = EINVAL;
|
|
1488
|
+
|
|
1489
|
+
log_hexdump(LOG_INFO, b->pos, mbuf_length(b), "parsed bad req %"PRIu64" "
|
|
1490
|
+
"res %d type %d state %d", r->id, r->result, r->type,
|
|
1491
|
+
r->state);
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1494
|
+
/*
|
|
1495
|
+
* Reference: http://redis.io/topics/protocol
|
|
1496
|
+
*
|
|
1497
|
+
* Redis will reply to commands with different kinds of replies. It is
|
|
1498
|
+
* possible to check the kind of reply from the first byte sent by the
|
|
1499
|
+
* server:
|
|
1500
|
+
* - with a single line reply the first byte of the reply will be "+"
|
|
1501
|
+
* - with an error message the first byte of the reply will be "-"
|
|
1502
|
+
* - with an integer number the first byte of the reply will be ":"
|
|
1503
|
+
* - with bulk reply the first byte of the reply will be "$"
|
|
1504
|
+
* - with multi-bulk reply the first byte of the reply will be "*"
|
|
1505
|
+
*
|
|
1506
|
+
* 1). Status reply (or single line reply) is in the form of a single line
|
|
1507
|
+
* string starting with "+" terminated by "\r\n".
|
|
1508
|
+
* 2). Error reply are similar to status replies. The only difference is
|
|
1509
|
+
* that the first byte is "-" instead of "+".
|
|
1510
|
+
* 3). Integer reply is just a CRLF terminated string representing an
|
|
1511
|
+
* integer, and prefixed by a ":" byte.
|
|
1512
|
+
* 4). Bulk reply is used by server to return a single binary safe string.
|
|
1513
|
+
* The first reply line is a "$" byte followed by the number of bytes
|
|
1514
|
+
* of the actual reply, followed by CRLF, then the actual data bytes,
|
|
1515
|
+
* followed by additional two bytes for the final CRLF. If the requested
|
|
1516
|
+
* value does not exist the bulk reply will use the special value '-1'
|
|
1517
|
+
* as the data length.
|
|
1518
|
+
* 5). Multi-bulk reply is used by the server to return many binary safe
|
|
1519
|
+
* strings (bulks) with the initial line indicating how many bulks that
|
|
1520
|
+
* will follow. The first byte of a multi bulk reply is always *.
|
|
1521
|
+
*/
|
|
1522
|
+
void
|
|
1523
|
+
redis_parse_rsp(struct msg *r)
|
|
1524
|
+
{
|
|
1525
|
+
struct mbuf *b;
|
|
1526
|
+
uint8_t *p, *m;
|
|
1527
|
+
uint8_t ch;
|
|
1528
|
+
enum {
|
|
1529
|
+
SW_START,
|
|
1530
|
+
SW_STATUS,
|
|
1531
|
+
SW_ERROR,
|
|
1532
|
+
SW_INTEGER,
|
|
1533
|
+
SW_INTEGER_START,
|
|
1534
|
+
SW_BULK,
|
|
1535
|
+
SW_BULK_LF,
|
|
1536
|
+
SW_BULK_ARG,
|
|
1537
|
+
SW_BULK_ARG_LF,
|
|
1538
|
+
SW_MULTIBULK,
|
|
1539
|
+
SW_MULTIBULK_NARG_LF,
|
|
1540
|
+
SW_MULTIBULK_ARGN_LEN,
|
|
1541
|
+
SW_MULTIBULK_ARGN_LEN_LF,
|
|
1542
|
+
SW_MULTIBULK_ARGN,
|
|
1543
|
+
SW_MULTIBULK_ARGN_LF,
|
|
1544
|
+
SW_RUNTO_CRLF,
|
|
1545
|
+
SW_ALMOST_DONE,
|
|
1546
|
+
SW_SENTINEL
|
|
1547
|
+
} state;
|
|
1548
|
+
|
|
1549
|
+
state = r->state;
|
|
1550
|
+
b = STAILQ_LAST(&r->mhdr, mbuf, next);
|
|
1551
|
+
|
|
1552
|
+
ASSERT(!r->request);
|
|
1553
|
+
ASSERT(state >= SW_START && state < SW_SENTINEL);
|
|
1554
|
+
ASSERT(b != NULL);
|
|
1555
|
+
ASSERT(b->pos <= b->last);
|
|
1556
|
+
|
|
1557
|
+
/* validate the parsing marker */
|
|
1558
|
+
ASSERT(r->pos != NULL);
|
|
1559
|
+
ASSERT(r->pos >= b->pos && r->pos <= b->last);
|
|
1560
|
+
|
|
1561
|
+
for (p = r->pos; p < b->last; p++) {
|
|
1562
|
+
ch = *p;
|
|
1563
|
+
|
|
1564
|
+
switch (state) {
|
|
1565
|
+
case SW_START:
|
|
1566
|
+
r->type = MSG_UNKNOWN;
|
|
1567
|
+
switch (ch) {
|
|
1568
|
+
case '+':
|
|
1569
|
+
p = p - 1; /* go back by 1 byte */
|
|
1570
|
+
r->type = MSG_RSP_REDIS_STATUS;
|
|
1571
|
+
state = SW_STATUS;
|
|
1572
|
+
break;
|
|
1573
|
+
|
|
1574
|
+
case '-':
|
|
1575
|
+
r->type = MSG_RSP_REDIS_ERROR;
|
|
1576
|
+
p = p - 1; /* go back by 1 byte */
|
|
1577
|
+
state = SW_ERROR;
|
|
1578
|
+
break;
|
|
1579
|
+
|
|
1580
|
+
case ':':
|
|
1581
|
+
r->type = MSG_RSP_REDIS_INTEGER;
|
|
1582
|
+
p = p - 1; /* go back by 1 byte */
|
|
1583
|
+
state = SW_INTEGER;
|
|
1584
|
+
break;
|
|
1585
|
+
|
|
1586
|
+
case '$':
|
|
1587
|
+
r->type = MSG_RSP_REDIS_BULK;
|
|
1588
|
+
p = p - 1; /* go back by 1 byte */
|
|
1589
|
+
state = SW_BULK;
|
|
1590
|
+
break;
|
|
1591
|
+
|
|
1592
|
+
case '*':
|
|
1593
|
+
r->type = MSG_RSP_REDIS_MULTIBULK;
|
|
1594
|
+
p = p - 1; /* go back by 1 byte */
|
|
1595
|
+
state = SW_MULTIBULK;
|
|
1596
|
+
break;
|
|
1597
|
+
|
|
1598
|
+
default:
|
|
1599
|
+
goto error;
|
|
1600
|
+
}
|
|
1601
|
+
|
|
1602
|
+
break;
|
|
1603
|
+
|
|
1604
|
+
case SW_STATUS:
|
|
1605
|
+
/* rsp_start <- p */
|
|
1606
|
+
state = SW_RUNTO_CRLF;
|
|
1607
|
+
break;
|
|
1608
|
+
|
|
1609
|
+
case SW_ERROR:
|
|
1610
|
+
/* rsp_start <- p */
|
|
1611
|
+
state = SW_RUNTO_CRLF;
|
|
1612
|
+
break;
|
|
1613
|
+
|
|
1614
|
+
case SW_INTEGER:
|
|
1615
|
+
/* rsp_start <- p */
|
|
1616
|
+
state = SW_INTEGER_START;
|
|
1617
|
+
r->integer = 0;
|
|
1618
|
+
break;
|
|
1619
|
+
|
|
1620
|
+
case SW_INTEGER_START:
|
|
1621
|
+
if (ch == CR) {
|
|
1622
|
+
state = SW_ALMOST_DONE;
|
|
1623
|
+
} else if (ch == '-') {
|
|
1624
|
+
;
|
|
1625
|
+
} else if (isdigit(ch)) {
|
|
1626
|
+
r->integer = r->integer * 10 + (uint32_t)(ch - '0');
|
|
1627
|
+
} else {
|
|
1628
|
+
goto error;
|
|
1629
|
+
}
|
|
1630
|
+
break;
|
|
1631
|
+
|
|
1632
|
+
case SW_RUNTO_CRLF:
|
|
1633
|
+
switch (ch) {
|
|
1634
|
+
case CR:
|
|
1635
|
+
state = SW_ALMOST_DONE;
|
|
1636
|
+
break;
|
|
1637
|
+
|
|
1638
|
+
default:
|
|
1639
|
+
break;
|
|
1640
|
+
}
|
|
1641
|
+
|
|
1642
|
+
break;
|
|
1643
|
+
|
|
1644
|
+
case SW_ALMOST_DONE:
|
|
1645
|
+
switch (ch) {
|
|
1646
|
+
case LF:
|
|
1647
|
+
/* rsp_end <- p */
|
|
1648
|
+
goto done;
|
|
1649
|
+
|
|
1650
|
+
default:
|
|
1651
|
+
goto error;
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1654
|
+
break;
|
|
1655
|
+
|
|
1656
|
+
case SW_BULK:
|
|
1657
|
+
if (r->token == NULL) {
|
|
1658
|
+
if (ch != '$') {
|
|
1659
|
+
goto error;
|
|
1660
|
+
}
|
|
1661
|
+
/* rsp_start <- p */
|
|
1662
|
+
r->token = p;
|
|
1663
|
+
r->rlen = 0;
|
|
1664
|
+
} else if (ch == '-') {
|
|
1665
|
+
state = SW_RUNTO_CRLF;
|
|
1666
|
+
} else if (isdigit(ch)) {
|
|
1667
|
+
r->rlen = r->rlen * 10 + (uint32_t)(ch - '0');
|
|
1668
|
+
} else if (ch == CR) {
|
|
1669
|
+
if ((p - r->token) <= 1) {
|
|
1670
|
+
goto error;
|
|
1671
|
+
}
|
|
1672
|
+
r->token = NULL;
|
|
1673
|
+
state = SW_BULK_LF;
|
|
1674
|
+
} else {
|
|
1675
|
+
goto error;
|
|
1676
|
+
}
|
|
1677
|
+
|
|
1678
|
+
break;
|
|
1679
|
+
|
|
1680
|
+
case SW_BULK_LF:
|
|
1681
|
+
switch (ch) {
|
|
1682
|
+
case LF:
|
|
1683
|
+
state = SW_BULK_ARG;
|
|
1684
|
+
break;
|
|
1685
|
+
|
|
1686
|
+
default:
|
|
1687
|
+
goto error;
|
|
1688
|
+
}
|
|
1689
|
+
|
|
1690
|
+
break;
|
|
1691
|
+
|
|
1692
|
+
case SW_BULK_ARG:
|
|
1693
|
+
m = p + r->rlen;
|
|
1694
|
+
if (m >= b->last) {
|
|
1695
|
+
r->rlen -= (uint32_t)(b->last - p);
|
|
1696
|
+
m = b->last - 1;
|
|
1697
|
+
p = m;
|
|
1698
|
+
break;
|
|
1699
|
+
}
|
|
1700
|
+
|
|
1701
|
+
if (*m != CR) {
|
|
1702
|
+
goto error;
|
|
1703
|
+
}
|
|
1704
|
+
|
|
1705
|
+
p = m; /* move forward by rlen bytes */
|
|
1706
|
+
r->rlen = 0;
|
|
1707
|
+
|
|
1708
|
+
state = SW_BULK_ARG_LF;
|
|
1709
|
+
|
|
1710
|
+
break;
|
|
1711
|
+
|
|
1712
|
+
case SW_BULK_ARG_LF:
|
|
1713
|
+
switch (ch) {
|
|
1714
|
+
case LF:
|
|
1715
|
+
goto done;
|
|
1716
|
+
|
|
1717
|
+
default:
|
|
1718
|
+
goto error;
|
|
1719
|
+
}
|
|
1720
|
+
|
|
1721
|
+
break;
|
|
1722
|
+
|
|
1723
|
+
case SW_MULTIBULK:
|
|
1724
|
+
if (r->token == NULL) {
|
|
1725
|
+
if (ch != '*') {
|
|
1726
|
+
goto error;
|
|
1727
|
+
}
|
|
1728
|
+
r->token = p;
|
|
1729
|
+
/* rsp_start <- p */
|
|
1730
|
+
r->narg_start = p;
|
|
1731
|
+
r->rnarg = 0;
|
|
1732
|
+
} else if (isdigit(ch)) {
|
|
1733
|
+
r->rnarg = r->rnarg * 10 + (uint32_t)(ch - '0');
|
|
1734
|
+
} else if (ch == CR) {
|
|
1735
|
+
if ((p - r->token) <= 1) {
|
|
1736
|
+
goto error;
|
|
1737
|
+
}
|
|
1738
|
+
r->narg = r->rnarg;
|
|
1739
|
+
r->narg_end = p;
|
|
1740
|
+
r->token = NULL;
|
|
1741
|
+
state = SW_MULTIBULK_NARG_LF;
|
|
1742
|
+
} else {
|
|
1743
|
+
goto error;
|
|
1744
|
+
}
|
|
1745
|
+
|
|
1746
|
+
break;
|
|
1747
|
+
|
|
1748
|
+
case SW_MULTIBULK_NARG_LF:
|
|
1749
|
+
switch (ch) {
|
|
1750
|
+
case LF:
|
|
1751
|
+
if (r->rnarg == 0) {
|
|
1752
|
+
/* response is '*0\r\n' */
|
|
1753
|
+
goto done;
|
|
1754
|
+
}
|
|
1755
|
+
state = SW_MULTIBULK_ARGN_LEN;
|
|
1756
|
+
break;
|
|
1757
|
+
|
|
1758
|
+
default:
|
|
1759
|
+
goto error;
|
|
1760
|
+
}
|
|
1761
|
+
|
|
1762
|
+
break;
|
|
1763
|
+
|
|
1764
|
+
case SW_MULTIBULK_ARGN_LEN:
|
|
1765
|
+
if (r->token == NULL) {
|
|
1766
|
+
if (ch != '$') {
|
|
1767
|
+
goto error;
|
|
1768
|
+
}
|
|
1769
|
+
r->token = p;
|
|
1770
|
+
r->rlen = 0;
|
|
1771
|
+
} else if (isdigit(ch)) {
|
|
1772
|
+
r->rlen = r->rlen * 10 + (uint32_t)(ch - '0');
|
|
1773
|
+
} else if (ch == '-') {
|
|
1774
|
+
;
|
|
1775
|
+
} else if (ch == CR) {
|
|
1776
|
+
if ((p - r->token) <= 1 || r->rnarg == 0) {
|
|
1777
|
+
goto error;
|
|
1778
|
+
}
|
|
1779
|
+
|
|
1780
|
+
if (r->rlen == 1 && (p - r->token) == 3) {
|
|
1781
|
+
/* handles not-found reply = '$-1'*/
|
|
1782
|
+
r->rlen = 0;
|
|
1783
|
+
state = SW_MULTIBULK_ARGN_LF;
|
|
1784
|
+
} else {
|
|
1785
|
+
state = SW_MULTIBULK_ARGN_LEN_LF;
|
|
1786
|
+
}
|
|
1787
|
+
r->rnarg--;
|
|
1788
|
+
r->token = NULL;
|
|
1789
|
+
|
|
1790
|
+
} else {
|
|
1791
|
+
goto error;
|
|
1792
|
+
}
|
|
1793
|
+
|
|
1794
|
+
break;
|
|
1795
|
+
|
|
1796
|
+
case SW_MULTIBULK_ARGN_LEN_LF:
|
|
1797
|
+
switch (ch) {
|
|
1798
|
+
case LF:
|
|
1799
|
+
state = SW_MULTIBULK_ARGN;
|
|
1800
|
+
break;
|
|
1801
|
+
|
|
1802
|
+
default:
|
|
1803
|
+
goto error;
|
|
1804
|
+
}
|
|
1805
|
+
|
|
1806
|
+
break;
|
|
1807
|
+
|
|
1808
|
+
case SW_MULTIBULK_ARGN:
|
|
1809
|
+
m = p + r->rlen;
|
|
1810
|
+
if (m >= b->last) {
|
|
1811
|
+
r->rlen -= (uint32_t)(b->last - p);
|
|
1812
|
+
m = b->last - 1;
|
|
1813
|
+
p = m;
|
|
1814
|
+
break;
|
|
1815
|
+
}
|
|
1816
|
+
|
|
1817
|
+
if (*m != CR) {
|
|
1818
|
+
goto error;
|
|
1819
|
+
}
|
|
1820
|
+
|
|
1821
|
+
p += r->rlen; /* move forward by rlen bytes */
|
|
1822
|
+
r->rlen = 0;
|
|
1823
|
+
|
|
1824
|
+
state = SW_MULTIBULK_ARGN_LF;
|
|
1825
|
+
|
|
1826
|
+
break;
|
|
1827
|
+
|
|
1828
|
+
case SW_MULTIBULK_ARGN_LF:
|
|
1829
|
+
switch (ch) {
|
|
1830
|
+
case LF:
|
|
1831
|
+
if (r->rnarg == 0) {
|
|
1832
|
+
goto done;
|
|
1833
|
+
}
|
|
1834
|
+
|
|
1835
|
+
state = SW_MULTIBULK_ARGN_LEN;
|
|
1836
|
+
break;
|
|
1837
|
+
|
|
1838
|
+
default:
|
|
1839
|
+
goto error;
|
|
1840
|
+
}
|
|
1841
|
+
|
|
1842
|
+
break;
|
|
1843
|
+
|
|
1844
|
+
case SW_SENTINEL:
|
|
1845
|
+
default:
|
|
1846
|
+
NOT_REACHED();
|
|
1847
|
+
break;
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
|
|
1851
|
+
ASSERT(p == b->last);
|
|
1852
|
+
r->pos = p;
|
|
1853
|
+
r->state = state;
|
|
1854
|
+
|
|
1855
|
+
if (b->last == b->end && r->token != NULL) {
|
|
1856
|
+
r->pos = r->token;
|
|
1857
|
+
r->token = NULL;
|
|
1858
|
+
r->result = MSG_PARSE_REPAIR;
|
|
1859
|
+
} else {
|
|
1860
|
+
r->result = MSG_PARSE_AGAIN;
|
|
1861
|
+
}
|
|
1862
|
+
|
|
1863
|
+
log_hexdump(LOG_VERB, b->pos, mbuf_length(b), "parsed rsp %"PRIu64" res %d "
|
|
1864
|
+
"type %d state %d rpos %d of %d", r->id, r->result, r->type,
|
|
1865
|
+
r->state, r->pos - b->pos, b->last - b->pos);
|
|
1866
|
+
return;
|
|
1867
|
+
|
|
1868
|
+
done:
|
|
1869
|
+
ASSERT(r->type > MSG_UNKNOWN && r->type < MSG_SENTINEL);
|
|
1870
|
+
r->pos = p + 1;
|
|
1871
|
+
ASSERT(r->pos <= b->last);
|
|
1872
|
+
r->state = SW_START;
|
|
1873
|
+
r->token = NULL;
|
|
1874
|
+
r->result = MSG_PARSE_OK;
|
|
1875
|
+
|
|
1876
|
+
log_hexdump(LOG_VERB, b->pos, mbuf_length(b), "parsed rsp %"PRIu64" res %d "
|
|
1877
|
+
"type %d state %d rpos %d of %d", r->id, r->result, r->type,
|
|
1878
|
+
r->state, r->pos - b->pos, b->last - b->pos);
|
|
1879
|
+
return;
|
|
1880
|
+
|
|
1881
|
+
error:
|
|
1882
|
+
r->result = MSG_PARSE_ERROR;
|
|
1883
|
+
r->state = state;
|
|
1884
|
+
errno = EINVAL;
|
|
1885
|
+
|
|
1886
|
+
log_hexdump(LOG_INFO, b->pos, mbuf_length(b), "parsed bad rsp %"PRIu64" "
|
|
1887
|
+
"res %d type %d state %d", r->id, r->result, r->type,
|
|
1888
|
+
r->state);
|
|
1889
|
+
}
|
|
1890
|
+
|
|
1891
|
+
/*
|
|
1892
|
+
* Pre-split copy handler invoked when the request is a multi vector -
|
|
1893
|
+
* 'mget' or 'del' request and is about to be split into two requests
|
|
1894
|
+
*/
|
|
1895
|
+
void
|
|
1896
|
+
redis_pre_splitcopy(struct mbuf *mbuf, void *arg)
|
|
1897
|
+
{
|
|
1898
|
+
struct msg *r = arg;
|
|
1899
|
+
int n;
|
|
1900
|
+
|
|
1901
|
+
ASSERT(r->request);
|
|
1902
|
+
ASSERT(r->narg > 1);
|
|
1903
|
+
ASSERT(mbuf_empty(mbuf));
|
|
1904
|
+
|
|
1905
|
+
switch (r->type) {
|
|
1906
|
+
case MSG_REQ_REDIS_MGET:
|
|
1907
|
+
n = nc_snprintf(mbuf->last, mbuf_size(mbuf), "*%d\r\n$4\r\nmget\r\n",
|
|
1908
|
+
r->narg - 1);
|
|
1909
|
+
break;
|
|
1910
|
+
|
|
1911
|
+
case MSG_REQ_REDIS_DEL:
|
|
1912
|
+
n = nc_snprintf(mbuf->last, mbuf_size(mbuf), "*%d\r\n$3\r\ndel\r\n",
|
|
1913
|
+
r->narg - 1);
|
|
1914
|
+
break;
|
|
1915
|
+
|
|
1916
|
+
default:
|
|
1917
|
+
n = 0;
|
|
1918
|
+
NOT_REACHED();
|
|
1919
|
+
}
|
|
1920
|
+
|
|
1921
|
+
mbuf->last += n;
|
|
1922
|
+
}
|
|
1923
|
+
|
|
1924
|
+
/*
|
|
1925
|
+
* Post-split copy handler invoked when the request is a multi vector -
|
|
1926
|
+
* 'mget' or 'del' request and has already been split into two requests
|
|
1927
|
+
*/
|
|
1928
|
+
rstatus_t
|
|
1929
|
+
redis_post_splitcopy(struct msg *r)
|
|
1930
|
+
{
|
|
1931
|
+
struct mbuf *hbuf, *nhbuf; /* head mbuf and new head mbuf */
|
|
1932
|
+
struct string hstr = string("*2"); /* header string */
|
|
1933
|
+
|
|
1934
|
+
ASSERT(r->request);
|
|
1935
|
+
ASSERT(r->type == MSG_REQ_REDIS_MGET || r->type == MSG_REQ_REDIS_DEL);
|
|
1936
|
+
ASSERT(!STAILQ_EMPTY(&r->mhdr));
|
|
1937
|
+
|
|
1938
|
+
nhbuf = mbuf_get();
|
|
1939
|
+
if (nhbuf == NULL) {
|
|
1940
|
+
return NC_ENOMEM;
|
|
1941
|
+
}
|
|
1942
|
+
|
|
1943
|
+
/*
|
|
1944
|
+
* Fix the head mbuf in the head (A) msg. The fix is straightforward
|
|
1945
|
+
* as we just need to skip over the narg token
|
|
1946
|
+
*/
|
|
1947
|
+
hbuf = STAILQ_FIRST(&r->mhdr);
|
|
1948
|
+
ASSERT(hbuf->pos == r->narg_start);
|
|
1949
|
+
ASSERT(hbuf->pos < r->narg_end && r->narg_end <= hbuf->last);
|
|
1950
|
+
hbuf->pos = r->narg_end;
|
|
1951
|
+
|
|
1952
|
+
/*
|
|
1953
|
+
* Add a new head mbuf in the head (A) msg that just contains '*2'
|
|
1954
|
+
* token
|
|
1955
|
+
*/
|
|
1956
|
+
STAILQ_INSERT_HEAD(&r->mhdr, nhbuf, next);
|
|
1957
|
+
mbuf_copy(nhbuf, hstr.data, hstr.len);
|
|
1958
|
+
|
|
1959
|
+
/* fix up the narg_start and narg_end */
|
|
1960
|
+
r->narg_start = nhbuf->pos;
|
|
1961
|
+
r->narg_end = nhbuf->last;
|
|
1962
|
+
|
|
1963
|
+
return NC_OK;
|
|
1964
|
+
}
|
|
1965
|
+
|
|
1966
|
+
/*
|
|
1967
|
+
* Pre-coalesce handler is invoked when the message is a response to
|
|
1968
|
+
* the fragmented multi vector request - 'mget' or 'del' and all the
|
|
1969
|
+
* responses to the fragmented request vector hasn't been received
|
|
1970
|
+
*/
|
|
1971
|
+
void
|
|
1972
|
+
redis_pre_coalesce(struct msg *r)
|
|
1973
|
+
{
|
|
1974
|
+
struct msg *pr = r->peer; /* peer request */
|
|
1975
|
+
struct mbuf *mbuf;
|
|
1976
|
+
|
|
1977
|
+
ASSERT(!r->request);
|
|
1978
|
+
ASSERT(pr->request);
|
|
1979
|
+
|
|
1980
|
+
if (pr->frag_id == 0) {
|
|
1981
|
+
/* do nothing, if not a response to a fragmented request */
|
|
1982
|
+
return;
|
|
1983
|
+
}
|
|
1984
|
+
|
|
1985
|
+
switch (r->type) {
|
|
1986
|
+
case MSG_RSP_REDIS_INTEGER:
|
|
1987
|
+
/* only redis 'del' fragmented request sends back integer reply */
|
|
1988
|
+
ASSERT(pr->type == MSG_REQ_REDIS_DEL);
|
|
1989
|
+
|
|
1990
|
+
mbuf = STAILQ_FIRST(&r->mhdr);
|
|
1991
|
+
/*
|
|
1992
|
+
* Our response parser guarantees that the integer reply will be
|
|
1993
|
+
* completely encapsulated in a single mbuf and we should skip over
|
|
1994
|
+
* all the mbuf contents and discard it as the parser has already
|
|
1995
|
+
* parsed the integer reply and stored it in msg->integer
|
|
1996
|
+
*/
|
|
1997
|
+
ASSERT(mbuf == STAILQ_LAST(&r->mhdr, mbuf, next));
|
|
1998
|
+
ASSERT(r->mlen == mbuf_length(mbuf));
|
|
1999
|
+
|
|
2000
|
+
r->mlen -= mbuf_length(mbuf);
|
|
2001
|
+
mbuf_rewind(mbuf);
|
|
2002
|
+
|
|
2003
|
+
/* accumulate the integer value in frag_owner of peer request */
|
|
2004
|
+
pr->frag_owner->integer += r->integer;
|
|
2005
|
+
break;
|
|
2006
|
+
|
|
2007
|
+
case MSG_RSP_REDIS_MULTIBULK:
|
|
2008
|
+
/* only redis 'mget' fragmented request sends back multi-bulk reply */
|
|
2009
|
+
ASSERT(pr->type == MSG_REQ_REDIS_MGET);
|
|
2010
|
+
|
|
2011
|
+
mbuf = STAILQ_FIRST(&r->mhdr);
|
|
2012
|
+
/*
|
|
2013
|
+
* Muti-bulk reply can span over multiple mbufs and in each reply
|
|
2014
|
+
* we should skip over the narg token. Our response parser
|
|
2015
|
+
* guarantees thaat the narg token and the immediately following
|
|
2016
|
+
* '\r\n' will exist in a contiguous region in the first mbuf
|
|
2017
|
+
*/
|
|
2018
|
+
ASSERT(r->narg_start == mbuf->pos);
|
|
2019
|
+
ASSERT(r->narg_start < r->narg_end);
|
|
2020
|
+
|
|
2021
|
+
r->narg_end += CRLF_LEN;
|
|
2022
|
+
r->mlen -= (uint32_t)(r->narg_end - r->narg_start);
|
|
2023
|
+
mbuf->pos = r->narg_end;
|
|
2024
|
+
|
|
2025
|
+
if (pr->first_fragment) {
|
|
2026
|
+
mbuf = mbuf_get();
|
|
2027
|
+
if (mbuf == NULL) {
|
|
2028
|
+
pr->error = 1;
|
|
2029
|
+
pr->err = EINVAL;
|
|
2030
|
+
return;
|
|
2031
|
+
}
|
|
2032
|
+
STAILQ_INSERT_HEAD(&r->mhdr, mbuf, next);
|
|
2033
|
+
}
|
|
2034
|
+
break;
|
|
2035
|
+
|
|
2036
|
+
default:
|
|
2037
|
+
/*
|
|
2038
|
+
* Valid responses for a fragmented request are MSG_RSP_REDIS_INTEGER or,
|
|
2039
|
+
* MSG_RSP_REDIS_MULTIBULK. For an invalid response, we send out -ERR
|
|
2040
|
+
* with EINVAL errno
|
|
2041
|
+
*/
|
|
2042
|
+
mbuf = STAILQ_FIRST(&r->mhdr);
|
|
2043
|
+
log_hexdump(LOG_ERR, mbuf->pos, mbuf_length(mbuf), "rsp fragment "
|
|
2044
|
+
"with unknown type %d", r->type);
|
|
2045
|
+
pr->error = 1;
|
|
2046
|
+
pr->err = EINVAL;
|
|
2047
|
+
break;
|
|
2048
|
+
}
|
|
2049
|
+
}
|
|
2050
|
+
|
|
2051
|
+
/*
|
|
2052
|
+
* Post-coalesce handler is invoked when the message is a response to
|
|
2053
|
+
* the fragmented multi vector request - 'mget' or 'del' and all the
|
|
2054
|
+
* responses to the fragmented request vector has been received and
|
|
2055
|
+
* the fragmented request is consider to be done
|
|
2056
|
+
*/
|
|
2057
|
+
void
|
|
2058
|
+
redis_post_coalesce(struct msg *r)
|
|
2059
|
+
{
|
|
2060
|
+
struct msg *pr = r->peer; /* peer response */
|
|
2061
|
+
struct mbuf *mbuf;
|
|
2062
|
+
int n;
|
|
2063
|
+
|
|
2064
|
+
ASSERT(r->request && r->first_fragment);
|
|
2065
|
+
if (r->error || r->ferror) {
|
|
2066
|
+
/* do nothing, if msg is in error */
|
|
2067
|
+
return;
|
|
2068
|
+
}
|
|
2069
|
+
|
|
2070
|
+
ASSERT(!pr->request);
|
|
2071
|
+
|
|
2072
|
+
switch (pr->type) {
|
|
2073
|
+
case MSG_RSP_REDIS_INTEGER:
|
|
2074
|
+
/* only redis 'del' fragmented request sends back integer reply */
|
|
2075
|
+
ASSERT(r->type == MSG_REQ_REDIS_DEL);
|
|
2076
|
+
|
|
2077
|
+
mbuf = STAILQ_FIRST(&pr->mhdr);
|
|
2078
|
+
|
|
2079
|
+
ASSERT(pr->mlen == 0);
|
|
2080
|
+
ASSERT(mbuf_empty(mbuf));
|
|
2081
|
+
|
|
2082
|
+
n = nc_scnprintf(mbuf->last, mbuf_size(mbuf), ":%d\r\n", r->integer);
|
|
2083
|
+
mbuf->last += n;
|
|
2084
|
+
pr->mlen += (uint32_t)n;
|
|
2085
|
+
break;
|
|
2086
|
+
|
|
2087
|
+
case MSG_RSP_REDIS_MULTIBULK:
|
|
2088
|
+
/* only redis 'mget' fragmented request sends back multi-bulk reply */
|
|
2089
|
+
ASSERT(r->type == MSG_REQ_REDIS_MGET);
|
|
2090
|
+
|
|
2091
|
+
mbuf = STAILQ_FIRST(&pr->mhdr);
|
|
2092
|
+
ASSERT(mbuf_empty(mbuf));
|
|
2093
|
+
|
|
2094
|
+
n = nc_scnprintf(mbuf->last, mbuf_size(mbuf), "*%d\r\n", r->nfrag);
|
|
2095
|
+
mbuf->last += n;
|
|
2096
|
+
pr->mlen += (uint32_t)n;
|
|
2097
|
+
break;
|
|
2098
|
+
|
|
2099
|
+
default:
|
|
2100
|
+
NOT_REACHED();
|
|
2101
|
+
}
|
|
2102
|
+
}
|