Mercurial > hg > nginx
annotate src/stream/ngx_stream_upstream_least_conn_module.c @ 6230:2a621245f4cf
Win32: MSVC 2015 compatibility.
Resolved warnings about declarations that hide previous local declarations.
Warnings about WSASocketA() being deprecated resolved by explicit use of
WSASocketW() instead of WSASocket(). When compiling without IPv6 support,
WinSock deprecated warnings are disabled to allow use of gethostbyname().
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Mon, 17 Aug 2015 18:09:17 +0300 |
parents | 68c106e6fa0a |
children | 2cd019520210 |
rev | line source |
---|---|
6115 | 1 |
2 /* | |
3 * Copyright (C) Maxim Dounin | |
4 * Copyright (C) Nginx, Inc. | |
5 */ | |
6 | |
7 | |
8 #include <ngx_config.h> | |
9 #include <ngx_core.h> | |
10 #include <ngx_stream.h> | |
11 | |
12 | |
13 static ngx_int_t ngx_stream_upstream_init_least_conn_peer( | |
14 ngx_stream_session_t *s, ngx_stream_upstream_srv_conf_t *us); | |
15 static ngx_int_t ngx_stream_upstream_get_least_conn_peer( | |
16 ngx_peer_connection_t *pc, void *data); | |
17 static char *ngx_stream_upstream_least_conn(ngx_conf_t *cf, ngx_command_t *cmd, | |
18 void *conf); | |
19 | |
20 | |
21 static ngx_command_t ngx_stream_upstream_least_conn_commands[] = { | |
22 | |
23 { ngx_string("least_conn"), | |
24 NGX_STREAM_UPS_CONF|NGX_CONF_NOARGS, | |
25 ngx_stream_upstream_least_conn, | |
26 0, | |
27 0, | |
28 NULL }, | |
29 | |
30 ngx_null_command | |
31 }; | |
32 | |
33 | |
34 static ngx_stream_module_t ngx_stream_upstream_least_conn_module_ctx = { | |
6174
68c106e6fa0a
Stream: added postconfiguration method to stream modules.
Vladimir Homutov <vl@nginx.com>
parents:
6115
diff
changeset
|
35 NULL, /* postconfiguration */ |
68c106e6fa0a
Stream: added postconfiguration method to stream modules.
Vladimir Homutov <vl@nginx.com>
parents:
6115
diff
changeset
|
36 |
6115 | 37 NULL, /* create main configuration */ |
38 NULL, /* init main configuration */ | |
39 | |
40 NULL, /* create server configuration */ | |
41 NULL, /* merge server configuration */ | |
42 }; | |
43 | |
44 | |
45 ngx_module_t ngx_stream_upstream_least_conn_module = { | |
46 NGX_MODULE_V1, | |
47 &ngx_stream_upstream_least_conn_module_ctx, /* module context */ | |
48 ngx_stream_upstream_least_conn_commands, /* module directives */ | |
49 NGX_STREAM_MODULE, /* module type */ | |
50 NULL, /* init master */ | |
51 NULL, /* init module */ | |
52 NULL, /* init process */ | |
53 NULL, /* init thread */ | |
54 NULL, /* exit thread */ | |
55 NULL, /* exit process */ | |
56 NULL, /* exit master */ | |
57 NGX_MODULE_V1_PADDING | |
58 }; | |
59 | |
60 | |
61 static ngx_int_t | |
62 ngx_stream_upstream_init_least_conn(ngx_conf_t *cf, | |
63 ngx_stream_upstream_srv_conf_t *us) | |
64 { | |
65 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, cf->log, 0, | |
66 "init least conn"); | |
67 | |
68 if (ngx_stream_upstream_init_round_robin(cf, us) != NGX_OK) { | |
69 return NGX_ERROR; | |
70 } | |
71 | |
72 us->peer.init = ngx_stream_upstream_init_least_conn_peer; | |
73 | |
74 return NGX_OK; | |
75 } | |
76 | |
77 | |
78 static ngx_int_t | |
79 ngx_stream_upstream_init_least_conn_peer(ngx_stream_session_t *s, | |
80 ngx_stream_upstream_srv_conf_t *us) | |
81 { | |
82 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, | |
83 "init least conn peer"); | |
84 | |
85 if (ngx_stream_upstream_init_round_robin_peer(s, us) != NGX_OK) { | |
86 return NGX_ERROR; | |
87 } | |
88 | |
89 s->upstream->peer.get = ngx_stream_upstream_get_least_conn_peer; | |
90 | |
91 return NGX_OK; | |
92 } | |
93 | |
94 | |
95 static ngx_int_t | |
96 ngx_stream_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data) | |
97 { | |
98 ngx_stream_upstream_rr_peer_data_t *rrp = data; | |
99 | |
100 time_t now; | |
101 uintptr_t m; | |
102 ngx_int_t rc, total; | |
103 ngx_uint_t i, n, p, many; | |
104 ngx_stream_upstream_rr_peer_t *peer, *best; | |
105 ngx_stream_upstream_rr_peers_t *peers; | |
106 | |
107 ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0, | |
108 "get least conn peer, try: %ui", pc->tries); | |
109 | |
110 if (rrp->peers->single) { | |
111 return ngx_stream_upstream_get_round_robin_peer(pc, rrp); | |
112 } | |
113 | |
114 pc->connection = NULL; | |
115 | |
116 now = ngx_time(); | |
117 | |
118 peers = rrp->peers; | |
119 | |
120 ngx_stream_upstream_rr_peers_wlock(peers); | |
121 | |
122 best = NULL; | |
123 total = 0; | |
124 | |
125 #if (NGX_SUPPRESS_WARN) | |
126 many = 0; | |
127 p = 0; | |
128 #endif | |
129 | |
130 for (peer = peers->peer, i = 0; | |
131 peer; | |
132 peer = peer->next, i++) | |
133 { | |
134 | |
135 n = i / (8 * sizeof(uintptr_t)); | |
136 m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t)); | |
137 | |
138 if (rrp->tried[n] & m) { | |
139 continue; | |
140 } | |
141 | |
142 if (peer->down) { | |
143 continue; | |
144 } | |
145 | |
146 if (peer->max_fails | |
147 && peer->fails >= peer->max_fails | |
148 && now - peer->checked <= peer->fail_timeout) | |
149 { | |
150 continue; | |
151 } | |
152 | |
153 /* | |
154 * select peer with least number of connections; if there are | |
155 * multiple peers with the same number of connections, select | |
156 * based on round-robin | |
157 */ | |
158 | |
159 if (best == NULL | |
160 || peer->conns * best->weight < best->conns * peer->weight) | |
161 { | |
162 best = peer; | |
163 many = 0; | |
164 p = i; | |
165 | |
166 } else if (peer->conns * best->weight == best->conns * peer->weight) { | |
167 many = 1; | |
168 } | |
169 } | |
170 | |
171 if (best == NULL) { | |
172 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, pc->log, 0, | |
173 "get least conn peer, no peer found"); | |
174 | |
175 goto failed; | |
176 } | |
177 | |
178 if (many) { | |
179 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, pc->log, 0, | |
180 "get least conn peer, many"); | |
181 | |
182 for (peer = best, i = p; | |
183 peer; | |
184 peer = peer->next, i++) | |
185 { | |
186 n = i / (8 * sizeof(uintptr_t)); | |
187 m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t)); | |
188 | |
189 if (rrp->tried[n] & m) { | |
190 continue; | |
191 } | |
192 | |
193 if (peer->down) { | |
194 continue; | |
195 } | |
196 | |
197 if (peer->conns * best->weight != best->conns * peer->weight) { | |
198 continue; | |
199 } | |
200 | |
201 if (peer->max_fails | |
202 && peer->fails >= peer->max_fails | |
203 && now - peer->checked <= peer->fail_timeout) | |
204 { | |
205 continue; | |
206 } | |
207 | |
208 peer->current_weight += peer->effective_weight; | |
209 total += peer->effective_weight; | |
210 | |
211 if (peer->effective_weight < peer->weight) { | |
212 peer->effective_weight++; | |
213 } | |
214 | |
215 if (peer->current_weight > best->current_weight) { | |
216 best = peer; | |
217 p = i; | |
218 } | |
219 } | |
220 } | |
221 | |
222 best->current_weight -= total; | |
223 | |
224 if (now - best->checked > best->fail_timeout) { | |
225 best->checked = now; | |
226 } | |
227 | |
228 pc->sockaddr = best->sockaddr; | |
229 pc->socklen = best->socklen; | |
230 pc->name = &best->name; | |
231 | |
232 best->conns++; | |
233 | |
234 rrp->current = best; | |
235 | |
236 n = p / (8 * sizeof(uintptr_t)); | |
237 m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t)); | |
238 | |
239 rrp->tried[n] |= m; | |
240 | |
241 ngx_stream_upstream_rr_peers_unlock(peers); | |
242 | |
243 return NGX_OK; | |
244 | |
245 failed: | |
246 | |
247 if (peers->next) { | |
248 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, pc->log, 0, | |
249 "get least conn peer, backup servers"); | |
250 | |
251 rrp->peers = peers->next; | |
252 | |
253 n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1)) | |
254 / (8 * sizeof(uintptr_t)); | |
255 | |
256 for (i = 0; i < n; i++) { | |
257 rrp->tried[i] = 0; | |
258 } | |
259 | |
260 ngx_stream_upstream_rr_peers_unlock(peers); | |
261 | |
262 rc = ngx_stream_upstream_get_least_conn_peer(pc, rrp); | |
263 | |
264 if (rc != NGX_BUSY) { | |
265 return rc; | |
266 } | |
267 | |
268 ngx_stream_upstream_rr_peers_wlock(peers); | |
269 } | |
270 | |
271 /* all peers failed, mark them as live for quick recovery */ | |
272 | |
273 for (peer = peers->peer; peer; peer = peer->next) { | |
274 peer->fails = 0; | |
275 } | |
276 | |
277 ngx_stream_upstream_rr_peers_unlock(peers); | |
278 | |
279 pc->name = peers->name; | |
280 | |
281 return NGX_BUSY; | |
282 } | |
283 | |
284 | |
285 static char * | |
286 ngx_stream_upstream_least_conn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
287 { | |
288 ngx_stream_upstream_srv_conf_t *uscf; | |
289 | |
290 uscf = ngx_stream_conf_get_module_srv_conf(cf, ngx_stream_upstream_module); | |
291 | |
292 if (uscf->peer.init_upstream) { | |
293 ngx_conf_log_error(NGX_LOG_WARN, cf, 0, | |
294 "load balancing method redefined"); | |
295 } | |
296 | |
297 uscf->peer.init_upstream = ngx_stream_upstream_init_least_conn; | |
298 | |
299 uscf->flags = NGX_STREAM_UPSTREAM_CREATE | |
300 |NGX_STREAM_UPSTREAM_WEIGHT | |
301 |NGX_STREAM_UPSTREAM_MAX_FAILS | |
302 |NGX_STREAM_UPSTREAM_FAIL_TIMEOUT | |
303 |NGX_STREAM_UPSTREAM_DOWN | |
304 |NGX_STREAM_UPSTREAM_BACKUP; | |
305 | |
306 return NGX_CONF_OK; | |
307 } |