From: Amaury Denoyelle Date: Thu, 1 Oct 2026 14:40:58 +0000 (+0200) Subject: MINOR: proxy: yield during servers purge X-Git-Tag: v3.5-dev9~15 X-Git-Url: https://git.kaiwu.me/?a=commitdiff_plain;h=71a914e0ff8440c3f0d17167732c7028afe57724;p=haproxy.git MINOR: proxy: yield during servers purge Function proxy_purge_servers() loops through server purge list and tries to remove them. This is executed under thread isolation for the whole function duration. To prevent blocking for too long, yield after 50 servers deleted. The purge task is immediately requeued but this gives an opportunity for the other threads to achieve some work. For now, a static value is applied as the yield limit. It may be useful to render it configurable if users want to prioritize traffic even more. --- diff --git a/src/proxy.c b/src/proxy.c index 0c8da9d0a..ad87f90fa 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -510,13 +510,25 @@ void proxy_drop(struct proxy *p) ha_free(&p); } -/* Try to delete servers flagged for purge in backend. */ -static int proxy_purge_servers(struct proxy *px) +/* Try to delete servers flagged for purge in backend. + * + * This function must only runs in thread isolation. To avoid too long run, at + * most instances are removed until the function returns, so + * that the caller can yield. + * + * Returns 0 if either all scheduled servers are deleted or iteration stopped + * on a server is still active. A non zero is used when count + * of servers were removed and purge list is not yet empty. + */ +static int proxy_purge_servers(struct proxy *px, int max_srv_delete) { struct server *srv; int ret; while (!LIST_ISEMPTY(&px->servers_purge)) { + if (!max_srv_delete) + break; + srv = LIST_NEXT(&px->servers_purge, struct server *, el_alt); if (!(srv->flags & SRV_F_TO_PURGE)) { LIST_DEL_INIT(&srv->el_alt); @@ -533,7 +545,7 @@ static int proxy_purge_servers(struct proxy *px) ha_notice("Server '%s/%s' purged.\n", px->id, srv->id); srv_unregister(srv); srv_drop(srv); - /* TODO yield after nth deletion performed in a row */ + --max_srv_delete; } else { /* Interrupt work on first server not yet removable. */ @@ -541,7 +553,7 @@ static int proxy_purge_servers(struct proxy *px) } } - return 0; + return !(LIST_ISEMPTY(&px->servers_purge) || max_srv_delete); } /* Proxy purge task handler, only used by user configured backend instances. @@ -551,6 +563,8 @@ static int proxy_purge_servers(struct proxy *px) struct task *proxy_process_purge(struct task *t, void *context, unsigned int state) { struct proxy *px = context; + /* constant for max number of server delete before yield */ + const int max_srv_delete = 50; /* Must not dereference before entering thread isolation and * checking task state, as proxy_drop() performed outside isolation @@ -566,8 +580,12 @@ struct task *proxy_process_purge(struct task *t, void *context, unsigned int sta goto requeue; } - if (!LIST_ISEMPTY(&px->servers_purge)) - proxy_purge_servers(px); + if (!LIST_ISEMPTY(&px->servers_purge)) { + if (proxy_purge_servers(px, max_srv_delete)) { + task_wakeup(px->purge_task, TASK_WOKEN_OTHER); + goto requeue; + } + } /* Set next task execution or cancel it if no more work to do. */ if (!LIST_ISEMPTY(&px->servers_purge))