MEDIUM: server: close idle conn on server deletion

To be able to delete a server, a number of preconditions must be
validated to ensure it is not in used anymore. Previously, if idle
connections were stored in the server, the deletion was cancelled. No
action was implemented to force idle connection closure, the only
solution was to wait for the periodic purging to be achieved.

This is an extra burden to be able to delete a server. Indeed, idle
connections are by definition inactive and can be closed prior to delete
a server. This is the exact purpose of this patch.

Idle connections removal is implemented inside "delete server" handler,
once it has been determined that the server can be freely removed. A
simple loop is run to call conn_release() over each idle connections.
Takeover is also executed before conn_release() to ensure tasks/tasklets
or any other sensible elements are not deleted from a foreign thread.

This patch should reduce the occurence of rejected "delete server"
execution, especially when connection reuse is high.
This commit is contained in:
Amaury Denoyelle 2024-03-13 11:33:50 +01:00
parent f3862a9bc7
commit 6e0afb2e27

View File

@ -5828,12 +5828,8 @@ int srv_check_for_deletion(const char *bename, const char *svname, struct proxy
/* Second, conditions that may change over time */
ret = 0;
/* Ensure that there is no active/idle/pending connection on the server.
*
* TODO idle connections should not prevent server deletion. A proper
* cleanup function should be implemented to be used here.
*/
if (srv->curr_used_conns || srv->curr_idle_conns ||
/* Ensure that there is no active/pending connection on the server. */
if (srv->curr_used_conns ||
!MT_LIST_ISEMPTY(&srv->sess_conns) ||
!eb_is_empty(&srv->queue.head) || srv_has_streams(srv)) {
msg = "Server still has connections attached to it, cannot remove it.";
@ -5862,7 +5858,7 @@ static int cli_parse_delete_server(char **args, char *payload, struct appctx *ap
struct server *prev_del;
struct ist be_name, sv_name;
const char *msg;
int ret;
int ret, i;
if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
return 1;
@ -5891,6 +5887,29 @@ static int cli_parse_delete_server(char **args, char *payload, struct appctx *ap
goto out;
}
/* Close idle connections attached to this server. */
for (i = tid;;) {
struct list *list = &srv->per_thr[i].idle_conn_list;
struct connection *conn;
while (!LIST_ISEMPTY(list)) {
conn = LIST_ELEM(list->n, struct connection *, idle_list);
if (i != tid) {
if (conn->mux && conn->mux->takeover)
conn->mux->takeover(conn, i, 1);
else if (conn->xprt && conn->xprt->takeover)
conn->xprt->takeover(conn, conn->ctx, i, 1);
}
conn_release(conn);
}
if ((i = ((i + 1 == global.nbthread) ? 0 : i + 1)) == tid)
break;
}
/* All idle connections should be removed now. */
BUG_ON(srv->curr_idle_conns);
/* removing cannot fail anymore when we reach this:
* publishing EVENT_HDL_SUB_SERVER_DEL
*/