From 3121c0093701ab522f6585768a90585d150663f1 Mon Sep 17 00:00:00 2001 From: Olivier Houchard Date: Mon, 9 Feb 2026 11:20:40 +0100 Subject: [PATCH] MEDIUM: servers: Use server_full to detect if a server is full Instead of checking the value of served to know if the server is full, make use of the newly introduced server_full where relevant, so that we have less access to served. --- include/haproxy/queue.h | 7 ++++--- include/haproxy/server-t.h | 1 + src/backend.c | 2 +- src/server.c | 19 +++++++++++++++++++ 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/include/haproxy/queue.h b/include/haproxy/queue.h index 1b02e1aca..2b1d0f384 100644 --- a/include/haproxy/queue.h +++ b/include/haproxy/queue.h @@ -78,7 +78,8 @@ static inline void pendconn_free(struct stream *s) /* Returns 0 if all slots are full on a server, or 1 if there are slots available. */ static inline int server_has_room(const struct server *s) { - return !s->maxconn || s->served < srv_dynamic_maxconn(s); + return ((s->server_max_static && !s->server_full) || + (!s->server_max_static && (!s->maxconn || s->served < srv_dynamic_maxconn(s)))); } /* returns 0 if nothing has to be done for server regarding queued connections, @@ -86,8 +87,8 @@ static inline int server_has_room(const struct server *s) { * for and if/else usage. */ static inline int may_dequeue_tasks(const struct server *s, const struct proxy *p) { - return (s && (s->queues_not_empty || (p->queues_not_empty && srv_currently_usable(s))) && - (!s->maxconn || s->served < srv_dynamic_maxconn(s))); + return (s && server_has_room(s) && + (s->queues_not_empty || (p->queues_not_empty && srv_currently_usable(s)))); } static inline int queue_limit_class(int class) diff --git a/include/haproxy/server-t.h b/include/haproxy/server-t.h index b08a7a807..300b0e74d 100644 --- a/include/haproxy/server-t.h +++ b/include/haproxy/server-t.h @@ -555,6 +555,7 @@ struct server { __decl_thread(HA_SPINLOCK_T state_lock);/* protect the following state fields */ uint8_t queues_not_empty; /* Are the request queues not empty ? Only changed when the queues go from non-empty to empty, and vice-versa. Protected by the state_lock lock when changed */ uint8_t server_full; /* we reached maxconn, and can no longer process more requests, protected by the state_lock */ + uint8_t server_max_static; /* the number of max requests for the server is static, and thus server_full can reliably be used */ }; /* data provided to EVENT_HDL_SUB_SERVER handlers through event_hdl facility */ diff --git a/src/backend.c b/src/backend.c index 5ff273272..444667de5 100644 --- a/src/backend.c +++ b/src/backend.c @@ -597,7 +597,7 @@ struct server *get_server_rnd(struct stream *s, const struct server *avoid) * the backend's queue instead. */ if (curr && - (curr->queues_not_empty || (curr->maxconn && curr->served >= srv_dynamic_maxconn(curr)))) + (curr->queues_not_empty || !server_has_room(curr))) curr = NULL; return curr; diff --git a/src/server.c b/src/server.c index d888988f4..551c152cf 100644 --- a/src/server.c +++ b/src/server.c @@ -3603,6 +3603,8 @@ int srv_postinit(struct server *srv) goto out; } } + if (!srv->slowstart && srv->minconn == srv->maxconn) + srv->server_max_static = 1; out: return err_code; @@ -5948,12 +5950,19 @@ static struct task *server_warmup(struct task *t, void *context, unsigned int st /* probably that we can refill this server with a bit more connections */ process_srv_queue(s, &full); + if (s->maxconn) { + HA_SPIN_LOCK(SERVER_LOCK, &s->state_lock); + s->server_full = (s->served >= s->maxconn); + HA_SPIN_UNLOCK(SERVER_LOCK, &s->state_lock); + } /* get back there in 1 second or 1/20th of the slowstart interval, * whichever is greater, resulting in small 5% steps. */ if (s->next_state == SRV_ST_STARTING) t->expire = tick_add(now_ms, MS_TO_TICKS(MAX(1000, s->slowstart / 20))); + else if (s->minconn == s->maxconn) + s->server_max_static = 1; return t; } @@ -6786,6 +6795,11 @@ static int _srv_update_status_op(struct server *s, enum srv_op_st_chg_cause caus */ xferred = process_srv_queue(s, &full); + if (s->maxconn) { + HA_SPIN_LOCK(SERVER_LOCK, &s->state_lock); + s->server_full = (s->served >= s->maxconn); + HA_SPIN_UNLOCK(SERVER_LOCK, &s->state_lock); + } tmptrash = alloc_trash_chunk(); if (tmptrash) { chunk_printf(tmptrash, @@ -6985,6 +6999,11 @@ static int _srv_update_status_adm(struct server *s, enum srv_adm_st_chg_cause ca * We will take as many as we can handle. */ xferred = process_srv_queue(s, &full); + if (s->maxconn) { + HA_SPIN_LOCK(SERVER_LOCK, &s->state_lock); + s->server_full = (s->served >= s->maxconn); + HA_SPIN_UNLOCK(SERVER_LOCK, &s->state_lock); + } } else if (s->next_admin & SRV_ADMF_MAINT) { /* remaining in maintenance mode, let's inform precisely about the