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,134 @@
|
|
|
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_CONF_H_
|
|
19
|
+
#define _NC_CONF_H_
|
|
20
|
+
|
|
21
|
+
#include <unistd.h>
|
|
22
|
+
#include <sys/types.h>
|
|
23
|
+
#include <sys/un.h>
|
|
24
|
+
#include <yaml.h>
|
|
25
|
+
|
|
26
|
+
#include <nc_core.h>
|
|
27
|
+
#include <hashkit/nc_hashkit.h>
|
|
28
|
+
|
|
29
|
+
#define CONF_OK (void *) NULL
|
|
30
|
+
#define CONF_ERROR (void *) "has an invalid value"
|
|
31
|
+
|
|
32
|
+
#define CONF_ROOT_DEPTH 1
|
|
33
|
+
#define CONF_MAX_DEPTH CONF_ROOT_DEPTH + 1
|
|
34
|
+
|
|
35
|
+
#define CONF_DEFAULT_ARGS 3
|
|
36
|
+
#define CONF_DEFAULT_POOL 8
|
|
37
|
+
#define CONF_DEFAULT_SERVERS 8
|
|
38
|
+
|
|
39
|
+
#define CONF_UNSET_NUM -1
|
|
40
|
+
#define CONF_UNSET_PTR NULL
|
|
41
|
+
#define CONF_UNSET_HASH (hash_type_t) -1
|
|
42
|
+
#define CONF_UNSET_DIST (dist_type_t) -1
|
|
43
|
+
|
|
44
|
+
#define CONF_DEFAULT_HASH HASH_FNV1A_64
|
|
45
|
+
#define CONF_DEFAULT_DIST DIST_KETAMA
|
|
46
|
+
#define CONF_DEFAULT_TIMEOUT -1
|
|
47
|
+
#define CONF_DEFAULT_LISTEN_BACKLOG 512
|
|
48
|
+
#define CONF_DEFAULT_CLIENT_CONNECTIONS 0
|
|
49
|
+
#define CONF_DEFAULT_REDIS false
|
|
50
|
+
#define CONF_DEFAULT_PRECONNECT false
|
|
51
|
+
#define CONF_DEFAULT_AUTO_EJECT_HOSTS false
|
|
52
|
+
#define CONF_DEFAULT_SERVER_RETRY_TIMEOUT 30 * 1000 /* in msec */
|
|
53
|
+
#define CONF_DEFAULT_SERVER_FAILURE_LIMIT 2
|
|
54
|
+
#define CONF_DEFAULT_SERVER_CONNECTIONS 1
|
|
55
|
+
#define CONF_DEFAULT_KETAMA_PORT 11211
|
|
56
|
+
|
|
57
|
+
struct conf_listen {
|
|
58
|
+
struct string pname; /* listen: as "name:port" */
|
|
59
|
+
struct string name; /* name */
|
|
60
|
+
int port; /* port */
|
|
61
|
+
struct sockinfo info; /* listen socket info */
|
|
62
|
+
unsigned valid:1; /* valid? */
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
struct conf_server {
|
|
66
|
+
struct string pname; /* server: as "name:port:weight" */
|
|
67
|
+
struct string name; /* name */
|
|
68
|
+
int port; /* port */
|
|
69
|
+
int weight; /* weight */
|
|
70
|
+
struct sockinfo info; /* connect socket info */
|
|
71
|
+
unsigned valid:1; /* valid? */
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
struct conf_pool {
|
|
75
|
+
struct string name; /* pool name (root node) */
|
|
76
|
+
struct conf_listen listen; /* listen: */
|
|
77
|
+
hash_type_t hash; /* hash: */
|
|
78
|
+
struct string hash_tag; /* hash_tag: */
|
|
79
|
+
dist_type_t distribution; /* distribution: */
|
|
80
|
+
int timeout; /* timeout: */
|
|
81
|
+
int backlog; /* backlog: */
|
|
82
|
+
int client_connections; /* client_connections: */
|
|
83
|
+
int redis; /* redis: */
|
|
84
|
+
int preconnect; /* preconnect: */
|
|
85
|
+
int auto_eject_hosts; /* auto_eject_hosts: */
|
|
86
|
+
int server_connections; /* server_connections: */
|
|
87
|
+
int server_retry_timeout; /* server_retry_timeout: in msec */
|
|
88
|
+
int server_failure_limit; /* server_failure_limit: */
|
|
89
|
+
struct array server; /* servers: conf_server[] */
|
|
90
|
+
unsigned valid:1; /* valid? */
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
struct conf {
|
|
94
|
+
char *fname; /* file name (ref in argv[]) */
|
|
95
|
+
FILE *fh; /* file handle */
|
|
96
|
+
struct array arg; /* string[] (parsed {key, value} pairs) */
|
|
97
|
+
struct array pool; /* conf_pool[] (parsed pools) */
|
|
98
|
+
uint32_t depth; /* parsed tree depth */
|
|
99
|
+
yaml_parser_t parser; /* yaml parser */
|
|
100
|
+
yaml_event_t event; /* yaml event */
|
|
101
|
+
yaml_token_t token; /* yaml token */
|
|
102
|
+
unsigned seq:1; /* sequence? */
|
|
103
|
+
unsigned valid_parser:1; /* valid parser? */
|
|
104
|
+
unsigned valid_event:1; /* valid event? */
|
|
105
|
+
unsigned valid_token:1; /* valid token? */
|
|
106
|
+
unsigned sound:1; /* sound? */
|
|
107
|
+
unsigned parsed:1; /* parsed? */
|
|
108
|
+
unsigned valid:1; /* valid? */
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
struct command {
|
|
112
|
+
struct string name;
|
|
113
|
+
char *(*set)(struct conf *cf, struct command *cmd, void *data);
|
|
114
|
+
int offset;
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
#define null_command { null_string, NULL, 0 }
|
|
118
|
+
|
|
119
|
+
char *conf_set_string(struct conf *cf, struct command *cmd, void *conf);
|
|
120
|
+
char *conf_set_listen(struct conf *cf, struct command *cmd, void *conf);
|
|
121
|
+
char *conf_add_server(struct conf *cf, struct command *cmd, void *conf);
|
|
122
|
+
char *conf_set_num(struct conf *cf, struct command *cmd, void *conf);
|
|
123
|
+
char * conf_set_bool(struct conf *cf, struct command *cmd, void *conf);
|
|
124
|
+
char *conf_set_hash(struct conf *cf, struct command *cmd, void *conf);
|
|
125
|
+
char *conf_set_distribution(struct conf *cf, struct command *cmd, void *conf);
|
|
126
|
+
char *conf_set_hashtag(struct conf *cf, struct command *cmd, void *conf);
|
|
127
|
+
|
|
128
|
+
rstatus_t conf_server_each_transform(void *elem, void *data);
|
|
129
|
+
rstatus_t conf_pool_each_transform(void *elem, void *data);
|
|
130
|
+
|
|
131
|
+
struct conf *conf_create(char *filename);
|
|
132
|
+
void conf_destroy(struct conf *cf);
|
|
133
|
+
|
|
134
|
+
#endif
|
|
@@ -0,0 +1,392 @@
|
|
|
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 <sys/uio.h>
|
|
19
|
+
|
|
20
|
+
#include <nc_core.h>
|
|
21
|
+
#include <nc_server.h>
|
|
22
|
+
#include <nc_client.h>
|
|
23
|
+
#include <nc_proxy.h>
|
|
24
|
+
#include <proto/nc_proto.h>
|
|
25
|
+
|
|
26
|
+
/*
|
|
27
|
+
* nc_connection.[ch]
|
|
28
|
+
* Connection (struct conn)
|
|
29
|
+
* + + +
|
|
30
|
+
* | | |
|
|
31
|
+
* | Proxy |
|
|
32
|
+
* | nc_proxy.[ch] |
|
|
33
|
+
* / \
|
|
34
|
+
* Client Server
|
|
35
|
+
* nc_client.[ch] nc_server.[ch]
|
|
36
|
+
*
|
|
37
|
+
* Nutcracker essentially multiplexes m client connections over n server
|
|
38
|
+
* connections. Usually m >> n, so that nutcracker can pipeline requests
|
|
39
|
+
* from several clients over a server connection and hence use the connection
|
|
40
|
+
* bandwidth to the server efficiently
|
|
41
|
+
*
|
|
42
|
+
* Client and server connection maintain two fifo queues for requests:
|
|
43
|
+
*
|
|
44
|
+
* 1). in_q (imsg_q): queue of incoming requests
|
|
45
|
+
* 2). out_q (omsg_q): queue of outstanding (outgoing) requests
|
|
46
|
+
*
|
|
47
|
+
* Request received over the client connection are forwarded to the server by
|
|
48
|
+
* enqueuing the request in the chosen server's in_q. From the client's
|
|
49
|
+
* perspective once the request is forwarded, it is outstanding and is tracked
|
|
50
|
+
* in the client's out_q (unless the request was tagged as noreply). The server
|
|
51
|
+
* in turn picks up requests from its own in_q in fifo order and puts them on
|
|
52
|
+
* the wire. Once the request is outstanding on the wire, and a response is
|
|
53
|
+
* expected for it, the server keeps track of outstanding requests it in its
|
|
54
|
+
* own out_q.
|
|
55
|
+
*
|
|
56
|
+
* The server's out_q enables us to pair a request with a response while the
|
|
57
|
+
* client's out_q enables us to pair request and response in the order in
|
|
58
|
+
* which they are received from the client.
|
|
59
|
+
*
|
|
60
|
+
*
|
|
61
|
+
* Clients Servers
|
|
62
|
+
* .
|
|
63
|
+
* in_q: <empty> .
|
|
64
|
+
* out_q: req11 -> req12 . in_q: req22
|
|
65
|
+
* (client1) . out_q: req11 -> req21 -> req12
|
|
66
|
+
* . (server1)
|
|
67
|
+
* in_q: <empty> .
|
|
68
|
+
* out_q: req21 -> req22 -> req23 .
|
|
69
|
+
* (client2) .
|
|
70
|
+
* . in_q: req23
|
|
71
|
+
* . out_q: <empty>
|
|
72
|
+
* . (server2)
|
|
73
|
+
*
|
|
74
|
+
* In the above example, client1 has two pipelined requests req11 and req12
|
|
75
|
+
* both of which are outstanding on the server connection server1. On the
|
|
76
|
+
* other hand, client2 has three requests req21, req22 and req23, of which
|
|
77
|
+
* only req21 is outstanding on the server connection while req22 and
|
|
78
|
+
* req23 are still waiting to be put on the wire. The fifo of client's
|
|
79
|
+
* out_q ensures that we always send back the response of request at the head
|
|
80
|
+
* of the queue, before sending out responses of other completed requests in
|
|
81
|
+
* the queue.
|
|
82
|
+
*
|
|
83
|
+
*/
|
|
84
|
+
|
|
85
|
+
static uint32_t nfree_connq; /* # free conn q */
|
|
86
|
+
static struct conn_tqh free_connq; /* free conn q */
|
|
87
|
+
|
|
88
|
+
static struct conn *
|
|
89
|
+
_conn_get(void)
|
|
90
|
+
{
|
|
91
|
+
struct conn *conn;
|
|
92
|
+
|
|
93
|
+
if (!TAILQ_EMPTY(&free_connq)) {
|
|
94
|
+
ASSERT(nfree_connq > 0);
|
|
95
|
+
|
|
96
|
+
conn = TAILQ_FIRST(&free_connq);
|
|
97
|
+
nfree_connq--;
|
|
98
|
+
TAILQ_REMOVE(&free_connq, conn, conn_tqe);
|
|
99
|
+
} else {
|
|
100
|
+
conn = nc_alloc(sizeof(*conn));
|
|
101
|
+
if (conn == NULL) {
|
|
102
|
+
return NULL;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
conn->owner = NULL;
|
|
107
|
+
|
|
108
|
+
conn->sd = -1;
|
|
109
|
+
/* {family, addrlen, addr} are initialized in enqueue handler */
|
|
110
|
+
|
|
111
|
+
TAILQ_INIT(&conn->imsg_q);
|
|
112
|
+
TAILQ_INIT(&conn->omsg_q);
|
|
113
|
+
conn->rmsg = NULL;
|
|
114
|
+
conn->smsg = NULL;
|
|
115
|
+
|
|
116
|
+
/*
|
|
117
|
+
* Callbacks {recv, recv_next, recv_done}, {send, send_next, send_done},
|
|
118
|
+
* {close, active}, parse, {ref, unref}, {enqueue_inq, dequeue_inq} and
|
|
119
|
+
* {enqueue_outq, dequeue_outq} are initialized by the wrapper.
|
|
120
|
+
*/
|
|
121
|
+
|
|
122
|
+
conn->send_bytes = 0;
|
|
123
|
+
conn->recv_bytes = 0;
|
|
124
|
+
|
|
125
|
+
conn->events = 0;
|
|
126
|
+
conn->err = 0;
|
|
127
|
+
conn->recv_active = 0;
|
|
128
|
+
conn->recv_ready = 0;
|
|
129
|
+
conn->send_active = 0;
|
|
130
|
+
conn->send_ready = 0;
|
|
131
|
+
|
|
132
|
+
conn->client = 0;
|
|
133
|
+
conn->proxy = 0;
|
|
134
|
+
conn->connecting = 0;
|
|
135
|
+
conn->connected = 0;
|
|
136
|
+
conn->eof = 0;
|
|
137
|
+
conn->done = 0;
|
|
138
|
+
conn->redis = 0;
|
|
139
|
+
|
|
140
|
+
return conn;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
struct conn *
|
|
144
|
+
conn_get(void *owner, bool client, bool redis)
|
|
145
|
+
{
|
|
146
|
+
struct conn *conn;
|
|
147
|
+
|
|
148
|
+
conn = _conn_get();
|
|
149
|
+
if (conn == NULL) {
|
|
150
|
+
return NULL;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/* connection either handles redis or memcache messages */
|
|
154
|
+
conn->redis = redis ? 1 : 0;
|
|
155
|
+
|
|
156
|
+
conn->client = client ? 1 : 0;
|
|
157
|
+
|
|
158
|
+
if (conn->client) {
|
|
159
|
+
/*
|
|
160
|
+
* client receives a request, possibly parsing it, and sends a
|
|
161
|
+
* response downstream.
|
|
162
|
+
*/
|
|
163
|
+
conn->recv = msg_recv;
|
|
164
|
+
conn->recv_next = req_recv_next;
|
|
165
|
+
conn->recv_done = req_recv_done;
|
|
166
|
+
|
|
167
|
+
conn->send = msg_send;
|
|
168
|
+
conn->send_next = rsp_send_next;
|
|
169
|
+
conn->send_done = rsp_send_done;
|
|
170
|
+
|
|
171
|
+
conn->close = client_close;
|
|
172
|
+
conn->active = client_active;
|
|
173
|
+
|
|
174
|
+
conn->ref = client_ref;
|
|
175
|
+
conn->unref = client_unref;
|
|
176
|
+
|
|
177
|
+
conn->enqueue_inq = NULL;
|
|
178
|
+
conn->dequeue_inq = NULL;
|
|
179
|
+
conn->enqueue_outq = req_client_enqueue_omsgq;
|
|
180
|
+
conn->dequeue_outq = req_client_dequeue_omsgq;
|
|
181
|
+
} else {
|
|
182
|
+
/*
|
|
183
|
+
* server receives a response, possibly parsing it, and sends a
|
|
184
|
+
* request upstream.
|
|
185
|
+
*/
|
|
186
|
+
conn->recv = msg_recv;
|
|
187
|
+
conn->recv_next = rsp_recv_next;
|
|
188
|
+
conn->recv_done = rsp_recv_done;
|
|
189
|
+
|
|
190
|
+
conn->send = msg_send;
|
|
191
|
+
conn->send_next = req_send_next;
|
|
192
|
+
conn->send_done = req_send_done;
|
|
193
|
+
|
|
194
|
+
conn->close = server_close;
|
|
195
|
+
conn->active = server_active;
|
|
196
|
+
|
|
197
|
+
conn->ref = server_ref;
|
|
198
|
+
conn->unref = server_unref;
|
|
199
|
+
|
|
200
|
+
conn->enqueue_inq = req_server_enqueue_imsgq;
|
|
201
|
+
conn->dequeue_inq = req_server_dequeue_imsgq;
|
|
202
|
+
conn->enqueue_outq = req_server_enqueue_omsgq;
|
|
203
|
+
conn->dequeue_outq = req_server_dequeue_omsgq;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
conn->ref(conn, owner);
|
|
207
|
+
|
|
208
|
+
log_debug(LOG_VVERB, "get conn %p client %d", conn, conn->client);
|
|
209
|
+
|
|
210
|
+
return conn;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
struct conn *
|
|
214
|
+
conn_get_proxy(void *owner)
|
|
215
|
+
{
|
|
216
|
+
struct server_pool *pool = owner;
|
|
217
|
+
struct conn *conn;
|
|
218
|
+
|
|
219
|
+
conn = _conn_get();
|
|
220
|
+
if (conn == NULL) {
|
|
221
|
+
return NULL;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
conn->redis = pool->redis;
|
|
225
|
+
|
|
226
|
+
conn->proxy = 1;
|
|
227
|
+
|
|
228
|
+
conn->recv = proxy_recv;
|
|
229
|
+
conn->recv_next = NULL;
|
|
230
|
+
conn->recv_done = NULL;
|
|
231
|
+
|
|
232
|
+
conn->send = NULL;
|
|
233
|
+
conn->send_next = NULL;
|
|
234
|
+
conn->send_done = NULL;
|
|
235
|
+
|
|
236
|
+
conn->close = proxy_close;
|
|
237
|
+
conn->active = NULL;
|
|
238
|
+
|
|
239
|
+
conn->ref = proxy_ref;
|
|
240
|
+
conn->unref = proxy_unref;
|
|
241
|
+
|
|
242
|
+
conn->enqueue_inq = NULL;
|
|
243
|
+
conn->dequeue_inq = NULL;
|
|
244
|
+
conn->enqueue_outq = NULL;
|
|
245
|
+
conn->dequeue_outq = NULL;
|
|
246
|
+
|
|
247
|
+
conn->ref(conn, owner);
|
|
248
|
+
|
|
249
|
+
log_debug(LOG_VVERB, "get conn %p proxy %d", conn, conn->proxy);
|
|
250
|
+
|
|
251
|
+
return conn;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
static void
|
|
255
|
+
conn_free(struct conn *conn)
|
|
256
|
+
{
|
|
257
|
+
log_debug(LOG_VVERB, "free conn %p", conn);
|
|
258
|
+
nc_free(conn);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
void
|
|
262
|
+
conn_put(struct conn *conn)
|
|
263
|
+
{
|
|
264
|
+
ASSERT(conn->sd < 0);
|
|
265
|
+
ASSERT(conn->owner == NULL);
|
|
266
|
+
|
|
267
|
+
log_debug(LOG_VVERB, "put conn %p", conn);
|
|
268
|
+
|
|
269
|
+
nfree_connq++;
|
|
270
|
+
TAILQ_INSERT_HEAD(&free_connq, conn, conn_tqe);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
void
|
|
274
|
+
conn_init(void)
|
|
275
|
+
{
|
|
276
|
+
log_debug(LOG_DEBUG, "conn size %d", sizeof(struct conn));
|
|
277
|
+
nfree_connq = 0;
|
|
278
|
+
TAILQ_INIT(&free_connq);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
void
|
|
282
|
+
conn_deinit(void)
|
|
283
|
+
{
|
|
284
|
+
struct conn *conn, *nconn; /* current and next connection */
|
|
285
|
+
|
|
286
|
+
for (conn = TAILQ_FIRST(&free_connq); conn != NULL;
|
|
287
|
+
conn = nconn, nfree_connq--) {
|
|
288
|
+
ASSERT(nfree_connq > 0);
|
|
289
|
+
nconn = TAILQ_NEXT(conn, conn_tqe);
|
|
290
|
+
conn_free(conn);
|
|
291
|
+
}
|
|
292
|
+
ASSERT(nfree_connq == 0);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
ssize_t
|
|
296
|
+
conn_recv(struct conn *conn, void *buf, size_t size)
|
|
297
|
+
{
|
|
298
|
+
ssize_t n;
|
|
299
|
+
|
|
300
|
+
ASSERT(buf != NULL);
|
|
301
|
+
ASSERT(size > 0);
|
|
302
|
+
ASSERT(conn->recv_ready);
|
|
303
|
+
|
|
304
|
+
for (;;) {
|
|
305
|
+
n = nc_read(conn->sd, buf, size);
|
|
306
|
+
|
|
307
|
+
log_debug(LOG_VERB, "recv on sd %d %zd of %zu", conn->sd, n, size);
|
|
308
|
+
|
|
309
|
+
if (n > 0) {
|
|
310
|
+
if (n < (ssize_t) size) {
|
|
311
|
+
conn->recv_ready = 0;
|
|
312
|
+
}
|
|
313
|
+
conn->recv_bytes += (size_t)n;
|
|
314
|
+
return n;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
if (n == 0) {
|
|
318
|
+
conn->recv_ready = 0;
|
|
319
|
+
conn->eof = 1;
|
|
320
|
+
log_debug(LOG_INFO, "recv on sd %d eof rb %zu sb %zu", conn->sd,
|
|
321
|
+
conn->recv_bytes, conn->send_bytes);
|
|
322
|
+
return n;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
if (errno == EINTR) {
|
|
326
|
+
log_debug(LOG_VERB, "recv on sd %d not ready - eintr", conn->sd);
|
|
327
|
+
continue;
|
|
328
|
+
} else if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
|
329
|
+
conn->recv_ready = 0;
|
|
330
|
+
log_debug(LOG_VERB, "recv on sd %d not ready - eagain", conn->sd);
|
|
331
|
+
return NC_EAGAIN;
|
|
332
|
+
} else {
|
|
333
|
+
conn->recv_ready = 0;
|
|
334
|
+
conn->err = errno;
|
|
335
|
+
log_error("recv on sd %d failed: %s", conn->sd, strerror(errno));
|
|
336
|
+
return NC_ERROR;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
NOT_REACHED();
|
|
341
|
+
|
|
342
|
+
return NC_ERROR;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
ssize_t
|
|
346
|
+
conn_sendv(struct conn *conn, struct array *sendv, size_t nsend)
|
|
347
|
+
{
|
|
348
|
+
ssize_t n;
|
|
349
|
+
|
|
350
|
+
ASSERT(array_n(sendv) > 0);
|
|
351
|
+
ASSERT(nsend != 0);
|
|
352
|
+
ASSERT(conn->send_ready);
|
|
353
|
+
|
|
354
|
+
for (;;) {
|
|
355
|
+
n = nc_writev(conn->sd, sendv->elem, sendv->nelem);
|
|
356
|
+
|
|
357
|
+
log_debug(LOG_VERB, "sendv on sd %d %zd of %zu in %"PRIu32" buffers",
|
|
358
|
+
conn->sd, n, nsend, sendv->nelem);
|
|
359
|
+
|
|
360
|
+
if (n > 0) {
|
|
361
|
+
if (n < (ssize_t) nsend) {
|
|
362
|
+
conn->send_ready = 0;
|
|
363
|
+
}
|
|
364
|
+
conn->send_bytes += (size_t)n;
|
|
365
|
+
return n;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
if (n == 0) {
|
|
369
|
+
log_warn("sendv on sd %d returned zero", conn->sd);
|
|
370
|
+
conn->send_ready = 0;
|
|
371
|
+
return 0;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
if (errno == EINTR) {
|
|
375
|
+
log_debug(LOG_VERB, "sendv on sd %d not ready - eintr", conn->sd);
|
|
376
|
+
continue;
|
|
377
|
+
} else if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
|
378
|
+
conn->send_ready = 0;
|
|
379
|
+
log_debug(LOG_VERB, "sendv on sd %d not ready - eagain", conn->sd);
|
|
380
|
+
return NC_EAGAIN;
|
|
381
|
+
} else {
|
|
382
|
+
conn->send_ready = 0;
|
|
383
|
+
conn->err = errno;
|
|
384
|
+
log_error("sendv on sd %d failed: %s", conn->sd, strerror(errno));
|
|
385
|
+
return NC_ERROR;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
NOT_REACHED();
|
|
390
|
+
|
|
391
|
+
return NC_ERROR;
|
|
392
|
+
}
|