blob: 410559d50bc8c28c95e9d05cae2163541852c613 [file] [log] [blame]
Igor Sysoev3d2fd182006-12-04 16:46:13 +00001
2/*
3 * Copyright (C) Igor Sysoev
Maxim Konovalovf8d59e32012-01-18 15:07:43 +00004 * Copyright (C) Nginx, Inc.
Igor Sysoev3d2fd182006-12-04 16:46:13 +00005 */
6
7
8#include <ngx_config.h>
9#include <ngx_core.h>
10#include <ngx_http.h>
11
12
Igor Sysoevde8ec1e2008-03-24 13:04:02 +000013static ngx_int_t ngx_http_upstream_cmp_servers(const void *one,
14 const void *two);
Igor Sysoevd12a5712007-07-28 16:04:01 +000015static ngx_uint_t
16ngx_http_upstream_get_peer(ngx_http_upstream_rr_peers_t *peers);
17
Igor Sysoev08b59752011-07-22 16:30:17 +000018#if (NGX_HTTP_SSL)
19
20static ngx_int_t ngx_http_upstream_empty_set_session(ngx_peer_connection_t *pc,
21 void *data);
22static void ngx_http_upstream_empty_save_session(ngx_peer_connection_t *pc,
23 void *data);
24
25#endif
26
Igor Sysoevd12a5712007-07-28 16:04:01 +000027
Igor Sysoev3d2fd182006-12-04 16:46:13 +000028ngx_int_t
29ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
30 ngx_http_upstream_srv_conf_t *us)
31{
32 ngx_url_t u;
33 ngx_uint_t i, j, n;
34 ngx_http_upstream_server_t *server;
Igor Sysoev6876bcd2007-08-09 13:54:33 +000035 ngx_http_upstream_rr_peers_t *peers, *backup;
Igor Sysoev3d2fd182006-12-04 16:46:13 +000036
37 us->peer.init = ngx_http_upstream_init_round_robin_peer;
38
39 if (us->servers) {
Igor Sysoev3d2fd182006-12-04 16:46:13 +000040 server = us->servers->elts;
41
Igor Sysoev6876bcd2007-08-09 13:54:33 +000042 n = 0;
43
Igor Sysoev3d2fd182006-12-04 16:46:13 +000044 for (i = 0; i < us->servers->nelts; i++) {
Igor Sysoev6876bcd2007-08-09 13:54:33 +000045 if (server[i].backup) {
46 continue;
47 }
48
Igor Sysoev3d2fd182006-12-04 16:46:13 +000049 n += server[i].naddrs;
50 }
51
52 peers = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t)
53 + sizeof(ngx_http_upstream_rr_peer_t) * (n - 1));
54 if (peers == NULL) {
55 return NGX_ERROR;
56 }
57
Igor Sysoev6876bcd2007-08-09 13:54:33 +000058 peers->single = (n == 1);
Igor Sysoev3d2fd182006-12-04 16:46:13 +000059 peers->number = n;
60 peers->name = &us->host;
61
62 n = 0;
63
64 for (i = 0; i < us->servers->nelts; i++) {
65 for (j = 0; j < server[i].naddrs; j++) {
Igor Sysoev6876bcd2007-08-09 13:54:33 +000066 if (server[i].backup) {
67 continue;
68 }
69
Igor Sysoev3d2fd182006-12-04 16:46:13 +000070 peers->peer[n].sockaddr = server[i].addrs[j].sockaddr;
71 peers->peer[n].socklen = server[i].addrs[j].socklen;
72 peers->peer[n].name = server[i].addrs[j].name;
Igor Sysoev3d2fd182006-12-04 16:46:13 +000073 peers->peer[n].max_fails = server[i].max_fails;
74 peers->peer[n].fail_timeout = server[i].fail_timeout;
75 peers->peer[n].down = server[i].down;
Igor Sysoev3625a452007-08-07 12:34:20 +000076 peers->peer[n].weight = server[i].down ? 0 : server[i].weight;
77 peers->peer[n].current_weight = peers->peer[n].weight;
Igor Sysoev3d2fd182006-12-04 16:46:13 +000078 n++;
79 }
80 }
81
82 us->peer.data = peers;
83
Igor Sysoev7a8e3392007-08-09 15:28:17 +000084 ngx_sort(&peers->peer[0], (size_t) n,
85 sizeof(ngx_http_upstream_rr_peer_t),
86 ngx_http_upstream_cmp_servers);
87
Igor Sysoev6876bcd2007-08-09 13:54:33 +000088 /* backup servers */
89
90 n = 0;
91
92 for (i = 0; i < us->servers->nelts; i++) {
93 if (!server[i].backup) {
94 continue;
95 }
96
97 n += server[i].naddrs;
98 }
99
100 if (n == 0) {
101 return NGX_OK;
102 }
103
104 backup = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t)
105 + sizeof(ngx_http_upstream_rr_peer_t) * (n - 1));
106 if (backup == NULL) {
107 return NGX_ERROR;
108 }
109
110 peers->single = 0;
111 backup->single = 0;
112 backup->number = n;
113 backup->name = &us->host;
114
115 n = 0;
116
117 for (i = 0; i < us->servers->nelts; i++) {
118 for (j = 0; j < server[i].naddrs; j++) {
119 if (!server[i].backup) {
120 continue;
121 }
122
123 backup->peer[n].sockaddr = server[i].addrs[j].sockaddr;
124 backup->peer[n].socklen = server[i].addrs[j].socklen;
125 backup->peer[n].name = server[i].addrs[j].name;
126 backup->peer[n].weight = server[i].weight;
127 backup->peer[n].current_weight = server[i].weight;
128 backup->peer[n].max_fails = server[i].max_fails;
129 backup->peer[n].fail_timeout = server[i].fail_timeout;
130 backup->peer[n].down = server[i].down;
131 n++;
132 }
133 }
134
135 peers->next = backup;
136
Igor Sysoev7a8e3392007-08-09 15:28:17 +0000137 ngx_sort(&backup->peer[0], (size_t) n,
138 sizeof(ngx_http_upstream_rr_peer_t),
139 ngx_http_upstream_cmp_servers);
140
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000141 return NGX_OK;
142 }
143
144
145 /* an upstream implicitly defined by proxy_pass, etc. */
146
Igor Sysoevbf3aaac2006-12-12 16:46:16 +0000147 if (us->port == 0 && us->default_port == 0) {
148 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
149 "no port in upstream \"%V\" in %s:%ui",
Igor Sysoev4b96baa2007-09-15 17:11:06 +0000150 &us->host, us->file_name, us->line);
Igor Sysoevbf3aaac2006-12-12 16:46:16 +0000151 return NGX_ERROR;
152 }
153
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000154 ngx_memzero(&u, sizeof(ngx_url_t));
155
156 u.host = us->host;
Igor Sysoevdb4e43c2006-12-13 15:06:46 +0000157 u.port = (in_port_t) (us->port ? us->port : us->default_port);
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000158
Igor Sysoev7ed63ee2007-10-08 08:55:12 +0000159 if (ngx_inet_resolve_host(cf->pool, &u) != NGX_OK) {
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000160 if (u.err) {
161 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
Igor Sysoev5d118d32006-12-11 08:59:30 +0000162 "%s in upstream \"%V\" in %s:%ui",
Igor Sysoev4b96baa2007-09-15 17:11:06 +0000163 u.err, &us->host, us->file_name, us->line);
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000164 }
165
166 return NGX_ERROR;
167 }
168
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000169 n = u.naddrs;
170
171 peers = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t)
172 + sizeof(ngx_http_upstream_rr_peer_t) * (n - 1));
173 if (peers == NULL) {
174 return NGX_ERROR;
175 }
176
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000177 peers->single = (n == 1);
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000178 peers->number = n;
179 peers->name = &us->host;
180
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000181 for (i = 0; i < u.naddrs; i++) {
Igor Sysoev47a1ebb2007-10-10 13:58:47 +0000182 peers->peer[i].sockaddr = u.addrs[i].sockaddr;
183 peers->peer[i].socklen = u.addrs[i].socklen;
184 peers->peer[i].name = u.addrs[i].name;
185 peers->peer[i].weight = 1;
186 peers->peer[i].current_weight = 1;
187 peers->peer[i].max_fails = 1;
188 peers->peer[i].fail_timeout = 10;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000189 }
190
191 us->peer.data = peers;
192
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000193 /* implicitly defined upstream has no backup servers */
194
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000195 return NGX_OK;
196}
197
198
Igor Sysoevde8ec1e2008-03-24 13:04:02 +0000199static ngx_int_t
Igor Sysoev7a8e3392007-08-09 15:28:17 +0000200ngx_http_upstream_cmp_servers(const void *one, const void *two)
201{
202 ngx_http_upstream_rr_peer_t *first, *second;
203
204 first = (ngx_http_upstream_rr_peer_t *) one;
205 second = (ngx_http_upstream_rr_peer_t *) two;
206
207 return (first->weight < second->weight);
208}
209
210
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000211ngx_int_t
212ngx_http_upstream_init_round_robin_peer(ngx_http_request_t *r,
213 ngx_http_upstream_srv_conf_t *us)
214{
215 ngx_uint_t n;
216 ngx_http_upstream_rr_peer_data_t *rrp;
217
218 rrp = r->upstream->peer.data;
219
220 if (rrp == NULL) {
221 rrp = ngx_palloc(r->pool, sizeof(ngx_http_upstream_rr_peer_data_t));
222 if (rrp == NULL) {
223 return NGX_ERROR;
224 }
225
226 r->upstream->peer.data = rrp;
227 }
228
229 rrp->peers = us->peer.data;
230 rrp->current = 0;
231
Maxim Douninb7fcb432011-08-18 17:04:52 +0000232 n = rrp->peers->number;
233
234 if (rrp->peers->next && rrp->peers->next->number > n) {
235 n = rrp->peers->next->number;
236 }
237
238 if (n <= 8 * sizeof(uintptr_t)) {
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000239 rrp->tried = &rrp->data;
240 rrp->data = 0;
241
242 } else {
Maxim Douninb7fcb432011-08-18 17:04:52 +0000243 n = (n + (8 * sizeof(uintptr_t) - 1)) / (8 * sizeof(uintptr_t));
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000244
245 rrp->tried = ngx_pcalloc(r->pool, n * sizeof(uintptr_t));
246 if (rrp->tried == NULL) {
247 return NGX_ERROR;
248 }
249 }
250
251 r->upstream->peer.get = ngx_http_upstream_get_round_robin_peer;
252 r->upstream->peer.free = ngx_http_upstream_free_round_robin_peer;
253 r->upstream->peer.tries = rrp->peers->number;
254#if (NGX_HTTP_SSL)
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000255 r->upstream->peer.set_session =
256 ngx_http_upstream_set_round_robin_peer_session;
257 r->upstream->peer.save_session =
258 ngx_http_upstream_save_round_robin_peer_session;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000259#endif
260
261 return NGX_OK;
262}
263
264
265ngx_int_t
Igor Sysoev96dd8af2007-11-27 13:34:13 +0000266ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r,
267 ngx_http_upstream_resolved_t *ur)
268{
269 u_char *p;
270 size_t len;
271 ngx_uint_t i, n;
272 struct sockaddr_in *sin;
273 ngx_http_upstream_rr_peers_t *peers;
274 ngx_http_upstream_rr_peer_data_t *rrp;
275
276 rrp = r->upstream->peer.data;
277
278 if (rrp == NULL) {
279 rrp = ngx_palloc(r->pool, sizeof(ngx_http_upstream_rr_peer_data_t));
280 if (rrp == NULL) {
281 return NGX_ERROR;
282 }
283
284 r->upstream->peer.data = rrp;
285 }
286
287 peers = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_rr_peers_t)
288 + sizeof(ngx_http_upstream_rr_peer_t) * (ur->naddrs - 1));
289 if (peers == NULL) {
290 return NGX_ERROR;
291 }
292
293 peers->single = (ur->naddrs == 1);
294 peers->number = ur->naddrs;
295 peers->name = &ur->host;
296
Igor Sysoev302cedc2008-12-23 19:35:12 +0000297 if (ur->sockaddr) {
298 peers->peer[0].sockaddr = ur->sockaddr;
299 peers->peer[0].socklen = ur->socklen;
300 peers->peer[0].name = ur->host;
301 peers->peer[0].weight = 1;
302 peers->peer[0].current_weight = 1;
303 peers->peer[0].max_fails = 1;
304 peers->peer[0].fail_timeout = 10;
Igor Sysoev96dd8af2007-11-27 13:34:13 +0000305
Igor Sysoev302cedc2008-12-23 19:35:12 +0000306 } else {
Igor Sysoev96dd8af2007-11-27 13:34:13 +0000307
Igor Sysoev302cedc2008-12-23 19:35:12 +0000308 for (i = 0; i < ur->naddrs; i++) {
309
310 len = NGX_INET_ADDRSTRLEN + sizeof(":65536") - 1;
311
312 p = ngx_pnalloc(r->pool, len);
313 if (p == NULL) {
314 return NGX_ERROR;
315 }
316
317 len = ngx_inet_ntop(AF_INET, &ur->addrs[i], p, NGX_INET_ADDRSTRLEN);
318 len = ngx_sprintf(&p[len], ":%d", ur->port) - p;
319
320 sin = ngx_pcalloc(r->pool, sizeof(struct sockaddr_in));
321 if (sin == NULL) {
322 return NGX_ERROR;
323 }
324
325 sin->sin_family = AF_INET;
326 sin->sin_port = htons(ur->port);
327 sin->sin_addr.s_addr = ur->addrs[i];
328
329 peers->peer[i].sockaddr = (struct sockaddr *) sin;
330 peers->peer[i].socklen = sizeof(struct sockaddr_in);
331 peers->peer[i].name.len = len;
332 peers->peer[i].name.data = p;
333 peers->peer[i].weight = 1;
334 peers->peer[i].current_weight = 1;
335 peers->peer[i].max_fails = 1;
336 peers->peer[i].fail_timeout = 10;
Igor Sysoev96dd8af2007-11-27 13:34:13 +0000337 }
Igor Sysoev96dd8af2007-11-27 13:34:13 +0000338 }
339
340 rrp->peers = peers;
341 rrp->current = 0;
342
343 if (rrp->peers->number <= 8 * sizeof(uintptr_t)) {
344 rrp->tried = &rrp->data;
345 rrp->data = 0;
346
347 } else {
348 n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1))
349 / (8 * sizeof(uintptr_t));
350
351 rrp->tried = ngx_pcalloc(r->pool, n * sizeof(uintptr_t));
352 if (rrp->tried == NULL) {
353 return NGX_ERROR;
354 }
355 }
356
357 r->upstream->peer.get = ngx_http_upstream_get_round_robin_peer;
358 r->upstream->peer.free = ngx_http_upstream_free_round_robin_peer;
359 r->upstream->peer.tries = rrp->peers->number;
360#if (NGX_HTTP_SSL)
Igor Sysoev08b59752011-07-22 16:30:17 +0000361 r->upstream->peer.set_session = ngx_http_upstream_empty_set_session;
362 r->upstream->peer.save_session = ngx_http_upstream_empty_save_session;
Igor Sysoev96dd8af2007-11-27 13:34:13 +0000363#endif
364
365 return NGX_OK;
366}
367
368
369ngx_int_t
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000370ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data)
371{
372 ngx_http_upstream_rr_peer_data_t *rrp = data;
373
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000374 time_t now;
375 uintptr_t m;
376 ngx_int_t rc;
377 ngx_uint_t i, n;
378 ngx_connection_t *c;
379 ngx_http_upstream_rr_peer_t *peer;
380 ngx_http_upstream_rr_peers_t *peers;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000381
382 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
383 "get rr peer, try: %ui", pc->tries);
384
385 now = ngx_time();
386
387 /* ngx_lock_mutex(rrp->peers->mutex); */
388
389 if (rrp->peers->last_cached) {
390
391 /* cached connection */
392
393 c = rrp->peers->cached[rrp->peers->last_cached];
394 rrp->peers->last_cached--;
395
396 /* ngx_unlock_mutex(ppr->peers->mutex); */
397
398#if (NGX_THREADS)
399 c->read->lock = c->read->own_lock;
400 c->write->lock = c->write->own_lock;
401#endif
402
403 pc->connection = c;
404 pc->cached = 1;
405
406 return NGX_OK;
407 }
408
409 pc->cached = 0;
410 pc->connection = NULL;
411
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000412 if (rrp->peers->single) {
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000413 peer = &rrp->peers->peer[0];
414
415 } else {
416
417 /* there are several peers */
418
419 if (pc->tries == rrp->peers->number) {
420
421 /* it's a first try - get a current peer */
422
Igor Sysoev012f2312007-08-24 15:58:13 +0000423 i = pc->tries;
424
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000425 for ( ;; ) {
Igor Sysoevd12a5712007-07-28 16:04:01 +0000426 rrp->current = ngx_http_upstream_get_peer(rrp->peers);
427
428 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
429 "get rr peer, current: %ui %i",
430 rrp->current,
431 rrp->peers->peer[rrp->current].current_weight);
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000432
433 n = rrp->current / (8 * sizeof(uintptr_t));
Igor Sysoev0687cb92007-05-21 13:48:14 +0000434 m = (uintptr_t) 1 << rrp->current % (8 * sizeof(uintptr_t));
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000435
436 if (!(rrp->tried[n] & m)) {
437 peer = &rrp->peers->peer[rrp->current];
438
439 if (!peer->down) {
440
441 if (peer->max_fails == 0
442 || peer->fails < peer->max_fails)
443 {
444 break;
445 }
446
Maxim Douninb713e482011-10-12 14:22:48 +0000447 if (now - peer->checked > peer->fail_timeout) {
448 peer->checked = now;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000449 break;
450 }
451
Igor Sysoevd12a5712007-07-28 16:04:01 +0000452 peer->current_weight = 0;
453
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000454 } else {
455 rrp->tried[n] |= m;
456 }
457
458 pc->tries--;
459 }
460
Igor Sysoev012f2312007-08-24 15:58:13 +0000461 if (pc->tries == 0) {
462 goto failed;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000463 }
464
Igor Sysoev012f2312007-08-24 15:58:13 +0000465 if (--i == 0) {
466 ngx_log_error(NGX_LOG_ALERT, pc->log, 0,
467 "round robin upstream stuck on %ui tries",
468 pc->tries);
469 goto failed;
470 }
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000471 }
472
473 peer->current_weight--;
474
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000475 } else {
Igor Sysoev012f2312007-08-24 15:58:13 +0000476
477 i = pc->tries;
478
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000479 for ( ;; ) {
480 n = rrp->current / (8 * sizeof(uintptr_t));
Igor Sysoev0687cb92007-05-21 13:48:14 +0000481 m = (uintptr_t) 1 << rrp->current % (8 * sizeof(uintptr_t));
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000482
483 if (!(rrp->tried[n] & m)) {
484
485 peer = &rrp->peers->peer[rrp->current];
486
487 if (!peer->down) {
488
489 if (peer->max_fails == 0
490 || peer->fails < peer->max_fails)
491 {
492 break;
493 }
494
Maxim Douninb713e482011-10-12 14:22:48 +0000495 if (now - peer->checked > peer->fail_timeout) {
496 peer->checked = now;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000497 break;
498 }
499
Igor Sysoevd12a5712007-07-28 16:04:01 +0000500 peer->current_weight = 0;
501
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000502 } else {
503 rrp->tried[n] |= m;
504 }
505
506 pc->tries--;
507 }
508
509 rrp->current++;
510
511 if (rrp->current >= rrp->peers->number) {
512 rrp->current = 0;
513 }
514
Igor Sysoev012f2312007-08-24 15:58:13 +0000515 if (pc->tries == 0) {
516 goto failed;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000517 }
518
Igor Sysoev012f2312007-08-24 15:58:13 +0000519 if (--i == 0) {
520 ngx_log_error(NGX_LOG_ALERT, pc->log, 0,
521 "round robin upstream stuck on %ui tries",
522 pc->tries);
523 goto failed;
524 }
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000525 }
526
527 peer->current_weight--;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000528 }
529
530 rrp->tried[n] |= m;
531 }
532
533 pc->sockaddr = peer->sockaddr;
534 pc->socklen = peer->socklen;
535 pc->name = &peer->name;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000536
537 /* ngx_unlock_mutex(rrp->peers->mutex); */
538
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000539 if (pc->tries == 1 && rrp->peers->next) {
540 pc->tries += rrp->peers->next->number;
541
542 n = rrp->peers->next->number / (8 * sizeof(uintptr_t)) + 1;
Igor Sysoevcc076092007-08-14 13:35:52 +0000543 for (i = 0; i < n; i++) {
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000544 rrp->tried[i] = 0;
545 }
546 }
547
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000548 return NGX_OK;
549
550failed:
551
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000552 peers = rrp->peers;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000553
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000554 if (peers->next) {
555
556 /* ngx_unlock_mutex(peers->mutex); */
557
558 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, "backup servers");
559
560 rrp->peers = peers->next;
561 pc->tries = rrp->peers->number;
562
563 n = rrp->peers->number / (8 * sizeof(uintptr_t)) + 1;
Igor Sysoevcc076092007-08-14 13:35:52 +0000564 for (i = 0; i < n; i++) {
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000565 rrp->tried[i] = 0;
566 }
567
568 rc = ngx_http_upstream_get_round_robin_peer(pc, rrp);
569
570 if (rc != NGX_BUSY) {
571 return rc;
572 }
573
574 /* ngx_lock_mutex(peers->mutex); */
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000575 }
576
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000577 /* all peers failed, mark them as live for quick recovery */
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000578
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000579 for (i = 0; i < peers->number; i++) {
580 peers->peer[i].fails = 0;
581 }
582
583 /* ngx_unlock_mutex(peers->mutex); */
584
585 pc->name = peers->name;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000586
587 return NGX_BUSY;
588}
589
590
Igor Sysoevd12a5712007-07-28 16:04:01 +0000591static ngx_uint_t
592ngx_http_upstream_get_peer(ngx_http_upstream_rr_peers_t *peers)
593{
Maxim Dounin624fbe92011-08-18 16:52:38 +0000594 ngx_uint_t i, n, reset = 0;
Igor Sysoevd12a5712007-07-28 16:04:01 +0000595 ngx_http_upstream_rr_peer_t *peer;
596
597 peer = &peers->peer[0];
598
599 for ( ;; ) {
600
601 for (i = 0; i < peers->number; i++) {
602
603 if (peer[i].current_weight <= 0) {
604 continue;
605 }
606
607 n = i;
608
609 while (i < peers->number - 1) {
610
611 i++;
612
613 if (peer[i].current_weight <= 0) {
614 continue;
615 }
616
617 if (peer[n].current_weight * 1000 / peer[i].current_weight
Igor Sysoevfcd9dda2007-09-09 18:23:21 +0000618 > peer[n].weight * 1000 / peer[i].weight)
Igor Sysoevd12a5712007-07-28 16:04:01 +0000619 {
620 return n;
621 }
622
623 n = i;
624 }
625
626 if (peer[i].current_weight > 0) {
627 n = i;
628 }
629
630 return n;
631 }
632
Maxim Dounin624fbe92011-08-18 16:52:38 +0000633 if (reset++) {
634 return 0;
635 }
636
Igor Sysoevd12a5712007-07-28 16:04:01 +0000637 for (i = 0; i < peers->number; i++) {
Igor Sysoev665b9fd2008-02-11 14:31:38 +0000638 peer[i].current_weight = peer[i].weight;
Igor Sysoevd12a5712007-07-28 16:04:01 +0000639 }
640 }
641}
642
643
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000644void
645ngx_http_upstream_free_round_robin_peer(ngx_peer_connection_t *pc, void *data,
646 ngx_uint_t state)
647{
648 ngx_http_upstream_rr_peer_data_t *rrp = data;
649
650 time_t now;
651 ngx_http_upstream_rr_peer_t *peer;
652
653 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
654 "free rr peer %ui %ui", pc->tries, state);
655
656 if (state == 0 && pc->tries == 0) {
657 return;
658 }
659
660 /* TODO: NGX_PEER_KEEPALIVE */
661
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000662 if (rrp->peers->single) {
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000663 pc->tries = 0;
664 return;
665 }
666
Maxim Douninb713e482011-10-12 14:22:48 +0000667 peer = &rrp->peers->peer[rrp->current];
668
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000669 if (state & NGX_PEER_FAILED) {
670 now = ngx_time();
671
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000672 /* ngx_lock_mutex(rrp->peers->mutex); */
673
674 peer->fails++;
675 peer->accessed = now;
Maxim Douninb713e482011-10-12 14:22:48 +0000676 peer->checked = now;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000677
Igor Sysoev333723e2008-08-26 14:34:16 +0000678 if (peer->max_fails) {
679 peer->current_weight -= peer->weight / peer->max_fails;
680 }
Igor Sysoevd12a5712007-07-28 16:04:01 +0000681
682 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
683 "free rr peer failed: %ui %i",
684 rrp->current, peer->current_weight);
685
686 if (peer->current_weight < 0) {
687 peer->current_weight = 0;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000688 }
689
690 /* ngx_unlock_mutex(rrp->peers->mutex); */
Maxim Douninb713e482011-10-12 14:22:48 +0000691
692 } else {
693
694 /* mark peer live if check passed */
695
696 if (peer->accessed < peer->checked) {
697 peer->fails = 0;
698 }
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000699 }
700
701 rrp->current++;
702
703 if (rrp->current >= rrp->peers->number) {
704 rrp->current = 0;
705 }
706
707 if (pc->tries) {
708 pc->tries--;
709 }
710
711 /* ngx_unlock_mutex(rrp->peers->mutex); */
712}
713
714
715#if (NGX_HTTP_SSL)
716
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000717ngx_int_t
718ngx_http_upstream_set_round_robin_peer_session(ngx_peer_connection_t *pc,
719 void *data)
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000720{
721 ngx_http_upstream_rr_peer_data_t *rrp = data;
722
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000723 ngx_int_t rc;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000724 ngx_ssl_session_t *ssl_session;
725 ngx_http_upstream_rr_peer_t *peer;
726
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000727 peer = &rrp->peers->peer[rrp->current];
728
729 /* TODO: threads only mutex */
730 /* ngx_lock_mutex(rrp->peers->mutex); */
731
732 ssl_session = peer->ssl_session;
733
734 rc = ngx_ssl_set_session(pc->connection, ssl_session);
735
736 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
Igor Sysoevb3dd3fd2007-08-31 12:13:12 +0000737 "set session: %p:%d",
738 ssl_session, ssl_session ? ssl_session->references : 0);
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000739
740 /* ngx_unlock_mutex(rrp->peers->mutex); */
741
742 return rc;
743}
744
745
746void
747ngx_http_upstream_save_round_robin_peer_session(ngx_peer_connection_t *pc,
748 void *data)
749{
750 ngx_http_upstream_rr_peer_data_t *rrp = data;
751
752 ngx_ssl_session_t *old_ssl_session, *ssl_session;
753 ngx_http_upstream_rr_peer_t *peer;
754
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000755 ssl_session = ngx_ssl_get_session(pc->connection);
756
757 if (ssl_session == NULL) {
758 return;
759 }
760
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000761 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
Igor Sysoevb3dd3fd2007-08-31 12:13:12 +0000762 "save session: %p:%d", ssl_session, ssl_session->references);
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000763
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000764 peer = &rrp->peers->peer[rrp->current];
765
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000766 /* TODO: threads only mutex */
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000767 /* ngx_lock_mutex(rrp->peers->mutex); */
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000768
769 old_ssl_session = peer->ssl_session;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000770 peer->ssl_session = ssl_session;
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000771
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000772 /* ngx_unlock_mutex(rrp->peers->mutex); */
773
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000774 if (old_ssl_session) {
775
776 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
Igor Sysoevb3dd3fd2007-08-31 12:13:12 +0000777 "old session: %p:%d",
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000778 old_ssl_session, old_ssl_session->references);
779
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000780 /* TODO: may block */
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000781
782 ngx_ssl_free_session(old_ssl_session);
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000783 }
784}
785
Igor Sysoev08b59752011-07-22 16:30:17 +0000786
787static ngx_int_t
788ngx_http_upstream_empty_set_session(ngx_peer_connection_t *pc, void *data)
789{
790 return NGX_OK;
791}
792
793
794static void
795ngx_http_upstream_empty_save_session(ngx_peer_connection_t *pc, void *data)
796{
797 return;
798}
799
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000800#endif