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.
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
+ }