src/http/modules/ngx_http_upstream_zone_module.c - nginx

Global variables defined

Functions defined

Macros defined

Source code


  1. /*
  2. * Copyright (C) Ruslan Ermilov
  3. * Copyright (C) Nginx, Inc.
  4. */


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


  8. static char *ngx_http_upstream_zone(ngx_conf_t *cf, ngx_command_t *cmd,
  9.     void *conf);
  10. static ngx_int_t ngx_http_upstream_init_zone(ngx_shm_zone_t *shm_zone,
  11.     void *data);
  12. static ngx_http_upstream_rr_peers_t *ngx_http_upstream_zone_copy_peers(
  13.     ngx_slab_pool_t *shpool, ngx_http_upstream_srv_conf_t *uscf,
  14.     ngx_http_upstream_srv_conf_t *ouscf);
  15. static ngx_http_upstream_rr_peer_t *ngx_http_upstream_zone_copy_peer(
  16.     ngx_http_upstream_rr_peers_t *peers, ngx_http_upstream_rr_peer_t *src);
  17. static ngx_int_t ngx_http_upstream_zone_preresolve(
  18.     ngx_http_upstream_rr_peer_t *resolve,
  19.     ngx_http_upstream_rr_peers_t *peers,
  20.     ngx_http_upstream_rr_peer_t *oresolve,
  21.     ngx_http_upstream_rr_peers_t *opeers);
  22. static void ngx_http_upstream_zone_set_single(
  23.     ngx_http_upstream_srv_conf_t *uscf);
  24. static void ngx_http_upstream_zone_remove_peer_locked(
  25.     ngx_http_upstream_rr_peers_t *peers, ngx_http_upstream_rr_peer_t *peer);
  26. static ngx_int_t ngx_http_upstream_zone_init_worker(ngx_cycle_t *cycle);
  27. static void ngx_http_upstream_zone_resolve_timer(ngx_event_t *event);
  28. static void ngx_http_upstream_zone_resolve_handler(ngx_resolver_ctx_t *ctx);


  29. static ngx_command_t  ngx_http_upstream_zone_commands[] = {

  30.     { ngx_string("zone"),
  31.       NGX_HTTP_UPS_CONF|NGX_CONF_TAKE12,
  32.       ngx_http_upstream_zone,
  33.       0,
  34.       0,
  35.       NULL },

  36.       ngx_null_command
  37. };


  38. static ngx_http_module_t  ngx_http_upstream_zone_module_ctx = {
  39.     NULL,                                  /* preconfiguration */
  40.     NULL,                                  /* postconfiguration */

  41.     NULL,                                  /* create main configuration */
  42.     NULL,                                  /* init main configuration */

  43.     NULL,                                  /* create server configuration */
  44.     NULL,                                  /* merge server configuration */

  45.     NULL,                                  /* create location configuration */
  46.     NULL                                   /* merge location configuration */
  47. };


  48. ngx_module_t  ngx_http_upstream_zone_module = {
  49.     NGX_MODULE_V1,
  50.     &ngx_http_upstream_zone_module_ctx,    /* module context */
  51.     ngx_http_upstream_zone_commands,       /* module directives */
  52.     NGX_HTTP_MODULE,                       /* module type */
  53.     NULL,                                  /* init master */
  54.     NULL,                                  /* init module */
  55.     ngx_http_upstream_zone_init_worker,    /* init process */
  56.     NULL,                                  /* init thread */
  57.     NULL,                                  /* exit thread */
  58.     NULL,                                  /* exit process */
  59.     NULL,                                  /* exit master */
  60.     NGX_MODULE_V1_PADDING
  61. };


  62. static char *
  63. ngx_http_upstream_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  64. {
  65.     ssize_t                         size;
  66.     ngx_str_t                      *value;
  67.     ngx_http_upstream_srv_conf_t   *uscf;
  68.     ngx_http_upstream_main_conf_t  *umcf;

  69.     uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module);
  70.     umcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_upstream_module);

  71.     value = cf->args->elts;

  72.     if (!value[1].len) {
  73.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  74.                            "invalid zone name \"%V\"", &value[1]);
  75.         return NGX_CONF_ERROR;
  76.     }

  77.     if (cf->args->nelts == 3) {
  78.         size = ngx_parse_size(&value[2]);

  79.         if (size == NGX_ERROR) {
  80.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  81.                                "invalid zone size \"%V\"", &value[2]);
  82.             return NGX_CONF_ERROR;
  83.         }

  84.         if (size < (ssize_t) (8 * ngx_pagesize)) {
  85.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  86.                                "zone \"%V\" is too small", &value[1]);
  87.             return NGX_CONF_ERROR;
  88.         }

  89.     } else {
  90.         size = 0;
  91.     }

  92.     uscf->shm_zone = ngx_shared_memory_add(cf, &value[1], size,
  93.                                            &ngx_http_upstream_module);
  94.     if (uscf->shm_zone == NULL) {
  95.         return NGX_CONF_ERROR;
  96.     }

  97.     uscf->shm_zone->init = ngx_http_upstream_init_zone;
  98.     uscf->shm_zone->data = umcf;

  99.     uscf->shm_zone->noreuse = 1;

  100.     return NGX_CONF_OK;
  101. }


  102. static ngx_int_t
  103. ngx_http_upstream_init_zone(ngx_shm_zone_t *shm_zone, void *data)
  104. {
  105.     size_t                          len;
  106.     ngx_uint_t                      i, j;
  107.     ngx_slab_pool_t                *shpool;
  108.     ngx_http_upstream_rr_peers_t   *peers, **peersp;
  109.     ngx_http_upstream_srv_conf_t   *uscf, *ouscf, **uscfp, **ouscfp;
  110.     ngx_http_upstream_main_conf_t  *umcf, *oumcf;

  111.     shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
  112.     umcf = shm_zone->data;
  113.     uscfp = umcf->upstreams.elts;

  114.     if (shm_zone->shm.exists) {
  115.         peers = shpool->data;

  116.         for (i = 0; i < umcf->upstreams.nelts; i++) {
  117.             uscf = uscfp[i];

  118.             if (uscf->shm_zone != shm_zone) {
  119.                 continue;
  120.             }

  121.             uscf->peer.data = peers;
  122.             peers = peers->zone_next;
  123.         }

  124.         return NGX_OK;
  125.     }

  126.     len = sizeof(" in upstream zone \"\"") + shm_zone->shm.name.len;

  127.     shpool->log_ctx = ngx_slab_alloc(shpool, len);
  128.     if (shpool->log_ctx == NULL) {
  129.         return NGX_ERROR;
  130.     }

  131.     ngx_sprintf(shpool->log_ctx, " in upstream zone \"%V\"%Z",
  132.                 &shm_zone->shm.name);


  133.     /* copy peers to shared memory */

  134.     peersp = (ngx_http_upstream_rr_peers_t **) (void *) &shpool->data;
  135.     oumcf = data;

  136.     for (i = 0; i < umcf->upstreams.nelts; i++) {
  137.         uscf = uscfp[i];

  138.         if (uscf->shm_zone != shm_zone) {
  139.             continue;
  140.         }

  141.         ouscf = NULL;

  142.         if (oumcf) {
  143.             ouscfp = oumcf->upstreams.elts;

  144.             for (j = 0; j < oumcf->upstreams.nelts; j++) {

  145.                  if (ouscfp[j]->shm_zone == NULL) {
  146.                      continue;
  147.                  }

  148.                  if (ouscfp[j]->shm_zone->shm.name.len != shm_zone->shm.name.len
  149.                      || ngx_memcmp(ouscfp[j]->shm_zone->shm.name.data,
  150.                                    shm_zone->shm.name.data,
  151.                                    shm_zone->shm.name.len)
  152.                         != 0)
  153.                  {
  154.                      continue;
  155.                  }

  156.                  if (ouscfp[j]->host.len == uscf->host.len
  157.                      && ngx_memcmp(ouscfp[j]->host.data, uscf->host.data,
  158.                                    uscf->host.len)
  159.                         == 0)
  160.                  {
  161.                      ouscf = ouscfp[j];
  162.                      break;
  163.                  }
  164.             }
  165.         }

  166.         peers = ngx_http_upstream_zone_copy_peers(shpool, uscf, ouscf);
  167.         if (peers == NULL) {
  168.             return NGX_ERROR;
  169.         }

  170.         *peersp = peers;
  171.         peersp = &peers->zone_next;
  172.     }

  173.     return NGX_OK;
  174. }


  175. static ngx_http_upstream_rr_peers_t *
  176. ngx_http_upstream_zone_copy_peers(ngx_slab_pool_t *shpool,
  177.     ngx_http_upstream_srv_conf_t *uscf, ngx_http_upstream_srv_conf_t *ouscf)
  178. {
  179.     ngx_str_t                     *name;
  180.     ngx_uint_t                    *config;
  181.     ngx_http_upstream_rr_peer_t   *peer, **peerp;
  182.     ngx_http_upstream_rr_peers_t  *peers, *opeers, *backup;

  183.     opeers = (ouscf ? ouscf->peer.data : NULL);

  184.     config = ngx_slab_calloc(shpool, sizeof(ngx_uint_t));
  185.     if (config == NULL) {
  186.         return NULL;
  187.     }

  188.     peers = ngx_slab_alloc(shpool, sizeof(ngx_http_upstream_rr_peers_t));
  189.     if (peers == NULL) {
  190.         return NULL;
  191.     }

  192.     ngx_memcpy(peers, uscf->peer.data, sizeof(ngx_http_upstream_rr_peers_t));

  193.     name = ngx_slab_alloc(shpool, sizeof(ngx_str_t));
  194.     if (name == NULL) {
  195.         return NULL;
  196.     }

  197.     name->data = ngx_slab_alloc(shpool, peers->name->len);
  198.     if (name->data == NULL) {
  199.         return NULL;
  200.     }

  201.     ngx_memcpy(name->data, peers->name->data, peers->name->len);
  202.     name->len = peers->name->len;

  203.     peers->name = name;

  204.     peers->shpool = shpool;
  205.     peers->config = config;

  206.     for (peerp = &peers->peer; *peerp; peerp = &peer->next) {
  207.         /* pool is unlocked */
  208.         peer = ngx_http_upstream_zone_copy_peer(peers, *peerp);
  209.         if (peer == NULL) {
  210.             return NULL;
  211.         }

  212.         *peerp = peer;
  213.         (*peers->config)++;
  214.     }

  215.     for (peerp = &peers->resolve; *peerp; peerp = &peer->next) {
  216.         peer = ngx_http_upstream_zone_copy_peer(peers, *peerp);
  217.         if (peer == NULL) {
  218.             return NULL;
  219.         }

  220.         *peerp = peer;
  221.         (*peers->config)++;
  222.     }

  223.     if (opeers) {

  224.         if (ngx_http_upstream_zone_preresolve(peers->resolve, peers,
  225.                                               opeers->resolve, opeers)
  226.             != NGX_OK)
  227.         {
  228.             return NULL;
  229.         }
  230.     }

  231.     if (peers->next == NULL) {
  232.         goto done;
  233.     }

  234.     backup = ngx_slab_alloc(shpool, sizeof(ngx_http_upstream_rr_peers_t));
  235.     if (backup == NULL) {
  236.         return NULL;
  237.     }

  238.     ngx_memcpy(backup, peers->next, sizeof(ngx_http_upstream_rr_peers_t));

  239.     backup->name = name;

  240.     backup->shpool = shpool;
  241.     backup->config = config;

  242.     for (peerp = &backup->peer; *peerp; peerp = &peer->next) {
  243.         /* pool is unlocked */
  244.         peer = ngx_http_upstream_zone_copy_peer(backup, *peerp);
  245.         if (peer == NULL) {
  246.             return NULL;
  247.         }

  248.         *peerp = peer;
  249.         (*backup->config)++;
  250.     }

  251.     for (peerp = &backup->resolve; *peerp; peerp = &peer->next) {
  252.         peer = ngx_http_upstream_zone_copy_peer(backup, *peerp);
  253.         if (peer == NULL) {
  254.             return NULL;
  255.         }

  256.         *peerp = peer;
  257.         (*backup->config)++;
  258.     }

  259.     peers->next = backup;

  260.     if (opeers && opeers->next) {

  261.         if (ngx_http_upstream_zone_preresolve(peers->resolve, backup,
  262.                                               opeers->resolve, opeers->next)
  263.             != NGX_OK)
  264.         {
  265.             return NULL;
  266.         }

  267.         if (ngx_http_upstream_zone_preresolve(backup->resolve, backup,
  268.                                               opeers->next->resolve,
  269.                                               opeers->next)
  270.             != NGX_OK)
  271.         {
  272.             return NULL;
  273.         }
  274.     }

  275. done:

  276.     uscf->peer.data = peers;

  277.     ngx_http_upstream_zone_set_single(uscf);

  278.     return peers;
  279. }


  280. static ngx_http_upstream_rr_peer_t *
  281. ngx_http_upstream_zone_copy_peer(ngx_http_upstream_rr_peers_t *peers,
  282.     ngx_http_upstream_rr_peer_t *src)
  283. {
  284.     ngx_slab_pool_t              *pool;
  285.     ngx_http_upstream_rr_peer_t  *dst;

  286.     pool = peers->shpool;

  287.     dst = ngx_slab_calloc_locked(pool, sizeof(ngx_http_upstream_rr_peer_t));
  288.     if (dst == NULL) {
  289.         return NULL;
  290.     }

  291.     if (src) {
  292.         ngx_memcpy(dst, src, sizeof(ngx_http_upstream_rr_peer_t));
  293.         dst->sockaddr = NULL;
  294.         dst->name.data = NULL;
  295. #if (NGX_HTTP_UPSTREAM_SID)
  296.         dst->sid.data = NULL;
  297. #endif
  298.         dst->server.data = NULL;
  299.         dst->host = NULL;
  300.     }

  301.     dst->sockaddr = ngx_slab_calloc_locked(pool, sizeof(ngx_sockaddr_t));
  302.     if (dst->sockaddr == NULL) {
  303.         goto failed;
  304.     }

  305.     dst->name.data = ngx_slab_calloc_locked(pool, NGX_SOCKADDR_STRLEN);
  306.     if (dst->name.data == NULL) {
  307.         goto failed;
  308.     }

  309. #if (NGX_HTTP_UPSTREAM_SID)
  310.     dst->sid.data = ngx_slab_calloc_locked(pool, NGX_HTTP_UPSTREAM_SID_LEN);
  311.     if (dst->sid.data == NULL) {
  312.         goto failed;
  313.     }
  314. #endif

  315.     if (src) {
  316.         ngx_memcpy(dst->sockaddr, src->sockaddr, src->socklen);
  317.         ngx_memcpy(dst->name.data, src->name.data, src->name.len);
  318. #if (NGX_HTTP_UPSTREAM_SID)
  319.         ngx_memcpy(dst->sid.data, src->sid.data, src->sid.len);
  320. #endif

  321.         dst->server.data = ngx_slab_alloc_locked(pool, src->server.len);
  322.         if (dst->server.data == NULL) {
  323.             goto failed;
  324.         }

  325.         ngx_memcpy(dst->server.data, src->server.data, src->server.len);

  326.         if (src->host) {
  327.             dst->host = ngx_slab_calloc_locked(pool,
  328.                                              sizeof(ngx_http_upstream_host_t));
  329.             if (dst->host == NULL) {
  330.                 goto failed;
  331.             }

  332.             dst->host->name.data = ngx_slab_alloc_locked(pool,
  333.                                                          src->host->name.len);
  334.             if (dst->host->name.data == NULL) {
  335.                 goto failed;
  336.             }

  337.             dst->host->peers = peers;
  338.             dst->host->peer = dst;

  339.             dst->host->name.len = src->host->name.len;
  340.             ngx_memcpy(dst->host->name.data, src->host->name.data,
  341.                        src->host->name.len);

  342.             if (src->host->service.len) {
  343.                 dst->host->service.data = ngx_slab_alloc_locked(pool,
  344.                                                         src->host->service.len);
  345.                 if (dst->host->service.data == NULL) {
  346.                     goto failed;
  347.                 }

  348.                 dst->host->service.len = src->host->service.len;
  349.                 ngx_memcpy(dst->host->service.data, src->host->service.data,
  350.                            src->host->service.len);
  351.             }
  352.         }
  353.     }

  354.     return dst;

  355. failed:

  356.     if (dst->host) {
  357.         if (dst->host->name.data) {
  358.             ngx_slab_free_locked(pool, dst->host->name.data);
  359.         }

  360.         ngx_slab_free_locked(pool, dst->host);
  361.     }

  362.     if (dst->server.data) {
  363.         ngx_slab_free_locked(pool, dst->server.data);
  364.     }

  365. #if (NGX_HTTP_UPSTREAM_SID)
  366.     if (dst->sid.data) {
  367.         ngx_slab_free_locked(pool, dst->sid.data);
  368.     }
  369. #endif

  370.     if (dst->name.data) {
  371.         ngx_slab_free_locked(pool, dst->name.data);
  372.     }

  373.     if (dst->sockaddr) {
  374.         ngx_slab_free_locked(pool, dst->sockaddr);
  375.     }

  376.     ngx_slab_free_locked(pool, dst);

  377.     return NULL;
  378. }


  379. static ngx_int_t
  380. ngx_http_upstream_zone_preresolve(ngx_http_upstream_rr_peer_t *resolve,
  381.     ngx_http_upstream_rr_peers_t *peers,
  382.     ngx_http_upstream_rr_peer_t *oresolve,
  383.     ngx_http_upstream_rr_peers_t *opeers)
  384. {
  385.     in_port_t                     port;
  386.     ngx_str_t                    *server;
  387.     ngx_http_upstream_host_t     *host;
  388.     ngx_http_upstream_rr_peer_t  *peer, *template, *opeer, **peerp;

  389.     if (resolve == NULL || oresolve == NULL) {
  390.         return NGX_OK;
  391.     }

  392.     for (peerp = &peers->peer; *peerp; peerp = &(*peerp)->next) {
  393.         /* void */
  394.     }

  395.     ngx_http_upstream_rr_peers_rlock(opeers);

  396.     for (template = resolve; template; template = template->next) {
  397.         for (opeer = oresolve; opeer; opeer = opeer->next) {

  398.             if (opeer->host->name.len != template->host->name.len
  399.                 || ngx_memcmp(opeer->host->name.data,
  400.                               template->host->name.data,
  401.                               template->host->name.len)
  402.                    != 0)
  403.             {
  404.                 continue;
  405.             }

  406.             if (opeer->host->service.len != template->host->service.len
  407.                 || ngx_memcmp(opeer->host->service.data,
  408.                               template->host->service.data,
  409.                               template->host->service.len)
  410.                    != 0)
  411.             {
  412.                 continue;
  413.             }

  414.             host = opeer->host;

  415.             for (opeer = opeers->peer; opeer; opeer = opeer->next) {

  416.                 if (opeer->host != host) {
  417.                     continue;
  418.                 }

  419.                 peer = ngx_http_upstream_zone_copy_peer(peers, NULL);
  420.                 if (peer == NULL) {
  421.                     ngx_http_upstream_rr_peers_unlock(opeers);
  422.                     return NGX_ERROR;
  423.                 }

  424.                 ngx_memcpy(peer->sockaddr, opeer->sockaddr, opeer->socklen);

  425.                 if (template->host->service.len == 0) {
  426.                     port = ngx_inet_get_port(template->sockaddr);
  427.                     ngx_inet_set_port(peer->sockaddr, port);
  428.                 }

  429.                 peer->socklen = opeer->socklen;

  430.                 peer->name.len = ngx_sock_ntop(peer->sockaddr, peer->socklen,
  431.                                                peer->name.data,
  432.                                                NGX_SOCKADDR_STRLEN, 1);

  433.                 peer->host = template->host;

  434.                 template->host->valid = host->valid;

  435.                 server = template->host->service.len ? &opeer->server
  436.                                                      : &template->server;

  437.                 peer->server.data = ngx_slab_alloc(peers->shpool, server->len);
  438.                 if (peer->server.data == NULL) {
  439.                     ngx_http_upstream_rr_peers_unlock(opeers);
  440.                     return NGX_ERROR;
  441.                 }

  442.                 ngx_memcpy(peer->server.data, server->data, server->len);
  443.                 peer->server.len = server->len;

  444.                 if (host->service.len == 0) {
  445.                     peer->weight = template->weight;

  446.                 } else {
  447.                     peer->weight = (template->weight != 1 ? template->weight
  448.                                                           : opeer->weight);
  449.                 }

  450.                 peer->effective_weight = peer->weight;
  451.                 peer->max_conns = template->max_conns;
  452.                 peer->max_fails = template->max_fails;
  453.                 peer->fail_timeout = template->fail_timeout;
  454.                 peer->down = template->down;

  455. #if (NGX_HTTP_UPSTREAM_SID)
  456.                 ngx_http_upstream_copy_round_robin_sid(peer, template);
  457. #endif

  458.                 (*peers->config)++;

  459.                 *peerp = peer;
  460.                 peerp = &peer->next;

  461.                 peers->number++;
  462.                 peers->tries += (peer->down == 0);
  463.                 peers->total_weight += peer->weight;
  464.                 peers->weighted = (peers->total_weight != peers->number);
  465.             }

  466.             break;
  467.         }
  468.     }

  469.     ngx_http_upstream_rr_peers_unlock(opeers);
  470.     return NGX_OK;
  471. }


  472. static void
  473. ngx_http_upstream_zone_set_single(ngx_http_upstream_srv_conf_t *uscf)
  474. {
  475.     ngx_http_upstream_rr_peers_t  *peers;

  476.     peers = uscf->peer.data;

  477.     if (peers->number == 1
  478.         && (peers->next == NULL || peers->next->number == 0))
  479.     {
  480.         peers->single = 1;

  481.     } else {
  482.         peers->single = 0;
  483.     }
  484. }


  485. static void
  486. ngx_http_upstream_zone_remove_peer_locked(ngx_http_upstream_rr_peers_t *peers,
  487.     ngx_http_upstream_rr_peer_t *peer)
  488. {
  489.     peers->total_weight -= peer->weight;
  490.     peers->number--;
  491.     peers->tries -= (peer->down == 0);
  492.     (*peers->config)++;
  493.     peers->weighted = (peers->total_weight != peers->number);

  494.     ngx_http_upstream_rr_peer_free(peers, peer);
  495. }


  496. static ngx_int_t
  497. ngx_http_upstream_zone_init_worker(ngx_cycle_t *cycle)
  498. {
  499.     time_t                          now;
  500.     ngx_msec_t                      timer;
  501.     ngx_uint_t                      i;
  502.     ngx_event_t                    *event;
  503.     ngx_http_upstream_rr_peer_t    *peer;
  504.     ngx_http_upstream_rr_peers_t   *peers;
  505.     ngx_http_upstream_srv_conf_t   *uscf, **uscfp;
  506.     ngx_http_upstream_main_conf_t  *umcf;

  507.     if (ngx_process != NGX_PROCESS_WORKER
  508.         && ngx_process != NGX_PROCESS_SINGLE)
  509.     {
  510.         return NGX_OK;
  511.     }

  512.     now = ngx_time();
  513.     umcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_upstream_module);

  514.     if (umcf == NULL) {
  515.         return NGX_OK;
  516.     }

  517.     uscfp = umcf->upstreams.elts;

  518.     for (i = 0; i < umcf->upstreams.nelts; i++) {

  519.         uscf = uscfp[i];

  520.         if (uscf->shm_zone == NULL) {
  521.             continue;
  522.         }

  523.         peers = uscf->peer.data;

  524.         do {
  525.             ngx_http_upstream_rr_peers_wlock(peers);

  526.             for (peer = peers->resolve; peer; peer = peer->next) {

  527.                 if (peer->host->worker != ngx_worker) {
  528.                     continue;
  529.                 }

  530.                 event = &peer->host->event;
  531.                 ngx_memzero(event, sizeof(ngx_event_t));

  532.                 event->data = uscf;
  533.                 event->handler = ngx_http_upstream_zone_resolve_timer;
  534.                 event->log = cycle->log;
  535.                 event->cancelable = 1;

  536.                 timer = (peer->host->valid > now)
  537.                         ? (ngx_msec_t) 1000 * (peer->host->valid - now) : 1;

  538.                 ngx_add_timer(event, timer);
  539.             }

  540.             ngx_http_upstream_rr_peers_unlock(peers);

  541.             peers = peers->next;

  542.         } while (peers);
  543.     }

  544.     return NGX_OK;
  545. }


  546. static void
  547. ngx_http_upstream_zone_resolve_timer(ngx_event_t *event)
  548. {
  549.     ngx_resolver_ctx_t            *ctx;
  550.     ngx_http_upstream_host_t      *host;
  551.     ngx_http_upstream_srv_conf_t  *uscf;

  552.     host = (ngx_http_upstream_host_t *) event;
  553.     uscf = event->data;

  554.     ctx = ngx_resolve_start(uscf->resolver, NULL);
  555.     if (ctx == NULL) {
  556.         goto retry;
  557.     }

  558.     if (ctx == NGX_NO_RESOLVER) {
  559.         ngx_log_error(NGX_LOG_ERR, event->log, 0,
  560.                       "no resolver defined to resolve %V", &host->name);
  561.         return;
  562.     }

  563.     ctx->name = host->name;
  564.     ctx->handler = ngx_http_upstream_zone_resolve_handler;
  565.     ctx->data = host;
  566.     ctx->timeout = uscf->resolver_timeout;
  567.     ctx->service = host->service;
  568.     ctx->cancelable = 1;

  569.     if (ngx_resolve_name(ctx) == NGX_OK) {
  570.         return;
  571.     }

  572. retry:

  573.     ngx_add_timer(event, ngx_max(uscf->resolver_timeout, 1000));
  574. }


  575. #define ngx_http_upstream_zone_addr_marked(addr)                              \
  576.     ((uintptr_t) (addr)->sockaddr & 1)

  577. #define ngx_http_upstream_zone_mark_addr(addr)                                \
  578.     (addr)->sockaddr = (struct sockaddr *) ((uintptr_t) (addr)->sockaddr | 1)

  579. #define ngx_http_upstream_zone_unmark_addr(addr)                              \
  580.     (addr)->sockaddr =                                                        \
  581.         (struct sockaddr *) ((uintptr_t) (addr)->sockaddr & ~((uintptr_t) 1))

  582. static void
  583. ngx_http_upstream_zone_resolve_handler(ngx_resolver_ctx_t *ctx)
  584. {
  585.     time_t                         now;
  586.     u_short                        min_priority;
  587.     in_port_t                      port;
  588.     ngx_str_t                     *server;
  589.     ngx_msec_t                     timer;
  590.     ngx_uint_t                     i, j, backup, addr_backup;
  591.     ngx_event_t                   *event;
  592.     ngx_resolver_addr_t           *addr;
  593.     ngx_resolver_srv_name_t       *srv;
  594.     ngx_http_upstream_host_t      *host;
  595.     ngx_http_upstream_rr_peer_t   *peer, *template, **peerp;
  596.     ngx_http_upstream_rr_peers_t  *peers;
  597.     ngx_http_upstream_srv_conf_t  *uscf;

  598.     host = ctx->data;
  599.     event = &host->event;
  600.     uscf = event->data;
  601.     peers = host->peers;
  602.     template = host->peer;

  603.     ngx_http_upstream_rr_peers_wlock(peers);

  604.     now = ngx_time();

  605.     for (i = 0; i < ctx->nsrvs; i++) {
  606.         srv = &ctx->srvs[i];

  607.         if (srv->state) {
  608.             ngx_log_error(NGX_LOG_ERR, event->log, 0,
  609.                           "%V could not be resolved (%i: %s) "
  610.                           "while resolving service %V of %V",
  611.                           &srv->name, srv->state,
  612.                           ngx_resolver_strerror(srv->state), &ctx->service,
  613.                           &ctx->name);
  614.         }
  615.     }

  616.     if (ctx->state) {
  617.         if (ctx->service.len) {
  618.             ngx_log_error(NGX_LOG_ERR, event->log, 0,
  619.                           "service %V of %V could not be resolved (%i: %s)",
  620.                           &ctx->service, &ctx->name, ctx->state,
  621.                           ngx_resolver_strerror(ctx->state));

  622.         } else {
  623.             ngx_log_error(NGX_LOG_ERR, event->log, 0,
  624.                           "%V could not be resolved (%i: %s)",
  625.                           &ctx->name, ctx->state,
  626.                           ngx_resolver_strerror(ctx->state));
  627.         }

  628.         if (ctx->state != NGX_RESOLVE_NXDOMAIN) {
  629.             ngx_http_upstream_rr_peers_unlock(peers);

  630.             ngx_resolve_name_done(ctx);

  631.             ngx_add_timer(event, ngx_max(uscf->resolver_timeout, 1000));
  632.             return;
  633.         }

  634.         /* NGX_RESOLVE_NXDOMAIN */

  635.         ctx->naddrs = 0;
  636.     }

  637.     backup = 0;
  638.     min_priority = 65535;

  639.     for (i = 0; i < ctx->naddrs; i++) {
  640.         min_priority = ngx_min(ctx->addrs[i].priority, min_priority);
  641.     }

  642. #if (NGX_DEBUG)
  643.     {
  644.     u_char  text[NGX_SOCKADDR_STRLEN];
  645.     size_t  len;

  646.     for (i = 0; i < ctx->naddrs; i++) {
  647.         len = ngx_sock_ntop(ctx->addrs[i].sockaddr, ctx->addrs[i].socklen,
  648.                             text, NGX_SOCKADDR_STRLEN, 1);

  649.         ngx_log_debug7(NGX_LOG_DEBUG_HTTP, event->log, 0,
  650.                        "name %V was resolved to %*s "
  651.                        "s:\"%V\" n:\"%V\" w:%d %s",
  652.                        &host->name, len, text, &host->service,
  653.                        &ctx->addrs[i].name, ctx->addrs[i].weight,
  654.                        ctx->addrs[i].priority != min_priority ? "backup" : "");
  655.     }
  656.     }
  657. #endif

  658. again:

  659.     for (peerp = &peers->peer; *peerp; /* void */ ) {
  660.         peer = *peerp;

  661.         if (peer->host != host) {
  662.             goto next;
  663.         }

  664.         for (j = 0; j < ctx->naddrs; j++) {

  665.             addr = &ctx->addrs[j];

  666.             addr_backup = (addr->priority != min_priority);
  667.             if (addr_backup != backup) {
  668.                 continue;
  669.             }

  670.             if (ngx_http_upstream_zone_addr_marked(addr)) {
  671.                 continue;
  672.             }

  673.             if (ngx_cmp_sockaddr(peer->sockaddr, peer->socklen,
  674.                                  addr->sockaddr, addr->socklen,
  675.                                  host->service.len != 0)
  676.                 != NGX_OK)
  677.             {
  678.                 continue;
  679.             }

  680.             if (host->service.len) {
  681.                 if (addr->name.len != peer->server.len
  682.                     || ngx_strncmp(addr->name.data, peer->server.data,
  683.                                    addr->name.len))
  684.                 {
  685.                     continue;
  686.                 }

  687.                 if (template->weight == 1 && addr->weight != peer->weight) {
  688.                     continue;
  689.                 }
  690.             }

  691.             ngx_http_upstream_zone_mark_addr(addr);

  692.             goto next;
  693.         }

  694.         *peerp = peer->next;
  695.         ngx_http_upstream_zone_remove_peer_locked(peers, peer);

  696.         ngx_http_upstream_zone_set_single(uscf);

  697.         continue;

  698.     next:

  699.         peerp = &peer->next;
  700.     }

  701.     for (i = 0; i < ctx->naddrs; i++) {

  702.         addr = &ctx->addrs[i];

  703.         addr_backup = (addr->priority != min_priority);
  704.         if (addr_backup != backup) {
  705.             continue;
  706.         }

  707.         if (ngx_http_upstream_zone_addr_marked(addr)) {
  708.             ngx_http_upstream_zone_unmark_addr(addr);
  709.             continue;
  710.         }

  711.         ngx_shmtx_lock(&peers->shpool->mutex);
  712.         peer = ngx_http_upstream_zone_copy_peer(peers, NULL);
  713.         ngx_shmtx_unlock(&peers->shpool->mutex);

  714.         if (peer == NULL) {
  715.             ngx_log_error(NGX_LOG_ERR, event->log, 0,
  716.                           "cannot add new server to upstream \"%V\", "
  717.                           "memory exhausted", peers->name);
  718.             goto done;
  719.         }

  720.         ngx_memcpy(peer->sockaddr, addr->sockaddr, addr->socklen);

  721.         if (host->service.len == 0) {
  722.             port = ngx_inet_get_port(template->sockaddr);
  723.             ngx_inet_set_port(peer->sockaddr, port);
  724.         }

  725.         peer->socklen = addr->socklen;

  726.         peer->name.len = ngx_sock_ntop(peer->sockaddr, peer->socklen,
  727.                                        peer->name.data, NGX_SOCKADDR_STRLEN, 1);

  728.         peer->host = template->host;

  729.         server = host->service.len ? &addr->name : &template->server;

  730.         peer->server.data = ngx_slab_alloc(peers->shpool, server->len);
  731.         if (peer->server.data == NULL) {
  732.             ngx_http_upstream_rr_peer_free(peers, peer);

  733.             ngx_log_error(NGX_LOG_ERR, event->log, 0,
  734.                           "cannot add new server to upstream \"%V\", "
  735.                           "memory exhausted", peers->name);
  736.             goto done;
  737.         }

  738.         peer->server.len = server->len;
  739.         ngx_memcpy(peer->server.data, server->data, server->len);

  740.         if (host->service.len == 0) {
  741.             peer->weight = template->weight;

  742.         } else {
  743.             peer->weight = (template->weight != 1 ? template->weight
  744.                                                   : addr->weight);
  745.         }

  746.         peer->effective_weight = peer->weight;
  747.         peer->max_conns = template->max_conns;
  748.         peer->max_fails = template->max_fails;
  749.         peer->fail_timeout = template->fail_timeout;
  750.         peer->down = template->down;

  751. #if (NGX_HTTP_UPSTREAM_SID)
  752.         ngx_http_upstream_copy_round_robin_sid(peer, template);
  753. #endif

  754.         *peerp = peer;
  755.         peerp = &peer->next;

  756.         peers->number++;
  757.         peers->tries += (peer->down == 0);
  758.         peers->total_weight += peer->weight;
  759.         peers->weighted = (peers->total_weight != peers->number);
  760.         (*peers->config)++;

  761.         ngx_http_upstream_zone_set_single(uscf);
  762.     }

  763.     if (host->service.len && peers->next) {
  764.         ngx_http_upstream_rr_peers_unlock(peers);

  765.         peers = peers->next;
  766.         backup = 1;

  767.         ngx_http_upstream_rr_peers_wlock(peers);

  768.         goto again;
  769.     }

  770. done:

  771.     host->valid = ctx->valid;

  772.     ngx_http_upstream_rr_peers_unlock(peers);

  773.     while (++i < ctx->naddrs) {
  774.         ngx_http_upstream_zone_unmark_addr(&ctx->addrs[i]);
  775.     }

  776.     timer = (ngx_msec_t) 1000 * (ctx->valid > now ? ctx->valid - now + 1 : 1);

  777.     ngx_resolve_name_done(ctx);

  778.     ngx_add_timer(event, timer);
  779. }