diff --git a/src/lb_fwlc.c b/src/lb_fwlc.c index 7bbeb621b7..4e1b7307f9 100644 --- a/src/lb_fwlc.c +++ b/src/lb_fwlc.c @@ -72,10 +72,29 @@ static inline void fwlc_queue_srv(struct server *s, unsigned int eweight) */ static void fwlc_srv_reposition(struct server *s, int locked) { + unsigned int inflight = _HA_ATOMIC_LOAD(&s->served) + _HA_ATOMIC_LOAD(&s->nbpend); + unsigned int new_key = inflight ? (inflight + 1) * SRV_EWGHT_MAX / s->cur_eweight : 0; + + /* some calls will be made for no change (e.g connect_server() after + * assign_server(). Let's check that first. + */ + if (s->lb_node.node.leaf_p && s->lb_node.key == new_key) + return; + HA_RWLOCK_WRLOCK(LBPRM_LOCK, &s->proxy->lbprm.lock); if (s->lb_tree) { - fwlc_dequeue_srv(s); - fwlc_queue_srv(s, s->cur_eweight); + /* we might have been waiting for a while on the lock above + * so it's worth testing again because other threads are very + * likely to have released a connection or taken one leading + * to our target value (50% of the case in measurements). + */ + inflight = _HA_ATOMIC_LOAD(&s->served) + _HA_ATOMIC_LOAD(&s->nbpend); + new_key = inflight ? (inflight + 1) * SRV_EWGHT_MAX / s->cur_eweight : 0; + if (!s->lb_node.node.leaf_p || s->lb_node.key != new_key) { + eb32_delete(&s->lb_node); + s->lb_node.key = new_key; + eb32_insert(s->lb_tree, &s->lb_node); + } } HA_RWLOCK_WRUNLOCK(LBPRM_LOCK, &s->proxy->lbprm.lock); }