static ngx_http_upstream_rr_peer_t *
ngx_http_upstream_get_peer(ngx_http_upstream_rr_peer_data_t *rrp)
{
    time_t                        now;
    uintptr_t                     m;
    ngx_int_t                     total;
    ngx_uint_t                    i, n;
    ngx_http_upstream_rr_peer_t  *peer, *best;
#if (NGX_HTTP_PERSISTENCE)
    ngx_int_t                     persist_index;


    persist_index = ngx_http_upstream_ps_get(rrp->request,
        rrp->peers->number, rrp->group);
#endif
    now = ngx_time();

    best = NULL;
    total = 0;

    for (i = 0; i < rrp->peers->number; i++) {
#if (NGX_HTTP_PERSISTENCE)
        if(persist_index >= 0) {
            i = persist_index;
        }
#endif
        n = i / (8 * sizeof(uintptr_t));
        m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t));

        if (rrp->tried[n] & m) {
#if (NGX_HTTP_PERSISTENCE)
            if(persist_index >= 0) {
                persist_index = -1;
                i = 0;
            }
#endif
            continue;
        }

        peer = &rrp->peers->peer[i];

        if (peer->down) {
#if (NGX_HTTP_PERSISTENCE)
            if(persist_index >= 0) {
                persist_index = -1;
                i = 0;
            }
#endif
            continue;
        }

#if (NGX_HTTP_UPSTREAM_CHECK)
        if (ngx_http_upstream_check_peer_down(peer->check_index)) {
            continue;
        }
#endif

        if (peer->max_fails
            && peer->fails >= peer->max_fails
            && now - peer->checked <= peer->fail_timeout)
        {
#if (NGX_HTTP_PERSISTENCE)
            if(persist_index >= 0) {
                persist_index = -1;
                i = 0;
            }
#endif
            continue;
        }

#if (NGX_HTTP_PERSISTENCE)
        if(persist_index >= 0) {
            best = peer;
            break;
        }
#endif
        peer->current_weight += peer->effective_weight;
        total += peer->effective_weight;

        if (peer->effective_weight < peer->weight) {
            peer->effective_weight++;
        }

        if (best == NULL || peer->current_weight > best->current_weight) {
            best = peer;
        }
    }

    if (best == NULL) {
        return NULL;
    }

    i = best - &rrp->peers->peer[0];

    rrp->current = i;

    n = i / (8 * sizeof(uintptr_t));
    m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t));

    rrp->tried[n] |= m;

    best->current_weight -= total;

    if (now - best->checked > best->fail_timeout) {
        best->checked = now;
    }

#if (NGX_HTTP_PERSISTENCE)
    ngx_http_upstream_ps_set(rrp->request, rrp->current, rrp->group);
#endif

    return best;
}
static ngx_int_t
ngx_http_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data)
{
    ngx_http_upstream_lc_peer_data_t  *lcp = data;

    time_t                         now;
    uintptr_t                      m;
    ngx_int_t                      rc, total;
    ngx_uint_t                     i, n, p, many;
    ngx_http_upstream_rr_peer_t   *peer, *best;
    ngx_http_upstream_rr_peers_t  *peers;
#if (NGX_HTTP_PERSISTENCE)
    ngx_int_t                      persist_index;
#endif

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
                   "get least conn peer, try: %ui", pc->tries);

    if (lcp->rrp.peers->single) {
        return lcp->get_rr_peer(pc, &lcp->rrp);
    }

    pc->cached = 0;
    pc->connection = NULL;

    now = ngx_time();

    peers = lcp->rrp.peers;

    best = NULL;
    total = 0;

#if (NGX_SUPPRESS_WARN)
    many = 0;
    p = 0;
#endif

#if (NGX_HTTP_PERSISTENCE)
    persist_index = ngx_http_upstream_ps_get(lcp->rrp.request,
        lcp->rrp.peers->number, lcp->rrp.group);
#endif
    for (i = 0; i < peers->number; i++) {
#if (NGX_HTTP_PERSISTENCE)
        if(persist_index >= 0) {
            i = persist_index;
        }
#endif
        n = i / (8 * sizeof(uintptr_t));
        m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t));

        if (lcp->rrp.tried[n] & m) {
#if (NGX_HTTP_PERSISTENCE)
            if(persist_index >= 0) {
                persist_index = -1;
                i = 0;
            }
#endif
            continue;
        }

        peer = &peers->peer[i];

        if (peer->down) {
#if (NGX_HTTP_PERSISTENCE)
            if(persist_index >= 0) {
                persist_index = -1;
                i = 0;
            }
#endif
            continue;
        }

#if (NGX_HTTP_UPSTREAM_CHECK)
        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
                "get least_conn peer, check_index: %ui",
                peer->check_index);

        if (ngx_http_upstream_check_peer_down(peer->check_index)) {
            continue;
        }
#endif

        if (peer->max_fails
            && peer->fails >= peer->max_fails
            && now - peer->checked <= peer->fail_timeout)
        {
#if (NGX_HTTP_PERSISTENCE)
            if(persist_index >= 0) {
                persist_index = -1;
                i = 0;
            }
#endif
            continue;
        }

#if (NGX_HTTP_PERSISTENCE)
        if(persist_index >= 0) {
            best = peer;
            p = persist_index;
            break;
        }
#endif
        /*
         * select peer with least number of connections; if there are
         * multiple peers with the same number of connections, select
         * based on round-robin
         */

        if (best == NULL
            || lcp->conns[i] * best->weight < lcp->conns[p] * peer->weight)
        {
            best = peer;
            many = 0;
            p = i;

        } else if (lcp->conns[i] * best->weight
                   == lcp->conns[p] * peer->weight)
        {
            many = 1;
        }
    }

    if (best == NULL) {
        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0,
                       "get least conn peer, no peer found");

        goto failed;
    }

    if (many) {
        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0,
                       "get least conn peer, many");

        for (i = p; i < peers->number; i++) {

            n = i / (8 * sizeof(uintptr_t));
            m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t));

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

            peer = &peers->peer[i];

            if (peer->down) {
                continue;
            }

#if (NGX_HTTP_UPSTREAM_CHECK)
            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
                    "get least_conn peer, check_index: %ui",
                    peer->check_index);

            if (ngx_http_upstream_check_peer_down(peer->check_index)) {
                continue;
            }
#endif

            if (lcp->conns[i] * best->weight != lcp->conns[p] * peer->weight) {
                continue;
            }

            if (peer->max_fails
                && peer->fails >= peer->max_fails
                && now - peer->checked <= peer->fail_timeout)
            {
                continue;
            }

            peer->current_weight += peer->effective_weight;
            total += peer->effective_weight;

            if (peer->effective_weight < peer->weight) {
                peer->effective_weight++;
            }

            if (peer->current_weight > best->current_weight) {
                best = peer;
                p = i;
            }
        }
    }

    best->current_weight -= total;

    if (now - best->checked > best->fail_timeout) {
        best->checked = now;
    }

    pc->sockaddr = best->sockaddr;
    pc->socklen = best->socklen;
    pc->name = &best->name;
    pc->host = &best->host;
    pc->dyn_resolve = best->dyn_resolve;

    lcp->rrp.current = p;

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

    lcp->rrp.tried[n] |= m;
    lcp->conns[p]++;

    if (pc->tries == 1 && peers->next) {
        pc->tries += peers->next->number;
    }

#if (NGX_HTTP_PERSISTENCE)
    ngx_http_upstream_ps_set(lcp->rrp.request, lcp->rrp.current,
            lcp->rrp.group);
#endif
    return NGX_OK;

failed:

    if (peers->next) {
        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0,
                       "get least conn peer, backup servers");

        lcp->conns += peers->number;

        lcp->rrp.peers = peers->next;
        pc->tries = lcp->rrp.peers->number;

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

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

        rc = ngx_http_upstream_get_least_conn_peer(pc, lcp);

        if (rc != NGX_BUSY) {
            return rc;
        }
    }

    /* all peers failed, mark them as live for quick recovery */

    for (i = 0; i < peers->number; i++) {
        peers->peer[i].fails = 0;
    }

    pc->name = peers->name;

    return NGX_BUSY;
}