From d4f7a2dbcc5f6a06bce4b36c9af60abe833d73d9 Mon Sep 17 00:00:00 2001 From: Amaury Denoyelle Date: Wed, 20 Aug 2025 10:01:46 +0200 Subject: [PATCH] MINOR: session: uninline functions related to BE conns management Move from header to source file functions related to session management of backend connections. These functions are big enough to remove inline attribute. --- include/haproxy/session.h | 164 +------------------------------------- src/session.c | 164 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 168 insertions(+), 160 deletions(-) diff --git a/include/haproxy/session.h b/include/haproxy/session.h index 714017ffa..7a8a73361 100644 --- a/include/haproxy/session.h +++ b/include/haproxy/session.h @@ -43,6 +43,10 @@ struct task *session_expire_embryonic(struct task *t, void *context, unsigned in void __session_add_glitch_ctr(struct session *sess, uint inc); void session_embryonic_build_legacy_err(struct session *sess, struct buffer *out); +int session_add_conn(struct session *sess, struct connection *conn); +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); /* 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 @@ -136,166 +140,6 @@ static inline void session_add_glitch_ctr(struct session *sess, uint inc) __session_add_glitch_ctr(sess, inc); } -/* Remove the connection from the session list, and destroy sess_priv_conns - * element if it's now empty. - */ -static inline void session_unown_conn(struct session *sess, struct connection *conn) -{ - struct sess_priv_conns *pconns = NULL; - - BUG_ON(objt_listener(conn->target)); - - /* WT: this currently is a workaround for an inconsistency between - * the link status of the connection in the session list and the - * connection's owner. This should be removed as soon as all this - * is addressed. Right now it's possible to enter here with a non-null - * conn->owner that points to a dead session, but in this case the - * element is not linked. - */ - if (!LIST_INLIST(&conn->sess_el)) - return; - - if (conn->flags & CO_FL_SESS_IDLE) - sess->idle_conns--; - LIST_DEL_INIT(&conn->sess_el); - conn->owner = NULL; - list_for_each_entry(pconns, &sess->priv_conns, sess_el) { - if (pconns->target == conn->target) { - if (LIST_ISEMPTY(&pconns->conn_list)) { - LIST_DELETE(&pconns->sess_el); - MT_LIST_DELETE(&pconns->srv_el); - pool_free(pool_head_sess_priv_conns, pconns); - } - break; - } - } -} - -/* Add the connection to the private conns list of session . Each - * connection is indexed by their respective target in the session. Nothing is - * performed if the connection is already in the session list. - * - * Returns true if conn is inserted or already present else false if a failure - * occurs during insertion. - */ -static inline int session_add_conn(struct session *sess, struct connection *conn) -{ - struct sess_priv_conns *pconns = NULL; - 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. */ - BUG_ON(!conn->target || objt_listener(conn->target)); - - /* A connection cannot be attached already to another session. - * - * This is safe as BE connections are flagged as private immediately - * after being created during connect_server(). The only potential - * issue would be if a connection is turned private later on during its - * lifetime. Currently, this happens only on NTLM headers detection, - * however this case is only implemented with HTTP/1.1 which cannot - * multiplex several streams on the same connection. - */ - BUG_ON(conn->owner && conn->owner != sess); - - /* Already attach to the session */ - if (!LIST_ISEMPTY(&conn->sess_el)) - return 1; - - list_for_each_entry(pconns, &sess->priv_conns, sess_el) { - if (pconns->target == conn->target) { - found = 1; - 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) - 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); - - /* Ensure owner is set for connection. It could have been reset - * prior on after a session_add_conn() failure. - */ - conn->owner = sess; - - return 1; -} - -/* Check that session is able to keep idle connection . This must - * be called each time a connection stored in a session becomes idle. - * - * Returns 0 if the connection is kept, else non-zero if the connection was - * explicitely removed from session. - */ -static inline int session_check_idle_conn(struct session *sess, struct connection *conn) -{ - /* Connection must be attached to session prior to this function call. */ - BUG_ON(!conn->owner || conn->owner != sess); - - /* Connection is not attached to a session. */ - if (!conn->owner) - return 0; - - /* Ensure conn is not already accounted as idle to prevent sess idle count excess increment. */ - BUG_ON(conn->flags & CO_FL_SESS_IDLE); - - if (sess->idle_conns >= sess->fe->max_out_conns) { - session_unown_conn(sess, conn); - conn->owner = NULL; - return -1; - } - else { - conn->flags |= CO_FL_SESS_IDLE; - sess->idle_conns++; - } - - return 0; -} - -/* Look for an available connection matching the target in the server - * list of the session . It returns a connection if found. Otherwise it - * returns NULL. - */ -static inline struct connection *session_get_conn(struct session *sess, void *target, int64_t hash) -{ - struct connection *srv_conn = NULL; - struct sess_priv_conns *pconns; - - list_for_each_entry(pconns, &sess->priv_conns, sess_el) { - if (pconns->target == target) { - list_for_each_entry(srv_conn, &pconns->conn_list, sess_el) { - if ((srv_conn->hash_node && srv_conn->hash_node->node.key == hash) && - srv_conn->mux && - (srv_conn->mux->avail_streams(srv_conn) > 0) && - !(srv_conn->flags & CO_FL_WAIT_XPRT)) { - if (srv_conn->flags & CO_FL_SESS_IDLE) { - srv_conn->flags &= ~CO_FL_SESS_IDLE; - sess->idle_conns--; - } - goto end; - } - } - srv_conn = NULL; /* No available connection found */ - goto end; - } - } - - end: - return srv_conn; -} - /* Returns the source address of the session and fallbacks on the client * connection if not set. It returns a const address on success or NULL on * failure. diff --git a/src/session.c b/src/session.c index c734d721c..507be71c6 100644 --- a/src/session.c +++ b/src/session.c @@ -577,6 +577,170 @@ void __session_add_glitch_ctr(struct session *sess, uint inc) stkctr_add_glitch_ctr(&sess->stkctr[i], inc); } + +/* Session management of backend connections. */ + +/* Add the connection to the private conns list of session . Each + * connection is indexed by their respective target in the session. Nothing is + * performed if the connection is already in the session list. + * + * Returns true if conn is inserted or already present else false if a failure + * occurs during insertion. + */ +int session_add_conn(struct session *sess, struct connection *conn) +{ + struct sess_priv_conns *pconns = NULL; + 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. */ + BUG_ON(!conn->target || objt_listener(conn->target)); + + /* A connection cannot be attached already to another session. + * + * This is safe as BE connections are flagged as private immediately + * after being created during connect_server(). The only potential + * issue would be if a connection is turned private later on during its + * lifetime. Currently, this happens only on NTLM headers detection, + * however this case is only implemented with HTTP/1.1 which cannot + * multiplex several streams on the same connection. + */ + BUG_ON(conn->owner && conn->owner != sess); + + /* Already attach to the session */ + if (!LIST_ISEMPTY(&conn->sess_el)) + return 1; + + list_for_each_entry(pconns, &sess->priv_conns, sess_el) { + if (pconns->target == conn->target) { + found = 1; + 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) + 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); + + /* Ensure owner is set for connection. It could have been reset + * prior on after a session_add_conn() failure. + */ + conn->owner = sess; + + return 1; +} + +/* Check that session is able to keep idle connection . This must + * be called each time a connection stored in a session becomes idle. + * + * Returns 0 if the connection is kept, else non-zero if the connection was + * explicitely removed from session. + */ +int session_check_idle_conn(struct session *sess, struct connection *conn) +{ + /* Connection must be attached to session prior to this function call. */ + BUG_ON(!conn->owner || conn->owner != sess); + + /* Connection is not attached to a session. */ + if (!conn->owner) + return 0; + + /* Ensure conn is not already accounted as idle to prevent sess idle count excess increment. */ + BUG_ON(conn->flags & CO_FL_SESS_IDLE); + + if (sess->idle_conns >= sess->fe->max_out_conns) { + session_unown_conn(sess, conn); + conn->owner = NULL; + return -1; + } + else { + conn->flags |= CO_FL_SESS_IDLE; + sess->idle_conns++; + } + + return 0; +} + +/* Look for an available connection matching the target in the server + * list of the session . It returns a connection if found. Otherwise it + * returns NULL. + */ +struct connection *session_get_conn(struct session *sess, void *target, int64_t hash) +{ + struct connection *srv_conn = NULL; + struct sess_priv_conns *pconns; + + list_for_each_entry(pconns, &sess->priv_conns, sess_el) { + if (pconns->target == target) { + list_for_each_entry(srv_conn, &pconns->conn_list, sess_el) { + if ((srv_conn->hash_node && srv_conn->hash_node->node.key == hash) && + srv_conn->mux && + (srv_conn->mux->avail_streams(srv_conn) > 0) && + !(srv_conn->flags & CO_FL_WAIT_XPRT)) { + if (srv_conn->flags & CO_FL_SESS_IDLE) { + srv_conn->flags &= ~CO_FL_SESS_IDLE; + sess->idle_conns--; + } + goto end; + } + } + srv_conn = NULL; /* No available connection found */ + goto end; + } + } + + end: + return srv_conn; +} + +/* Remove the connection from the session list, and destroy sess_priv_conns + * element if it's now empty. + */ +void session_unown_conn(struct session *sess, struct connection *conn) +{ + struct sess_priv_conns *pconns = NULL; + + BUG_ON(objt_listener(conn->target)); + + /* WT: this currently is a workaround for an inconsistency between + * the link status of the connection in the session list and the + * connection's owner. This should be removed as soon as all this + * is addressed. Right now it's possible to enter here with a non-null + * conn->owner that points to a dead session, but in this case the + * element is not linked. + */ + if (!LIST_INLIST(&conn->sess_el)) + return; + + if (conn->flags & CO_FL_SESS_IDLE) + sess->idle_conns--; + LIST_DEL_INIT(&conn->sess_el); + conn->owner = NULL; + list_for_each_entry(pconns, &sess->priv_conns, sess_el) { + if (pconns->target == conn->target) { + if (LIST_ISEMPTY(&pconns->conn_list)) { + LIST_DELETE(&pconns->sess_el); + MT_LIST_DELETE(&pconns->srv_el); + pool_free(pool_head_sess_priv_conns, pconns); + } + break; + } + } +} + + /* * Local variables: * c-indent-level: 8