src/http/ngx_http_upstream_round_robin.c - nginx source code

Functions defined

Macros defined

Source code


  1. /*
  2. * Copyright (C) Igor Sysoev
  3. * Copyright (C) Nginx, Inc.
  4. */


  5. #include <ngx_config.h>
  6. #include <ngx_core.h>
  7. #include <ngx_http.h>


  8. #define ngx_http_upstream_tries(p) ((p)->tries                                \
  9.                                     + ((p)->next ? (p)->next->tries : 0))


  10. static ngx_http_upstream_rr_peer_t *ngx_http_upstream_get_peer(
  11.     ngx_http_upstream_rr_peer_data_t *rrp);

  12. #if (NGX_HTTP_SSL)

  13. static ngx_int_t ngx_http_upstream_empty_set_session(ngx_peer_connection_t *pc,
  14.     void *data);
  15. static void ngx_http_upstream_empty_save_session(ngx_peer_connection_t *pc,
  16.     void *data);

  17. #endif


  18. ngx_int_t
  19. ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
  20.     ngx_http_upstream_srv_conf_t *us)
  21. {
  22.     ngx_url_t                      u;
  23.     ngx_uint_t                     i, j, n, r, w, t;
  24.     ngx_http_upstream_server_t    *server;
  25.     ngx_http_upstream_rr_peer_t   *peer, **peerp;
  26.     ngx_http_upstream_rr_peers_t  *peers, *backup;
  27. #if (NGX_HTTP_UPSTREAM_ZONE)
  28.     ngx_uint_t                     resolve;
  29.     ngx_http_core_loc_conf_t      *clcf;
  30.     ngx_http_upstream_rr_peer_t  **rpeerp;
  31. #endif

  32.     us->peer.init = ngx_http_upstream_init_round_robin_peer;

  33.     if (us->servers) {
  34.         server = us->servers->elts;

  35.         n = 0;
  36.         r = 0;
  37.         w = 0;
  38.         t = 0;

  39. #if (NGX_HTTP_UPSTREAM_ZONE)
  40.         resolve = 0;
  41. #endif

  42.         for (i = 0; i < us->servers->nelts; i++) {

  43. #if (NGX_HTTP_UPSTREAM_ZONE)
  44.             if (server[i].host.len) {
  45.                 resolve = 1;
  46.             }
  47. #endif

  48.             if (server[i].backup) {
  49.                 continue;
  50.             }

  51. #if (NGX_HTTP_UPSTREAM_ZONE)
  52.             if (server[i].host.len) {
  53.                 r++;
  54.                 continue;
  55.             }
  56. #endif

  57.             n += server[i].naddrs;
  58.             w += server[i].naddrs * server[i].weight;

  59.             if (!server[i].down) {
  60.                 t += server[i].naddrs;
  61.             }
  62.         }

  63. #if (NGX_HTTP_UPSTREAM_ZONE)
  64.         if (us->shm_zone) {

  65.             if (resolve && !(us->flags & NGX_HTTP_UPSTREAM_MODIFY)) {
  66.                 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
  67.                               "load balancing method does not support"
  68.                               " resolving names at run time in"
  69.                               " upstream \"%V\" in %s:%ui",
  70.                               &us->host, us->file_name, us->line);
  71.                 return NGX_ERROR;
  72.             }

  73.             clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);

  74.             if (us->resolver == NULL) {
  75.                 us->resolver = clcf->resolver;
  76.             }

  77.             /*
  78.              * Without "resolver_timeout" in http{} the merged value is unset.
  79.              */
  80.             ngx_conf_merge_msec_value(us->resolver_timeout,
  81.                                       clcf->resolver_timeout, 30000);

  82.             if (resolve
  83.                 && (us->resolver == NULL
  84.                     || us->resolver->connections.nelts == 0))
  85.             {
  86.                 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
  87.                               "no resolver defined to resolve names"
  88.                               " at run time in upstream \"%V\" in %s:%ui",
  89.                               &us->host, us->file_name, us->line);
  90.                 return NGX_ERROR;
  91.             }

  92.         } else if (resolve) {

  93.             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
  94.                           "resolving names at run time requires"
  95.                           " upstream \"%V\" in %s:%ui"
  96.                           " to be in shared memory",
  97.                           &us->host, us->file_name, us->line);
  98.             return NGX_ERROR;
  99.         }
  100. #endif

  101.         if (n + r == 0) {
  102.             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
  103.                           "no servers in upstream \"%V\" in %s:%ui",
  104.                           &us->host, us->file_name, us->line);
  105.             return NGX_ERROR;
  106.         }

  107.         peers = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t));
  108.         if (peers == NULL) {
  109.             return NGX_ERROR;
  110.         }

  111.         peer = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peer_t)
  112.                                      * (n + r));
  113.         if (peer == NULL) {
  114.             return NGX_ERROR;
  115.         }

  116.         peers->single = (n == 1);
  117.         peers->number = n;
  118.         peers->weighted = (w != n);
  119.         peers->total_weight = w;
  120.         peers->tries = t;
  121.         peers->name = &us->host;

  122.         n = 0;
  123.         peerp = &peers->peer;

  124. #if (NGX_HTTP_UPSTREAM_ZONE)
  125.         rpeerp = &peers->resolve;
  126. #endif

  127.         for (i = 0; i < us->servers->nelts; i++) {
  128.             if (server[i].backup) {
  129.                 continue;
  130.             }

  131. #if (NGX_HTTP_UPSTREAM_ZONE)
  132.             if (server[i].host.len) {

  133.                 peer[n].host = ngx_pcalloc(cf->pool,
  134.                                            sizeof(ngx_http_upstream_host_t));
  135.                 if (peer[n].host == NULL) {
  136.                     return NGX_ERROR;
  137.                 }

  138.                 peer[n].host->name = server[i].host;
  139.                 peer[n].host->service = server[i].service;

  140.                 peer[n].sockaddr = server[i].addrs[0].sockaddr;
  141.                 peer[n].socklen = server[i].addrs[0].socklen;
  142.                 peer[n].name = server[i].addrs[0].name;
  143.                 peer[n].weight = server[i].weight;
  144.                 peer[n].effective_weight = server[i].weight;
  145.                 peer[n].current_weight = 0;
  146.                 peer[n].max_conns = server[i].max_conns;
  147.                 peer[n].max_fails = server[i].max_fails;
  148.                 peer[n].fail_timeout = server[i].fail_timeout;
  149.                 peer[n].down = server[i].down;
  150.                 peer[n].server = server[i].name;

  151.                 *rpeerp = &peer[n];
  152.                 rpeerp = &peer[n].next;
  153.                 n++;

  154.                 continue;
  155.             }
  156. #endif

  157.             for (j = 0; j < server[i].naddrs; j++) {
  158.                 peer[n].sockaddr = server[i].addrs[j].sockaddr;
  159.                 peer[n].socklen = server[i].addrs[j].socklen;
  160.                 peer[n].name = server[i].addrs[j].name;
  161.                 peer[n].weight = server[i].weight;
  162.                 peer[n].effective_weight = server[i].weight;
  163.                 peer[n].current_weight = 0;
  164.                 peer[n].max_conns = server[i].max_conns;
  165.                 peer[n].max_fails = server[i].max_fails;
  166.                 peer[n].fail_timeout = server[i].fail_timeout;
  167.                 peer[n].down = server[i].down;
  168.                 peer[n].server = server[i].name;

  169.                 *peerp = &peer[n];
  170.                 peerp = &peer[n].next;
  171.                 n++;
  172.             }
  173.         }

  174.         us->peer.data = peers;

  175.         /* backup servers */

  176.         n = 0;
  177.         r = 0;
  178.         w = 0;
  179.         t = 0;

  180.         for (i = 0; i < us->servers->nelts; i++) {
  181.             if (!server[i].backup) {
  182.                 continue;
  183.             }

  184. #if (NGX_HTTP_UPSTREAM_ZONE)
  185.             if (server[i].host.len) {
  186.                 r++;
  187.                 continue;
  188.             }
  189. #endif

  190.             n += server[i].naddrs;
  191.             w += server[i].naddrs * server[i].weight;

  192.             if (!server[i].down) {
  193.                 t += server[i].naddrs;
  194.             }
  195.         }

  196.         if (n == 0
  197. #if (NGX_HTTP_UPSTREAM_ZONE)
  198.             && !resolve
  199. #endif
  200.         ) {
  201.             return NGX_OK;
  202.         }

  203.         if (n + r == 0 && !(us->flags & NGX_HTTP_UPSTREAM_BACKUP)) {
  204.             return NGX_OK;
  205.         }

  206.         backup = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t));
  207.         if (backup == NULL) {
  208.             return NGX_ERROR;
  209.         }

  210.         peer = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peer_t)
  211.                                      * (n + r));
  212.         if (peer == NULL) {
  213.             return NGX_ERROR;
  214.         }

  215.         if (n > 0) {
  216.             peers->single = 0;
  217.         }

  218.         backup->single = 0;
  219.         backup->number = n;
  220.         backup->weighted = (w != n);
  221.         backup->total_weight = w;
  222.         backup->tries = t;
  223.         backup->name = &us->host;

  224.         n = 0;
  225.         peerp = &backup->peer;

  226. #if (NGX_HTTP_UPSTREAM_ZONE)
  227.         rpeerp = &backup->resolve;
  228. #endif

  229.         for (i = 0; i < us->servers->nelts; i++) {
  230.             if (!server[i].backup) {
  231.                 continue;
  232.             }

  233. #if (NGX_HTTP_UPSTREAM_ZONE)
  234.             if (server[i].host.len) {

  235.                 peer[n].host = ngx_pcalloc(cf->pool,
  236.                                            sizeof(ngx_http_upstream_host_t));
  237.                 if (peer[n].host == NULL) {
  238.                     return NGX_ERROR;
  239.                 }

  240.                 peer[n].host->name = server[i].host;
  241.                 peer[n].host->service = server[i].service;

  242.                 peer[n].sockaddr = server[i].addrs[0].sockaddr;
  243.                 peer[n].socklen = server[i].addrs[0].socklen;
  244.                 peer[n].name = server[i].addrs[0].name;
  245.                 peer[n].weight = server[i].weight;
  246.                 peer[n].effective_weight = server[i].weight;
  247.                 peer[n].current_weight = 0;
  248.                 peer[n].max_conns = server[i].max_conns;
  249.                 peer[n].max_fails = server[i].max_fails;
  250.                 peer[n].fail_timeout = server[i].fail_timeout;
  251.                 peer[n].down = server[i].down;
  252.                 peer[n].server = server[i].name;

  253.                 *rpeerp = &peer[n];
  254.                 rpeerp = &peer[n].next;
  255.                 n++;

  256.                 continue;
  257.             }
  258. #endif

  259.             for (j = 0; j < server[i].naddrs; j++) {
  260.                 peer[n].sockaddr = server[i].addrs[j].sockaddr;
  261.                 peer[n].socklen = server[i].addrs[j].socklen;
  262.                 peer[n].name = server[i].addrs[j].name;
  263.                 peer[n].weight = server[i].weight;
  264.                 peer[n].effective_weight = server[i].weight;
  265.                 peer[n].current_weight = 0;
  266.                 peer[n].max_conns = server[i].max_conns;
  267.                 peer[n].max_fails = server[i].max_fails;
  268.                 peer[n].fail_timeout = server[i].fail_timeout;
  269.                 peer[n].down = server[i].down;
  270.                 peer[n].server = server[i].name;

  271.                 *peerp = &peer[n];
  272.                 peerp = &peer[n].next;
  273.                 n++;
  274.             }
  275.         }

  276.         peers->next = backup;

  277.         return NGX_OK;
  278.     }


  279.     /* an upstream implicitly defined by proxy_pass, etc. */

  280.     if (us->port == 0) {
  281.         ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
  282.                       "no port in upstream \"%V\" in %s:%ui",
  283.                       &us->host, us->file_name, us->line);
  284.         return NGX_ERROR;
  285.     }

  286.     ngx_memzero(&u, sizeof(ngx_url_t));

  287.     u.host = us->host;
  288.     u.port = us->port;

  289.     if (ngx_inet_resolve_host(cf->pool, &u) != NGX_OK) {
  290.         if (u.err) {
  291.             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
  292.                           "%s in upstream \"%V\" in %s:%ui",
  293.                           u.err, &us->host, us->file_name, us->line);
  294.         }

  295.         return NGX_ERROR;
  296.     }

  297.     n = u.naddrs;

  298.     peers = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t));
  299.     if (peers == NULL) {
  300.         return NGX_ERROR;
  301.     }

  302.     peer = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peer_t) * n);
  303.     if (peer == NULL) {
  304.         return NGX_ERROR;
  305.     }

  306.     peers->single = (n == 1);
  307.     peers->number = n;
  308.     peers->weighted = 0;
  309.     peers->total_weight = n;
  310.     peers->tries = n;
  311.     peers->name = &us->host;

  312.     peerp = &peers->peer;

  313.     for (i = 0; i < u.naddrs; i++) {
  314.         peer[i].sockaddr = u.addrs[i].sockaddr;
  315.         peer[i].socklen = u.addrs[i].socklen;
  316.         peer[i].name = u.addrs[i].name;
  317.         peer[i].weight = 1;
  318.         peer[i].effective_weight = 1;
  319.         peer[i].current_weight = 0;
  320.         peer[i].max_conns = 0;
  321.         peer[i].max_fails = 1;
  322.         peer[i].fail_timeout = 10;
  323.         *peerp = &peer[i];
  324.         peerp = &peer[i].next;
  325.     }

  326.     us->peer.data = peers;

  327.     /* implicitly defined upstream has no backup servers */

  328.     return NGX_OK;
  329. }


  330. ngx_int_t
  331. ngx_http_upstream_init_round_robin_peer(ngx_http_request_t *r,
  332.     ngx_http_upstream_srv_conf_t *us)
  333. {
  334.     ngx_uint_t                         n;
  335.     ngx_http_upstream_rr_peer_data_t  *rrp;

  336.     rrp = r->upstream->peer.data;

  337.     if (rrp == NULL) {
  338.         rrp = ngx_palloc(r->pool, sizeof(ngx_http_upstream_rr_peer_data_t));
  339.         if (rrp == NULL) {
  340.             return NGX_ERROR;
  341.         }

  342.         r->upstream->peer.data = rrp;
  343.     }

  344.     rrp->peers = us->peer.data;
  345.     rrp->current = NULL;

  346.     ngx_http_upstream_rr_peers_rlock(rrp->peers);

  347. #if (NGX_HTTP_UPSTREAM_ZONE)
  348.     rrp->config = rrp->peers->config ? *rrp->peers->config : 0;
  349. #endif

  350.     n = rrp->peers->number;

  351.     if (rrp->peers->next && rrp->peers->next->number > n) {
  352.         n = rrp->peers->next->number;
  353.     }

  354.     r->upstream->peer.tries = ngx_http_upstream_tries(rrp->peers);

  355.     ngx_http_upstream_rr_peers_unlock(rrp->peers);

  356.     if (n <= 8 * sizeof(uintptr_t)) {
  357.         rrp->tried = &rrp->data;
  358.         rrp->data = 0;

  359.     } else {
  360.         n = (n + (8 * sizeof(uintptr_t) - 1)) / (8 * sizeof(uintptr_t));

  361.         rrp->tried = ngx_pcalloc(r->pool, n * sizeof(uintptr_t));
  362.         if (rrp->tried == NULL) {
  363.             return NGX_ERROR;
  364.         }
  365.     }

  366.     r->upstream->peer.get = ngx_http_upstream_get_round_robin_peer;
  367.     r->upstream->peer.free = ngx_http_upstream_free_round_robin_peer;
  368. #if (NGX_HTTP_SSL)
  369.     r->upstream->peer.set_session =
  370.                                ngx_http_upstream_set_round_robin_peer_session;
  371.     r->upstream->peer.save_session =
  372.                                ngx_http_upstream_save_round_robin_peer_session;
  373. #endif

  374.     return NGX_OK;
  375. }


  376. ngx_int_t
  377. ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r,
  378.     ngx_http_upstream_resolved_t *ur)
  379. {
  380.     u_char                            *p;
  381.     size_t                             len;
  382.     socklen_t                          socklen;
  383.     ngx_uint_t                         i, n;
  384.     struct sockaddr                   *sockaddr;
  385.     ngx_http_upstream_rr_peer_t       *peer, **peerp;
  386.     ngx_http_upstream_rr_peers_t      *peers;
  387.     ngx_http_upstream_rr_peer_data_t  *rrp;

  388.     rrp = r->upstream->peer.data;

  389.     if (rrp == NULL) {
  390.         rrp = ngx_palloc(r->pool, sizeof(ngx_http_upstream_rr_peer_data_t));
  391.         if (rrp == NULL) {
  392.             return NGX_ERROR;
  393.         }

  394.         r->upstream->peer.data = rrp;
  395.     }

  396.     peers = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_rr_peers_t));
  397.     if (peers == NULL) {
  398.         return NGX_ERROR;
  399.     }

  400.     peer = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_rr_peer_t)
  401.                                 * ur->naddrs);
  402.     if (peer == NULL) {
  403.         return NGX_ERROR;
  404.     }

  405.     peers->single = (ur->naddrs == 1);
  406.     peers->number = ur->naddrs;
  407.     peers->tries = ur->naddrs;
  408.     peers->name = &ur->host;

  409.     if (ur->sockaddr) {
  410.         peer[0].sockaddr = ur->sockaddr;
  411.         peer[0].socklen = ur->socklen;
  412.         peer[0].name = ur->name.data ? ur->name : ur->host;
  413.         peer[0].weight = 1;
  414.         peer[0].effective_weight = 1;
  415.         peer[0].current_weight = 0;
  416.         peer[0].max_conns = 0;
  417.         peer[0].max_fails = 1;
  418.         peer[0].fail_timeout = 10;
  419.         peers->peer = peer;

  420.     } else {
  421.         peerp = &peers->peer;

  422.         for (i = 0; i < ur->naddrs; i++) {

  423.             socklen = ur->addrs[i].socklen;

  424.             sockaddr = ngx_palloc(r->pool, socklen);
  425.             if (sockaddr == NULL) {
  426.                 return NGX_ERROR;
  427.             }

  428.             ngx_memcpy(sockaddr, ur->addrs[i].sockaddr, socklen);
  429.             ngx_inet_set_port(sockaddr, ur->port);

  430.             p = ngx_pnalloc(r->pool, NGX_SOCKADDR_STRLEN);
  431.             if (p == NULL) {
  432.                 return NGX_ERROR;
  433.             }

  434.             len = ngx_sock_ntop(sockaddr, socklen, p, NGX_SOCKADDR_STRLEN, 1);

  435.             peer[i].sockaddr = sockaddr;
  436.             peer[i].socklen = socklen;
  437.             peer[i].name.len = len;
  438.             peer[i].name.data = p;
  439.             peer[i].weight = 1;
  440.             peer[i].effective_weight = 1;
  441.             peer[i].current_weight = 0;
  442.             peer[i].max_conns = 0;
  443.             peer[i].max_fails = 1;
  444.             peer[i].fail_timeout = 10;
  445.             *peerp = &peer[i];
  446.             peerp = &peer[i].next;
  447.         }
  448.     }

  449.     rrp->peers = peers;
  450.     rrp->current = NULL;
  451.     rrp->config = 0;

  452.     if (rrp->peers->number <= 8 * sizeof(uintptr_t)) {
  453.         rrp->tried = &rrp->data;
  454.         rrp->data = 0;

  455.     } else {
  456.         n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1))
  457.                 / (8 * sizeof(uintptr_t));

  458.         rrp->tried = ngx_pcalloc(r->pool, n * sizeof(uintptr_t));
  459.         if (rrp->tried == NULL) {
  460.             return NGX_ERROR;
  461.         }
  462.     }

  463.     r->upstream->peer.get = ngx_http_upstream_get_round_robin_peer;
  464.     r->upstream->peer.free = ngx_http_upstream_free_round_robin_peer;
  465.     r->upstream->peer.tries = ngx_http_upstream_tries(rrp->peers);
  466. #if (NGX_HTTP_SSL)
  467.     r->upstream->peer.set_session = ngx_http_upstream_empty_set_session;
  468.     r->upstream->peer.save_session = ngx_http_upstream_empty_save_session;
  469. #endif

  470.     return NGX_OK;
  471. }


  472. ngx_int_t
  473. ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data)
  474. {
  475.     ngx_http_upstream_rr_peer_data_t  *rrp = data;

  476.     ngx_int_t                      rc;
  477.     ngx_uint_t                     i, n;
  478.     ngx_http_upstream_rr_peer_t   *peer;
  479.     ngx_http_upstream_rr_peers_t  *peers;

  480.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
  481.                    "get rr peer, try: %ui", pc->tries);

  482.     pc->cached = 0;
  483.     pc->connection = NULL;

  484.     peers = rrp->peers;
  485.     ngx_http_upstream_rr_peers_wlock(peers);

  486. #if (NGX_HTTP_UPSTREAM_ZONE)
  487.     if (peers->config && rrp->config != *peers->config) {
  488.         goto busy;
  489.     }
  490. #endif

  491.     if (peers->single) {
  492.         peer = peers->peer;

  493.         if (peer->down) {
  494.             goto failed;
  495.         }

  496.         if (peer->max_conns && peer->conns >= peer->max_conns) {
  497.             goto failed;
  498.         }

  499.         rrp->current = peer;
  500.         ngx_http_upstream_rr_peer_ref(peers, peer);

  501.     } else {

  502.         /* there are several peers */

  503.         peer = ngx_http_upstream_get_peer(rrp);

  504.         if (peer == NULL) {
  505.             goto failed;
  506.         }

  507.         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
  508.                        "get rr peer, current: %p %i",
  509.                        peer, peer->current_weight);
  510.     }

  511.     pc->sockaddr = peer->sockaddr;
  512.     pc->socklen = peer->socklen;
  513.     pc->name = &peer->name;

  514.     peer->conns++;

  515.     ngx_http_upstream_rr_peers_unlock(peers);

  516.     return NGX_OK;

  517. failed:

  518.     if (peers->next) {

  519.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, "backup servers");

  520.         rrp->peers = peers->next;

  521.         n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1))
  522.                 / (8 * sizeof(uintptr_t));

  523.         for (i = 0; i < n; i++) {
  524.             rrp->tried[i] = 0;
  525.         }

  526.         ngx_http_upstream_rr_peers_unlock(peers);

  527.         rc = ngx_http_upstream_get_round_robin_peer(pc, rrp);

  528.         if (rc != NGX_BUSY) {
  529.             return rc;
  530.         }

  531.         ngx_http_upstream_rr_peers_wlock(peers);
  532.     }

  533. #if (NGX_HTTP_UPSTREAM_ZONE)
  534. busy:
  535. #endif

  536.     ngx_http_upstream_rr_peers_unlock(peers);

  537.     pc->name = peers->name;

  538.     return NGX_BUSY;
  539. }


  540. static ngx_http_upstream_rr_peer_t *
  541. ngx_http_upstream_get_peer(ngx_http_upstream_rr_peer_data_t *rrp)
  542. {
  543.     time_t                        now;
  544.     uintptr_t                     m;
  545.     ngx_int_t                     total;
  546.     ngx_uint_t                    i, n, p;
  547.     ngx_http_upstream_rr_peer_t  *peer, *best;

  548.     now = ngx_time();

  549.     best = NULL;
  550.     total = 0;

  551. #if (NGX_SUPPRESS_WARN)
  552.     p = 0;
  553. #endif

  554.     for (peer = rrp->peers->peer, i = 0;
  555.          peer;
  556.          peer = peer->next, i++)
  557.     {
  558.         n = i / (8 * sizeof(uintptr_t));
  559.         m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t));

  560.         if (rrp->tried[n] & m) {
  561.             continue;
  562.         }

  563.         if (peer->down) {
  564.             continue;
  565.         }

  566.         if (peer->max_fails
  567.             && peer->fails >= peer->max_fails
  568.             && now - peer->checked <= peer->fail_timeout)
  569.         {
  570.             continue;
  571.         }

  572.         if (peer->max_conns && peer->conns >= peer->max_conns) {
  573.             continue;
  574.         }

  575.         peer->current_weight += peer->effective_weight;
  576.         total += peer->effective_weight;

  577.         if (peer->effective_weight < peer->weight) {
  578.             peer->effective_weight++;
  579.         }

  580.         if (best == NULL || peer->current_weight > best->current_weight) {
  581.             best = peer;
  582.             p = i;
  583.         }
  584.     }

  585.     if (best == NULL) {
  586.         return NULL;
  587.     }

  588.     rrp->current = best;
  589.     ngx_http_upstream_rr_peer_ref(rrp->peers, best);

  590.     n = p / (8 * sizeof(uintptr_t));
  591.     m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t));

  592.     rrp->tried[n] |= m;

  593.     best->current_weight -= total;

  594.     if (now - best->checked > best->fail_timeout) {
  595.         best->checked = now;
  596.     }

  597.     return best;
  598. }


  599. void
  600. ngx_http_upstream_free_round_robin_peer(ngx_peer_connection_t *pc, void *data,
  601.     ngx_uint_t state)
  602. {
  603.     ngx_http_upstream_rr_peer_data_t  *rrp = data;

  604.     time_t                       now;
  605.     ngx_http_upstream_rr_peer_t  *peer;

  606.     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
  607.                    "free rr peer %ui %ui", pc->tries, state);

  608.     /* TODO: NGX_PEER_KEEPALIVE */

  609.     peer = rrp->current;

  610.     ngx_http_upstream_rr_peers_rlock(rrp->peers);
  611.     ngx_http_upstream_rr_peer_lock(rrp->peers, peer);

  612.     if (rrp->peers->single) {

  613.         if (peer->fails) {
  614.             peer->fails = 0;
  615.         }

  616.         peer->conns--;

  617.         if (ngx_http_upstream_rr_peer_unref(rrp->peers, peer) == NGX_OK) {
  618.             ngx_http_upstream_rr_peer_unlock(rrp->peers, peer);
  619.         }

  620.         ngx_http_upstream_rr_peers_unlock(rrp->peers);

  621.         pc->tries = 0;
  622.         return;
  623.     }

  624.     if (state & NGX_PEER_FAILED) {
  625.         now = ngx_time();

  626.         peer->fails++;
  627.         peer->accessed = now;
  628.         peer->checked = now;

  629.         if (peer->max_fails) {
  630.             peer->effective_weight -= peer->weight / peer->max_fails;

  631.             if (peer->fails >= peer->max_fails) {
  632.                 ngx_log_error(NGX_LOG_WARN, pc->log, 0,
  633.                               "upstream server temporarily disabled");
  634.             }
  635.         }

  636.         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
  637.                        "free rr peer failed: %p %i",
  638.                        peer, peer->effective_weight);

  639.         if (peer->effective_weight < 0) {
  640.             peer->effective_weight = 0;
  641.         }

  642.     } else {

  643.         /* mark peer live if check passed */

  644.         if (peer->accessed < peer->checked) {
  645.             peer->fails = 0;
  646.         }
  647.     }

  648.     peer->conns--;

  649.     if (ngx_http_upstream_rr_peer_unref(rrp->peers, peer) == NGX_OK) {
  650.         ngx_http_upstream_rr_peer_unlock(rrp->peers, peer);
  651.     }

  652.     ngx_http_upstream_rr_peers_unlock(rrp->peers);

  653.     if (pc->tries) {
  654.         pc->tries--;
  655.     }
  656. }


  657. #if (NGX_HTTP_SSL)

  658. ngx_int_t
  659. ngx_http_upstream_set_round_robin_peer_session(ngx_peer_connection_t *pc,
  660.     void *data)
  661. {
  662.     ngx_http_upstream_rr_peer_data_t  *rrp = data;

  663.     ngx_int_t                      rc;
  664.     ngx_ssl_session_t             *ssl_session;
  665.     ngx_http_upstream_rr_peer_t   *peer;
  666. #if (NGX_HTTP_UPSTREAM_ZONE)
  667.     int                            len;
  668.     const u_char                  *p;
  669.     ngx_http_upstream_rr_peers_t  *peers;
  670.     u_char                         buf[NGX_SSL_MAX_SESSION_SIZE];
  671. #endif

  672.     peer = rrp->current;

  673. #if (NGX_HTTP_UPSTREAM_ZONE)
  674.     peers = rrp->peers;

  675.     if (peers->shpool) {
  676.         ngx_http_upstream_rr_peers_rlock(peers);
  677.         ngx_http_upstream_rr_peer_lock(peers, peer);

  678.         if (peer->ssl_session == NULL) {
  679.             ngx_http_upstream_rr_peer_unlock(peers, peer);
  680.             ngx_http_upstream_rr_peers_unlock(peers);
  681.             return NGX_OK;
  682.         }

  683.         len = peer->ssl_session_len;

  684.         ngx_memcpy(buf, peer->ssl_session, len);

  685.         ngx_http_upstream_rr_peer_unlock(peers, peer);
  686.         ngx_http_upstream_rr_peers_unlock(peers);

  687.         p = buf;
  688.         ssl_session = d2i_SSL_SESSION(NULL, &p, len);

  689.         rc = ngx_ssl_set_session(pc->connection, ssl_session);

  690.         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
  691.                        "set session: %p", ssl_session);

  692.         ngx_ssl_free_session(ssl_session);

  693.         return rc;
  694.     }
  695. #endif

  696.     ssl_session = peer->ssl_session;

  697.     rc = ngx_ssl_set_session(pc->connection, ssl_session);

  698.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
  699.                    "set session: %p", ssl_session);

  700.     return rc;
  701. }


  702. void
  703. ngx_http_upstream_save_round_robin_peer_session(ngx_peer_connection_t *pc,
  704.     void *data)
  705. {
  706.     ngx_http_upstream_rr_peer_data_t  *rrp = data;

  707.     ngx_ssl_session_t             *old_ssl_session, *ssl_session;
  708.     ngx_http_upstream_rr_peer_t   *peer;
  709. #if (NGX_HTTP_UPSTREAM_ZONE)
  710.     int                            len;
  711.     u_char                        *p;
  712.     ngx_http_upstream_rr_peers_t  *peers;
  713.     u_char                         buf[NGX_SSL_MAX_SESSION_SIZE];
  714. #endif

  715. #if (NGX_HTTP_UPSTREAM_ZONE)
  716.     peers = rrp->peers;

  717.     if (peers->shpool) {

  718.         ssl_session = ngx_ssl_get0_session(pc->connection);

  719.         if (ssl_session == NULL) {
  720.             return;
  721.         }

  722.         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
  723.                        "save session: %p", ssl_session);

  724.         len = i2d_SSL_SESSION(ssl_session, NULL);

  725.         /* do not cache too big session */

  726.         if (len > NGX_SSL_MAX_SESSION_SIZE) {
  727.             return;
  728.         }

  729.         p = buf;
  730.         (void) i2d_SSL_SESSION(ssl_session, &p);

  731.         peer = rrp->current;

  732.         ngx_http_upstream_rr_peers_rlock(peers);
  733.         ngx_http_upstream_rr_peer_lock(peers, peer);

  734.         if (len > peer->ssl_session_len) {
  735.             ngx_shmtx_lock(&peers->shpool->mutex);

  736.             if (peer->ssl_session) {
  737.                 ngx_slab_free_locked(peers->shpool, peer->ssl_session);
  738.             }

  739.             peer->ssl_session = ngx_slab_alloc_locked(peers->shpool, len);

  740.             ngx_shmtx_unlock(&peers->shpool->mutex);

  741.             if (peer->ssl_session == NULL) {
  742.                 peer->ssl_session_len = 0;

  743.                 ngx_http_upstream_rr_peer_unlock(peers, peer);
  744.                 ngx_http_upstream_rr_peers_unlock(peers);
  745.                 return;
  746.             }

  747.             peer->ssl_session_len = len;
  748.         }

  749.         ngx_memcpy(peer->ssl_session, buf, len);

  750.         ngx_http_upstream_rr_peer_unlock(peers, peer);
  751.         ngx_http_upstream_rr_peers_unlock(peers);

  752.         return;
  753.     }
  754. #endif

  755.     ssl_session = ngx_ssl_get_session(pc->connection);

  756.     if (ssl_session == NULL) {
  757.         return;
  758.     }

  759.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
  760.                    "save session: %p", ssl_session);

  761.     peer = rrp->current;

  762.     old_ssl_session = peer->ssl_session;
  763.     peer->ssl_session = ssl_session;

  764.     if (old_ssl_session) {

  765.         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
  766.                        "old session: %p", old_ssl_session);

  767.         /* TODO: may block */

  768.         ngx_ssl_free_session(old_ssl_session);
  769.     }
  770. }


  771. static ngx_int_t
  772. ngx_http_upstream_empty_set_session(ngx_peer_connection_t *pc, void *data)
  773. {
  774.     return NGX_OK;
  775. }


  776. static void
  777. ngx_http_upstream_empty_save_session(ngx_peer_connection_t *pc, void *data)
  778. {
  779.     return;
  780. }

  781. #endif