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,253 @@
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_MESSAGE_H_
19
+ #define _NC_MESSAGE_H_
20
+
21
+ #include <nc_core.h>
22
+
23
+ typedef void (*msg_parse_t)(struct msg *);
24
+ typedef rstatus_t (*msg_post_splitcopy_t)(struct msg *);
25
+ typedef void (*msg_coalesce_t)(struct msg *r);
26
+
27
+ typedef enum msg_parse_result {
28
+ MSG_PARSE_OK, /* parsing ok */
29
+ MSG_PARSE_ERROR, /* parsing error */
30
+ MSG_PARSE_REPAIR, /* more to parse -> repair parsed & unparsed data */
31
+ MSG_PARSE_FRAGMENT, /* multi-vector request -> fragment */
32
+ MSG_PARSE_AGAIN, /* incomplete -> parse again */
33
+ } msg_parse_result_t;
34
+
35
+ typedef enum msg_type {
36
+ MSG_UNKNOWN,
37
+ MSG_REQ_MC_GET, /* memcache retrieval requests */
38
+ MSG_REQ_MC_GETS,
39
+ MSG_REQ_MC_DELETE, /* memcache delete request */
40
+ MSG_REQ_MC_CAS, /* memcache cas request and storage request */
41
+ MSG_REQ_MC_SET, /* memcache storage request */
42
+ MSG_REQ_MC_ADD,
43
+ MSG_REQ_MC_REPLACE,
44
+ MSG_REQ_MC_APPEND,
45
+ MSG_REQ_MC_PREPEND,
46
+ MSG_REQ_MC_INCR, /* memcache arithmetic request */
47
+ MSG_REQ_MC_DECR,
48
+ MSG_REQ_MC_QUIT, /* memcache quit request */
49
+ MSG_RSP_MC_NUM, /* memcache arithmetic response */
50
+ MSG_RSP_MC_STORED, /* memcache cas and storage response */
51
+ MSG_RSP_MC_NOT_STORED,
52
+ MSG_RSP_MC_EXISTS,
53
+ MSG_RSP_MC_NOT_FOUND,
54
+ MSG_RSP_MC_END,
55
+ MSG_RSP_MC_VALUE,
56
+ MSG_RSP_MC_DELETED, /* memcache delete response */
57
+ MSG_RSP_MC_ERROR, /* memcache error responses */
58
+ MSG_RSP_MC_CLIENT_ERROR,
59
+ MSG_RSP_MC_SERVER_ERROR,
60
+ MSG_REQ_REDIS_DEL, /* redis commands - keys */
61
+ MSG_REQ_REDIS_EXISTS,
62
+ MSG_REQ_REDIS_EXPIRE,
63
+ MSG_REQ_REDIS_EXPIREAT,
64
+ MSG_REQ_REDIS_PEXPIRE,
65
+ MSG_REQ_REDIS_PEXPIREAT,
66
+ MSG_REQ_REDIS_PERSIST,
67
+ MSG_REQ_REDIS_PTTL,
68
+ MSG_REQ_REDIS_TTL,
69
+ MSG_REQ_REDIS_TYPE,
70
+ MSG_REQ_REDIS_APPEND, /* redis requests - string */
71
+ MSG_REQ_REDIS_BITCOUNT,
72
+ MSG_REQ_REDIS_DECR,
73
+ MSG_REQ_REDIS_DECRBY,
74
+ MSG_REQ_REDIS_GET,
75
+ MSG_REQ_REDIS_GETBIT,
76
+ MSG_REQ_REDIS_GETRANGE,
77
+ MSG_REQ_REDIS_GETSET,
78
+ MSG_REQ_REDIS_INCR,
79
+ MSG_REQ_REDIS_INCRBY,
80
+ MSG_REQ_REDIS_INCRBYFLOAT,
81
+ MSG_REQ_REDIS_MGET,
82
+ MSG_REQ_REDIS_PSETEX,
83
+ MSG_REQ_REDIS_SET,
84
+ MSG_REQ_REDIS_SETBIT,
85
+ MSG_REQ_REDIS_SETEX,
86
+ MSG_REQ_REDIS_SETNX,
87
+ MSG_REQ_REDIS_SETRANGE,
88
+ MSG_REQ_REDIS_STRLEN,
89
+ MSG_REQ_REDIS_HDEL, /* redis requests - hashes */
90
+ MSG_REQ_REDIS_HEXISTS,
91
+ MSG_REQ_REDIS_HGET,
92
+ MSG_REQ_REDIS_HGETALL,
93
+ MSG_REQ_REDIS_HINCRBY,
94
+ MSG_REQ_REDIS_HINCRBYFLOAT,
95
+ MSG_REQ_REDIS_HKEYS,
96
+ MSG_REQ_REDIS_HLEN,
97
+ MSG_REQ_REDIS_HMGET,
98
+ MSG_REQ_REDIS_HMSET,
99
+ MSG_REQ_REDIS_HSET,
100
+ MSG_REQ_REDIS_HSETNX,
101
+ MSG_REQ_REDIS_HVALS,
102
+ MSG_REQ_REDIS_LINDEX, /* redis requests - lists */
103
+ MSG_REQ_REDIS_LINSERT,
104
+ MSG_REQ_REDIS_LLEN,
105
+ MSG_REQ_REDIS_LPOP,
106
+ MSG_REQ_REDIS_LPUSH,
107
+ MSG_REQ_REDIS_LPUSHX,
108
+ MSG_REQ_REDIS_LRANGE,
109
+ MSG_REQ_REDIS_LREM,
110
+ MSG_REQ_REDIS_LSET,
111
+ MSG_REQ_REDIS_LTRIM,
112
+ MSG_REQ_REDIS_RPOP,
113
+ MSG_REQ_REDIS_RPOPLPUSH,
114
+ MSG_REQ_REDIS_RPUSH,
115
+ MSG_REQ_REDIS_RPUSHX,
116
+ MSG_REQ_REDIS_SADD, /* redis requests - sets */
117
+ MSG_REQ_REDIS_SCARD,
118
+ MSG_REQ_REDIS_SDIFF,
119
+ MSG_REQ_REDIS_SDIFFSTORE,
120
+ MSG_REQ_REDIS_SINTER,
121
+ MSG_REQ_REDIS_SINTERSTORE,
122
+ MSG_REQ_REDIS_SISMEMBER,
123
+ MSG_REQ_REDIS_SMEMBERS,
124
+ MSG_REQ_REDIS_SMOVE,
125
+ MSG_REQ_REDIS_SPOP,
126
+ MSG_REQ_REDIS_SRANDMEMBER,
127
+ MSG_REQ_REDIS_SREM,
128
+ MSG_REQ_REDIS_SUNION,
129
+ MSG_REQ_REDIS_SUNIONSTORE,
130
+ MSG_REQ_REDIS_ZADD, /* redis requests - sorted sets */
131
+ MSG_REQ_REDIS_ZCARD,
132
+ MSG_REQ_REDIS_ZCOUNT,
133
+ MSG_REQ_REDIS_ZINCRBY,
134
+ MSG_REQ_REDIS_ZINTERSTORE,
135
+ MSG_REQ_REDIS_ZRANGE,
136
+ MSG_REQ_REDIS_ZRANGEBYSCORE,
137
+ MSG_REQ_REDIS_ZRANK,
138
+ MSG_REQ_REDIS_ZREM,
139
+ MSG_REQ_REDIS_ZREMRANGEBYRANK,
140
+ MSG_REQ_REDIS_ZREMRANGEBYSCORE,
141
+ MSG_REQ_REDIS_ZREVRANGE,
142
+ MSG_REQ_REDIS_ZREVRANGEBYSCORE,
143
+ MSG_REQ_REDIS_ZREVRANK,
144
+ MSG_REQ_REDIS_ZSCORE,
145
+ MSG_REQ_REDIS_ZUNIONSTORE,
146
+ MSG_REQ_REDIS_EVAL, /* redis requests - eval */
147
+ MSG_REQ_REDIS_EVALSHA,
148
+ MSG_RSP_REDIS_STATUS, /* redis response */
149
+ MSG_RSP_REDIS_ERROR,
150
+ MSG_RSP_REDIS_INTEGER,
151
+ MSG_RSP_REDIS_BULK,
152
+ MSG_RSP_REDIS_MULTIBULK,
153
+ MSG_SENTINEL
154
+ } msg_type_t;
155
+
156
+ struct msg {
157
+ TAILQ_ENTRY(msg) c_tqe; /* link in client q */
158
+ TAILQ_ENTRY(msg) s_tqe; /* link in server q */
159
+ TAILQ_ENTRY(msg) m_tqe; /* link in send q / free q */
160
+
161
+ uint64_t id; /* message id */
162
+ struct msg *peer; /* message peer */
163
+ struct conn *owner; /* message owner - client | server */
164
+
165
+ struct rbnode tmo_rbe; /* entry in rbtree */
166
+
167
+ struct mhdr mhdr; /* message mbuf header */
168
+ uint32_t mlen; /* message length */
169
+
170
+ int state; /* current parser state */
171
+ uint8_t *pos; /* parser position marker */
172
+ uint8_t *token; /* token marker */
173
+
174
+ msg_parse_t parser; /* message parser */
175
+ msg_parse_result_t result; /* message parsing result */
176
+
177
+ mbuf_copy_t pre_splitcopy; /* message pre-split copy */
178
+ msg_post_splitcopy_t post_splitcopy; /* message post-split copy */
179
+ msg_coalesce_t pre_coalesce; /* message pre-coalesce */
180
+ msg_coalesce_t post_coalesce; /* message post-coalesce */
181
+
182
+ msg_type_t type; /* message type */
183
+
184
+ uint8_t *key_start; /* key start */
185
+ uint8_t *key_end; /* key end */
186
+
187
+ uint32_t vlen; /* value length (memcache) */
188
+ uint8_t *end; /* end marker (memcache) */
189
+
190
+ uint8_t *narg_start; /* narg start (redis) */
191
+ uint8_t *narg_end; /* narg end (redis) */
192
+ uint32_t narg; /* # arguments (redis) */
193
+ uint32_t rnarg; /* running # arg used by parsing fsa (redis) */
194
+ uint32_t rlen; /* running length in parsing fsa (redis) */
195
+ uint32_t integer; /* integer reply value (redis) */
196
+
197
+ struct msg *frag_owner; /* owner of fragment message */
198
+ uint32_t nfrag; /* # fragment */
199
+ uint64_t frag_id; /* id of fragmented message */
200
+
201
+ err_t err; /* errno on error? */
202
+ unsigned error:1; /* error? */
203
+ unsigned ferror:1; /* one or more fragments are in error? */
204
+ unsigned request:1; /* request? or response? */
205
+ unsigned quit:1; /* quit request? */
206
+ unsigned noreply:1; /* noreply? */
207
+ unsigned done:1; /* done? */
208
+ unsigned fdone:1; /* all fragments are done? */
209
+ unsigned first_fragment:1;/* first fragment? */
210
+ unsigned last_fragment:1; /* last fragment? */
211
+ unsigned swallow:1; /* swallow response? */
212
+ unsigned redis:1; /* redis? */
213
+ };
214
+
215
+ TAILQ_HEAD(msg_tqh, msg);
216
+
217
+ struct msg *msg_tmo_min(void);
218
+ void msg_tmo_insert(struct msg *msg, struct conn *conn);
219
+ void msg_tmo_delete(struct msg *msg);
220
+
221
+ void msg_init(void);
222
+ void msg_deinit(void);
223
+ struct msg *msg_get(struct conn *conn, bool request, bool redis);
224
+ void msg_put(struct msg *msg);
225
+ struct msg *msg_get_error(bool redis, err_t err);
226
+ void msg_dump(struct msg *msg);
227
+ bool msg_empty(struct msg *msg);
228
+ rstatus_t msg_recv(struct context *ctx, struct conn *conn);
229
+ rstatus_t msg_send(struct context *ctx, struct conn *conn);
230
+
231
+ struct msg *req_get(struct conn *conn);
232
+ void req_put(struct msg *msg);
233
+ bool req_done(struct conn *conn, struct msg *msg);
234
+ bool req_error(struct conn *conn, struct msg *msg);
235
+ void req_server_enqueue_imsgq(struct context *ctx, struct conn *conn, struct msg *msg);
236
+ void req_server_dequeue_imsgq(struct context *ctx, struct conn *conn, struct msg *msg);
237
+ void req_client_enqueue_omsgq(struct context *ctx, struct conn *conn, struct msg *msg);
238
+ void req_server_enqueue_omsgq(struct context *ctx, struct conn *conn, struct msg *msg);
239
+ void req_client_dequeue_omsgq(struct context *ctx, struct conn *conn, struct msg *msg);
240
+ void req_server_dequeue_omsgq(struct context *ctx, struct conn *conn, struct msg *msg);
241
+ struct msg *req_recv_next(struct context *ctx, struct conn *conn, bool alloc);
242
+ void req_recv_done(struct context *ctx, struct conn *conn, struct msg *msg, struct msg *nmsg);
243
+ struct msg *req_send_next(struct context *ctx, struct conn *conn);
244
+ void req_send_done(struct context *ctx, struct conn *conn, struct msg *msg);
245
+
246
+ struct msg *rsp_get(struct conn *conn);
247
+ void rsp_put(struct msg *msg);
248
+ struct msg *rsp_recv_next(struct context *ctx, struct conn *conn, bool alloc);
249
+ void rsp_recv_done(struct context *ctx, struct conn *conn, struct msg *msg, struct msg *nmsg);
250
+ struct msg *rsp_send_next(struct context *ctx, struct conn *conn);
251
+ void rsp_send_done(struct context *ctx, struct conn *conn, struct msg *msg);
252
+
253
+ #endif
@@ -0,0 +1,359 @@
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/un.h>
19
+
20
+ #include <nc_core.h>
21
+ #include <nc_server.h>
22
+ #include <nc_event.h>
23
+ #include <nc_proxy.h>
24
+
25
+ void
26
+ proxy_ref(struct conn *conn, void *owner)
27
+ {
28
+ struct server_pool *pool = owner;
29
+
30
+ ASSERT(!conn->client && conn->proxy);
31
+ ASSERT(conn->owner == NULL);
32
+
33
+ conn->family = pool->family;
34
+ conn->addrlen = pool->addrlen;
35
+ conn->addr = pool->addr;
36
+
37
+ pool->p_conn = conn;
38
+
39
+ /* owner of the proxy connection is the server pool */
40
+ conn->owner = owner;
41
+
42
+ log_debug(LOG_VVERB, "ref conn %p owner %p into pool %"PRIu32"", conn,
43
+ pool, pool->idx);
44
+ }
45
+
46
+ void
47
+ proxy_unref(struct conn *conn)
48
+ {
49
+ struct server_pool *pool;
50
+
51
+ ASSERT(!conn->client && conn->proxy);
52
+ ASSERT(conn->owner != NULL);
53
+
54
+ pool = conn->owner;
55
+ conn->owner = NULL;
56
+
57
+ pool->p_conn = NULL;
58
+
59
+ log_debug(LOG_VVERB, "unref conn %p owner %p from pool %"PRIu32"", conn,
60
+ pool, pool->idx);
61
+ }
62
+
63
+ void
64
+ proxy_close(struct context *ctx, struct conn *conn)
65
+ {
66
+ rstatus_t status;
67
+
68
+ ASSERT(!conn->client && conn->proxy);
69
+
70
+ if (conn->sd < 0) {
71
+ conn->unref(conn);
72
+ conn_put(conn);
73
+ return;
74
+ }
75
+
76
+ ASSERT(conn->rmsg == NULL);
77
+ ASSERT(conn->smsg == NULL);
78
+ ASSERT(TAILQ_EMPTY(&conn->imsg_q));
79
+ ASSERT(TAILQ_EMPTY(&conn->omsg_q));
80
+
81
+ conn->unref(conn);
82
+
83
+ status = close(conn->sd);
84
+ if (status < 0) {
85
+ log_error("close p %d failed, ignored: %s", conn->sd, strerror(errno));
86
+ }
87
+ conn->sd = -1;
88
+
89
+ conn_put(conn);
90
+ }
91
+
92
+ static rstatus_t
93
+ proxy_reuse(struct conn *p)
94
+ {
95
+ rstatus_t status;
96
+ struct sockaddr_un *un;
97
+
98
+ switch (p->family) {
99
+ case AF_INET:
100
+ case AF_INET6:
101
+ status = nc_set_reuseaddr(p->sd);
102
+ break;
103
+
104
+ case AF_UNIX:
105
+ /*
106
+ * bind() will fail if the pathname already exist. So, we call unlink()
107
+ * to delete the pathname, in case it already exists. If it does not
108
+ * exist, unlink() returns error, which we ignore
109
+ */
110
+ un = (struct sockaddr_un *) p->addr;
111
+ unlink(un->sun_path);
112
+ status = NC_OK;
113
+ break;
114
+
115
+ default:
116
+ NOT_REACHED();
117
+ status = NC_ERROR;
118
+ }
119
+
120
+ return status;
121
+ }
122
+
123
+ static rstatus_t
124
+ proxy_listen(struct context *ctx, struct conn *p)
125
+ {
126
+ rstatus_t status;
127
+ struct server_pool *pool = p->owner;
128
+
129
+ ASSERT(p->proxy);
130
+
131
+ p->sd = socket(p->family, SOCK_STREAM, 0);
132
+ if (p->sd < 0) {
133
+ log_error("socket failed: %s", strerror(errno));
134
+ return NC_ERROR;
135
+ }
136
+
137
+ status = proxy_reuse(p);
138
+ if (status < 0) {
139
+ log_error("reuse of addr '%.*s' for listening on p %d failed: %s",
140
+ pool->addrstr.len, pool->addrstr.data, p->sd,
141
+ strerror(errno));
142
+ return NC_ERROR;
143
+ }
144
+
145
+ status = bind(p->sd, p->addr, p->addrlen);
146
+ if (status < 0) {
147
+ log_error("bind on p %d to addr '%.*s' failed: %s", p->sd,
148
+ pool->addrstr.len, pool->addrstr.data, strerror(errno));
149
+ return NC_ERROR;
150
+ }
151
+
152
+ status = listen(p->sd, pool->backlog);
153
+ if (status < 0) {
154
+ log_error("listen on p %d on addr '%.*s' failed: %s", p->sd,
155
+ pool->addrstr.len, pool->addrstr.data, strerror(errno));
156
+ return NC_ERROR;
157
+ }
158
+
159
+ status = nc_set_nonblocking(p->sd);
160
+ if (status < 0) {
161
+ log_error("set nonblock on p %d on addr '%.*s' failed: %s", p->sd,
162
+ pool->addrstr.len, pool->addrstr.data, strerror(errno));
163
+ return NC_ERROR;
164
+ }
165
+
166
+ status = event_add_conn(ctx->ep, p);
167
+ if (status < 0) {
168
+ log_error("event add conn e %d p %d on addr '%.*s' failed: %s",
169
+ ctx->ep, p->sd, pool->addrstr.len, pool->addrstr.data,
170
+ strerror(errno));
171
+ return NC_ERROR;
172
+ }
173
+
174
+ status = event_del_out(ctx->ep, p);
175
+ if (status < 0) {
176
+ log_error("event del out e %d p %d on addr '%.*s' failed: %s",
177
+ ctx->ep, p->sd, pool->addrstr.len, pool->addrstr.data,
178
+ strerror(errno));
179
+ return NC_ERROR;
180
+ }
181
+
182
+ return NC_OK;
183
+ }
184
+
185
+ rstatus_t
186
+ proxy_each_init(void *elem, void *data)
187
+ {
188
+ rstatus_t status;
189
+ struct server_pool *pool = elem;
190
+ struct conn *p;
191
+
192
+ p = conn_get_proxy(pool);
193
+ if (p == NULL) {
194
+ return NC_ENOMEM;
195
+ }
196
+
197
+ status = proxy_listen(pool->ctx, p);
198
+ if (status != NC_OK) {
199
+ p->close(pool->ctx, p);
200
+ return status;
201
+ }
202
+
203
+ log_debug(LOG_NOTICE, "p %d listening on '%.*s' in %s pool %"PRIu32" '%.*s'"
204
+ " with %"PRIu32" servers", p->sd, pool->addrstr.len,
205
+ pool->addrstr.data, pool->redis ? "redis" : "memcache",
206
+ pool->idx, pool->name.len, pool->name.data,
207
+ array_n(&pool->server));
208
+
209
+ return NC_OK;
210
+ }
211
+
212
+ rstatus_t
213
+ proxy_init(struct context *ctx)
214
+ {
215
+ rstatus_t status;
216
+
217
+ ASSERT(array_n(&ctx->pool) != 0);
218
+
219
+ status = array_each(&ctx->pool, proxy_each_init, NULL);
220
+ if (status != NC_OK) {
221
+ proxy_deinit(ctx);
222
+ return status;
223
+ }
224
+
225
+ log_debug(LOG_VVERB, "init proxy with %"PRIu32" pools",
226
+ array_n(&ctx->pool));
227
+
228
+ return NC_OK;
229
+ }
230
+
231
+ rstatus_t
232
+ proxy_each_deinit(void *elem, void *data)
233
+ {
234
+ struct server_pool *pool = elem;
235
+ struct conn *p;
236
+
237
+ p = pool->p_conn;
238
+ if (p != NULL) {
239
+ p->close(pool->ctx, p);
240
+ }
241
+
242
+ return NC_OK;
243
+ }
244
+
245
+ void
246
+ proxy_deinit(struct context *ctx)
247
+ {
248
+ rstatus_t status;
249
+
250
+ ASSERT(array_n(&ctx->pool) != 0);
251
+
252
+ status = array_each(&ctx->pool, proxy_each_deinit, NULL);
253
+ if (status != NC_OK) {
254
+ return;
255
+ }
256
+
257
+ log_debug(LOG_VVERB, "deinit proxy with %"PRIu32" pools",
258
+ array_n(&ctx->pool));
259
+ }
260
+
261
+ static rstatus_t
262
+ proxy_accept(struct context *ctx, struct conn *p)
263
+ {
264
+ rstatus_t status;
265
+ struct conn *c;
266
+ int sd;
267
+
268
+ ASSERT(p->proxy && !p->client);
269
+ ASSERT(p->sd > 0);
270
+ ASSERT(p->recv_active && p->recv_ready);
271
+
272
+ for (;;) {
273
+ sd = accept(p->sd, NULL, NULL);
274
+ if (sd < 0) {
275
+ if (errno == EINTR) {
276
+ log_debug(LOG_VERB, "accept on p %d not ready - eintr", p->sd);
277
+ continue;
278
+ }
279
+
280
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
281
+ log_debug(LOG_VERB, "accept on p %d not ready - eagain", p->sd);
282
+ p->recv_ready = 0;
283
+ return NC_OK;
284
+ }
285
+
286
+ /*
287
+ * FIXME: On EMFILE or ENFILE mask out IN event on the proxy; mask
288
+ * it back in when some existing connection gets closed
289
+ */
290
+
291
+ log_error("accept on p %d failed: %s", p->sd, strerror(errno));
292
+ return NC_ERROR;
293
+ }
294
+
295
+ break;
296
+ }
297
+
298
+ c = conn_get(p->owner, true, p->redis);
299
+ if (c == NULL) {
300
+ log_error("get conn for c %d from p %d failed: %s", sd, p->sd,
301
+ strerror(errno));
302
+ status = close(sd);
303
+ if (status < 0) {
304
+ log_error("close c %d failed, ignored: %s", sd, strerror(errno));
305
+ }
306
+ return NC_ENOMEM;
307
+ }
308
+ c->sd = sd;
309
+
310
+ stats_pool_incr(ctx, c->owner, client_connections);
311
+
312
+ status = nc_set_nonblocking(c->sd);
313
+ if (status < 0) {
314
+ log_error("set nonblock on c %d from p %d failed: %s", c->sd, p->sd,
315
+ strerror(errno));
316
+ c->close(ctx, c);
317
+ return status;
318
+ }
319
+
320
+ if (p->family == AF_INET || p->family == AF_INET6) {
321
+ status = nc_set_tcpnodelay(c->sd);
322
+ if (status < 0) {
323
+ log_warn("set tcpnodelay on c %d from p %d failed, ignored: %s",
324
+ c->sd, p->sd, strerror(errno));
325
+ }
326
+ }
327
+
328
+ status = event_add_conn(ctx->ep, c);
329
+ if (status < 0) {
330
+ log_error("event add conn of c %d from p %d failed: %s", c->sd, p->sd,
331
+ strerror(errno));
332
+ c->close(ctx, c);
333
+ return status;
334
+ }
335
+
336
+ log_debug(LOG_NOTICE, "accepted c %d on p %d from '%s'", c->sd, p->sd,
337
+ nc_unresolve_peer_desc(c->sd));
338
+
339
+ return NC_OK;
340
+ }
341
+
342
+ rstatus_t
343
+ proxy_recv(struct context *ctx, struct conn *conn)
344
+ {
345
+ rstatus_t status;
346
+
347
+ ASSERT(conn->proxy && !conn->client);
348
+ ASSERT(conn->recv_active);
349
+
350
+ conn->recv_ready = 1;
351
+ do {
352
+ status = proxy_accept(ctx, conn);
353
+ if (status != NC_OK) {
354
+ return status;
355
+ }
356
+ } while (conn->recv_ready);
357
+
358
+ return NC_OK;
359
+ }