MINOR: session: refactor alloc/lookup of sess_conns elements

By default backend connections are stored into idle/avail server trees.
However, if such connections cannot be shared between multiple clients,
session serves as the alternative storage.

To be able to quickly reuse a backend conn from a session, they are
indexed by their target, which is either a server or a backend proxy.
This is the purpose of 'struct sess_priv_conns' intermediary stockage
element.

Lookup and allocation of these elements are performed in several session
function, for example to add, get or remove a backend connection from a
session. The purpose of this patch is to simplify this by providing two
internal functions sess_alloc_sess_conns() and sess_get_sess_conns().

Along with this, a new BUG_ON() is added into session_unown_conn(),
which ensure that sess_priv_conns element is found when the connection
is removed from the session.
This commit is contained in:
Amaury Denoyelle 2025-08-21 15:59:33 +02:00
parent d4f7a2dbcc
commit f3e8e863c9

View File

@ -580,6 +580,56 @@ void __session_add_glitch_ctr(struct session *sess, uint inc)
/* Session management of backend connections. */ /* Session management of backend connections. */
/* Allocate a storage element into <sess> session which refers to <target>
* endpoint. This storage can be used to attach new connections
* to the session.
*
* Returns the allocated element or NULL on failure.
*/
static struct sess_priv_conns *sess_alloc_sess_conns(struct session *sess,
enum obj_type *target)
{
struct sess_priv_conns *pconns;
struct server *srv;
pconns = pool_alloc(pool_head_sess_priv_conns);
if (!pconns)
return NULL;
pconns->target = target;
LIST_INIT(&pconns->conn_list);
LIST_APPEND(&sess->priv_conns, &pconns->sess_el);
MT_LIST_INIT(&pconns->srv_el);
/* If <target> endpoint is a server, also attach storage element into it. */
if ((srv = objt_server(target)))
MT_LIST_APPEND(&srv->sess_conns, &pconns->srv_el);
pconns->tid = tid;
return pconns;
}
/* Retrieve the backend connections storage element from <sess> session which
* refers to <target> endpoint.
*
* This function usage must be protected with idle_conns lock.
*
* Returns the storage element or NULL if not found;
*/
static struct sess_priv_conns *sess_get_sess_conns(struct session *sess,
enum obj_type *target)
{
struct sess_priv_conns *pconns;
list_for_each_entry(pconns, &sess->priv_conns, sess_el) {
if (pconns->target == target)
return pconns;
}
return NULL;
}
/* Add the connection <conn> to the private conns list of session <sess>. Each /* Add the connection <conn> to the private conns list of session <sess>. Each
* connection is indexed by their respective target in the session. Nothing is * connection is indexed by their respective target in the session. Nothing is
* performed if the connection is already in the session list. * performed if the connection is already in the session list.
@ -589,9 +639,7 @@ void __session_add_glitch_ctr(struct session *sess, uint inc)
*/ */
int session_add_conn(struct session *sess, struct connection *conn) int session_add_conn(struct session *sess, struct connection *conn)
{ {
struct sess_priv_conns *pconns = NULL; struct sess_priv_conns *pconns;
struct server *srv = objt_server(conn->target);
int found = 0;
/* Connection target is used to index it in the session. Only BE conns are expected in session list. */ /* Connection target is used to index it in the session. Only BE conns are expected in session list. */
BUG_ON(!conn->target || objt_listener(conn->target)); BUG_ON(!conn->target || objt_listener(conn->target));
@ -611,29 +659,14 @@ int session_add_conn(struct session *sess, struct connection *conn)
if (!LIST_ISEMPTY(&conn->sess_el)) if (!LIST_ISEMPTY(&conn->sess_el))
return 1; return 1;
list_for_each_entry(pconns, &sess->priv_conns, sess_el) { pconns = sess_get_sess_conns(sess, conn->target);
if (pconns->target == conn->target) { if (!pconns) {
found = 1; pconns = sess_alloc_sess_conns(sess, conn->target);
break;
}
}
if (!found) {
/* The session has no connection for the server, create a new entry */
pconns = pool_alloc(pool_head_sess_priv_conns);
if (!pconns) if (!pconns)
return 0; return 0;
pconns->target = conn->target;
LIST_INIT(&pconns->conn_list);
LIST_APPEND(&sess->priv_conns, &pconns->sess_el);
MT_LIST_INIT(&pconns->srv_el);
if (srv)
MT_LIST_APPEND(&srv->sess_conns, &pconns->srv_el);
pconns->tid = tid;
} }
LIST_APPEND(&pconns->conn_list, &conn->sess_el);
LIST_APPEND(&pconns->conn_list, &conn->sess_el);
/* Ensure owner is set for connection. It could have been reset /* Ensure owner is set for connection. It could have been reset
* prior on after a session_add_conn() failure. * prior on after a session_add_conn() failure.
*/ */
@ -679,30 +712,31 @@ int session_check_idle_conn(struct session *sess, struct connection *conn)
*/ */
struct connection *session_get_conn(struct session *sess, void *target, int64_t hash) struct connection *session_get_conn(struct session *sess, void *target, int64_t hash)
{ {
struct connection *srv_conn = NULL; struct connection *srv_conn, *res = NULL;
struct sess_priv_conns *pconns; struct sess_priv_conns *pconns;
list_for_each_entry(pconns, &sess->priv_conns, sess_el) { pconns = sess_get_sess_conns(sess, target);
if (pconns->target == target) { if (!pconns)
list_for_each_entry(srv_conn, &pconns->conn_list, sess_el) { goto end;
if ((srv_conn->hash_node && srv_conn->hash_node->node.key == hash) &&
srv_conn->mux && /* Search into pconns for a connection with matching params and available streams. */
(srv_conn->mux->avail_streams(srv_conn) > 0) && list_for_each_entry(srv_conn, &pconns->conn_list, sess_el) {
!(srv_conn->flags & CO_FL_WAIT_XPRT)) { if ((srv_conn->hash_node && srv_conn->hash_node->node.key == hash) &&
if (srv_conn->flags & CO_FL_SESS_IDLE) { srv_conn->mux &&
srv_conn->flags &= ~CO_FL_SESS_IDLE; (srv_conn->mux->avail_streams(srv_conn) > 0) &&
sess->idle_conns--; !(srv_conn->flags & CO_FL_WAIT_XPRT)) {
} if (srv_conn->flags & CO_FL_SESS_IDLE) {
goto end; srv_conn->flags &= ~CO_FL_SESS_IDLE;
} sess->idle_conns--;
} }
srv_conn = NULL; /* No available connection found */
goto end; res = srv_conn;
break;
} }
} }
end: end:
return srv_conn; return res;
} }
/* Remove the connection from the session list, and destroy sess_priv_conns /* Remove the connection from the session list, and destroy sess_priv_conns
@ -728,15 +762,13 @@ void session_unown_conn(struct session *sess, struct connection *conn)
sess->idle_conns--; sess->idle_conns--;
LIST_DEL_INIT(&conn->sess_el); LIST_DEL_INIT(&conn->sess_el);
conn->owner = NULL; conn->owner = NULL;
list_for_each_entry(pconns, &sess->priv_conns, sess_el) {
if (pconns->target == conn->target) { pconns = sess_get_sess_conns(sess, conn->target);
if (LIST_ISEMPTY(&pconns->conn_list)) { BUG_ON(!pconns); /* if conn is attached to session, its sess_conn must exists. */
LIST_DELETE(&pconns->sess_el); if (LIST_ISEMPTY(&pconns->conn_list)) {
MT_LIST_DELETE(&pconns->srv_el); LIST_DELETE(&pconns->sess_el);
pool_free(pool_head_sess_priv_conns, pconns); MT_LIST_DELETE(&pconns->srv_el);
} pool_free(pool_head_sess_priv_conns, pconns);
break;
}
} }
} }