comparison src/http/ngx_http_upstream_round_robin.c @ 260:0effe91f6083 NGINX_0_5_0

nginx 0.5.0 *) Change: the parameters in the "%name" form in the "log_format" directive are not supported anymore. *) Change: the "proxy_upstream_max_fails", "proxy_upstream_fail_timeout", "fastcgi_upstream_max_fails", "fastcgi_upstream_fail_timeout", "memcached_upstream_max_fails", and "memcached_upstream_fail_timeout" directives are not supported anymore. *) Feature: the "server" directive in the "upstream" context supports the "max_fails", "fail_timeout", and "down" parameters. *) Feature: the "ip_hash" directive inside the "upstream" block. *) Feature: the WAIT status in the "Auth-Status" header line of the IMAP/POP3 proxy authentication server response. *) Bugfix: nginx could not be built on 64-bit platforms; bug appeared in 0.4.14.
author Igor Sysoev <http://sysoev.ru>
date Mon, 04 Dec 2006 00:00:00 +0300
parents
children e0b1d0a6c629
comparison
equal deleted inserted replaced
259:c68f18041059 260:0effe91f6083
1
2 /*
3 * Copyright (C) Igor Sysoev
4 */
5
6
7 #include <ngx_config.h>
8 #include <ngx_core.h>
9 #include <ngx_http.h>
10
11
12 ngx_int_t
13 ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
14 ngx_http_upstream_srv_conf_t *us)
15 {
16 ngx_url_t u;
17 ngx_uint_t i, j, n;
18 ngx_http_upstream_server_t *server;
19 ngx_http_upstream_rr_peers_t *peers;
20
21 us->peer.init = ngx_http_upstream_init_round_robin_peer;
22
23 if (us->servers) {
24 n = 0;
25 server = us->servers->elts;
26
27 for (i = 0; i < us->servers->nelts; i++) {
28 n += server[i].naddrs;
29 }
30
31 peers = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t)
32 + sizeof(ngx_http_upstream_rr_peer_t) * (n - 1));
33 if (peers == NULL) {
34 return NGX_ERROR;
35 }
36
37 peers->number = n;
38 peers->name = &us->host;
39
40 n = 0;
41
42 for (i = 0; i < us->servers->nelts; i++) {
43 for (j = 0; j < server[i].naddrs; j++) {
44 peers->peer[n].sockaddr = server[i].addrs[j].sockaddr;
45 peers->peer[n].socklen = server[i].addrs[j].socklen;
46 peers->peer[n].name = server[i].addrs[j].name;
47 peers->peer[n].weight = server[i].weight;
48 peers->peer[n].current_weight = server[i].weight;
49 peers->peer[n].max_fails = server[i].max_fails;
50 peers->peer[n].fail_timeout = server[i].fail_timeout;
51 peers->peer[n].down = server[i].down;
52 n++;
53 }
54 }
55
56 us->peer.data = peers;
57
58 return NGX_OK;
59 }
60
61
62 /* an upstream implicitly defined by proxy_pass, etc. */
63
64 ngx_memzero(&u, sizeof(ngx_url_t));
65
66 u.host = us->host;
67 u.portn = us->port;
68
69 if (ngx_inet_resolve_host(cf, &u) != NGX_OK) {
70 if (u.err) {
71 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
72 "%s in upstream host \"%V\" is not found in %s:%ui",
73 u.err, &us->host, us->file_name.data, us->line);
74 }
75
76 return NGX_ERROR;
77 }
78
79 n = u.naddrs;
80
81 peers = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t)
82 + sizeof(ngx_http_upstream_rr_peer_t) * (n - 1));
83 if (peers == NULL) {
84 return NGX_ERROR;
85 }
86
87 peers->number = n;
88 peers->name = &us->host;
89
90 n = 0;
91
92 for (i = 0; i < u.naddrs; i++) {
93 peers->peer[n].sockaddr = u.addrs[i].sockaddr;
94 peers->peer[n].socklen = u.addrs[i].socklen;
95 peers->peer[n].name = u.addrs[i].name;
96 peers->peer[n].weight = 1;
97 peers->peer[n].current_weight = 1;
98 peers->peer[n].max_fails = 1;
99 peers->peer[n].fail_timeout = 10;
100 n++;
101 }
102
103 us->peer.data = peers;
104
105 return NGX_OK;
106 }
107
108
109 ngx_int_t
110 ngx_http_upstream_init_round_robin_peer(ngx_http_request_t *r,
111 ngx_http_upstream_srv_conf_t *us)
112 {
113 ngx_uint_t n;
114 ngx_http_upstream_rr_peer_data_t *rrp;
115
116 rrp = r->upstream->peer.data;
117
118 if (rrp == NULL) {
119 rrp = ngx_palloc(r->pool, sizeof(ngx_http_upstream_rr_peer_data_t));
120 if (rrp == NULL) {
121 return NGX_ERROR;
122 }
123
124 r->upstream->peer.data = rrp;
125 }
126
127 rrp->peers = us->peer.data;
128 rrp->current = 0;
129
130 if (rrp->peers->number <= 8 * sizeof(uintptr_t)) {
131 rrp->tried = &rrp->data;
132 rrp->data = 0;
133
134 } else {
135 n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1))
136 / (8 * sizeof(uintptr_t));
137
138 rrp->tried = ngx_pcalloc(r->pool, n * sizeof(uintptr_t));
139 if (rrp->tried == NULL) {
140 return NGX_ERROR;
141 }
142 }
143
144 r->upstream->peer.get = ngx_http_upstream_get_round_robin_peer;
145 r->upstream->peer.free = ngx_http_upstream_free_round_robin_peer;
146 r->upstream->peer.tries = rrp->peers->number;
147 #if (NGX_HTTP_SSL)
148 r->upstream->peer.save_session = ngx_http_upstream_save_round_robin_peer;
149 #endif
150
151 return NGX_OK;
152 }
153
154
155 ngx_int_t
156 ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data)
157 {
158 ngx_http_upstream_rr_peer_data_t *rrp = data;
159
160 time_t now;
161 uintptr_t m;
162 ngx_uint_t i, n;
163 ngx_connection_t *c;
164 ngx_http_upstream_rr_peer_t *peer;
165
166 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
167 "get rr peer, try: %ui", pc->tries);
168
169 now = ngx_time();
170
171 /* ngx_lock_mutex(rrp->peers->mutex); */
172
173 if (rrp->peers->last_cached) {
174
175 /* cached connection */
176
177 c = rrp->peers->cached[rrp->peers->last_cached];
178 rrp->peers->last_cached--;
179
180 /* ngx_unlock_mutex(ppr->peers->mutex); */
181
182 #if (NGX_THREADS)
183 c->read->lock = c->read->own_lock;
184 c->write->lock = c->write->own_lock;
185 #endif
186
187 pc->connection = c;
188 pc->cached = 1;
189
190 return NGX_OK;
191 }
192
193 pc->cached = 0;
194 pc->connection = NULL;
195
196 if (rrp->peers->number == 1) {
197 peer = &rrp->peers->peer[0];
198
199 } else {
200
201 /* there are several peers */
202
203 if (pc->tries == rrp->peers->number) {
204
205 /* it's a first try - get a current peer */
206
207 for ( ;; ) {
208 rrp->current = rrp->peers->current;
209
210 n = rrp->current / (8 * sizeof(uintptr_t));
211 m = 1 << rrp->current % (8 * sizeof(uintptr_t));
212
213 if (!(rrp->tried[n] & m)) {
214 peer = &rrp->peers->peer[rrp->current];
215
216 if (!peer->down) {
217
218 if (peer->max_fails == 0
219 || peer->fails < peer->max_fails)
220 {
221 break;
222 }
223
224 if (now - peer->accessed > peer->fail_timeout) {
225 peer->fails = 0;
226 break;
227 }
228
229 } else {
230 rrp->tried[n] |= m;
231 }
232
233 pc->tries--;
234 }
235
236 rrp->peers->current++;
237
238 if (rrp->peers->current >= rrp->peers->number) {
239 rrp->peers->current = 0;
240 }
241
242 if (pc->tries) {
243 continue;
244 }
245
246 goto failed;
247 }
248
249 peer->current_weight--;
250
251 if (peer->current_weight == 0) {
252 peer->current_weight = peer->weight;
253
254 rrp->peers->current++;
255
256 if (rrp->peers->current >= rrp->peers->number) {
257 rrp->peers->current = 0;
258 }
259 }
260
261 } else {
262 for ( ;; ) {
263 n = rrp->current / (8 * sizeof(uintptr_t));
264 m = 1 << rrp->current % (8 * sizeof(uintptr_t));
265
266 if (!(rrp->tried[n] & m)) {
267
268 peer = &rrp->peers->peer[rrp->current];
269
270 if (!peer->down) {
271
272 if (peer->max_fails == 0
273 || peer->fails < peer->max_fails)
274 {
275 break;
276 }
277
278 if (now - peer->accessed > peer->fail_timeout) {
279 peer->fails = 0;
280 break;
281 }
282
283 } else {
284 rrp->tried[n] |= m;
285 }
286
287 pc->tries--;
288 }
289
290 rrp->current++;
291
292 if (rrp->current >= rrp->peers->number) {
293 rrp->current = 0;
294 }
295
296 if (pc->tries) {
297 continue;
298 }
299
300 goto failed;
301 }
302
303 peer->current_weight--;
304
305 if (peer->current_weight == 0) {
306 peer->current_weight = peer->weight;
307
308 if (rrp->current == rrp->peers->current) {
309 rrp->peers->current++;
310
311 if (rrp->peers->current >= rrp->peers->number) {
312 rrp->peers->current = 0;
313 }
314 }
315 }
316 }
317
318 rrp->tried[n] |= m;
319 }
320
321 pc->sockaddr = peer->sockaddr;
322 pc->socklen = peer->socklen;
323 pc->name = &peer->name;
324 #if (NGX_SSL)
325 pc->ssl_session = peer->ssl_session;
326 #endif
327
328 /* ngx_unlock_mutex(rrp->peers->mutex); */
329
330 return NGX_OK;
331
332 failed:
333
334 /* all peers failed, mark them as live for quick recovery */
335
336 for (i = 0; i < rrp->peers->number; i++) {
337 rrp->peers->peer[i].fails = 0;
338 }
339
340 /* ngx_unlock_mutex(rrp->peers->mutex); */
341
342 pc->name = rrp->peers->name;
343
344 return NGX_BUSY;
345 }
346
347
348 void
349 ngx_http_upstream_free_round_robin_peer(ngx_peer_connection_t *pc, void *data,
350 ngx_uint_t state)
351 {
352 ngx_http_upstream_rr_peer_data_t *rrp = data;
353
354 time_t now;
355 ngx_http_upstream_rr_peer_t *peer;
356
357 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
358 "free rr peer %ui %ui", pc->tries, state);
359
360 if (state == 0 && pc->tries == 0) {
361 return;
362 }
363
364 /* TODO: NGX_PEER_KEEPALIVE */
365
366 if (rrp->peers->number == 1) {
367 pc->tries = 0;
368 return;
369 }
370
371 if (state & NGX_PEER_FAILED) {
372 now = ngx_time();
373
374 peer = &rrp->peers->peer[rrp->current];
375
376 /* ngx_lock_mutex(rrp->peers->mutex); */
377
378 peer->fails++;
379 peer->accessed = now;
380
381 if (peer->current_weight > 1) {
382 peer->current_weight /= 2;
383 }
384
385 /* ngx_unlock_mutex(rrp->peers->mutex); */
386 }
387
388 rrp->current++;
389
390 if (rrp->current >= rrp->peers->number) {
391 rrp->current = 0;
392 }
393
394 if (pc->tries) {
395 pc->tries--;
396 }
397
398 /* ngx_unlock_mutex(rrp->peers->mutex); */
399 }
400
401
402 #if (NGX_HTTP_SSL)
403
404 void
405 ngx_http_upstream_save_round_robin_peer(ngx_peer_connection_t *pc, void *data)
406 {
407 ngx_http_upstream_rr_peer_data_t *rrp = data;
408
409 ngx_ssl_session_t *ssl_session;
410 ngx_http_upstream_rr_peer_t *peer;
411
412 ssl_session = ngx_ssl_get_session(pc->connection);
413
414 if (ssl_session == NULL) {
415 return;
416 }
417
418 peer = &rrp->peers->peer[rrp->current];
419
420 /* ngx_lock_mutex(rrp->peers->mutex); */
421 peer->ssl_session = ssl_session;
422 /* ngx_unlock_mutex(rrp->peers->mutex); */
423
424 if (pc->ssl_session) {
425 /* TODO: may block */
426 ngx_ssl_free_session(pc->ssl_session);
427 }
428 }
429
430 #endif