Update and clean Tomato RAF files
[tomato.git] / release / src / router / nginx / src / http / ngx_http_upstream_round_robin.c
blobd786ed14254bc6eeb11458ef8c32f101f8e61a9f
2 /*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
5 */
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 #include <ngx_http.h>
13 static ngx_http_upstream_rr_peer_t *ngx_http_upstream_get_peer(
14 ngx_http_upstream_rr_peer_data_t *rrp);
16 #if (NGX_HTTP_SSL)
18 static ngx_int_t ngx_http_upstream_empty_set_session(ngx_peer_connection_t *pc,
19 void *data);
20 static void ngx_http_upstream_empty_save_session(ngx_peer_connection_t *pc,
21 void *data);
23 #endif
26 ngx_int_t
27 ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
28 ngx_http_upstream_srv_conf_t *us)
30 ngx_url_t u;
31 ngx_uint_t i, j, n, w;
32 ngx_http_upstream_server_t *server;
33 ngx_http_upstream_rr_peers_t *peers, *backup;
35 us->peer.init = ngx_http_upstream_init_round_robin_peer;
37 if (us->servers) {
38 server = us->servers->elts;
40 n = 0;
41 w = 0;
43 for (i = 0; i < us->servers->nelts; i++) {
44 if (server[i].backup) {
45 continue;
48 n += server[i].naddrs;
49 w += server[i].naddrs * server[i].weight;
52 if (n == 0) {
53 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
54 "no servers in upstream \"%V\" in %s:%ui",
55 &us->host, us->file_name, us->line);
56 return NGX_ERROR;
59 peers = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t)
60 + sizeof(ngx_http_upstream_rr_peer_t) * (n - 1));
61 if (peers == NULL) {
62 return NGX_ERROR;
65 peers->single = (n == 1);
66 peers->number = n;
67 peers->weighted = (w != n);
68 peers->total_weight = w;
69 peers->name = &us->host;
71 n = 0;
73 for (i = 0; i < us->servers->nelts; i++) {
74 for (j = 0; j < server[i].naddrs; j++) {
75 if (server[i].backup) {
76 continue;
79 peers->peer[n].sockaddr = server[i].addrs[j].sockaddr;
80 peers->peer[n].socklen = server[i].addrs[j].socklen;
81 peers->peer[n].name = server[i].addrs[j].name;
82 peers->peer[n].max_fails = server[i].max_fails;
83 peers->peer[n].fail_timeout = server[i].fail_timeout;
84 peers->peer[n].down = server[i].down;
85 peers->peer[n].weight = server[i].weight;
86 peers->peer[n].effective_weight = server[i].weight;
87 peers->peer[n].current_weight = 0;
88 n++;
92 us->peer.data = peers;
94 /* backup servers */
96 n = 0;
97 w = 0;
99 for (i = 0; i < us->servers->nelts; i++) {
100 if (!server[i].backup) {
101 continue;
104 n += server[i].naddrs;
105 w += server[i].naddrs * server[i].weight;
108 if (n == 0) {
109 return NGX_OK;
112 backup = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t)
113 + sizeof(ngx_http_upstream_rr_peer_t) * (n - 1));
114 if (backup == NULL) {
115 return NGX_ERROR;
118 peers->single = 0;
119 backup->single = 0;
120 backup->number = n;
121 backup->weighted = (w != n);
122 backup->total_weight = w;
123 backup->name = &us->host;
125 n = 0;
127 for (i = 0; i < us->servers->nelts; i++) {
128 for (j = 0; j < server[i].naddrs; j++) {
129 if (!server[i].backup) {
130 continue;
133 backup->peer[n].sockaddr = server[i].addrs[j].sockaddr;
134 backup->peer[n].socklen = server[i].addrs[j].socklen;
135 backup->peer[n].name = server[i].addrs[j].name;
136 backup->peer[n].weight = server[i].weight;
137 backup->peer[n].effective_weight = server[i].weight;
138 backup->peer[n].current_weight = 0;
139 backup->peer[n].max_fails = server[i].max_fails;
140 backup->peer[n].fail_timeout = server[i].fail_timeout;
141 backup->peer[n].down = server[i].down;
142 n++;
146 peers->next = backup;
148 return NGX_OK;
152 /* an upstream implicitly defined by proxy_pass, etc. */
154 if (us->port == 0) {
155 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
156 "no port in upstream \"%V\" in %s:%ui",
157 &us->host, us->file_name, us->line);
158 return NGX_ERROR;
161 ngx_memzero(&u, sizeof(ngx_url_t));
163 u.host = us->host;
164 u.port = us->port;
166 if (ngx_inet_resolve_host(cf->pool, &u) != NGX_OK) {
167 if (u.err) {
168 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
169 "%s in upstream \"%V\" in %s:%ui",
170 u.err, &us->host, us->file_name, us->line);
173 return NGX_ERROR;
176 n = u.naddrs;
178 peers = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t)
179 + sizeof(ngx_http_upstream_rr_peer_t) * (n - 1));
180 if (peers == NULL) {
181 return NGX_ERROR;
184 peers->single = (n == 1);
185 peers->number = n;
186 peers->weighted = 0;
187 peers->total_weight = n;
188 peers->name = &us->host;
190 for (i = 0; i < u.naddrs; i++) {
191 peers->peer[i].sockaddr = u.addrs[i].sockaddr;
192 peers->peer[i].socklen = u.addrs[i].socklen;
193 peers->peer[i].name = u.addrs[i].name;
194 peers->peer[i].weight = 1;
195 peers->peer[i].effective_weight = 1;
196 peers->peer[i].current_weight = 0;
197 peers->peer[i].max_fails = 1;
198 peers->peer[i].fail_timeout = 10;
201 us->peer.data = peers;
203 /* implicitly defined upstream has no backup servers */
205 return NGX_OK;
209 ngx_int_t
210 ngx_http_upstream_init_round_robin_peer(ngx_http_request_t *r,
211 ngx_http_upstream_srv_conf_t *us)
213 ngx_uint_t n;
214 ngx_http_upstream_rr_peer_data_t *rrp;
216 rrp = r->upstream->peer.data;
218 if (rrp == NULL) {
219 rrp = ngx_palloc(r->pool, sizeof(ngx_http_upstream_rr_peer_data_t));
220 if (rrp == NULL) {
221 return NGX_ERROR;
224 r->upstream->peer.data = rrp;
227 rrp->peers = us->peer.data;
228 rrp->current = 0;
230 n = rrp->peers->number;
232 if (rrp->peers->next && rrp->peers->next->number > n) {
233 n = rrp->peers->next->number;
236 if (n <= 8 * sizeof(uintptr_t)) {
237 rrp->tried = &rrp->data;
238 rrp->data = 0;
240 } else {
241 n = (n + (8 * sizeof(uintptr_t) - 1)) / (8 * sizeof(uintptr_t));
243 rrp->tried = ngx_pcalloc(r->pool, n * sizeof(uintptr_t));
244 if (rrp->tried == NULL) {
245 return NGX_ERROR;
249 r->upstream->peer.get = ngx_http_upstream_get_round_robin_peer;
250 r->upstream->peer.free = ngx_http_upstream_free_round_robin_peer;
251 r->upstream->peer.tries = rrp->peers->number;
252 #if (NGX_HTTP_SSL)
253 r->upstream->peer.set_session =
254 ngx_http_upstream_set_round_robin_peer_session;
255 r->upstream->peer.save_session =
256 ngx_http_upstream_save_round_robin_peer_session;
257 #endif
259 return NGX_OK;
263 ngx_int_t
264 ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r,
265 ngx_http_upstream_resolved_t *ur)
267 u_char *p;
268 size_t len;
269 ngx_uint_t i, n;
270 struct sockaddr_in *sin;
271 ngx_http_upstream_rr_peers_t *peers;
272 ngx_http_upstream_rr_peer_data_t *rrp;
274 rrp = r->upstream->peer.data;
276 if (rrp == NULL) {
277 rrp = ngx_palloc(r->pool, sizeof(ngx_http_upstream_rr_peer_data_t));
278 if (rrp == NULL) {
279 return NGX_ERROR;
282 r->upstream->peer.data = rrp;
285 peers = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_rr_peers_t)
286 + sizeof(ngx_http_upstream_rr_peer_t) * (ur->naddrs - 1));
287 if (peers == NULL) {
288 return NGX_ERROR;
291 peers->single = (ur->naddrs == 1);
292 peers->number = ur->naddrs;
293 peers->name = &ur->host;
295 if (ur->sockaddr) {
296 peers->peer[0].sockaddr = ur->sockaddr;
297 peers->peer[0].socklen = ur->socklen;
298 peers->peer[0].name = ur->host;
299 peers->peer[0].weight = 1;
300 peers->peer[0].effective_weight = 1;
301 peers->peer[0].current_weight = 0;
302 peers->peer[0].max_fails = 1;
303 peers->peer[0].fail_timeout = 10;
305 } else {
307 for (i = 0; i < ur->naddrs; i++) {
309 len = NGX_INET_ADDRSTRLEN + sizeof(":65536") - 1;
311 p = ngx_pnalloc(r->pool, len);
312 if (p == NULL) {
313 return NGX_ERROR;
316 len = ngx_inet_ntop(AF_INET, &ur->addrs[i], p, NGX_INET_ADDRSTRLEN);
317 len = ngx_sprintf(&p[len], ":%d", ur->port) - p;
319 sin = ngx_pcalloc(r->pool, sizeof(struct sockaddr_in));
320 if (sin == NULL) {
321 return NGX_ERROR;
324 sin->sin_family = AF_INET;
325 sin->sin_port = htons(ur->port);
326 sin->sin_addr.s_addr = ur->addrs[i];
328 peers->peer[i].sockaddr = (struct sockaddr *) sin;
329 peers->peer[i].socklen = sizeof(struct sockaddr_in);
330 peers->peer[i].name.len = len;
331 peers->peer[i].name.data = p;
332 peers->peer[i].weight = 1;
333 peers->peer[i].effective_weight = 1;
334 peers->peer[i].current_weight = 0;
335 peers->peer[i].max_fails = 1;
336 peers->peer[i].fail_timeout = 10;
340 rrp->peers = peers;
341 rrp->current = 0;
343 if (rrp->peers->number <= 8 * sizeof(uintptr_t)) {
344 rrp->tried = &rrp->data;
345 rrp->data = 0;
347 } else {
348 n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1))
349 / (8 * sizeof(uintptr_t));
351 rrp->tried = ngx_pcalloc(r->pool, n * sizeof(uintptr_t));
352 if (rrp->tried == NULL) {
353 return NGX_ERROR;
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)
361 r->upstream->peer.set_session = ngx_http_upstream_empty_set_session;
362 r->upstream->peer.save_session = ngx_http_upstream_empty_save_session;
363 #endif
365 return NGX_OK;
369 ngx_int_t
370 ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data)
372 ngx_http_upstream_rr_peer_data_t *rrp = data;
374 ngx_int_t rc;
375 ngx_uint_t i, n;
376 ngx_http_upstream_rr_peer_t *peer;
377 ngx_http_upstream_rr_peers_t *peers;
379 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
380 "get rr peer, try: %ui", pc->tries);
382 /* ngx_lock_mutex(rrp->peers->mutex); */
384 pc->cached = 0;
385 pc->connection = NULL;
387 if (rrp->peers->single) {
388 peer = &rrp->peers->peer[0];
390 if (peer->down) {
391 goto failed;
394 } else {
396 /* there are several peers */
398 peer = ngx_http_upstream_get_peer(rrp);
400 if (peer == NULL) {
401 goto failed;
404 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
405 "get rr peer, current: %ui %i",
406 rrp->current, peer->current_weight);
409 pc->sockaddr = peer->sockaddr;
410 pc->socklen = peer->socklen;
411 pc->name = &peer->name;
413 /* ngx_unlock_mutex(rrp->peers->mutex); */
415 if (pc->tries == 1 && rrp->peers->next) {
416 pc->tries += rrp->peers->next->number;
419 return NGX_OK;
421 failed:
423 peers = rrp->peers;
425 if (peers->next) {
427 /* ngx_unlock_mutex(peers->mutex); */
429 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, "backup servers");
431 rrp->peers = peers->next;
432 pc->tries = rrp->peers->number;
434 n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1))
435 / (8 * sizeof(uintptr_t));
437 for (i = 0; i < n; i++) {
438 rrp->tried[i] = 0;
441 rc = ngx_http_upstream_get_round_robin_peer(pc, rrp);
443 if (rc != NGX_BUSY) {
444 return rc;
447 /* ngx_lock_mutex(peers->mutex); */
450 /* all peers failed, mark them as live for quick recovery */
452 for (i = 0; i < peers->number; i++) {
453 peers->peer[i].fails = 0;
456 /* ngx_unlock_mutex(peers->mutex); */
458 pc->name = peers->name;
460 return NGX_BUSY;
464 static ngx_http_upstream_rr_peer_t *
465 ngx_http_upstream_get_peer(ngx_http_upstream_rr_peer_data_t *rrp)
467 time_t now;
468 uintptr_t m;
469 ngx_int_t total;
470 ngx_uint_t i, n;
471 ngx_http_upstream_rr_peer_t *peer, *best;
473 now = ngx_time();
475 best = NULL;
476 total = 0;
478 for (i = 0; i < rrp->peers->number; i++) {
480 n = i / (8 * sizeof(uintptr_t));
481 m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t));
483 if (rrp->tried[n] & m) {
484 continue;
487 peer = &rrp->peers->peer[i];
489 if (peer->down) {
490 continue;
493 if (peer->max_fails
494 && peer->fails >= peer->max_fails
495 && now - peer->checked <= peer->fail_timeout)
497 continue;
500 peer->current_weight += peer->effective_weight;
501 total += peer->effective_weight;
503 if (peer->effective_weight < peer->weight) {
504 peer->effective_weight++;
507 if (best == NULL || peer->current_weight > best->current_weight) {
508 best = peer;
512 if (best == NULL) {
513 return NULL;
516 i = best - &rrp->peers->peer[0];
518 rrp->current = i;
520 n = i / (8 * sizeof(uintptr_t));
521 m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t));
523 rrp->tried[n] |= m;
525 best->current_weight -= total;
526 best->checked = now;
528 return best;
532 void
533 ngx_http_upstream_free_round_robin_peer(ngx_peer_connection_t *pc, void *data,
534 ngx_uint_t state)
536 ngx_http_upstream_rr_peer_data_t *rrp = data;
538 time_t now;
539 ngx_http_upstream_rr_peer_t *peer;
541 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
542 "free rr peer %ui %ui", pc->tries, state);
544 /* TODO: NGX_PEER_KEEPALIVE */
546 if (rrp->peers->single) {
547 pc->tries = 0;
548 return;
551 peer = &rrp->peers->peer[rrp->current];
553 if (state & NGX_PEER_FAILED) {
554 now = ngx_time();
556 /* ngx_lock_mutex(rrp->peers->mutex); */
558 peer->fails++;
559 peer->accessed = now;
560 peer->checked = now;
562 if (peer->max_fails) {
563 peer->effective_weight -= peer->weight / peer->max_fails;
566 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
567 "free rr peer failed: %ui %i",
568 rrp->current, peer->effective_weight);
570 if (peer->effective_weight < 0) {
571 peer->effective_weight = 0;
574 /* ngx_unlock_mutex(rrp->peers->mutex); */
576 } else {
578 /* mark peer live if check passed */
580 if (peer->accessed < peer->checked) {
581 peer->fails = 0;
585 if (pc->tries) {
586 pc->tries--;
589 /* ngx_unlock_mutex(rrp->peers->mutex); */
593 #if (NGX_HTTP_SSL)
595 ngx_int_t
596 ngx_http_upstream_set_round_robin_peer_session(ngx_peer_connection_t *pc,
597 void *data)
599 ngx_http_upstream_rr_peer_data_t *rrp = data;
601 ngx_int_t rc;
602 ngx_ssl_session_t *ssl_session;
603 ngx_http_upstream_rr_peer_t *peer;
605 peer = &rrp->peers->peer[rrp->current];
607 /* TODO: threads only mutex */
608 /* ngx_lock_mutex(rrp->peers->mutex); */
610 ssl_session = peer->ssl_session;
612 rc = ngx_ssl_set_session(pc->connection, ssl_session);
614 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
615 "set session: %p:%d",
616 ssl_session, ssl_session ? ssl_session->references : 0);
618 /* ngx_unlock_mutex(rrp->peers->mutex); */
620 return rc;
624 void
625 ngx_http_upstream_save_round_robin_peer_session(ngx_peer_connection_t *pc,
626 void *data)
628 ngx_http_upstream_rr_peer_data_t *rrp = data;
630 ngx_ssl_session_t *old_ssl_session, *ssl_session;
631 ngx_http_upstream_rr_peer_t *peer;
633 ssl_session = ngx_ssl_get_session(pc->connection);
635 if (ssl_session == NULL) {
636 return;
639 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
640 "save session: %p:%d", ssl_session, ssl_session->references);
642 peer = &rrp->peers->peer[rrp->current];
644 /* TODO: threads only mutex */
645 /* ngx_lock_mutex(rrp->peers->mutex); */
647 old_ssl_session = peer->ssl_session;
648 peer->ssl_session = ssl_session;
650 /* ngx_unlock_mutex(rrp->peers->mutex); */
652 if (old_ssl_session) {
654 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
655 "old session: %p:%d",
656 old_ssl_session, old_ssl_session->references);
658 /* TODO: may block */
660 ngx_ssl_free_session(old_ssl_session);
665 static ngx_int_t
666 ngx_http_upstream_empty_set_session(ngx_peer_connection_t *pc, void *data)
668 return NGX_OK;
672 static void
673 ngx_http_upstream_empty_save_session(ngx_peer_connection_t *pc, void *data)
675 return;
678 #endif