ha_free(&p);
}
-/* Try to delete servers flagged for purge in <px> backend. */
-static int proxy_purge_servers(struct proxy *px)
+/* Try to delete servers flagged for purge in <px> backend.
+ *
+ * This function must only runs in thread isolation. To avoid too long run, at
+ * most <max_srv_delete> 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 <max_srv_delete> 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);
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. */
}
}
- return 0;
+ return !(LIST_ISEMPTY(&px->servers_purge) || max_srv_delete);
}
/* Proxy purge task handler, only used by user configured backend instances.
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 <px> before entering thread isolation and
* checking task state, as proxy_drop() performed outside isolation
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))