]> git.kaiwu.me - haproxy.git/commitdiff
OPTIM: lb-chash: don't look for more servers when there is only one
authorWilly Tarreau <w@1wt.eu>
Fri, 13 Nov 2026 10:06:31 +0000 (11:06 +0100)
committerWilly Tarreau <w@1wt.eu>
Fri, 13 Nov 2026 16:31:34 +0000 (17:31 +0100)
The chash_get_server_hash() function never makes a special case for a
single server. Worse, when asked to avoid a specific one and it is the
only one, or when the chosen server is not eligible, the function will
run over all its positions at the end. Thus having a single server in
a config with a weight 256 and asking to avoid it burns a lot of CPU.

Let's just test for this case after picking the first server. If the
total servers count is 1, we can just leave.

src/lb_chash.c

index 12a933a218bfece674b142a5811f04defa05d2fe..cc63a9ae79bf2ded32126efdac6753cb08938dbb 100644 (file)
@@ -419,18 +419,19 @@ struct server *chash_get_server_hash(struct proxy *p, unsigned int hash, const s
        struct server *nsrv, *psrv;
        struct eb_root *root;
        unsigned int dn, dp;
+       int tot = 0;
        int loop;
        int hashafnty;
 
        HA_RWLOCK_RDLOCK(LBPRM_LOCK, &p->lbprm.lock);
 
-       if (p->srv_act)
+       if ((tot = p->srv_act))
                root = &p->lbprm.chash.act;
        else if (p->lbprm.fbck) {
                nsrv = p->lbprm.fbck;
                goto out;
        }
-       else if (p->srv_bck)
+       else if ((tot = p->srv_bck))
                root = &p->lbprm.chash.bck;
        else {
                nsrv = NULL;
@@ -446,11 +447,16 @@ struct server *chash_get_server_hash(struct proxy *p, unsigned int hash, const s
                goto out;
        }
 
+       nsrv = eb32_entry(next, struct tree_occ, node)->server;
+
+       /* if there's only one server, no need to go further */
+       if (tot == 1)
+               goto out;
+
        prev = eb32_prev(next);
        if (!prev)
                prev = eb32_last(root);
 
-       nsrv = eb32_entry(next, struct tree_occ, node)->server;
        psrv = eb32_entry(prev, struct tree_occ, node)->server;
 
        /* OK we're located between two servers, let's