nutcracker 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
}
|