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,332 @@
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 <nc_core.h>
19
+ #include <nc_server.h>
20
+ #include <nc_event.h>
21
+
22
+ struct msg *
23
+ rsp_get(struct conn *conn)
24
+ {
25
+ struct msg *msg;
26
+
27
+ ASSERT(!conn->client && !conn->proxy);
28
+
29
+ msg = msg_get(conn, false, conn->redis);
30
+ if (msg == NULL) {
31
+ conn->err = errno;
32
+ }
33
+
34
+ return msg;
35
+ }
36
+
37
+ void
38
+ rsp_put(struct msg *msg)
39
+ {
40
+ ASSERT(!msg->request);
41
+ ASSERT(msg->peer == NULL);
42
+ msg_put(msg);
43
+ }
44
+
45
+ static struct msg *
46
+ rsp_make_error(struct context *ctx, struct conn *conn, struct msg *msg)
47
+ {
48
+ struct msg *pmsg; /* peer message (response) */
49
+ struct msg *cmsg, *nmsg; /* current and next message (request) */
50
+ uint64_t id;
51
+ err_t err;
52
+
53
+ ASSERT(conn->client && !conn->proxy);
54
+ ASSERT(msg->request && req_error(conn, msg));
55
+ ASSERT(msg->owner == conn);
56
+
57
+ id = msg->frag_id;
58
+ if (id != 0) {
59
+ for (err = 0, cmsg = TAILQ_NEXT(msg, c_tqe);
60
+ cmsg != NULL && cmsg->frag_id == id;
61
+ cmsg = nmsg) {
62
+ nmsg = TAILQ_NEXT(cmsg, c_tqe);
63
+
64
+ /* dequeue request (error fragment) from client outq */
65
+ conn->dequeue_outq(ctx, conn, cmsg);
66
+ if (err == 0 && cmsg->err != 0) {
67
+ err = cmsg->err;
68
+ }
69
+
70
+ req_put(cmsg);
71
+ }
72
+ } else {
73
+ err = msg->err;
74
+ }
75
+
76
+ pmsg = msg->peer;
77
+ if (pmsg != NULL) {
78
+ ASSERT(!pmsg->request && pmsg->peer == msg);
79
+ msg->peer = NULL;
80
+ pmsg->peer = NULL;
81
+ rsp_put(pmsg);
82
+ }
83
+
84
+ return msg_get_error(conn->redis, err);
85
+ }
86
+
87
+ struct msg *
88
+ rsp_recv_next(struct context *ctx, struct conn *conn, bool alloc)
89
+ {
90
+ struct msg *msg;
91
+
92
+ ASSERT(!conn->client && !conn->proxy);
93
+ ASSERT(!conn->connecting);
94
+
95
+ if (conn->eof) {
96
+ msg = conn->rmsg;
97
+
98
+ /* server sent eof before sending the entire request */
99
+ if (msg != NULL) {
100
+ conn->rmsg = NULL;
101
+
102
+ ASSERT(msg->peer == NULL);
103
+ ASSERT(!msg->request);
104
+
105
+ log_error("eof s %d discarding incomplete rsp %"PRIu64" len "
106
+ "%"PRIu32"", conn->sd, msg->id, msg->mlen);
107
+
108
+ rsp_put(msg);
109
+ }
110
+
111
+ /*
112
+ * We treat TCP half-close from a server different from how we treat
113
+ * those from a client. On a FIN from a server, we close the connection
114
+ * immediately by sending the second FIN even if there were outstanding
115
+ * or pending requests. This is actually a tricky part in the FA, as
116
+ * we don't expect this to happen unless the server is misbehaving or
117
+ * it crashes
118
+ */
119
+ conn->done = 1;
120
+ log_error("s %d active %d is done", conn->sd, conn->active(conn));
121
+
122
+ return NULL;
123
+ }
124
+
125
+ msg = conn->rmsg;
126
+ if (msg != NULL) {
127
+ ASSERT(!msg->request);
128
+ return msg;
129
+ }
130
+
131
+ if (!alloc) {
132
+ return NULL;
133
+ }
134
+
135
+ msg = rsp_get(conn);
136
+ if (msg != NULL) {
137
+ conn->rmsg = msg;
138
+ }
139
+
140
+ return msg;
141
+ }
142
+
143
+ static bool
144
+ rsp_filter(struct context *ctx, struct conn *conn, struct msg *msg)
145
+ {
146
+ struct msg *pmsg;
147
+
148
+ ASSERT(!conn->client && !conn->proxy);
149
+
150
+ if (msg_empty(msg)) {
151
+ ASSERT(conn->rmsg == NULL);
152
+ log_debug(LOG_VERB, "filter empty rsp %"PRIu64" on s %d", msg->id,
153
+ conn->sd);
154
+ rsp_put(msg);
155
+ return true;
156
+ }
157
+
158
+ pmsg = TAILQ_FIRST(&conn->omsg_q);
159
+ if (pmsg == NULL) {
160
+ log_error("filter stray rsp %"PRIu64" len %"PRIu32" on s %d", msg->id,
161
+ msg->mlen, conn->sd);
162
+ rsp_put(msg);
163
+ errno = EINVAL;
164
+ conn->err = errno;
165
+ return true;
166
+ }
167
+ ASSERT(pmsg->peer == NULL);
168
+ ASSERT(pmsg->request && !pmsg->done);
169
+
170
+ if (pmsg->swallow) {
171
+ conn->dequeue_outq(ctx, conn, pmsg);
172
+ pmsg->done = 1;
173
+
174
+ log_debug(LOG_INFO, "swallow rsp %"PRIu64" len %"PRIu32" of req "
175
+ "%"PRIu64" on s %d", msg->id, msg->mlen, pmsg->id,
176
+ conn->sd);
177
+
178
+ rsp_put(msg);
179
+ req_put(pmsg);
180
+ return true;
181
+ }
182
+
183
+ return false;
184
+ }
185
+
186
+ static void
187
+ rsp_forward_stats(struct context *ctx, struct server *server, struct msg *msg)
188
+ {
189
+ ASSERT(!msg->request);
190
+
191
+ stats_server_incr(ctx, server, responses);
192
+ stats_server_incr_by(ctx, server, response_bytes, msg->mlen);
193
+ }
194
+
195
+ static void
196
+ rsp_forward(struct context *ctx, struct conn *s_conn, struct msg *msg)
197
+ {
198
+ rstatus_t status;
199
+ struct msg *pmsg;
200
+ struct conn *c_conn;
201
+
202
+ ASSERT(!s_conn->client && !s_conn->proxy);
203
+
204
+ /* response from server implies that server is ok and heartbeating */
205
+ server_ok(ctx, s_conn);
206
+
207
+ /* dequeue peer message (request) from server */
208
+ pmsg = TAILQ_FIRST(&s_conn->omsg_q);
209
+ ASSERT(pmsg != NULL && pmsg->peer == NULL);
210
+ ASSERT(pmsg->request && !pmsg->done);
211
+
212
+ s_conn->dequeue_outq(ctx, s_conn, pmsg);
213
+ pmsg->done = 1;
214
+
215
+ /* establish msg <-> pmsg (response <-> request) link */
216
+ pmsg->peer = msg;
217
+ msg->peer = pmsg;
218
+
219
+ msg->pre_coalesce(msg);
220
+
221
+ c_conn = pmsg->owner;
222
+ ASSERT(c_conn->client && !c_conn->proxy);
223
+
224
+ if (req_done(c_conn, TAILQ_FIRST(&c_conn->omsg_q))) {
225
+ status = event_add_out(ctx->ep, c_conn);
226
+ if (status != NC_OK) {
227
+ c_conn->err = errno;
228
+ }
229
+ }
230
+
231
+ rsp_forward_stats(ctx, s_conn->owner, msg);
232
+ }
233
+
234
+ void
235
+ rsp_recv_done(struct context *ctx, struct conn *conn, struct msg *msg,
236
+ struct msg *nmsg)
237
+ {
238
+ ASSERT(!conn->client && !conn->proxy);
239
+ ASSERT(msg != NULL && conn->rmsg == msg);
240
+ ASSERT(!msg->request);
241
+ ASSERT(msg->owner == conn);
242
+ ASSERT(nmsg == NULL || !nmsg->request);
243
+
244
+ /* enqueue next message (response), if any */
245
+ conn->rmsg = nmsg;
246
+
247
+ if (rsp_filter(ctx, conn, msg)) {
248
+ return;
249
+ }
250
+
251
+ rsp_forward(ctx, conn, msg);
252
+ }
253
+
254
+ struct msg *
255
+ rsp_send_next(struct context *ctx, struct conn *conn)
256
+ {
257
+ rstatus_t status;
258
+ struct msg *msg, *pmsg; /* response and it's peer request */
259
+
260
+ ASSERT(conn->client && !conn->proxy);
261
+
262
+ pmsg = TAILQ_FIRST(&conn->omsg_q);
263
+ if (pmsg == NULL || !req_done(conn, pmsg)) {
264
+ /* nothing is outstanding, initiate close? */
265
+ if (pmsg == NULL && conn->eof) {
266
+ conn->done = 1;
267
+ log_debug(LOG_INFO, "c %d is done", conn->sd);
268
+ }
269
+
270
+ status = event_del_out(ctx->ep, conn);
271
+ if (status != NC_OK) {
272
+ conn->err = errno;
273
+ }
274
+
275
+ return NULL;
276
+ }
277
+
278
+ msg = conn->smsg;
279
+ if (msg != NULL) {
280
+ ASSERT(!msg->request && msg->peer != NULL);
281
+ ASSERT(req_done(conn, msg->peer));
282
+ pmsg = TAILQ_NEXT(msg->peer, c_tqe);
283
+ }
284
+
285
+ if (pmsg == NULL || !req_done(conn, pmsg)) {
286
+ conn->smsg = NULL;
287
+ return NULL;
288
+ }
289
+ ASSERT(pmsg->request && !pmsg->swallow);
290
+
291
+ if (req_error(conn, pmsg)) {
292
+ msg = rsp_make_error(ctx, conn, pmsg);
293
+ if (msg == NULL) {
294
+ conn->err = errno;
295
+ return NULL;
296
+ }
297
+ msg->peer = pmsg;
298
+ pmsg->peer = msg;
299
+ stats_pool_incr(ctx, conn->owner, forward_error);
300
+ } else {
301
+ msg = pmsg->peer;
302
+ }
303
+ ASSERT(!msg->request);
304
+
305
+ conn->smsg = msg;
306
+
307
+ log_debug(LOG_VVERB, "send next rsp %"PRIu64" on c %d", msg->id, conn->sd);
308
+
309
+ return msg;
310
+ }
311
+
312
+ void
313
+ rsp_send_done(struct context *ctx, struct conn *conn, struct msg *msg)
314
+ {
315
+ struct msg *pmsg; /* peer message (request) */
316
+
317
+ ASSERT(conn->client && !conn->proxy);
318
+ ASSERT(conn->smsg == NULL);
319
+
320
+ log_debug(LOG_VVERB, "send done rsp %"PRIu64" on c %d", msg->id, conn->sd);
321
+
322
+ pmsg = msg->peer;
323
+
324
+ ASSERT(!msg->request && pmsg->request);
325
+ ASSERT(pmsg->peer == msg);
326
+ ASSERT(pmsg->done && !pmsg->swallow);
327
+
328
+ /* dequeue request from client outq */
329
+ conn->dequeue_outq(ctx, conn, pmsg);
330
+
331
+ req_put(pmsg);
332
+ }
@@ -0,0 +1,841 @@
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 <stdlib.h>
19
+ #include <unistd.h>
20
+
21
+ #include <nc_core.h>
22
+ #include <nc_event.h>
23
+ #include <nc_server.h>
24
+ #include <nc_conf.h>
25
+
26
+ void
27
+ server_ref(struct conn *conn, void *owner)
28
+ {
29
+ struct server *server = owner;
30
+
31
+ ASSERT(!conn->client && !conn->proxy);
32
+ ASSERT(conn->owner == NULL);
33
+
34
+ conn->family = server->family;
35
+ conn->addrlen = server->addrlen;
36
+ conn->addr = server->addr;
37
+
38
+ server->ns_conn_q++;
39
+ TAILQ_INSERT_TAIL(&server->s_conn_q, conn, conn_tqe);
40
+
41
+ conn->owner = owner;
42
+
43
+ log_debug(LOG_VVERB, "ref conn %p owner %p into '%.*s", conn, server,
44
+ server->pname.len, server->pname.data);
45
+ }
46
+
47
+ void
48
+ server_unref(struct conn *conn)
49
+ {
50
+ struct server *server;
51
+
52
+ ASSERT(!conn->client && !conn->proxy);
53
+ ASSERT(conn->owner != NULL);
54
+
55
+ server = conn->owner;
56
+ conn->owner = NULL;
57
+
58
+ ASSERT(server->ns_conn_q != 0);
59
+ server->ns_conn_q--;
60
+ TAILQ_REMOVE(&server->s_conn_q, conn, conn_tqe);
61
+
62
+ log_debug(LOG_VVERB, "unref conn %p owner %p from '%.*s'", conn, server,
63
+ server->pname.len, server->pname.data);
64
+ }
65
+
66
+ int
67
+ server_timeout(struct conn *conn)
68
+ {
69
+ struct server *server;
70
+ struct server_pool *pool;
71
+
72
+ ASSERT(!conn->client && !conn->proxy);
73
+
74
+ server = conn->owner;
75
+ pool = server->owner;
76
+
77
+ return pool->timeout;
78
+ }
79
+
80
+ bool
81
+ server_active(struct conn *conn)
82
+ {
83
+ ASSERT(!conn->client && !conn->proxy);
84
+
85
+ if (!TAILQ_EMPTY(&conn->imsg_q)) {
86
+ log_debug(LOG_VVERB, "s %d is active", conn->sd);
87
+ return true;
88
+ }
89
+
90
+ if (!TAILQ_EMPTY(&conn->omsg_q)) {
91
+ log_debug(LOG_VVERB, "s %d is active", conn->sd);
92
+ return true;
93
+ }
94
+
95
+ if (conn->rmsg != NULL) {
96
+ log_debug(LOG_VVERB, "s %d is active", conn->sd);
97
+ return true;
98
+ }
99
+
100
+ if (conn->smsg != NULL) {
101
+ log_debug(LOG_VVERB, "s %d is active", conn->sd);
102
+ return true;
103
+ }
104
+
105
+ log_debug(LOG_VVERB, "s %d is inactive", conn->sd);
106
+
107
+ return false;
108
+ }
109
+
110
+ static rstatus_t
111
+ server_each_set_owner(void *elem, void *data)
112
+ {
113
+ struct server *s = elem;
114
+ struct server_pool *sp = data;
115
+
116
+ s->owner = sp;
117
+
118
+ return NC_OK;
119
+ }
120
+
121
+ rstatus_t
122
+ server_init(struct array *server, struct array *conf_server,
123
+ struct server_pool *sp)
124
+ {
125
+ rstatus_t status;
126
+ uint32_t nserver;
127
+
128
+ nserver = array_n(conf_server);
129
+ ASSERT(nserver != 0);
130
+ ASSERT(array_n(server) == 0);
131
+
132
+ status = array_init(server, nserver, sizeof(struct server));
133
+ if (status != NC_OK) {
134
+ return status;
135
+ }
136
+
137
+ /* transform conf server to server */
138
+ status = array_each(conf_server, conf_server_each_transform, server);
139
+ if (status != NC_OK) {
140
+ server_deinit(server);
141
+ return status;
142
+ }
143
+ ASSERT(array_n(server) == nserver);
144
+
145
+ /* set server owner */
146
+ status = array_each(server, server_each_set_owner, sp);
147
+ if (status != NC_OK) {
148
+ server_deinit(server);
149
+ return status;
150
+ }
151
+
152
+ log_debug(LOG_DEBUG, "init %"PRIu32" servers in pool %"PRIu32" '%.*s'",
153
+ nserver, sp->idx, sp->name.len, sp->name.data);
154
+
155
+ return NC_OK;
156
+ }
157
+
158
+ void
159
+ server_deinit(struct array *server)
160
+ {
161
+ uint32_t i, nserver;
162
+
163
+ for (i = 0, nserver = array_n(server); i < nserver; i++) {
164
+ struct server *s;
165
+
166
+ s = array_pop(server);
167
+ ASSERT(TAILQ_EMPTY(&s->s_conn_q) && s->ns_conn_q == 0);
168
+ }
169
+ array_deinit(server);
170
+ }
171
+
172
+ struct conn *
173
+ server_conn(struct server *server)
174
+ {
175
+ struct server_pool *pool;
176
+ struct conn *conn;
177
+
178
+ pool = server->owner;
179
+
180
+ /*
181
+ * FIXME: handle multiple server connections per server and do load
182
+ * balancing on it. Support multiple algorithms for
183
+ * 'server_connections:' > 0 key
184
+ */
185
+
186
+ if (server->ns_conn_q < pool->server_connections) {
187
+ return conn_get(server, false, pool->redis);
188
+ }
189
+ ASSERT(server->ns_conn_q == pool->server_connections);
190
+
191
+ /*
192
+ * Pick a server connection from the head of the queue and insert
193
+ * it back into the tail of queue to maintain the lru order
194
+ */
195
+ conn = TAILQ_FIRST(&server->s_conn_q);
196
+ ASSERT(!conn->client && !conn->proxy);
197
+
198
+ TAILQ_REMOVE(&server->s_conn_q, conn, conn_tqe);
199
+ TAILQ_INSERT_TAIL(&server->s_conn_q, conn, conn_tqe);
200
+
201
+ return conn;
202
+ }
203
+
204
+ static rstatus_t
205
+ server_each_preconnect(void *elem, void *data)
206
+ {
207
+ rstatus_t status;
208
+ struct server *server;
209
+ struct server_pool *pool;
210
+ struct conn *conn;
211
+
212
+ server = elem;
213
+ pool = server->owner;
214
+
215
+ conn = server_conn(server);
216
+ if (conn == NULL) {
217
+ return NC_ENOMEM;
218
+ }
219
+
220
+ status = server_connect(pool->ctx, server, conn);
221
+ if (status != NC_OK) {
222
+ log_warn("connect to server '%.*s' failed, ignored: %s",
223
+ server->pname.len, server->pname.data, strerror(errno));
224
+ server_close(pool->ctx, conn);
225
+ }
226
+
227
+ return NC_OK;
228
+ }
229
+
230
+ static rstatus_t
231
+ server_each_disconnect(void *elem, void *data)
232
+ {
233
+ struct server *server;
234
+ struct server_pool *pool;
235
+
236
+ server = elem;
237
+ pool = server->owner;
238
+
239
+ while (!TAILQ_EMPTY(&server->s_conn_q)) {
240
+ struct conn *conn;
241
+
242
+ ASSERT(server->ns_conn_q > 0);
243
+
244
+ conn = TAILQ_FIRST(&server->s_conn_q);
245
+ conn->close(pool->ctx, conn);
246
+ }
247
+
248
+ return NC_OK;
249
+ }
250
+
251
+ static void
252
+ server_failure(struct context *ctx, struct server *server)
253
+ {
254
+ struct server_pool *pool = server->owner;
255
+ int64_t now, next;
256
+ rstatus_t status;
257
+
258
+ if (!pool->auto_eject_hosts) {
259
+ return;
260
+ }
261
+
262
+ server->failure_count++;
263
+
264
+ log_debug(LOG_VERB, "server '%.*s' failure count %"PRIu32" limit %"PRIu32,
265
+ server->pname.len, server->pname.data, server->failure_count,
266
+ pool->server_failure_limit);
267
+
268
+ if (server->failure_count < pool->server_failure_limit) {
269
+ return;
270
+ }
271
+
272
+ now = nc_usec_now();
273
+ if (now < 0) {
274
+ return;
275
+ }
276
+ next = now + pool->server_retry_timeout;
277
+
278
+ log_debug(LOG_INFO, "update pool %"PRIu32" '%.*s' to delete server '%.*s' "
279
+ "for next %"PRIu32" secs", pool->idx, pool->name.len,
280
+ pool->name.data, server->pname.len, server->pname.data,
281
+ pool->server_retry_timeout / 1000 / 1000);
282
+
283
+ stats_pool_incr(ctx, pool, server_ejects);
284
+
285
+ server->failure_count = 0;
286
+ server->next_retry = next;
287
+
288
+ status = server_pool_run(pool);
289
+ if (status != NC_OK) {
290
+ log_error("updating pool %"PRIu32" '%.*s' failed: %s", pool->idx,
291
+ pool->name.len, pool->name.data, strerror(errno));
292
+ }
293
+ }
294
+
295
+ static void
296
+ server_close_stats(struct context *ctx, struct server *server, err_t err,
297
+ unsigned eof, unsigned connected)
298
+ {
299
+ if (connected) {
300
+ stats_server_decr(ctx, server, server_connections);
301
+ }
302
+
303
+ if (eof) {
304
+ stats_server_incr(ctx, server, server_eof);
305
+ return;
306
+ }
307
+
308
+ switch (err) {
309
+ case ETIMEDOUT:
310
+ stats_server_incr(ctx, server, server_timedout);
311
+ break;
312
+ case EPIPE:
313
+ case ECONNRESET:
314
+ case ECONNABORTED:
315
+ case ECONNREFUSED:
316
+ case ENOTCONN:
317
+ case ENETDOWN:
318
+ case ENETUNREACH:
319
+ case EHOSTDOWN:
320
+ case EHOSTUNREACH:
321
+ default:
322
+ stats_server_incr(ctx, server, server_err);
323
+ break;
324
+ }
325
+ }
326
+
327
+ void
328
+ server_close(struct context *ctx, struct conn *conn)
329
+ {
330
+ rstatus_t status;
331
+ struct msg *msg, *nmsg; /* current and next message */
332
+ struct conn *c_conn; /* peer client connection */
333
+
334
+ ASSERT(!conn->client && !conn->proxy);
335
+
336
+ server_close_stats(ctx, conn->owner, conn->err, conn->eof,
337
+ conn->connected);
338
+
339
+ if (conn->sd < 0) {
340
+ server_failure(ctx, conn->owner);
341
+ conn->unref(conn);
342
+ conn_put(conn);
343
+ return;
344
+ }
345
+
346
+ for (msg = TAILQ_FIRST(&conn->imsg_q); msg != NULL; msg = nmsg) {
347
+ nmsg = TAILQ_NEXT(msg, s_tqe);
348
+
349
+ /* dequeue the message (request) from server inq */
350
+ conn->dequeue_inq(ctx, conn, msg);
351
+
352
+ /*
353
+ * Don't send any error response, if
354
+ * 1. request is tagged as noreply or,
355
+ * 2. client has already closed its connection
356
+ */
357
+ if (msg->swallow || msg->noreply) {
358
+ log_debug(LOG_INFO, "close s %d swallow req %"PRIu64" len %"PRIu32
359
+ " type %d", conn->sd, msg->id, msg->mlen, msg->type);
360
+ req_put(msg);
361
+ } else {
362
+ c_conn = msg->owner;
363
+ ASSERT(c_conn->client && !c_conn->proxy);
364
+
365
+ msg->done = 1;
366
+ msg->error = 1;
367
+ msg->err = conn->err;
368
+
369
+ if (req_done(c_conn, TAILQ_FIRST(&c_conn->omsg_q))) {
370
+ event_add_out(ctx->ep, msg->owner);
371
+ }
372
+
373
+ log_debug(LOG_INFO, "close s %d schedule error for req %"PRIu64" "
374
+ "len %"PRIu32" type %d from c %d%c %s", conn->sd, msg->id,
375
+ msg->mlen, msg->type, c_conn->sd, conn->err ? ':' : ' ',
376
+ conn->err ? strerror(conn->err): " ");
377
+ }
378
+ }
379
+ ASSERT(TAILQ_EMPTY(&conn->imsg_q));
380
+
381
+ for (msg = TAILQ_FIRST(&conn->omsg_q); msg != NULL; msg = nmsg) {
382
+ nmsg = TAILQ_NEXT(msg, s_tqe);
383
+
384
+ /* dequeue the message (request) from server outq */
385
+ conn->dequeue_outq(ctx, conn, msg);
386
+
387
+ if (msg->swallow) {
388
+ log_debug(LOG_INFO, "close s %d swallow req %"PRIu64" len %"PRIu32
389
+ " type %d", conn->sd, msg->id, msg->mlen, msg->type);
390
+ req_put(msg);
391
+ } else {
392
+ c_conn = msg->owner;
393
+ ASSERT(c_conn->client && !c_conn->proxy);
394
+
395
+ msg->done = 1;
396
+ msg->error = 1;
397
+ msg->err = conn->err;
398
+
399
+ if (req_done(c_conn, TAILQ_FIRST(&c_conn->omsg_q))) {
400
+ event_add_out(ctx->ep, msg->owner);
401
+ }
402
+
403
+ log_debug(LOG_INFO, "close s %d schedule error for req %"PRIu64" "
404
+ "len %"PRIu32" type %d from c %d%c %s", conn->sd, msg->id,
405
+ msg->mlen, msg->type, c_conn->sd, conn->err ? ':' : ' ',
406
+ conn->err ? strerror(conn->err): " ");
407
+ }
408
+ }
409
+ ASSERT(TAILQ_EMPTY(&conn->omsg_q));
410
+
411
+ msg = conn->rmsg;
412
+ if (msg != NULL) {
413
+ conn->rmsg = NULL;
414
+
415
+ ASSERT(!msg->request);
416
+ ASSERT(msg->peer == NULL);
417
+
418
+ rsp_put(msg);
419
+
420
+ log_debug(LOG_INFO, "close s %d discarding rsp %"PRIu64" len %"PRIu32" "
421
+ "in error", conn->sd, msg->id, msg->mlen);
422
+ }
423
+
424
+ ASSERT(conn->smsg == NULL);
425
+
426
+ server_failure(ctx, conn->owner);
427
+
428
+ conn->unref(conn);
429
+
430
+ status = close(conn->sd);
431
+ if (status < 0) {
432
+ log_error("close s %d failed, ignored: %s", conn->sd, strerror(errno));
433
+ }
434
+ conn->sd = -1;
435
+
436
+ conn_put(conn);
437
+ }
438
+
439
+ rstatus_t
440
+ server_connect(struct context *ctx, struct server *server, struct conn *conn)
441
+ {
442
+ rstatus_t status;
443
+
444
+ ASSERT(!conn->client && !conn->proxy);
445
+
446
+ if (conn->sd > 0) {
447
+ /* already connected on server connection */
448
+ return NC_OK;
449
+ }
450
+
451
+ log_debug(LOG_VVERB, "connect to server '%.*s'", server->pname.len,
452
+ server->pname.data);
453
+
454
+ conn->sd = socket(conn->family, SOCK_STREAM, 0);
455
+ if (conn->sd < 0) {
456
+ log_error("socket for server '%.*s' failed: %s", server->pname.len,
457
+ server->pname.data, strerror(errno));
458
+ status = NC_ERROR;
459
+ goto error;
460
+ }
461
+
462
+ status = nc_set_nonblocking(conn->sd);
463
+ if (status != NC_OK) {
464
+ log_error("set nonblock on s %d for server '%.*s' failed: %s",
465
+ conn->sd, server->pname.len, server->pname.data,
466
+ strerror(errno));
467
+ goto error;
468
+ }
469
+
470
+ status = nc_set_tcpnodelay(conn->sd);
471
+ if (status != NC_OK) {
472
+ log_warn("set tcpnodelay on s %d for server '%.*s' failed, ignored: %s",
473
+ conn->sd, server->pname.len, server->pname.data,
474
+ strerror(errno));
475
+ }
476
+
477
+ status = event_add_conn(ctx->ep, conn);
478
+ if (status != NC_OK) {
479
+ log_error("event add conn e %d s %d for server '%.*s' failed: %s",
480
+ ctx->ep, conn->sd, server->pname.len, server->pname.data,
481
+ strerror(errno));
482
+ goto error;
483
+ }
484
+
485
+ ASSERT(!conn->connecting && !conn->connected);
486
+
487
+ status = connect(conn->sd, conn->addr, conn->addrlen);
488
+ if (status != NC_OK) {
489
+ if (errno == EINPROGRESS) {
490
+ conn->connecting = 1;
491
+ log_debug(LOG_DEBUG, "connecting on s %d to server '%.*s'",
492
+ conn->sd, server->pname.len, server->pname.data);
493
+ return NC_OK;
494
+ }
495
+
496
+ log_error("connect on s %d to server '%.*s' failed: %s", conn->sd,
497
+ server->pname.len, server->pname.data, strerror(errno));
498
+
499
+ goto error;
500
+ }
501
+
502
+ ASSERT(!conn->connecting);
503
+ conn->connected = 1;
504
+ log_debug(LOG_INFO, "connected on s %d to server '%.*s'", conn->sd,
505
+ server->pname.len, server->pname.data);
506
+
507
+ return NC_OK;
508
+
509
+ error:
510
+ conn->err = errno;
511
+ return status;
512
+ }
513
+
514
+ void
515
+ server_connected(struct context *ctx, struct conn *conn)
516
+ {
517
+ struct server *server = conn->owner;
518
+
519
+ ASSERT(!conn->client && !conn->proxy);
520
+ ASSERT(conn->connecting && !conn->connected);
521
+
522
+ stats_server_incr(ctx, server, server_connections);
523
+
524
+ conn->connecting = 0;
525
+ conn->connected = 1;
526
+
527
+ log_debug(LOG_INFO, "connected on s %d to server '%.*s'", conn->sd,
528
+ server->pname.len, server->pname.data);
529
+ }
530
+
531
+ void
532
+ server_ok(struct context *ctx, struct conn *conn)
533
+ {
534
+ struct server *server = conn->owner;
535
+
536
+ ASSERT(!conn->client && !conn->proxy);
537
+ ASSERT(conn->connected);
538
+
539
+ if (server->failure_count != 0) {
540
+ log_debug(LOG_VERB, "reset server '%.*s' failure count from %"PRIu32
541
+ " to 0", server->pname.len, server->pname.data,
542
+ server->failure_count);
543
+ server->failure_count = 0;
544
+ server->next_retry = 0LL;
545
+ }
546
+ }
547
+
548
+ static rstatus_t
549
+ server_pool_update(struct server_pool *pool)
550
+ {
551
+ rstatus_t status;
552
+ int64_t now;
553
+ uint32_t pnlive_server; /* prev # live server */
554
+
555
+ if (!pool->auto_eject_hosts) {
556
+ return NC_OK;
557
+ }
558
+
559
+ if (pool->next_rebuild == 0LL) {
560
+ return NC_OK;
561
+ }
562
+
563
+ now = nc_usec_now();
564
+ if (now < 0) {
565
+ return NC_ERROR;
566
+ }
567
+
568
+ if (now <= pool->next_rebuild) {
569
+ if (pool->nlive_server == 0) {
570
+ errno = ECONNREFUSED;
571
+ return NC_ERROR;
572
+ }
573
+ return NC_OK;
574
+ }
575
+
576
+ pnlive_server = pool->nlive_server;
577
+
578
+ status = server_pool_run(pool);
579
+ if (status != NC_OK) {
580
+ log_error("updating pool %"PRIu32" with dist %d failed: %s", pool->idx,
581
+ pool->dist_type, strerror(errno));
582
+ return status;
583
+ }
584
+
585
+ log_debug(LOG_INFO, "update pool %"PRIu32" '%.*s' to add %"PRIu32" servers",
586
+ pool->idx, pool->name.len, pool->name.data,
587
+ pool->nlive_server - pnlive_server);
588
+
589
+
590
+ return NC_OK;
591
+ }
592
+
593
+ static uint32_t
594
+ server_pool_hash(struct server_pool *pool, uint8_t *key, uint32_t keylen)
595
+ {
596
+ ASSERT(array_n(&pool->server) != 0);
597
+
598
+ if (array_n(&pool->server) == 1) {
599
+ return 0;
600
+ }
601
+
602
+ ASSERT(key != NULL && keylen != 0);
603
+
604
+ return pool->key_hash((char *)key, keylen);
605
+ }
606
+
607
+ static struct server *
608
+ server_pool_server(struct server_pool *pool, uint8_t *key, uint32_t keylen)
609
+ {
610
+ struct server *server;
611
+ uint32_t hash, idx;
612
+
613
+ ASSERT(array_n(&pool->server) != 0);
614
+ ASSERT(key != NULL && keylen != 0);
615
+
616
+ switch (pool->dist_type) {
617
+ case DIST_KETAMA:
618
+ hash = server_pool_hash(pool, key, keylen);
619
+ idx = ketama_dispatch(pool->continuum, pool->ncontinuum, hash);
620
+ break;
621
+
622
+ case DIST_MODULA:
623
+ hash = server_pool_hash(pool, key, keylen);
624
+ idx = modula_dispatch(pool->continuum, pool->ncontinuum, hash);
625
+ break;
626
+
627
+ case DIST_RANDOM:
628
+ idx = random_dispatch(pool->continuum, pool->ncontinuum, 0);
629
+ break;
630
+
631
+ default:
632
+ NOT_REACHED();
633
+ return NULL;
634
+ }
635
+ ASSERT(idx < array_n(&pool->server));
636
+
637
+ server = array_get(&pool->server, idx);
638
+
639
+ log_debug(LOG_VERB, "key '%.*s' on dist %d maps to server '%.*s'", keylen,
640
+ key, pool->dist_type, server->pname.len, server->pname.data);
641
+
642
+ return server;
643
+ }
644
+
645
+ struct conn *
646
+ server_pool_conn(struct context *ctx, struct server_pool *pool, uint8_t *key,
647
+ uint32_t keylen)
648
+ {
649
+ rstatus_t status;
650
+ struct server *server;
651
+ struct conn *conn;
652
+
653
+ status = server_pool_update(pool);
654
+ if (status != NC_OK) {
655
+ return NULL;
656
+ }
657
+
658
+ /* from a given {key, keylen} pick a server from pool */
659
+ server = server_pool_server(pool, key, keylen);
660
+ if (server == NULL) {
661
+ return NULL;
662
+ }
663
+
664
+ /* pick a connection to a given server */
665
+ conn = server_conn(server);
666
+ if (conn == NULL) {
667
+ return NULL;
668
+ }
669
+
670
+ status = server_connect(ctx, server, conn);
671
+ if (status != NC_OK) {
672
+ server_close(ctx, conn);
673
+ return NULL;
674
+ }
675
+
676
+ return conn;
677
+ }
678
+
679
+ static rstatus_t
680
+ server_pool_each_preconnect(void *elem, void *data)
681
+ {
682
+ rstatus_t status;
683
+ struct server_pool *sp = elem;
684
+
685
+ if (!sp->preconnect) {
686
+ return NC_OK;
687
+ }
688
+
689
+ status = array_each(&sp->server, server_each_preconnect, NULL);
690
+ if (status != NC_OK) {
691
+ return status;
692
+ }
693
+
694
+ return NC_OK;
695
+ }
696
+
697
+ rstatus_t
698
+ server_pool_preconnect(struct context *ctx)
699
+ {
700
+ rstatus_t status;
701
+
702
+ status = array_each(&ctx->pool, server_pool_each_preconnect, NULL);
703
+ if (status != NC_OK) {
704
+ return status;
705
+ }
706
+
707
+ return NC_OK;
708
+ }
709
+
710
+ static rstatus_t
711
+ server_pool_each_disconnect(void *elem, void *data)
712
+ {
713
+ rstatus_t status;
714
+ struct server_pool *sp = elem;
715
+
716
+ status = array_each(&sp->server, server_each_disconnect, NULL);
717
+ if (status != NC_OK) {
718
+ return status;
719
+ }
720
+
721
+ return NC_OK;
722
+ }
723
+
724
+ void
725
+ server_pool_disconnect(struct context *ctx)
726
+ {
727
+ array_each(&ctx->pool, server_pool_each_disconnect, NULL);
728
+ }
729
+
730
+ static rstatus_t
731
+ server_pool_each_set_owner(void *elem, void *data)
732
+ {
733
+ struct server_pool *sp = elem;
734
+ struct context *ctx = data;
735
+
736
+ sp->ctx = ctx;
737
+
738
+ return NC_OK;
739
+ }
740
+
741
+ rstatus_t
742
+ server_pool_run(struct server_pool *pool)
743
+ {
744
+ ASSERT(array_n(&pool->server) != 0);
745
+
746
+ switch (pool->dist_type) {
747
+ case DIST_KETAMA:
748
+ return ketama_update(pool);
749
+
750
+ case DIST_MODULA:
751
+ return modula_update(pool);
752
+
753
+ case DIST_RANDOM:
754
+ return random_update(pool);
755
+
756
+ default:
757
+ NOT_REACHED();
758
+ return NC_ERROR;
759
+ }
760
+
761
+ return NC_OK;
762
+ }
763
+
764
+ static rstatus_t
765
+ server_pool_each_run(void *elem, void *data)
766
+ {
767
+ return server_pool_run(elem);
768
+ }
769
+
770
+ rstatus_t
771
+ server_pool_init(struct array *server_pool, struct array *conf_pool,
772
+ struct context *ctx)
773
+ {
774
+ rstatus_t status;
775
+ uint32_t npool;
776
+
777
+ npool = array_n(conf_pool);
778
+ ASSERT(npool != 0);
779
+ ASSERT(array_n(server_pool) == 0);
780
+
781
+ status = array_init(server_pool, npool, sizeof(struct server_pool));
782
+ if (status != NC_OK) {
783
+ return status;
784
+ }
785
+
786
+ /* transform conf pool to server pool */
787
+ status = array_each(conf_pool, conf_pool_each_transform, server_pool);
788
+ if (status != NC_OK) {
789
+ server_pool_deinit(server_pool);
790
+ return status;
791
+ }
792
+ ASSERT(array_n(server_pool) == npool);
793
+
794
+ /* set ctx as the server pool owner */
795
+ status = array_each(server_pool, server_pool_each_set_owner, ctx);
796
+ if (status != NC_OK) {
797
+ server_pool_deinit(server_pool);
798
+ return status;
799
+ }
800
+
801
+ /* update server pool continuum */
802
+ status = array_each(server_pool, server_pool_each_run, NULL);
803
+ if (status != NC_OK) {
804
+ server_pool_deinit(server_pool);
805
+ return status;
806
+ }
807
+
808
+ log_debug(LOG_DEBUG, "init %"PRIu32" pools", npool);
809
+
810
+ return NC_OK;
811
+ }
812
+
813
+ void
814
+ server_pool_deinit(struct array *server_pool)
815
+ {
816
+ uint32_t i, npool;
817
+
818
+ for (i = 0, npool = array_n(server_pool); i < npool; i++) {
819
+ struct server_pool *sp;
820
+
821
+ sp = array_pop(server_pool);
822
+ ASSERT(sp->p_conn == NULL);
823
+ ASSERT(TAILQ_EMPTY(&sp->c_conn_q) && sp->nc_conn_q == 0);
824
+
825
+ if (sp->continuum != NULL) {
826
+ nc_free(sp->continuum);
827
+ sp->ncontinuum = 0;
828
+ sp->nserver_continuum = 0;
829
+ sp->nlive_server = 0;
830
+ }
831
+
832
+ server_deinit(&sp->server);
833
+
834
+ log_debug(LOG_DEBUG, "deinit pool %"PRIu32" '%.*s'", sp->idx,
835
+ sp->name.len, sp->name.data);
836
+ }
837
+
838
+ array_deinit(server_pool);
839
+
840
+ log_debug(LOG_DEBUG, "deinit %"PRIu32" pools", npool);
841
+ }