]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: server: close private idle connection before server deletion
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 14 Mar 2024 10:24:19 +0000 (11:24 +0100)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Fri, 22 Mar 2024 16:12:27 +0000 (17:12 +0100)
This commit similar to the following one :
  65ae241dcfe710e1cdd3ec4e7a9bde38d2e4c116
  MEDIUM: server: close idle conn before server deletion

This patch implements a similar logic, this time to close private idle
connections stored in sessions. The principle is identical to the above
commit : conn_release() is used on idle connections after a takeover to
ensure thread safety.

An extra change was required to be able to execute takeover on such
connections. Their original thread ID was unknown, contrary to non
private connections which are stored in sharded lists. As such, a new
tid member has been added under sess_priv_conns chaining element.

include/haproxy/session-t.h
include/haproxy/session.h
src/server.c

index aa2bf1e82f55406745d7097f831b2804835b5ba8..8c59477df6b7270871969e69c55805d3b7069b4d 100644 (file)
@@ -72,6 +72,8 @@ struct sess_priv_conns {
 
        struct list sess_el;            /* Element of session.priv_conns */
        struct mt_list srv_el;          /* Element of server.sess_conns */
+
+       int tid;
 };
 
 #endif /* _HAPROXY_SESSION_T_H */
index d9ff726a9ac6946aa54c1b5afe71823775297100..b70a5a89c2620d6440d0cc6fcc282dac83a7cce8 100644 (file)
@@ -204,6 +204,8 @@ static inline int session_add_conn(struct session *sess, struct connection *conn
                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);
 
index 92d3fee94cffcd642ec9d414d22b09e4e994f630..badcf3851138a2d4fd828ed983489ccc9f40a95b 100644 (file)
@@ -5830,7 +5830,6 @@ int srv_check_for_deletion(const char *bename, const char *svname, struct proxy
 
        /* 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.";
                goto leave;
@@ -5857,6 +5856,8 @@ static int cli_parse_delete_server(char **args, char *payload, struct appctx *ap
        struct server *srv;
        struct server *prev_del;
        struct ist be_name, sv_name;
+       struct mt_list *elt1, elt2;
+       struct sess_priv_conns *sess_conns = NULL;
        const char *msg;
        int ret, i;
 
@@ -5910,6 +5911,31 @@ static int cli_parse_delete_server(char **args, char *payload, struct appctx *ap
        /* All idle connections should be removed now. */
        BUG_ON(srv->curr_idle_conns);
 
+       /* Close idle private connections attached to this server. */
+       mt_list_for_each_entry_safe(sess_conns, &srv->sess_conns, srv_el, elt1, elt2) {
+               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));
+
+                       LIST_DEL_INIT(&conn->sess_el);
+                       conn->owner = NULL;
+                       conn->flags &= ~CO_FL_SESS_IDLE;
+                       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);
+               }
+
+               LIST_DELETE(&sess_conns->sess_el);
+               MT_LIST_DELETE_SAFE(elt1);
+               pool_free(pool_head_sess_priv_conns, sess_conns);
+       }
+
        /* removing cannot fail anymore when we reach this:
         * publishing EVENT_HDL_SUB_SERVER_DEL
         */