nutcracker 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (149) hide show
  1. data/README.md +22 -0
  2. data/Rakefile +55 -0
  3. data/bin/nutcracker +2 -0
  4. data/ext/nutcracker/ChangeLog +66 -0
  5. data/ext/nutcracker/LICENSE +177 -0
  6. data/ext/nutcracker/Makefile.am +7 -0
  7. data/ext/nutcracker/Makefile.in +726 -0
  8. data/ext/nutcracker/NOTICE +124 -0
  9. data/ext/nutcracker/README.md +240 -0
  10. data/ext/nutcracker/aclocal.m4 +956 -0
  11. data/ext/nutcracker/conf/nutcracker.leaf.yml +10 -0
  12. data/ext/nutcracker/conf/nutcracker.root.yml +8 -0
  13. data/ext/nutcracker/conf/nutcracker.yml +67 -0
  14. data/ext/nutcracker/config.h.in +316 -0
  15. data/ext/nutcracker/config/config.guess +1561 -0
  16. data/ext/nutcracker/config/config.sub +1686 -0
  17. data/ext/nutcracker/config/depcomp +630 -0
  18. data/ext/nutcracker/config/install-sh +520 -0
  19. data/ext/nutcracker/config/ltmain.sh +8413 -0
  20. data/ext/nutcracker/config/missing +376 -0
  21. data/ext/nutcracker/configure +18862 -0
  22. data/ext/nutcracker/configure.ac +155 -0
  23. data/ext/nutcracker/contrib/Makefile.am +3 -0
  24. data/ext/nutcracker/contrib/Makefile.in +560 -0
  25. data/ext/nutcracker/contrib/yaml-0.1.4.tar.gz +0 -0
  26. data/ext/nutcracker/contrib/yaml-0.1.4/LICENSE +19 -0
  27. data/ext/nutcracker/contrib/yaml-0.1.4/Makefile.am +20 -0
  28. data/ext/nutcracker/contrib/yaml-0.1.4/Makefile.in +736 -0
  29. data/ext/nutcracker/contrib/yaml-0.1.4/README +27 -0
  30. data/ext/nutcracker/contrib/yaml-0.1.4/aclocal.m4 +956 -0
  31. data/ext/nutcracker/contrib/yaml-0.1.4/config.h.in +80 -0
  32. data/ext/nutcracker/contrib/yaml-0.1.4/config/config.guess +1561 -0
  33. data/ext/nutcracker/contrib/yaml-0.1.4/config/config.sub +1686 -0
  34. data/ext/nutcracker/contrib/yaml-0.1.4/config/depcomp +630 -0
  35. data/ext/nutcracker/contrib/yaml-0.1.4/config/install-sh +520 -0
  36. data/ext/nutcracker/contrib/yaml-0.1.4/config/ltmain.sh +8406 -0
  37. data/ext/nutcracker/contrib/yaml-0.1.4/config/missing +376 -0
  38. data/ext/nutcracker/contrib/yaml-0.1.4/configure +13085 -0
  39. data/ext/nutcracker/contrib/yaml-0.1.4/configure.ac +75 -0
  40. data/ext/nutcracker/contrib/yaml-0.1.4/doc/doxygen.cfg +222 -0
  41. data/ext/nutcracker/contrib/yaml-0.1.4/include/yaml.h +1971 -0
  42. data/ext/nutcracker/contrib/yaml-0.1.4/m4/libtool.m4 +7357 -0
  43. data/ext/nutcracker/contrib/yaml-0.1.4/m4/ltoptions.m4 +368 -0
  44. data/ext/nutcracker/contrib/yaml-0.1.4/m4/ltsugar.m4 +123 -0
  45. data/ext/nutcracker/contrib/yaml-0.1.4/m4/ltversion.m4 +23 -0
  46. data/ext/nutcracker/contrib/yaml-0.1.4/m4/lt~obsolete.m4 +92 -0
  47. data/ext/nutcracker/contrib/yaml-0.1.4/src/Makefile.am +4 -0
  48. data/ext/nutcracker/contrib/yaml-0.1.4/src/Makefile.in +484 -0
  49. data/ext/nutcracker/contrib/yaml-0.1.4/src/api.c +1392 -0
  50. data/ext/nutcracker/contrib/yaml-0.1.4/src/dumper.c +394 -0
  51. data/ext/nutcracker/contrib/yaml-0.1.4/src/emitter.c +2329 -0
  52. data/ext/nutcracker/contrib/yaml-0.1.4/src/loader.c +432 -0
  53. data/ext/nutcracker/contrib/yaml-0.1.4/src/parser.c +1374 -0
  54. data/ext/nutcracker/contrib/yaml-0.1.4/src/reader.c +465 -0
  55. data/ext/nutcracker/contrib/yaml-0.1.4/src/scanner.c +3570 -0
  56. data/ext/nutcracker/contrib/yaml-0.1.4/src/writer.c +141 -0
  57. data/ext/nutcracker/contrib/yaml-0.1.4/src/yaml_private.h +640 -0
  58. data/ext/nutcracker/contrib/yaml-0.1.4/tests/Makefile.am +8 -0
  59. data/ext/nutcracker/contrib/yaml-0.1.4/tests/Makefile.in +675 -0
  60. data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-deconstructor-alt.c +800 -0
  61. data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-deconstructor.c +1130 -0
  62. data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-reformatter-alt.c +217 -0
  63. data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-reformatter.c +202 -0
  64. data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-dumper.c +311 -0
  65. data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-emitter.c +327 -0
  66. data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-loader.c +63 -0
  67. data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-parser.c +63 -0
  68. data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-scanner.c +63 -0
  69. data/ext/nutcracker/contrib/yaml-0.1.4/tests/test-reader.c +354 -0
  70. data/ext/nutcracker/contrib/yaml-0.1.4/tests/test-version.c +29 -0
  71. data/ext/nutcracker/extconf.rb +5 -0
  72. data/ext/nutcracker/m4/libtool.m4 +7376 -0
  73. data/ext/nutcracker/m4/ltoptions.m4 +368 -0
  74. data/ext/nutcracker/m4/ltsugar.m4 +123 -0
  75. data/ext/nutcracker/m4/ltversion.m4 +23 -0
  76. data/ext/nutcracker/m4/lt~obsolete.m4 +92 -0
  77. data/ext/nutcracker/notes/c-styleguide.txt +425 -0
  78. data/ext/nutcracker/notes/debug.txt +96 -0
  79. data/ext/nutcracker/notes/memcache.txt +123 -0
  80. data/ext/nutcracker/notes/recommendation.md +118 -0
  81. data/ext/nutcracker/notes/redis.md +415 -0
  82. data/ext/nutcracker/notes/socket.txt +131 -0
  83. data/ext/nutcracker/scripts/multi_get.sh +26 -0
  84. data/ext/nutcracker/scripts/nutcracker.init +73 -0
  85. data/ext/nutcracker/scripts/nutcracker.spec +52 -0
  86. data/ext/nutcracker/scripts/pipelined_read.sh +23 -0
  87. data/ext/nutcracker/scripts/pipelined_write.sh +29 -0
  88. data/ext/nutcracker/scripts/populate_memcached.sh +24 -0
  89. data/ext/nutcracker/scripts/redis-check.py +23 -0
  90. data/ext/nutcracker/scripts/redis-check.sh +564 -0
  91. data/ext/nutcracker/src/Makefile.am +46 -0
  92. data/ext/nutcracker/src/Makefile.in +726 -0
  93. data/ext/nutcracker/src/hashkit/Makefile.am +22 -0
  94. data/ext/nutcracker/src/hashkit/Makefile.in +501 -0
  95. data/ext/nutcracker/src/hashkit/nc_crc32.c +105 -0
  96. data/ext/nutcracker/src/hashkit/nc_fnv.c +82 -0
  97. data/ext/nutcracker/src/hashkit/nc_hashkit.h +74 -0
  98. data/ext/nutcracker/src/hashkit/nc_hsieh.c +93 -0
  99. data/ext/nutcracker/src/hashkit/nc_jenkins.c +230 -0
  100. data/ext/nutcracker/src/hashkit/nc_ketama.c +240 -0
  101. data/ext/nutcracker/src/hashkit/nc_md5.c +379 -0
  102. data/ext/nutcracker/src/hashkit/nc_modula.c +144 -0
  103. data/ext/nutcracker/src/hashkit/nc_murmur.c +99 -0
  104. data/ext/nutcracker/src/hashkit/nc_one_at_a_time.c +51 -0
  105. data/ext/nutcracker/src/hashkit/nc_random.c +146 -0
  106. data/ext/nutcracker/src/nc.c +573 -0
  107. data/ext/nutcracker/src/nc_array.c +204 -0
  108. data/ext/nutcracker/src/nc_array.h +73 -0
  109. data/ext/nutcracker/src/nc_client.c +189 -0
  110. data/ext/nutcracker/src/nc_client.h +28 -0
  111. data/ext/nutcracker/src/nc_conf.c +1766 -0
  112. data/ext/nutcracker/src/nc_conf.h +134 -0
  113. data/ext/nutcracker/src/nc_connection.c +392 -0
  114. data/ext/nutcracker/src/nc_connection.h +99 -0
  115. data/ext/nutcracker/src/nc_core.c +334 -0
  116. data/ext/nutcracker/src/nc_core.h +131 -0
  117. data/ext/nutcracker/src/nc_event.c +214 -0
  118. data/ext/nutcracker/src/nc_event.h +39 -0
  119. data/ext/nutcracker/src/nc_log.c +254 -0
  120. data/ext/nutcracker/src/nc_log.h +120 -0
  121. data/ext/nutcracker/src/nc_mbuf.c +285 -0
  122. data/ext/nutcracker/src/nc_mbuf.h +67 -0
  123. data/ext/nutcracker/src/nc_message.c +828 -0
  124. data/ext/nutcracker/src/nc_message.h +253 -0
  125. data/ext/nutcracker/src/nc_proxy.c +359 -0
  126. data/ext/nutcracker/src/nc_proxy.h +34 -0
  127. data/ext/nutcracker/src/nc_queue.h +788 -0
  128. data/ext/nutcracker/src/nc_rbtree.c +348 -0
  129. data/ext/nutcracker/src/nc_rbtree.h +47 -0
  130. data/ext/nutcracker/src/nc_request.c +588 -0
  131. data/ext/nutcracker/src/nc_response.c +332 -0
  132. data/ext/nutcracker/src/nc_server.c +841 -0
  133. data/ext/nutcracker/src/nc_server.h +143 -0
  134. data/ext/nutcracker/src/nc_signal.c +131 -0
  135. data/ext/nutcracker/src/nc_signal.h +34 -0
  136. data/ext/nutcracker/src/nc_stats.c +1188 -0
  137. data/ext/nutcracker/src/nc_stats.h +206 -0
  138. data/ext/nutcracker/src/nc_string.c +109 -0
  139. data/ext/nutcracker/src/nc_string.h +112 -0
  140. data/ext/nutcracker/src/nc_util.c +619 -0
  141. data/ext/nutcracker/src/nc_util.h +214 -0
  142. data/ext/nutcracker/src/proto/Makefile.am +14 -0
  143. data/ext/nutcracker/src/proto/Makefile.in +482 -0
  144. data/ext/nutcracker/src/proto/nc_memcache.c +1306 -0
  145. data/ext/nutcracker/src/proto/nc_proto.h +155 -0
  146. data/ext/nutcracker/src/proto/nc_redis.c +2102 -0
  147. data/lib/nutcracker.rb +7 -0
  148. data/lib/nutcracker/version.rb +3 -0
  149. metadata +194 -0
@@ -0,0 +1,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
+ }