From: Amaury Denoyelle Date: Thu, 14 Aug 2025 16:18:01 +0000 (+0200) Subject: MINOR: server: shard by thread sess_conns member X-Git-Tag: v3.3-dev8~81 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=f234b40cdeaaff6d94b1b341cac9401458e1a2b3;p=thirdparty%2Fhaproxy.git MINOR: server: shard by thread sess_conns member Server member is a mt_list which contains every backend connections attached to a session which targets this server. These connecions are not present in idle server trees. The main utility of this list is to be able to cleanup these connections prior to removing a server via "del server" CLI. However, this procedure will be adjusted by a future patch. As such, member must be moved into srv_per_thread struct. Effectively, this duplicates a list for every threads. This commit does not introduce functional change. Its goal is to ensure that these connections are now ordered by their owning thread, which will allow to implement a purge, similarly to idle connections attached to servers. --- diff --git a/include/haproxy/server-t.h b/include/haproxy/server-t.h index 780803384..85dcd63da 100644 --- a/include/haproxy/server-t.h +++ b/include/haproxy/server-t.h @@ -266,6 +266,7 @@ struct srv_per_thread { struct eb_root idle_conns; /* Shareable idle connections */ struct eb_root safe_conns; /* Safe idle connections */ struct eb_root avail_conns; /* Connections in use, but with still new streams available */ + struct mt_list sess_conns; /* Connections attached to a session which cannot be shared across clients */ /* Secondary idle conn storage used in parallel to idle/safe trees. * Used to sort them by last usage and purge them in reverse order. @@ -388,8 +389,6 @@ struct server { unsigned int max_used_conns; /* Max number of used connections (the counter is reset at each connection purges */ unsigned int est_need_conns; /* Estimate on the number of needed connections (max of curr and previous max_used) */ - struct mt_list sess_conns; /* list of private conns managed by a session on this server */ - /* Element below are usd by LB algorithms and must be doable in * parallel to other threads reusing connections above. */ diff --git a/src/server.c b/src/server.c index d75d8f39e..b469b7ca8 100644 --- a/src/server.c +++ b/src/server.c @@ -3072,8 +3072,6 @@ struct server *new_server(struct proxy *proxy) srv->agent.proxy = proxy; srv->xprt = srv->check.xprt = srv->agent.xprt = xprt_get(XPRT_RAW); - MT_LIST_INIT(&srv->sess_conns); - guid_init(&srv->guid); MT_LIST_INIT(&srv->watcher_list); @@ -5935,6 +5933,7 @@ static int srv_init_per_thr(struct server *srv) srv->per_thr[i].idle_conns = EB_ROOT; srv->per_thr[i].safe_conns = EB_ROOT; srv->per_thr[i].avail_conns = EB_ROOT; + MT_LIST_INIT(&srv->per_thr[i].sess_conns); MT_LIST_INIT(&srv->per_thr[i].streams); LIST_INIT(&srv->per_thr[i].idle_conn_list); @@ -6428,29 +6427,34 @@ static int cli_parse_delete_server(char **args, char *payload, struct appctx *ap BUG_ON(srv->curr_idle_conns); /* Close idle private connections attached to this server. */ - MT_LIST_FOR_EACH_ENTRY_LOCKED(sess_conns, &srv->sess_conns, srv_el, back) { - struct connection *conn, *conn_back; - list_for_each_entry_safe(conn, conn_back, &sess_conns->conn_list, sess_el) { - - /* Only idle connections should be present if srv_check_for_deletion() is true. */ - BUG_ON(!(conn->flags & CO_FL_SESS_IDLE)); - --((struct session *)conn->owner)->idle_conns; - - LIST_DEL_INIT(&conn->sess_el); - conn->owner = NULL; - - if (sess_conns->tid != tid) { - if (conn->mux && conn->mux->takeover) - conn->mux->takeover(conn, sess_conns->tid, 1); - else if (conn->xprt && conn->xprt->takeover) - conn->xprt->takeover(conn, conn->ctx, sess_conns->tid, 1); + for (i = tid;;) { + MT_LIST_FOR_EACH_ENTRY_LOCKED(sess_conns, &srv->per_thr[i].sess_conns, srv_el, back) { + struct connection *conn, *conn_back; + list_for_each_entry_safe(conn, conn_back, &sess_conns->conn_list, sess_el) { + + /* Only idle connections should be present if srv_check_for_deletion() is true. */ + BUG_ON(!(conn->flags & CO_FL_SESS_IDLE)); + --((struct session *)conn->owner)->idle_conns; + + LIST_DEL_INIT(&conn->sess_el); + conn->owner = NULL; + + if (sess_conns->tid != tid) { + if (conn->mux && conn->mux->takeover) + conn->mux->takeover(conn, sess_conns->tid, 1); + else if (conn->xprt && conn->xprt->takeover) + conn->xprt->takeover(conn, conn->ctx, sess_conns->tid, 1); + } + conn_release(conn); } - conn_release(conn); + + LIST_DELETE(&sess_conns->sess_el); + pool_free(pool_head_sess_priv_conns, sess_conns); + sess_conns = NULL; } - LIST_DELETE(&sess_conns->sess_el); - pool_free(pool_head_sess_priv_conns, sess_conns); - sess_conns = NULL; + if ((i = ((i + 1 == global.nbthread) ? 0 : i + 1)) == tid) + break; } /* removing cannot fail anymore when we reach this: diff --git a/src/session.c b/src/session.c index 5e99c92f1..8f871f815 100644 --- a/src/session.c +++ b/src/session.c @@ -617,7 +617,7 @@ static struct sess_priv_conns *sess_alloc_sess_conns(struct session *sess, MT_LIST_INIT(&pconns->srv_el); /* If endpoint is a server, also attach storage element into it. */ if ((srv = objt_server(target))) - MT_LIST_APPEND(&srv->sess_conns, &pconns->srv_el); + MT_LIST_APPEND(&srv->per_thr[tid].sess_conns, &pconns->srv_el); pconns->tid = tid;