MAJOR: server: implement purging of private idle connections

When a server goes into maintenance, or if its IP address is changed,
idle connections attached to it are scheduled for deletion via the purge
mechanism. Connections are moved from server idle/safe list to the purge
list relative to their thread. Connections are freed on their owned
thread by the scheduled purge task.

This patch extends this procedure to also handle private idle
connections stored in sessions instead of servers. This is possible
thanks via <sess_conns> list server member. A call to the newly
defined-function session_purge_conns() is performed on each list
element. This moves private connections from their session to the purge
list alongside other server idle connections.

This change relies on the serie of previous commits which ensure that
access to private idle connections is now thread-safe, with idle_conns
lock usage and careful manipulation of private idle conns in
input/output handlers.

The main benefit of this patch is that now all idle connections
targetting a server set in maintenance are removed. Previously, private
connections would remain until their attach sessions were closed.
This commit is contained in:
Amaury Denoyelle 2025-08-08 17:13:43 +02:00
parent 17a1daca72
commit 7a6e3c1a73
3 changed files with 45 additions and 0 deletions

View File

@ -49,6 +49,7 @@ int session_check_idle_conn(struct session *sess, struct connection *conn);
struct connection *session_get_conn(struct session *sess, void *target, int64_t hash);
void session_unown_conn(struct session *sess, struct connection *conn);
int session_detach_idle_conn(struct session *sess, struct connection *conn);
int sess_conns_cleanup_all_idle(struct sess_priv_conns *sess_conns);
/* Remove the refcount from the session to the tracked counters, and clear the
* pointer to ensure this is only performed once. The caller is responsible for

View File

@ -7210,6 +7210,7 @@ static int srv_migrate_conns_to_remove(struct list *list, struct mt_list *toremo
*/
static void srv_cleanup_connections(struct server *srv)
{
struct sess_priv_conns *sess_conns;
int did_remove;
int i;
@ -7221,8 +7222,23 @@ static void srv_cleanup_connections(struct server *srv)
for (i = tid;;) {
did_remove = 0;
HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[i].idle_conns_lock);
/* idle connections */
if (srv_migrate_conns_to_remove(&srv->per_thr[i].idle_conn_list, &idle_conns[i].toremove_conns, -1) > 0)
did_remove = 1;
/* session attached connections */
while ((sess_conns = MT_LIST_POP(&srv->per_thr[i].sess_conns, struct sess_priv_conns *, srv_el))) {
if (sess_conns_cleanup_all_idle(sess_conns)) {
did_remove = 1;
if (LIST_ISEMPTY(&sess_conns->conn_list)) {
LIST_DELETE(&sess_conns->sess_el);
pool_free(pool_head_sess_priv_conns, sess_conns);
}
}
}
HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[i].idle_conns_lock);
if (did_remove)
task_wakeup(idle_conns[i].cleanup_task, TASK_WOKEN_OTHER);

View File

@ -874,6 +874,34 @@ int session_detach_idle_conn(struct session *sess, struct connection *conn)
return 1;
}
/* Remove every idle backend connections stored in <sess_conns> and move them
* into the purge list. If <sess_conns> is empty it is also removed from the
* session and freed.
*
* Returns the number of connections moved to purge list.
*/
int sess_conns_cleanup_all_idle(struct sess_priv_conns *sess_conns)
{
struct connection *conn, *back;
int conn_tid = sess_conns->tid;
int i = 0;
list_for_each_entry_safe(conn, back, &sess_conns->conn_list, sess_el) {
if (!(conn->flags & CO_FL_SESS_IDLE))
continue;
/* Decrement session idle counter. */
--((struct session *)conn->owner)->idle_conns;
LIST_DEL_INIT(&conn->sess_el);
MT_LIST_APPEND(&idle_conns[conn_tid].toremove_conns,
&conn->toremove_list);
++i;
}
return i;
}
/*
* Local variables: