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