nutcracker 0.4.0.16 → 0.4.1.18
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Rakefile +3 -3
- data/ext/nutcracker/ChangeLog +33 -8
- data/ext/nutcracker/Makefile.in +34 -21
- data/ext/nutcracker/README.md +61 -26
- data/ext/nutcracker/aclocal.m4 +34 -31
- data/ext/nutcracker/autom4te.cache/output.0 +1875 -1330
- data/ext/nutcracker/autom4te.cache/output.1 +1875 -1330
- data/ext/nutcracker/autom4te.cache/requests +232 -451
- data/ext/nutcracker/autom4te.cache/traces.0 +2256 -2129
- data/ext/nutcracker/autom4te.cache/traces.1 +73 -59
- data/ext/nutcracker/config.h.in +1 -2
- data/ext/nutcracker/config.h.in~ +333 -0
- data/ext/nutcracker/config/compile +1 -1
- data/ext/nutcracker/config/config.guess +13 -160
- data/ext/nutcracker/config/config.sub +25 -11
- data/ext/nutcracker/config/depcomp +1 -1
- data/ext/nutcracker/config/install-sh +170 -196
- data/ext/nutcracker/config/ltmain.sh +3509 -2018
- data/ext/nutcracker/config/missing +1 -1
- data/ext/nutcracker/configure +1874 -1329
- data/ext/nutcracker/configure.ac +3 -2
- data/ext/nutcracker/contrib/Makefile.in +18 -5
- 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 +832 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/README +27 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/aclocal.m4 +1157 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/autom4te.cache/output.0 +13342 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/autom4te.cache/output.1 +14611 -0
- data/ext/nutcracker/{autom4te.cache → contrib/yaml-0.1.4/autom4te.cache}/output.2 +3465 -8761
- data/ext/nutcracker/contrib/yaml-0.1.4/autom4te.cache/requests +516 -0
- data/ext/nutcracker/{autom4te.cache/traces.2 → contrib/yaml-0.1.4/autom4te.cache/traces.0} +662 -698
- data/ext/nutcracker/contrib/yaml-0.1.4/autom4te.cache/traces.1 +577 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/autom4te.cache/traces.2 +2721 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/config.h.in +79 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/config.h.in~ +80 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/config/compile +347 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/config/config.guess +1421 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/config/config.sub +1807 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/config/depcomp +791 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/config/install-sh +501 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/config/ltmain.sh +11147 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/config/missing +215 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/config/test-driver +148 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/configure +14611 -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 +8369 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/m4/ltoptions.m4 +437 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/m4/ltsugar.m4 +124 -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 +99 -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 +600 -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 +1083 -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/m4/libtool.m4 +1474 -1087
- data/ext/nutcracker/m4/ltoptions.m4 +90 -37
- data/ext/nutcracker/m4/ltsugar.m4 +4 -3
- data/ext/nutcracker/m4/ltversion.m4 +6 -6
- data/ext/nutcracker/m4/lt~obsolete.m4 +4 -3
- data/ext/nutcracker/man/nutcracker.8 +1 -1
- data/ext/nutcracker/notes/memcache.md +162 -0
- data/ext/nutcracker/notes/recommendation.md +10 -5
- data/ext/nutcracker/notes/redis.md +23 -9
- data/ext/nutcracker/scripts/nutcracker.init +10 -0
- data/ext/nutcracker/scripts/nutcracker.init.debian +83 -0
- data/ext/nutcracker/scripts/nutcracker.spec +36 -2
- data/ext/nutcracker/scripts/redis-check.sh +4 -0
- data/ext/nutcracker/src/Makefile.am +6 -1
- data/ext/nutcracker/src/Makefile.in +26 -12
- data/ext/nutcracker/src/event/Makefile.in +19 -6
- data/ext/nutcracker/src/hashkit/Makefile.in +19 -6
- data/ext/nutcracker/src/hashkit/nc_jenkins.c +1 -1
- data/ext/nutcracker/src/hashkit/nc_ketama.c +3 -3
- data/ext/nutcracker/src/nc.c +1 -1
- data/ext/nutcracker/src/nc_conf.c +67 -19
- data/ext/nutcracker/src/nc_conf.h +9 -4
- data/ext/nutcracker/src/nc_connection.c +35 -2
- data/ext/nutcracker/src/nc_connection.h +53 -47
- data/ext/nutcracker/src/nc_core.c +8 -1
- data/ext/nutcracker/src/nc_message.c +23 -7
- data/ext/nutcracker/src/nc_message.h +24 -1
- data/ext/nutcracker/src/nc_proxy.c +14 -3
- data/ext/nutcracker/src/nc_rbtree.c +1 -5
- data/ext/nutcracker/src/nc_request.c +58 -10
- data/ext/nutcracker/src/nc_response.c +27 -4
- data/ext/nutcracker/src/nc_server.c +33 -5
- data/ext/nutcracker/src/nc_server.h +10 -9
- data/ext/nutcracker/src/nc_string.h +17 -0
- data/ext/nutcracker/src/nc_util.c +5 -1
- data/ext/nutcracker/src/proto/Makefile.in +19 -6
- data/ext/nutcracker/src/proto/nc_memcache.c +76 -12
- data/ext/nutcracker/src/proto/nc_proto.h +9 -0
- data/ext/nutcracker/src/proto/nc_redis.c +400 -18
- data/lib/nutcracker.rb +1 -1
- data/lib/nutcracker/version.rb +1 -1
- metadata +61 -6
- data/ext/nutcracker/notes/memcache.txt +0 -123
@@ -70,13 +70,12 @@ struct server {
|
|
70
70
|
uint32_t idx; /* server index */
|
71
71
|
struct server_pool *owner; /* owner pool */
|
72
72
|
|
73
|
-
struct string pname; /*
|
74
|
-
struct string name; /* name (ref in conf_server) */
|
73
|
+
struct string pname; /* hostname:port:weight (ref in conf_server) */
|
74
|
+
struct string name; /* hostname:port or [name] (ref in conf_server) */
|
75
|
+
struct string addrstr; /* hostname (ref in conf_server) */
|
75
76
|
uint16_t port; /* port */
|
76
77
|
uint32_t weight; /* weight */
|
77
|
-
|
78
|
-
socklen_t addrlen; /* socket length */
|
79
|
-
struct sockaddr *addr; /* socket address (ref in conf_server) */
|
78
|
+
struct sockinfo info; /* server socket info */
|
80
79
|
|
81
80
|
uint32_t ns_conn_q; /* # server connection */
|
82
81
|
struct conn_tqh s_conn_q; /* server connection q */
|
@@ -101,21 +100,23 @@ struct server_pool {
|
|
101
100
|
int64_t next_rebuild; /* next distribution rebuild time in usec */
|
102
101
|
|
103
102
|
struct string name; /* pool name (ref in conf_pool) */
|
104
|
-
struct string addrstr; /* pool address (ref in conf_pool) */
|
103
|
+
struct string addrstr; /* pool address - hostname:port (ref in conf_pool) */
|
105
104
|
uint16_t port; /* port */
|
106
|
-
|
107
|
-
|
108
|
-
struct sockaddr *addr; /* socket address (ref in conf_pool) */
|
105
|
+
struct sockinfo info; /* listen socket info */
|
106
|
+
mode_t perm; /* socket permission */
|
109
107
|
int dist_type; /* distribution type (dist_type_t) */
|
110
108
|
int key_hash_type; /* key hash type (hash_type_t) */
|
111
109
|
hash_t key_hash; /* key hasher */
|
112
110
|
struct string hash_tag; /* key hash tag (ref in conf_pool) */
|
113
111
|
int timeout; /* timeout in msec */
|
114
112
|
int backlog; /* listen backlog */
|
113
|
+
int redis_db; /* redis database to connect to */
|
115
114
|
uint32_t client_connections; /* maximum # client connection */
|
116
115
|
uint32_t server_connections; /* maximum # server connection */
|
117
116
|
int64_t server_retry_timeout; /* server retry timeout in usec */
|
118
117
|
uint32_t server_failure_limit; /* server failure limit */
|
118
|
+
struct string redis_auth; /* redis_auth password (matches requirepass on redis) */
|
119
|
+
unsigned require_auth; /* require_auth? */
|
119
120
|
unsigned auto_eject_hosts:1; /* auto_eject_hosts? */
|
120
121
|
unsigned preconnect:1; /* preconnect? */
|
121
122
|
unsigned redis:1; /* redis? */
|
@@ -77,12 +77,29 @@ int string_compare(const struct string *s1, const struct string *s2);
|
|
77
77
|
#define nc_strndup(_s, _n) \
|
78
78
|
(uint8_t *)strndup((char *)(_s), (size_t)(_n));
|
79
79
|
|
80
|
+
/*
|
81
|
+
* snprintf(s, n, ...) will write at most n - 1 of the characters printed into
|
82
|
+
* the output string; the nth character then gets the terminating `\0'; if
|
83
|
+
* the return value is greater than or equal to the n argument, the string
|
84
|
+
* was too short and some of the printed characters were discarded; the output
|
85
|
+
* is always null-terminated.
|
86
|
+
*
|
87
|
+
* Note that, the return value of snprintf() is always the number of characters
|
88
|
+
* that would be printed into the output string, assuming n were limited not
|
89
|
+
* including the trailing `\0' used to end output.
|
90
|
+
*
|
91
|
+
* scnprintf(s, n, ...) is same as snprintf() except, it returns the number
|
92
|
+
* of characters printed into the output string not including the trailing '\0'
|
93
|
+
*/
|
80
94
|
#define nc_snprintf(_s, _n, ...) \
|
81
95
|
snprintf((char *)(_s), (size_t)(_n), __VA_ARGS__)
|
82
96
|
|
83
97
|
#define nc_scnprintf(_s, _n, ...) \
|
84
98
|
_scnprintf((char *)(_s), (size_t)(_n), __VA_ARGS__)
|
85
99
|
|
100
|
+
#define nc_vsnprintf(_s, _n, _f, _a) \
|
101
|
+
vsnprintf((char *)(_s), (size_t)(_n), _f, _a)
|
102
|
+
|
86
103
|
#define nc_vscnprintf(_s, _n, _f, _a) \
|
87
104
|
_vscnprintf((char *)(_s), (size_t)(_n), _f, _a)
|
88
105
|
|
@@ -489,8 +489,12 @@ nc_resolve_inet(struct string *name, int port, struct sockinfo *si)
|
|
489
489
|
|
490
490
|
nc_snprintf(service, NC_UINTMAX_MAXLEN, "%d", port);
|
491
491
|
|
492
|
+
/*
|
493
|
+
* getaddrinfo() returns zero on success or one of the error codes listed
|
494
|
+
* in gai_strerror(3) if an error occurs
|
495
|
+
*/
|
492
496
|
status = getaddrinfo(node, service, &hints, &ai);
|
493
|
-
if (status
|
497
|
+
if (status != 0) {
|
494
498
|
log_error("address resolution of node '%s' service '%s' failed: %s",
|
495
499
|
node, service, gai_strerror(status));
|
496
500
|
return -1;
|
@@ -1,7 +1,7 @@
|
|
1
|
-
# Makefile.in generated by automake 1.
|
1
|
+
# Makefile.in generated by automake 1.15 from Makefile.am.
|
2
2
|
# @configure_input@
|
3
3
|
|
4
|
-
# Copyright (C) 1994-
|
4
|
+
# Copyright (C) 1994-2014 Free Software Foundation, Inc.
|
5
5
|
|
6
6
|
# This Makefile.in is free software; the Free Software Foundation
|
7
7
|
# gives unlimited permission to copy and/or distribute it,
|
@@ -16,7 +16,17 @@
|
|
16
16
|
|
17
17
|
|
18
18
|
VPATH = @srcdir@
|
19
|
-
am__is_gnu_make =
|
19
|
+
am__is_gnu_make = { \
|
20
|
+
if test -z '$(MAKELEVEL)'; then \
|
21
|
+
false; \
|
22
|
+
elif test -n '$(MAKE_HOST)'; then \
|
23
|
+
true; \
|
24
|
+
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
|
25
|
+
true; \
|
26
|
+
else \
|
27
|
+
false; \
|
28
|
+
fi; \
|
29
|
+
}
|
20
30
|
am__make_running_with_option = \
|
21
31
|
case $${target_option-} in \
|
22
32
|
?) ;; \
|
@@ -80,8 +90,6 @@ POST_UNINSTALL = :
|
|
80
90
|
build_triplet = @build@
|
81
91
|
host_triplet = @host@
|
82
92
|
subdir = src/proto
|
83
|
-
DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
|
84
|
-
$(top_srcdir)/config/depcomp $(noinst_HEADERS)
|
85
93
|
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
86
94
|
am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
|
87
95
|
$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
|
@@ -89,6 +97,8 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
|
|
89
97
|
$(top_srcdir)/configure.ac
|
90
98
|
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
91
99
|
$(ACLOCAL_M4)
|
100
|
+
DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
|
101
|
+
$(am__DIST_COMMON)
|
92
102
|
mkinstalldirs = $(install_sh) -d
|
93
103
|
CONFIG_HEADER = $(top_builddir)/config.h
|
94
104
|
CONFIG_CLEAN_FILES =
|
@@ -168,6 +178,7 @@ am__define_uniq_tagged_files = \
|
|
168
178
|
done | $(am__uniquify_input)`
|
169
179
|
ETAGS = etags
|
170
180
|
CTAGS = ctags
|
181
|
+
am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/config/depcomp
|
171
182
|
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
172
183
|
ACLOCAL = @ACLOCAL@
|
173
184
|
AMTAR = @AMTAR@
|
@@ -212,6 +223,7 @@ LIBTOOL = @LIBTOOL@
|
|
212
223
|
LIPO = @LIPO@
|
213
224
|
LN_S = @LN_S@
|
214
225
|
LTLIBOBJS = @LTLIBOBJS@
|
226
|
+
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
|
215
227
|
MAKEINFO = @MAKEINFO@
|
216
228
|
MANIFEST_TOOL = @MANIFEST_TOOL@
|
217
229
|
MKDIR_P = @MKDIR_P@
|
@@ -314,7 +326,6 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
|
|
314
326
|
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/proto/Makefile'; \
|
315
327
|
$(am__cd) $(top_srcdir) && \
|
316
328
|
$(AUTOMAKE) --foreign src/proto/Makefile
|
317
|
-
.PRECIOUS: Makefile
|
318
329
|
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
319
330
|
@case '$?' in \
|
320
331
|
*config.status*) \
|
@@ -581,6 +592,8 @@ uninstall-am:
|
|
581
592
|
mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
|
582
593
|
tags tags-am uninstall uninstall-am
|
583
594
|
|
595
|
+
.PRECIOUS: Makefile
|
596
|
+
|
584
597
|
|
585
598
|
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
586
599
|
# Otherwise a system limit (for SysV at least) may be exceeded.
|
@@ -121,6 +121,20 @@ memcache_delete(struct msg *r)
|
|
121
121
|
return false;
|
122
122
|
}
|
123
123
|
|
124
|
+
/*
|
125
|
+
* Return true, if the memcache command is a touch command, otherwise
|
126
|
+
* return false
|
127
|
+
*/
|
128
|
+
static bool
|
129
|
+
memcache_touch(struct msg *r)
|
130
|
+
{
|
131
|
+
if (r->type == MSG_REQ_MC_TOUCH) {
|
132
|
+
return true;
|
133
|
+
}
|
134
|
+
|
135
|
+
return false;
|
136
|
+
}
|
137
|
+
|
124
138
|
void
|
125
139
|
memcache_parse_req(struct msg *r)
|
126
140
|
{
|
@@ -243,6 +257,14 @@ memcache_parse_req(struct msg *r)
|
|
243
257
|
|
244
258
|
break;
|
245
259
|
|
260
|
+
case 5:
|
261
|
+
if (str5cmp(m, 't', 'o', 'u', 'c', 'h')) {
|
262
|
+
r->type = MSG_REQ_MC_TOUCH;
|
263
|
+
break;
|
264
|
+
}
|
265
|
+
|
266
|
+
break;
|
267
|
+
|
246
268
|
case 6:
|
247
269
|
if (str6cmp(m, 'a', 'p', 'p', 'e', 'n', 'd')) {
|
248
270
|
r->type = MSG_REQ_MC_APPEND;
|
@@ -282,6 +304,7 @@ memcache_parse_req(struct msg *r)
|
|
282
304
|
case MSG_REQ_MC_PREPEND:
|
283
305
|
case MSG_REQ_MC_INCR:
|
284
306
|
case MSG_REQ_MC_DECR:
|
307
|
+
case MSG_REQ_MC_TOUCH:
|
285
308
|
if (ch == CR) {
|
286
309
|
goto error;
|
287
310
|
}
|
@@ -320,13 +343,17 @@ memcache_parse_req(struct msg *r)
|
|
320
343
|
}
|
321
344
|
if (ch == ' ' || ch == CR) {
|
322
345
|
struct keypos *kpos;
|
323
|
-
|
324
|
-
if (
|
346
|
+
int keylen = p - r->token;
|
347
|
+
if (keylen > MEMCACHE_MAX_KEY_LENGTH) {
|
325
348
|
log_error("parsed bad req %"PRIu64" of type %d with key "
|
326
349
|
"prefix '%.*s...' and length %d that exceeds "
|
327
350
|
"maximum key length", r->id, r->type, 16,
|
328
351
|
r->token, p - r->token);
|
329
352
|
goto error;
|
353
|
+
} else if (keylen == 0) {
|
354
|
+
log_error("parsed bad req %"PRIu64" of type %d with an "
|
355
|
+
"empty key", r->id, r->type);
|
356
|
+
goto error;
|
330
357
|
}
|
331
358
|
|
332
359
|
kpos = array_push(r->keys);
|
@@ -342,7 +369,7 @@ memcache_parse_req(struct msg *r)
|
|
342
369
|
/* get next state */
|
343
370
|
if (memcache_storage(r)) {
|
344
371
|
state = SW_SPACES_BEFORE_FLAGS;
|
345
|
-
} else if (memcache_arithmetic(r)) {
|
372
|
+
} else if (memcache_arithmetic(r) || memcache_touch(r) ) {
|
346
373
|
state = SW_SPACES_BEFORE_NUM;
|
347
374
|
} else if (memcache_delete(r)) {
|
348
375
|
state = SW_RUNTO_CRLF;
|
@@ -531,7 +558,7 @@ memcache_parse_req(struct msg *r)
|
|
531
558
|
|
532
559
|
case SW_SPACES_BEFORE_NUM:
|
533
560
|
if (ch != ' ') {
|
534
|
-
if (!isdigit(ch)) {
|
561
|
+
if (!(isdigit(ch) || ch == '-')) {
|
535
562
|
goto error;
|
536
563
|
}
|
537
564
|
/* num_start <- p; num <- ch - '0' */
|
@@ -562,7 +589,7 @@ memcache_parse_req(struct msg *r)
|
|
562
589
|
break;
|
563
590
|
|
564
591
|
case 'n':
|
565
|
-
if (memcache_storage(r) || memcache_arithmetic(r) || memcache_delete(r)) {
|
592
|
+
if (memcache_storage(r) || memcache_arithmetic(r) || memcache_delete(r) || memcache_touch(r)) {
|
566
593
|
/* noreply_start <- p */
|
567
594
|
r->token = p;
|
568
595
|
state = SW_NOREPLY;
|
@@ -593,7 +620,7 @@ memcache_parse_req(struct msg *r)
|
|
593
620
|
case CR:
|
594
621
|
m = r->token;
|
595
622
|
if (((p - m) == 7) && str7cmp(m, 'n', 'o', 'r', 'e', 'p', 'l', 'y')) {
|
596
|
-
ASSERT(memcache_storage(r) || memcache_arithmetic(r) || memcache_delete(r));
|
623
|
+
ASSERT(memcache_storage(r) || memcache_arithmetic(r) || memcache_delete(r) || memcache_touch(r));
|
597
624
|
r->token = NULL;
|
598
625
|
/* noreply_end <- p - 1 */
|
599
626
|
r->noreply = 1;
|
@@ -854,6 +881,11 @@ memcache_parse_rsp(struct msg *r)
|
|
854
881
|
break;
|
855
882
|
}
|
856
883
|
|
884
|
+
if (str7cmp(m, 'T', 'O', 'U', 'C', 'H', 'E', 'D')) {
|
885
|
+
r->type = MSG_RSP_MC_TOUCHED;
|
886
|
+
break;
|
887
|
+
}
|
888
|
+
|
857
889
|
break;
|
858
890
|
|
859
891
|
case 9:
|
@@ -895,6 +927,7 @@ memcache_parse_rsp(struct msg *r)
|
|
895
927
|
case MSG_RSP_MC_EXISTS:
|
896
928
|
case MSG_RSP_MC_NOT_FOUND:
|
897
929
|
case MSG_RSP_MC_DELETED:
|
930
|
+
case MSG_RSP_MC_TOUCHED:
|
898
931
|
state = SW_CRLF;
|
899
932
|
break;
|
900
933
|
|
@@ -1167,6 +1200,12 @@ error:
|
|
1167
1200
|
r->state);
|
1168
1201
|
}
|
1169
1202
|
|
1203
|
+
bool
|
1204
|
+
memcache_failure(struct msg *r)
|
1205
|
+
{
|
1206
|
+
return false;
|
1207
|
+
}
|
1208
|
+
|
1170
1209
|
static rstatus_t
|
1171
1210
|
memcache_append_key(struct msg *r, uint8_t *key, uint32_t keylen)
|
1172
1211
|
{
|
@@ -1377,9 +1416,8 @@ memcache_pre_coalesce(struct msg *r)
|
|
1377
1416
|
}
|
1378
1417
|
|
1379
1418
|
/*
|
1380
|
-
*
|
1381
|
-
|
1382
|
-
* */
|
1419
|
+
* Copy one response from src to dst and return bytes copied
|
1420
|
+
*/
|
1383
1421
|
static rstatus_t
|
1384
1422
|
memcache_copy_bulk(struct msg *dst, struct msg *src)
|
1385
1423
|
{
|
@@ -1403,9 +1441,10 @@ memcache_copy_bulk(struct msg *dst, struct msg *src)
|
|
1403
1441
|
}
|
1404
1442
|
p = mbuf->pos;
|
1405
1443
|
|
1406
|
-
/*
|
1407
|
-
|
1408
|
-
|
1444
|
+
/*
|
1445
|
+
* get : VALUE key 0 len\r\nval\r\n
|
1446
|
+
* gets: VALUE key 0 len cas\r\nval\r\n
|
1447
|
+
*/
|
1409
1448
|
ASSERT(*p == 'V');
|
1410
1449
|
for (i = 0; i < 3; i++) { /* eat 'VALUE key 0 ' */
|
1411
1450
|
for (; *p != ' ';) {
|
@@ -1495,3 +1534,28 @@ memcache_post_coalesce(struct msg *request)
|
|
1495
1534
|
return;
|
1496
1535
|
}
|
1497
1536
|
}
|
1537
|
+
|
1538
|
+
void
|
1539
|
+
memcache_post_connect(struct context *ctx, struct conn *conn, struct server *server)
|
1540
|
+
{
|
1541
|
+
}
|
1542
|
+
|
1543
|
+
void
|
1544
|
+
memcache_swallow_msg(struct conn *conn, struct msg *pmsg, struct msg *msg)
|
1545
|
+
{
|
1546
|
+
}
|
1547
|
+
|
1548
|
+
rstatus_t
|
1549
|
+
memcache_add_auth(struct context *ctx, struct conn *c_conn, struct conn *s_conn)
|
1550
|
+
{
|
1551
|
+
NOT_REACHED();
|
1552
|
+
return NC_OK;
|
1553
|
+
}
|
1554
|
+
|
1555
|
+
rstatus_t
|
1556
|
+
memcache_reply(struct msg *r)
|
1557
|
+
{
|
1558
|
+
NOT_REACHED();
|
1559
|
+
return NC_OK;
|
1560
|
+
}
|
1561
|
+
|
@@ -140,15 +140,24 @@
|
|
140
140
|
|
141
141
|
void memcache_parse_req(struct msg *r);
|
142
142
|
void memcache_parse_rsp(struct msg *r);
|
143
|
+
bool memcache_failure(struct msg *r);
|
143
144
|
void memcache_pre_coalesce(struct msg *r);
|
144
145
|
void memcache_post_coalesce(struct msg *r);
|
146
|
+
rstatus_t memcache_add_auth(struct context *ctx, struct conn *c_conn, struct conn *s_conn);
|
145
147
|
rstatus_t memcache_fragment(struct msg *r, uint32_t ncontinuum, struct msg_tqh *frag_msgq);
|
148
|
+
rstatus_t memcache_reply(struct msg *r);
|
149
|
+
void memcache_post_connect(struct context *ctx, struct conn *conn, struct server *server);
|
150
|
+
void memcache_swallow_msg(struct conn *conn, struct msg *pmsg, struct msg *msg);
|
146
151
|
|
147
152
|
void redis_parse_req(struct msg *r);
|
148
153
|
void redis_parse_rsp(struct msg *r);
|
154
|
+
bool redis_failure(struct msg *r);
|
149
155
|
void redis_pre_coalesce(struct msg *r);
|
150
156
|
void redis_post_coalesce(struct msg *r);
|
157
|
+
rstatus_t redis_add_auth(struct context *ctx, struct conn *c_conn, struct conn *s_conn);
|
151
158
|
rstatus_t redis_fragment(struct msg *r, uint32_t ncontinuum, struct msg_tqh *frag_msgq);
|
152
159
|
rstatus_t redis_reply(struct msg *r);
|
160
|
+
void redis_post_connect(struct context *ctx, struct conn *conn, struct server *server);
|
161
|
+
void redis_swallow_msg(struct conn *conn, struct msg *pmsg, struct msg *msg);
|
153
162
|
|
154
163
|
#endif
|
@@ -17,10 +17,24 @@
|
|
17
17
|
|
18
18
|
#include <stdio.h>
|
19
19
|
#include <ctype.h>
|
20
|
+
#include <math.h>
|
20
21
|
|
21
22
|
#include <nc_core.h>
|
22
23
|
#include <nc_proto.h>
|
23
24
|
|
25
|
+
#define RSP_STRING(ACTION) \
|
26
|
+
ACTION( ok, "+OK\r\n" ) \
|
27
|
+
ACTION( pong, "+PONG\r\n" ) \
|
28
|
+
ACTION( invalid_password, "-ERR invalid password\r\n" ) \
|
29
|
+
ACTION( auth_required, "-NOAUTH Authentication required\r\n" ) \
|
30
|
+
ACTION( no_password, "-ERR Client sent AUTH, but no password is set\r\n" ) \
|
31
|
+
|
32
|
+
#define DEFINE_ACTION(_var, _str) static struct string rsp_##_var = string(_str);
|
33
|
+
RSP_STRING( DEFINE_ACTION )
|
34
|
+
#undef DEFINE_ACTION
|
35
|
+
|
36
|
+
static rstatus_t redis_handle_auth_req(struct msg *request, struct msg *response);
|
37
|
+
|
24
38
|
/*
|
25
39
|
* Return true, if the redis command take no key, otherwise
|
26
40
|
* return false
|
@@ -51,7 +65,6 @@ redis_arg0(struct msg *r)
|
|
51
65
|
case MSG_REQ_REDIS_EXISTS:
|
52
66
|
case MSG_REQ_REDIS_PERSIST:
|
53
67
|
case MSG_REQ_REDIS_PTTL:
|
54
|
-
case MSG_REQ_REDIS_SORT:
|
55
68
|
case MSG_REQ_REDIS_TTL:
|
56
69
|
case MSG_REQ_REDIS_TYPE:
|
57
70
|
case MSG_REQ_REDIS_DUMP:
|
@@ -75,8 +88,8 @@ redis_arg0(struct msg *r)
|
|
75
88
|
case MSG_REQ_REDIS_SPOP:
|
76
89
|
|
77
90
|
case MSG_REQ_REDIS_ZCARD:
|
78
|
-
|
79
91
|
case MSG_REQ_REDIS_PFCOUNT:
|
92
|
+
case MSG_REQ_REDIS_AUTH:
|
80
93
|
return true;
|
81
94
|
|
82
95
|
default:
|
@@ -198,6 +211,8 @@ static bool
|
|
198
211
|
redis_argn(struct msg *r)
|
199
212
|
{
|
200
213
|
switch (r->type) {
|
214
|
+
case MSG_REQ_REDIS_SORT:
|
215
|
+
|
201
216
|
case MSG_REQ_REDIS_BITCOUNT:
|
202
217
|
|
203
218
|
case MSG_REQ_REDIS_SET:
|
@@ -300,6 +315,37 @@ redis_argeval(struct msg *r)
|
|
300
315
|
return false;
|
301
316
|
}
|
302
317
|
|
318
|
+
/*
|
319
|
+
* Return true, if the redis response is an error response i.e. a simple
|
320
|
+
* string whose first character is '-', otherwise return false.
|
321
|
+
*/
|
322
|
+
static bool
|
323
|
+
redis_error(struct msg *r)
|
324
|
+
{
|
325
|
+
switch (r->type) {
|
326
|
+
case MSG_RSP_REDIS_ERROR:
|
327
|
+
case MSG_RSP_REDIS_ERROR_ERR:
|
328
|
+
case MSG_RSP_REDIS_ERROR_OOM:
|
329
|
+
case MSG_RSP_REDIS_ERROR_BUSY:
|
330
|
+
case MSG_RSP_REDIS_ERROR_NOAUTH:
|
331
|
+
case MSG_RSP_REDIS_ERROR_LOADING:
|
332
|
+
case MSG_RSP_REDIS_ERROR_BUSYKEY:
|
333
|
+
case MSG_RSP_REDIS_ERROR_MISCONF:
|
334
|
+
case MSG_RSP_REDIS_ERROR_NOSCRIPT:
|
335
|
+
case MSG_RSP_REDIS_ERROR_READONLY:
|
336
|
+
case MSG_RSP_REDIS_ERROR_WRONGTYPE:
|
337
|
+
case MSG_RSP_REDIS_ERROR_EXECABORT:
|
338
|
+
case MSG_RSP_REDIS_ERROR_MASTERDOWN:
|
339
|
+
case MSG_RSP_REDIS_ERROR_NOREPLICAS:
|
340
|
+
return true;
|
341
|
+
|
342
|
+
default:
|
343
|
+
break;
|
344
|
+
}
|
345
|
+
|
346
|
+
return false;
|
347
|
+
}
|
348
|
+
|
303
349
|
/*
|
304
350
|
* Reference: http://redis.io/topics/protocol
|
305
351
|
*
|
@@ -625,6 +671,12 @@ redis_parse_req(struct msg *r)
|
|
625
671
|
break;
|
626
672
|
}
|
627
673
|
|
674
|
+
if (str4icmp(m, 'a', 'u', 't', 'h')) {
|
675
|
+
r->type = MSG_REQ_REDIS_AUTH;
|
676
|
+
r->noforward = 1;
|
677
|
+
break;
|
678
|
+
}
|
679
|
+
|
628
680
|
break;
|
629
681
|
|
630
682
|
case 5:
|
@@ -1051,6 +1103,8 @@ redis_parse_req(struct msg *r)
|
|
1051
1103
|
case LF:
|
1052
1104
|
if (redis_argz(r)) {
|
1053
1105
|
goto done;
|
1106
|
+
} else if (r->narg == 1) {
|
1107
|
+
goto error;
|
1054
1108
|
} else if (redis_argeval(r)) {
|
1055
1109
|
state = SW_ARG1_LEN;
|
1056
1110
|
} else {
|
@@ -1074,11 +1128,6 @@ redis_parse_req(struct msg *r)
|
|
1074
1128
|
} else if (isdigit(ch)) {
|
1075
1129
|
r->rlen = r->rlen * 10 + (uint32_t)(ch - '0');
|
1076
1130
|
} else if (ch == CR) {
|
1077
|
-
if (r->rlen == 0) {
|
1078
|
-
log_error("parsed bad req %"PRIu64" of type %d with empty "
|
1079
|
-
"key", r->id, r->type);
|
1080
|
-
goto error;
|
1081
|
-
}
|
1082
1131
|
if (r->rlen >= mbuf_data_size()) {
|
1083
1132
|
log_error("parsed bad req %"PRIu64" of type %d with key "
|
1084
1133
|
"length %d that greater than or equal to maximum"
|
@@ -1178,8 +1227,8 @@ redis_parse_req(struct msg *r)
|
|
1178
1227
|
}
|
1179
1228
|
state = SW_KEY_LEN;
|
1180
1229
|
} else if (redis_argkvx(r)) {
|
1181
|
-
if (r->
|
1182
|
-
goto
|
1230
|
+
if (r->narg % 2 == 0) {
|
1231
|
+
goto error;
|
1183
1232
|
}
|
1184
1233
|
state = SW_ARG1_LEN;
|
1185
1234
|
} else if (redis_argeval(r)) {
|
@@ -1672,6 +1721,7 @@ redis_parse_rsp(struct msg *r)
|
|
1672
1721
|
SW_ERROR,
|
1673
1722
|
SW_INTEGER,
|
1674
1723
|
SW_INTEGER_START,
|
1724
|
+
SW_SIMPLE,
|
1675
1725
|
SW_BULK,
|
1676
1726
|
SW_BULK_LF,
|
1677
1727
|
SW_BULK_ARG,
|
@@ -1748,8 +1798,125 @@ redis_parse_rsp(struct msg *r)
|
|
1748
1798
|
break;
|
1749
1799
|
|
1750
1800
|
case SW_ERROR:
|
1751
|
-
|
1752
|
-
|
1801
|
+
if (r->token == NULL) {
|
1802
|
+
if (ch != '-') {
|
1803
|
+
goto error;
|
1804
|
+
}
|
1805
|
+
/* rsp_start <- p */
|
1806
|
+
r->token = p;
|
1807
|
+
}
|
1808
|
+
if (ch == ' ' || ch == CR) {
|
1809
|
+
m = r->token;
|
1810
|
+
r->token = NULL;
|
1811
|
+
switch (p - m) {
|
1812
|
+
|
1813
|
+
case 4:
|
1814
|
+
/*
|
1815
|
+
* -ERR no such key\r\n
|
1816
|
+
* -ERR syntax error\r\n
|
1817
|
+
* -ERR source and destination objects are the same\r\n
|
1818
|
+
* -ERR index out of range\r\n
|
1819
|
+
*/
|
1820
|
+
if (str4cmp(m, '-', 'E', 'R', 'R')) {
|
1821
|
+
r->type = MSG_RSP_REDIS_ERROR_ERR;
|
1822
|
+
break;
|
1823
|
+
}
|
1824
|
+
|
1825
|
+
/* -OOM command not allowed when used memory > 'maxmemory'.\r\n */
|
1826
|
+
if (str4cmp(m, '-', 'O', 'O', 'M')) {
|
1827
|
+
r->type = MSG_RSP_REDIS_ERROR_OOM;
|
1828
|
+
break;
|
1829
|
+
}
|
1830
|
+
|
1831
|
+
break;
|
1832
|
+
|
1833
|
+
case 5:
|
1834
|
+
/* -BUSY Redis is busy running a script. You can only call SCRIPT KILL or SHUTDOWN NOSAVE.\r\n" */
|
1835
|
+
if (str5cmp(m, '-', 'B', 'U', 'S', 'Y')) {
|
1836
|
+
r->type = MSG_RSP_REDIS_ERROR_BUSY;
|
1837
|
+
break;
|
1838
|
+
}
|
1839
|
+
|
1840
|
+
break;
|
1841
|
+
|
1842
|
+
case 7:
|
1843
|
+
/* -NOAUTH Authentication required.\r\n */
|
1844
|
+
if (str7cmp(m, '-', 'N', 'O', 'A', 'U', 'T', 'H')) {
|
1845
|
+
r->type = MSG_RSP_REDIS_ERROR_NOAUTH;
|
1846
|
+
break;
|
1847
|
+
}
|
1848
|
+
|
1849
|
+
break;
|
1850
|
+
|
1851
|
+
case 8:
|
1852
|
+
/* rsp: "-LOADING Redis is loading the dataset in memory\r\n" */
|
1853
|
+
if (str8cmp(m, '-', 'L', 'O', 'A', 'D', 'I', 'N', 'G')) {
|
1854
|
+
r->type = MSG_RSP_REDIS_ERROR_LOADING;
|
1855
|
+
break;
|
1856
|
+
}
|
1857
|
+
|
1858
|
+
/* -BUSYKEY Target key name already exists.\r\n */
|
1859
|
+
if (str8cmp(m, '-', 'B', 'U', 'S', 'Y', 'K', 'E', 'Y')) {
|
1860
|
+
r->type = MSG_RSP_REDIS_ERROR_BUSYKEY;
|
1861
|
+
break;
|
1862
|
+
}
|
1863
|
+
|
1864
|
+
/* "-MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for details about the error.\r\n" */
|
1865
|
+
if (str8cmp(m, '-', 'M', 'I', 'S', 'C', 'O', 'N', 'F')) {
|
1866
|
+
r->type = MSG_RSP_REDIS_ERROR_MISCONF;
|
1867
|
+
break;
|
1868
|
+
}
|
1869
|
+
|
1870
|
+
break;
|
1871
|
+
|
1872
|
+
case 9:
|
1873
|
+
/* -NOSCRIPT No matching script. Please use EVAL.\r\n */
|
1874
|
+
if (str9cmp(m, '-', 'N', 'O', 'S', 'C', 'R', 'I', 'P', 'T')) {
|
1875
|
+
r->type = MSG_RSP_REDIS_ERROR_NOSCRIPT;
|
1876
|
+
break;
|
1877
|
+
}
|
1878
|
+
|
1879
|
+
/* -READONLY You can't write against a read only slave.\r\n */
|
1880
|
+
if (str9cmp(m, '-', 'R', 'E', 'A', 'D', 'O', 'N', 'L', 'Y')) {
|
1881
|
+
r->type = MSG_RSP_REDIS_ERROR_READONLY;
|
1882
|
+
break;
|
1883
|
+
}
|
1884
|
+
|
1885
|
+
break;
|
1886
|
+
|
1887
|
+
case 10:
|
1888
|
+
/* -WRONGTYPE Operation against a key holding the wrong kind of value\r\n */
|
1889
|
+
if (str10cmp(m, '-', 'W', 'R', 'O', 'N', 'G', 'T', 'Y', 'P', 'E')) {
|
1890
|
+
r->type = MSG_RSP_REDIS_ERROR_WRONGTYPE;
|
1891
|
+
break;
|
1892
|
+
}
|
1893
|
+
|
1894
|
+
/* -EXECABORT Transaction discarded because of previous errors.\r\n" */
|
1895
|
+
if (str10cmp(m, '-', 'E', 'X', 'E', 'C', 'A', 'B', 'O', 'R', 'T')) {
|
1896
|
+
r->type = MSG_RSP_REDIS_ERROR_EXECABORT;
|
1897
|
+
break;
|
1898
|
+
}
|
1899
|
+
|
1900
|
+
break;
|
1901
|
+
|
1902
|
+
case 11:
|
1903
|
+
/* -MASTERDOWN Link with MASTER is down and slave-serve-stale-data is set to 'no'.\r\n */
|
1904
|
+
if (str11cmp(m, '-', 'M', 'A', 'S', 'T', 'E', 'R', 'D', 'O', 'W', 'N')) {
|
1905
|
+
r->type = MSG_RSP_REDIS_ERROR_MASTERDOWN;
|
1906
|
+
break;
|
1907
|
+
}
|
1908
|
+
|
1909
|
+
/* -NOREPLICAS Not enough good slaves to write.\r\n */
|
1910
|
+
if (str11cmp(m, '-', 'N', 'O', 'R', 'E', 'P', 'L', 'I', 'C', 'A', 'S')) {
|
1911
|
+
r->type = MSG_RSP_REDIS_ERROR_NOREPLICAS;
|
1912
|
+
break;
|
1913
|
+
}
|
1914
|
+
|
1915
|
+
break;
|
1916
|
+
}
|
1917
|
+
state = SW_RUNTO_CRLF;
|
1918
|
+
}
|
1919
|
+
|
1753
1920
|
break;
|
1754
1921
|
|
1755
1922
|
case SW_INTEGER:
|
@@ -1758,6 +1925,13 @@ redis_parse_rsp(struct msg *r)
|
|
1758
1925
|
r->integer = 0;
|
1759
1926
|
break;
|
1760
1927
|
|
1928
|
+
case SW_SIMPLE:
|
1929
|
+
if (ch == CR) {
|
1930
|
+
state = SW_MULTIBULK_ARGN_LF;
|
1931
|
+
r->rnarg--;
|
1932
|
+
}
|
1933
|
+
break;
|
1934
|
+
|
1761
1935
|
case SW_INTEGER_START:
|
1762
1936
|
if (ch == CR) {
|
1763
1937
|
state = SW_ALMOST_DONE;
|
@@ -1897,6 +2071,7 @@ redis_parse_rsp(struct msg *r)
|
|
1897
2071
|
/* response is '*0\r\n' */
|
1898
2072
|
goto done;
|
1899
2073
|
}
|
2074
|
+
|
1900
2075
|
state = SW_MULTIBULK_ARGN_LEN;
|
1901
2076
|
break;
|
1902
2077
|
|
@@ -1938,9 +2113,17 @@ redis_parse_rsp(struct msg *r)
|
|
1938
2113
|
break;
|
1939
2114
|
}
|
1940
2115
|
|
1941
|
-
if (ch
|
2116
|
+
if (ch == ':' || ch == '+' || ch == '-') {
|
2117
|
+
/* handles not-found reply = '$-1' or integer reply = ':<num>' */
|
2118
|
+
/* and *2\r\n$2\r\nr0\r\n+OK\r\n or *1\r\n+OK\r\n */
|
2119
|
+
state = SW_SIMPLE;
|
2120
|
+
break;
|
2121
|
+
}
|
2122
|
+
|
2123
|
+
if (ch != '$') {
|
1942
2124
|
goto error;
|
1943
2125
|
}
|
2126
|
+
|
1944
2127
|
r->token = p;
|
1945
2128
|
r->rlen = 0;
|
1946
2129
|
} else if (isdigit(ch)) {
|
@@ -1952,8 +2135,7 @@ redis_parse_rsp(struct msg *r)
|
|
1952
2135
|
goto error;
|
1953
2136
|
}
|
1954
2137
|
|
1955
|
-
if ((r->rlen == 1 && (p - r->token) == 3)
|
1956
|
-
/* handles not-found reply = '$-1' or integer reply = ':<num>' */
|
2138
|
+
if ((r->rlen == 1 && (p - r->token) == 3)) {
|
1957
2139
|
r->rlen = 0;
|
1958
2140
|
state = SW_MULTIBULK_ARGN_LF;
|
1959
2141
|
} else {
|
@@ -2062,6 +2244,37 @@ error:
|
|
2062
2244
|
r->state);
|
2063
2245
|
}
|
2064
2246
|
|
2247
|
+
/*
|
2248
|
+
* Return true, if redis replies with a transient server failure response,
|
2249
|
+
* otherwise return false
|
2250
|
+
*
|
2251
|
+
* Transient failures on redis are scenarios when it is temporarily
|
2252
|
+
* unresponsive and responds with the following protocol specific error
|
2253
|
+
* reply:
|
2254
|
+
* -OOM, when redis is out-of-memory
|
2255
|
+
* -BUSY, when redis is busy
|
2256
|
+
* -LOADING when redis is loading dataset into memory
|
2257
|
+
*
|
2258
|
+
* See issue: https://github.com/twitter/twemproxy/issues/369
|
2259
|
+
*/
|
2260
|
+
bool
|
2261
|
+
redis_failure(struct msg *r)
|
2262
|
+
{
|
2263
|
+
ASSERT(!r->request);
|
2264
|
+
|
2265
|
+
switch (r->type) {
|
2266
|
+
case MSG_RSP_REDIS_ERROR_OOM:
|
2267
|
+
case MSG_RSP_REDIS_ERROR_BUSY:
|
2268
|
+
case MSG_RSP_REDIS_ERROR_LOADING:
|
2269
|
+
return true;
|
2270
|
+
|
2271
|
+
default:
|
2272
|
+
break;
|
2273
|
+
}
|
2274
|
+
|
2275
|
+
return false;
|
2276
|
+
}
|
2277
|
+
|
2065
2278
|
/*
|
2066
2279
|
* copy one bulk from src to dst
|
2067
2280
|
*
|
@@ -2443,8 +2656,10 @@ redis_fragment(struct msg *r, uint32_t ncontinuum, struct msg_tqh *frag_msgq)
|
|
2443
2656
|
case MSG_REQ_REDIS_MGET:
|
2444
2657
|
case MSG_REQ_REDIS_DEL:
|
2445
2658
|
return redis_fragment_argx(r, ncontinuum, frag_msgq, 1);
|
2659
|
+
|
2446
2660
|
case MSG_REQ_REDIS_MSET:
|
2447
2661
|
return redis_fragment_argx(r, ncontinuum, frag_msgq, 2);
|
2662
|
+
|
2448
2663
|
default:
|
2449
2664
|
return NC_OK;
|
2450
2665
|
}
|
@@ -2453,13 +2668,23 @@ redis_fragment(struct msg *r, uint32_t ncontinuum, struct msg_tqh *frag_msgq)
|
|
2453
2668
|
rstatus_t
|
2454
2669
|
redis_reply(struct msg *r)
|
2455
2670
|
{
|
2671
|
+
struct conn *c_conn;
|
2456
2672
|
struct msg *response = r->peer;
|
2457
2673
|
|
2458
|
-
ASSERT(response != NULL);
|
2674
|
+
ASSERT(response != NULL && response->owner != NULL);
|
2675
|
+
|
2676
|
+
c_conn = response->owner;
|
2677
|
+
if (r->type == MSG_REQ_REDIS_AUTH) {
|
2678
|
+
return redis_handle_auth_req(r, response);
|
2679
|
+
}
|
2680
|
+
|
2681
|
+
if (!conn_authenticated(c_conn)) {
|
2682
|
+
return msg_append(response, rsp_auth_required.data, rsp_auth_required.len);
|
2683
|
+
}
|
2459
2684
|
|
2460
2685
|
switch (r->type) {
|
2461
2686
|
case MSG_REQ_REDIS_PING:
|
2462
|
-
return msg_append(response,
|
2687
|
+
return msg_append(response, rsp_pong.data, rsp_pong.len);
|
2463
2688
|
|
2464
2689
|
default:
|
2465
2690
|
NOT_REACHED();
|
@@ -2470,10 +2695,10 @@ redis_reply(struct msg *r)
|
|
2470
2695
|
void
|
2471
2696
|
redis_post_coalesce_mset(struct msg *request)
|
2472
2697
|
{
|
2473
|
-
struct msg *response = request->peer;
|
2474
2698
|
rstatus_t status;
|
2699
|
+
struct msg *response = request->peer;
|
2475
2700
|
|
2476
|
-
status = msg_append(response,
|
2701
|
+
status = msg_append(response, rsp_ok.data, rsp_ok.len);
|
2477
2702
|
if (status != NC_OK) {
|
2478
2703
|
response->error = 1; /* mark this msg as err */
|
2479
2704
|
response->err = errno;
|
@@ -2546,11 +2771,168 @@ redis_post_coalesce(struct msg *r)
|
|
2546
2771
|
switch (r->type) {
|
2547
2772
|
case MSG_REQ_REDIS_MGET:
|
2548
2773
|
return redis_post_coalesce_mget(r);
|
2774
|
+
|
2549
2775
|
case MSG_REQ_REDIS_DEL:
|
2550
2776
|
return redis_post_coalesce_del(r);
|
2777
|
+
|
2551
2778
|
case MSG_REQ_REDIS_MSET:
|
2552
2779
|
return redis_post_coalesce_mset(r);
|
2780
|
+
|
2553
2781
|
default:
|
2554
2782
|
NOT_REACHED();
|
2555
2783
|
}
|
2556
2784
|
}
|
2785
|
+
|
2786
|
+
static rstatus_t
|
2787
|
+
redis_handle_auth_req(struct msg *req, struct msg *rsp)
|
2788
|
+
{
|
2789
|
+
struct conn *conn = (struct conn *)rsp->owner;
|
2790
|
+
struct server_pool *pool;
|
2791
|
+
struct keypos *kpos;
|
2792
|
+
uint8_t *key;
|
2793
|
+
uint32_t keylen;
|
2794
|
+
bool valid;
|
2795
|
+
|
2796
|
+
ASSERT(conn->client && !conn->proxy);
|
2797
|
+
|
2798
|
+
pool = (struct server_pool *)conn->owner;
|
2799
|
+
|
2800
|
+
if (!pool->require_auth) {
|
2801
|
+
/*
|
2802
|
+
* AUTH command from the client in absence of a redis_auth:
|
2803
|
+
* directive should be treated as an error
|
2804
|
+
*/
|
2805
|
+
return msg_append(rsp, rsp_no_password.data, rsp_no_password.len);
|
2806
|
+
}
|
2807
|
+
|
2808
|
+
kpos = array_get(req->keys, 0);
|
2809
|
+
key = kpos->start;
|
2810
|
+
keylen = (uint32_t)(kpos->end - kpos->start);
|
2811
|
+
valid = (keylen == pool->redis_auth.len) &&
|
2812
|
+
(memcmp(pool->redis_auth.data, key, keylen) == 0) ? true : false;
|
2813
|
+
if (valid) {
|
2814
|
+
conn->authenticated = 1;
|
2815
|
+
return msg_append(rsp, rsp_ok.data, rsp_ok.len);
|
2816
|
+
}
|
2817
|
+
|
2818
|
+
/*
|
2819
|
+
* Password in the AUTH command doesn't match the one configured in
|
2820
|
+
* redis_auth: directive
|
2821
|
+
*
|
2822
|
+
* We mark the connection has unauthenticated until the client
|
2823
|
+
* reauthenticates with the correct password
|
2824
|
+
*/
|
2825
|
+
conn->authenticated = 0;
|
2826
|
+
return msg_append(rsp, rsp_invalid_password.data, rsp_invalid_password.len);
|
2827
|
+
}
|
2828
|
+
|
2829
|
+
rstatus_t
|
2830
|
+
redis_add_auth(struct context *ctx, struct conn *c_conn, struct conn *s_conn)
|
2831
|
+
{
|
2832
|
+
rstatus_t status;
|
2833
|
+
struct msg *msg;
|
2834
|
+
struct server_pool *pool;
|
2835
|
+
|
2836
|
+
ASSERT(!s_conn->client && !s_conn->proxy);
|
2837
|
+
ASSERT(!conn_authenticated(s_conn));
|
2838
|
+
|
2839
|
+
pool = c_conn->owner;
|
2840
|
+
|
2841
|
+
msg = msg_get(c_conn, true, c_conn->redis);
|
2842
|
+
if (msg == NULL) {
|
2843
|
+
c_conn->err = errno;
|
2844
|
+
return NC_ENOMEM;
|
2845
|
+
}
|
2846
|
+
|
2847
|
+
status = msg_prepend_format(msg, "*2\r\n$4\r\nAUTH\r\n$%d\r\n%s\r\n",
|
2848
|
+
pool->redis_auth.len, pool->redis_auth.data);
|
2849
|
+
if (status != NC_OK) {
|
2850
|
+
msg_put(msg);
|
2851
|
+
return status;
|
2852
|
+
}
|
2853
|
+
|
2854
|
+
msg->swallow = 1;
|
2855
|
+
s_conn->enqueue_inq(ctx, s_conn, msg);
|
2856
|
+
s_conn->authenticated = 1;
|
2857
|
+
|
2858
|
+
return NC_OK;
|
2859
|
+
}
|
2860
|
+
|
2861
|
+
void
|
2862
|
+
redis_post_connect(struct context *ctx, struct conn *conn, struct server *server)
|
2863
|
+
{
|
2864
|
+
rstatus_t status;
|
2865
|
+
struct server_pool *pool = server->owner;
|
2866
|
+
struct msg *msg;
|
2867
|
+
int digits;
|
2868
|
+
|
2869
|
+
ASSERT(!conn->client && conn->connected);
|
2870
|
+
ASSERT(conn->redis);
|
2871
|
+
|
2872
|
+
/*
|
2873
|
+
* By default, every connection to redis uses the database DB 0. You
|
2874
|
+
* can select a different one on a per-connection basis by sending
|
2875
|
+
* a request 'SELECT <redis_db>', where <redis_db> is the configured
|
2876
|
+
* on a per pool basis in the configuration
|
2877
|
+
*/
|
2878
|
+
if (pool->redis_db <= 0) {
|
2879
|
+
return;
|
2880
|
+
}
|
2881
|
+
|
2882
|
+
/*
|
2883
|
+
* Create a fake client message and add it to the pipeline. We force this
|
2884
|
+
* message to be head of queue as it might already contain a command
|
2885
|
+
* that triggered the connect.
|
2886
|
+
*/
|
2887
|
+
msg = msg_get(conn, true, conn->redis);
|
2888
|
+
if (msg == NULL) {
|
2889
|
+
return;
|
2890
|
+
}
|
2891
|
+
|
2892
|
+
digits = (pool->redis_db >= 10) ? (int)log10(pool->redis_db) + 1 : 1;
|
2893
|
+
status = msg_prepend_format(msg, "*2\r\n$6\r\nSELECT\r\n$%d\r\n%d\r\n", digits, pool->redis_db);
|
2894
|
+
if (status != NC_OK) {
|
2895
|
+
msg_put(msg);
|
2896
|
+
return;
|
2897
|
+
}
|
2898
|
+
msg->type = MSG_REQ_REDIS_SELECT;
|
2899
|
+
msg->result = MSG_PARSE_OK;
|
2900
|
+
msg->swallow = 1;
|
2901
|
+
msg->owner = NULL;
|
2902
|
+
|
2903
|
+
/* enqueue as head and send */
|
2904
|
+
req_server_enqueue_imsgq_head(ctx, conn, msg);
|
2905
|
+
msg_send(ctx, conn);
|
2906
|
+
|
2907
|
+
log_debug(LOG_NOTICE, "sent 'SELECT %d' to %s | %s", pool->redis_db,
|
2908
|
+
pool->name.data, server->name.data);
|
2909
|
+
}
|
2910
|
+
|
2911
|
+
void
|
2912
|
+
redis_swallow_msg(struct conn *conn, struct msg *pmsg, struct msg *msg)
|
2913
|
+
{
|
2914
|
+
if (pmsg != NULL && pmsg->type == MSG_REQ_REDIS_SELECT &&
|
2915
|
+
msg != NULL && redis_error(msg)) {
|
2916
|
+
struct server* conn_server;
|
2917
|
+
struct server_pool* conn_pool;
|
2918
|
+
struct mbuf* rsp_buffer;
|
2919
|
+
uint8_t message[128];
|
2920
|
+
size_t copy_len;
|
2921
|
+
|
2922
|
+
/*
|
2923
|
+
* Get a substring from the message so that the inital - and the trailing
|
2924
|
+
* \r\n is removed.
|
2925
|
+
*/
|
2926
|
+
conn_server = (struct server*)conn->owner;
|
2927
|
+
conn_pool = conn_server->owner;
|
2928
|
+
rsp_buffer = STAILQ_LAST(&msg->mhdr, mbuf, next);
|
2929
|
+
copy_len = MIN(mbuf_length(rsp_buffer) - 3, sizeof(message) - 1);
|
2930
|
+
|
2931
|
+
nc_memcpy(message, &rsp_buffer->start[1], copy_len);
|
2932
|
+
message[copy_len] = 0;
|
2933
|
+
|
2934
|
+
log_warn("SELECT %d failed on %s | %s: %s",
|
2935
|
+
conn_pool->redis_db, conn_pool->name.data,
|
2936
|
+
conn_server->name.data, message);
|
2937
|
+
}
|
2938
|
+
}
|