]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: connection/server: refactor idle conn purge 20250808-ade-purge-conn-for-del-server
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Mon, 4 Aug 2025 12:55:07 +0000 (14:55 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 20 Aug 2025 15:32:30 +0000 (17:32 +0200)
14 files changed:
include/haproxy/connection-t.h
include/haproxy/server-t.h
include/haproxy/server.h
src/backend.c
src/cfgparse.c
src/connection.c
src/haproxy.c
src/mux_fcgi.c
src/mux_h1.c
src/mux_h2.c
src/mux_spop.c
src/server.c
src/session.c
src/ssl_sock.c

index 571943131622a5e98d914e3e6d9457b1448d5551..6bb47c6bd24f6c71a063a866f03cada2154b4c0a 100644 (file)
@@ -608,7 +608,7 @@ struct connection {
        struct wait_event *subs; /* Task to wake when awaited events are ready */
        union {
                struct list    idle_list; /* list element for idle connection in server idle list */
-               struct mt_list toremove_list; /* list element when idle connection is ready to be purged */
+               struct mt_list purge_el; /* list element when idle connection is ready to be purged */
        };
        union {
                struct list sess_el;       /* used by private backend conns, list elem into session */
@@ -772,11 +772,11 @@ union mux_sctl_dbg_str_ctx {
  * accessible from foreign threads.
  */
 struct idle_conns {
-       struct mt_list toremove_conns;
-       struct task *cleanup_task;
-       __decl_thread(HA_SPINLOCK_T idle_conns_lock);
-} THREAD_ALIGNED(64);
+       struct mt_list purged_list;
+       struct task *task_free_purged;
 
+       __decl_thread(HA_SPINLOCK_T lock);
+} THREAD_ALIGNED(64);
 
 /* Termination events logs:
  * Each event is stored on 8 bits: 4 bits bor the event location and
index 8f15c21e90b0595374810606eb008f1178f35515..204483a086bfff7fb3009ed82026f8f09a46ce60 100644 (file)
@@ -379,7 +379,7 @@ struct server {
         * thread, and generally at the same time.
         */
        THREAD_ALIGN(64);
-       struct eb32_node idle_node;             /* When to next do cleanup in the idle connections */
+       struct eb32_node purge_node;            /* When to next do cleanup in the idle connections */
        unsigned int curr_idle_conns;           /* Current number of orphan idling connections, both the idle and the safe lists */
        unsigned int curr_idle_nb;              /* Current number of connections in the idle list */
        unsigned int curr_safe_nb;              /* Current number of connections in the safe list */
index 9d401ffc9754a1d67e57dae2a02c3f1c9f310c74..7503f4b35d507082ad7c2ddc1e73030a5294153d 100644 (file)
@@ -38,9 +38,9 @@
 #include <haproxy/tools.h>
 
 
-__decl_thread(extern HA_SPINLOCK_T idle_conn_srv_lock);
-extern struct idle_conns idle_conns[MAX_THREADS];
-extern struct task *idle_conn_task;
+__decl_thread(extern HA_SPINLOCK_T purge_conns_lock);
+extern struct task *task_purge_servers;
+
 extern struct mt_list servers_list;
 extern struct dict server_key_dict;
 
@@ -98,7 +98,6 @@ struct connection *srv_lookup_conn_next(struct connection *conn);
 void _srv_add_idle(struct server *srv, struct connection *conn, int is_safe);
 int srv_add_to_idle_list(struct server *srv, struct connection *conn, int is_safe);
 void srv_add_to_avail_list(struct server *srv, struct connection *conn);
-struct task *srv_cleanup_toremove_conns(struct task *task, void *context, unsigned int state);
 
 int srv_apply_track(struct server *srv, struct proxy *curproxy);
 
index 3b4aef681d1d65c879b71e056967744e690d6d35..dc836348c73218b86dfd8e0b71c413859d2c1293 100644 (file)
@@ -1310,7 +1310,7 @@ struct connection *conn_backend_get(int reuse_mode,
         * to end up with two threads using the same connection.
         */
        i = tid;
-       HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+       HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
        conn = srv_lookup_conn(is_safe ? &srv->per_thr[tid].safe_conns : &srv->per_thr[tid].idle_conns, hash);
        if (conn)
                conn_delete_from_tree(conn);
@@ -1325,7 +1325,7 @@ struct connection *conn_backend_get(int reuse_mode,
                        is_safe = 1;
                }
        }
-       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
 
        /* If we found a connection in our own list, and we don't have to
         * steal one from another thread, then we're done.
@@ -1364,7 +1364,7 @@ check_tgid:
                if (!srv->curr_idle_thr[i] || i == tid)
                        continue;
 
-               if (HA_SPIN_TRYLOCK(IDLE_CONNS_LOCK, &idle_conns[i].idle_conns_lock) != 0)
+               if (HA_SPIN_TRYLOCK(IDLE_CONNS_LOCK, &idle_conns[i].lock) != 0)
                        continue;
                conn = srv_lookup_conn(is_safe ? &srv->per_thr[i].safe_conns : &srv->per_thr[i].idle_conns, hash);
                while (conn) {
@@ -1392,7 +1392,7 @@ check_tgid:
                                conn = srv_lookup_conn_next(conn);
                        }
                }
-               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[i].idle_conns_lock);
+               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[i].lock);
        } while (!found && (i = (i + 1 == curtg->base + curtg->count) ? curtg->base : i + 1) != stop);
 
        if (!found && (global.tune.tg_takeover == FULL_THREADGROUP_TAKEOVER ||
@@ -1517,12 +1517,12 @@ kill_random_idle_conn(struct server *srv)
        for (i = 0; i < global.nbthread; i++) {
                curtid = (i + tid) % global.nbthread;
 
-               if (HA_SPIN_TRYLOCK(IDLE_CONNS_LOCK, &idle_conns[curtid].idle_conns_lock) != 0)
+               if (HA_SPIN_TRYLOCK(IDLE_CONNS_LOCK, &idle_conns[curtid].lock) != 0)
                        continue;
                conn = takeover_random_idle_conn(&srv->per_thr[curtid].idle_conns, curtid);
                if (!conn)
                        conn = takeover_random_idle_conn(&srv->per_thr[curtid].safe_conns, curtid);
-               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[curtid].idle_conns_lock);
+               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[curtid].lock);
                if (conn)
                        break;
        }
@@ -1744,9 +1744,9 @@ int be_reuse_connection(int64_t hash, struct session *sess,
 
                        if (avail <= 1) {
                                /* no more streams available, remove it from the list */
-                               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+                               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                                conn_delete_from_tree(srv_conn);
-                               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+                               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                        }
 
                        if (avail >= 1) {
@@ -1848,11 +1848,11 @@ int connect_server(struct stream *s)
                /* We have more FDs than deemed acceptable, attempt to kill an idling connection. */
                struct connection *tokill_conn = NULL;
                /* First, try from our own idle list */
-               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                if (!LIST_ISEMPTY(&srv->per_thr[tid].idle_conn_list)) {
                        tokill_conn = LIST_ELEM(srv->per_thr[tid].idle_conn_list.n, struct connection *, idle_list);
                        conn_delete_from_tree(tokill_conn);
-                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
 
                        /* Release the idle lock before calling mux->destroy.
                         * It will in turn call srv_release_conn through
@@ -1861,7 +1861,7 @@ int connect_server(struct stream *s)
                        tokill_conn->mux->destroy(tokill_conn->ctx);
                }
                else {
-                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                }
 
                /* If not, iterate over other thread's idling pool, and try to grab one */
@@ -1875,21 +1875,20 @@ int connect_server(struct stream *s)
                                // see it possibly larger.
                                ALREADY_CHECKED(i);
 
-                               if (HA_SPIN_TRYLOCK(IDLE_CONNS_LOCK, &idle_conns[i].idle_conns_lock) != 0)
+                               if (HA_SPIN_TRYLOCK(IDLE_CONNS_LOCK, &idle_conns[i].lock) != 0)
                                        continue;
 
                                if (!LIST_ISEMPTY(&srv->per_thr[i].idle_conn_list)) {
                                        tokill_conn = LIST_ELEM(srv->per_thr[i].idle_conn_list.n, struct connection *, idle_list);
                                        conn_delete_from_tree(tokill_conn);
                                }
-                               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[i].idle_conns_lock);
+                               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[i].lock);
 
                                if (tokill_conn) {
                                        /* We got one, put it into the concerned thread's to kill list, and wake it's kill task */
-
-                                       MT_LIST_APPEND(&idle_conns[i].toremove_conns,
-                                                      &tokill_conn->toremove_list);
-                                       task_wakeup(idle_conns[i].cleanup_task, TASK_WOKEN_OTHER);
+                                       MT_LIST_APPEND(&idle_conns[i].purged_list,
+                                                      &tokill_conn->purge_el);
+                                       task_wakeup(idle_conns[i].task_free_purged, TASK_WOKEN_OTHER);
                                        break;
                                }
 
index 040e3554990f2ea0499db6452222f0ca0ea66c29..5109ce0b7d0a725b255657d51a7dd55137bcc758 100644 (file)
@@ -4201,30 +4201,6 @@ out_uri_auth_compat:
        /* At this point, target names have already been resolved. */
        /***********************************************************/
 
-       idle_conn_task = task_new_anywhere();
-       if (!idle_conn_task) {
-               ha_alert("parsing : failed to allocate global idle connection task.\n");
-               cfgerr++;
-       }
-       else {
-               idle_conn_task->process = srv_cleanup_idle_conns;
-               idle_conn_task->context = NULL;
-
-               for (i = 0; i < global.nbthread; i++) {
-                       idle_conns[i].cleanup_task = task_new_on(i);
-                       if (!idle_conns[i].cleanup_task) {
-                               ha_alert("parsing : failed to allocate idle connection tasks for thread '%d'.\n", i);
-                               cfgerr++;
-                               break;
-                       }
-
-                       idle_conns[i].cleanup_task->process = srv_cleanup_toremove_conns;
-                       idle_conns[i].cleanup_task->context = NULL;
-                       HA_SPIN_INIT(&idle_conns[i].idle_conns_lock);
-                       MT_LIST_INIT(&idle_conns[i].toremove_conns);
-               }
-       }
-
        /* perform the final checks before creating tasks */
 
        /* starting to initialize the main proxies list */
index 65a45b90f2acf92639fcc9b23d867a6e8dd6f5a8..0323df9a198df6a20770151f36ca8362f8d4b9d8 100644 (file)
@@ -76,7 +76,7 @@ struct conn_tlv_list *conn_get_tlv(struct connection *conn, int type)
 /* Remove <conn> idle connection from its attached tree (idle, safe or avail).
  * If also present in the secondary server idle list, conn is removed from it.
  *
- * Must be called with idle_conns_lock held.
+ * Must be called with lock held.
  */
 void conn_delete_from_tree(struct connection *conn)
 {
@@ -225,9 +225,9 @@ int conn_notify_mux(struct connection *conn, int old_flags, int forced_wake)
                struct server *srv = objt_server(conn->target);
 
                if (conn_in_list) {
-                       HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+                       HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                        conn_delete_from_tree(conn);
-                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                }
 
                ret = conn->mux->wake(conn);
@@ -250,9 +250,9 @@ int conn_notify_mux(struct connection *conn, int old_flags, int forced_wake)
                                }
                        }
                        else {
-                               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+                               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                                _srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST);
-                               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+                               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                        }
                }
        }
@@ -505,7 +505,7 @@ void conn_init(struct connection *conn, void *target)
        conn->target = target;
        conn->destroy_cb = NULL;
        conn->proxy_netns = NULL;
-       MT_LIST_INIT(&conn->toremove_list);
+       MT_LIST_INIT(&conn->purge_el);
        if (conn_is_back(conn))
                LIST_INIT(&conn->sess_el);
        else
@@ -602,13 +602,13 @@ void conn_free(struct connection *conn)
        if (conn_is_back(conn))
                conn_backend_deinit(conn);
 
-       /* Remove the conn from toremove_list.
+       /* Remove the conn from purge list.
         *
         * This is needed to prevent a double-free in case the connection was
         * already scheduled from cleaning but is freed before via another
         * call.
         */
-       MT_LIST_DELETE(&conn->toremove_list);
+       MT_LIST_DELETE(&conn->purge_el);
 
        sockaddr_free(&conn->src);
        sockaddr_free(&conn->dst);
@@ -3022,6 +3022,21 @@ int conn_reverse(struct connection *conn)
        return 0;
 }
 
+/* Handler for task_free_purged of idle_conns. Free all connections registered
+ * in the purge list of the current thread.
+ */
+static struct task *free_purged_conns(struct task *task, void *context, unsigned int state)
+{
+       struct connection *conn;
+
+       while ((conn = MT_LIST_POP(&idle_conns[tid].purged_list,
+                                  struct connection *, purge_el)) != NULL) {
+               conn->mux->destroy(conn->ctx);
+       }
+
+       return task;
+}
+
 /* Handler of the task of mux_stopping_data.
  * Called on soft-stop.
  */
@@ -3060,12 +3075,28 @@ static int deallocate_mux_cleanup(void)
 }
 REGISTER_PER_THREAD_FREE(deallocate_mux_cleanup);
 
-static void deinit_idle_conns(void)
+static int allocate_idle_conns(void)
+{
+       idle_conns[tid].task_free_purged = task_new_on(tid);
+       if (!idle_conns[tid].task_free_purged) {
+               ha_alert("Failed to allocate idle connection tasks for thread '%d'.\n", tid);
+               return 0;
+       }
+
+       idle_conns[tid].task_free_purged->process = free_purged_conns;
+       idle_conns[tid].task_free_purged->context = NULL;
+       HA_SPIN_INIT(&idle_conns[tid].lock);
+       MT_LIST_INIT(&idle_conns[tid].purged_list);
+
+       return 1;
+}
+REGISTER_PER_THREAD_ALLOC(allocate_idle_conns);
+
+static void deinit_gc_purged_conns(void)
 {
        int i;
 
-       for (i = 0; i < global.nbthread; i++) {
-               task_destroy(idle_conns[i].cleanup_task);
-       }
+       for (i = 0; i < global.nbthread; i++)
+               task_destroy(idle_conns[i].task_free_purged);
 }
-REGISTER_POST_DEINIT(deinit_idle_conns);
+REGISTER_POST_DEINIT(deinit_gc_purged_conns);
index e0f196a343e043b82b3f02988e33a6342ab058fd..b2c69c2b1f26a012def61414a08e648a7ba68325 100644 (file)
@@ -2694,8 +2694,8 @@ void deinit(void)
        ha_free(&global.server_state_base);
        ha_free(&global.server_state_file);
        ha_free(&global.stats_file);
-       task_destroy(idle_conn_task);
-       idle_conn_task = NULL;
+       task_destroy(task_purge_servers);
+       task_purge_servers = NULL;
 
        list_for_each_entry_safe(log, logb, &global.loggers, list) {
                LIST_DEL_INIT(&log->list);
index 5b0ec5ba34b618cc1d9a25084b77f66c202df74a..fd4f7d4fbafceb5a40da87d5f2a20f3791347076 100644 (file)
@@ -3048,13 +3048,13 @@ struct task *fcgi_io_cb(struct task *t, void *ctx, unsigned int state)
                /* the tasklet was idling on an idle connection, it might have
                 * been stolen, let's be careful!
                 */
-               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                if (tl->context == NULL) {
                        /* The connection has been taken over by another thread,
                         * we're no longer responsible for it, so just free the
                         * tasklet, and do nothing.
                         */
-                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                        tasklet_free(tl);
                        return NULL;
                }
@@ -3069,7 +3069,7 @@ struct task *fcgi_io_cb(struct task *t, void *ctx, unsigned int state)
                                conn_delete_from_tree(conn);
                }
 
-               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
        } else {
                /* we're certain the connection was not in an idle list */
                conn = fconn->conn;
@@ -3104,9 +3104,9 @@ struct task *fcgi_io_cb(struct task *t, void *ctx, unsigned int state)
                                }
                        }
                        else {
-                               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+                               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                                _srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST);
-                               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+                               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                        }
                }
                else {
@@ -3302,19 +3302,19 @@ struct task *fcgi_timeout_task(struct task *t, void *context, unsigned int state
        TRACE_ENTER(FCGI_EV_FCONN_WAKE, (fconn ? fconn->conn : NULL));
 
        if (fconn) {
-               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
 
                /* Somebody already stole the connection from us, so we should not
                 * free it, we just have to free the task.
                 */
                if (!t->context) {
-                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                        fconn = NULL;
                        goto do_leave;
                }
 
                if (!expired) {
-                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                        TRACE_DEVEL("leaving (not expired)", FCGI_EV_FCONN_WAKE, fconn->conn);
                        return t;
                }
@@ -3327,7 +3327,7 @@ struct task *fcgi_timeout_task(struct task *t, void *context, unsigned int state
                else if (fconn->conn->flags & CO_FL_SESS_IDLE)
                        conn_delete_from_sess(fconn->conn);
 
-               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
 
                fcgi_conn_report_term_evt(fconn, muxc_tevt_type_tout);
        }
index 59768e3d384b7d93cb2fe48475f3ea511cd3b883..dc75843ffa8da98ef721cb865abcaa80ad96ceed 100644 (file)
@@ -4290,13 +4290,13 @@ struct task *h1_io_cb(struct task *t, void *ctx, unsigned int state)
                /* the tasklet was idling on an idle connection, it might have
                 * been stolen, let's be careful!
                 */
-               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                if (tl->context == NULL) {
                        /* The connection has been taken over by another thread,
                         * we're no longer responsible for it, so just free the
                         * tasklet, and do nothing.
                         */
-                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                        tasklet_free(tl);
                        return NULL;
                }
@@ -4314,7 +4314,7 @@ struct task *h1_io_cb(struct task *t, void *ctx, unsigned int state)
                                conn_delete_from_tree(conn);
                }
 
-               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
        } else {
                /* we're certain the connection was not in an idle list */
                conn = h1c->conn;
@@ -4349,9 +4349,9 @@ struct task *h1_io_cb(struct task *t, void *ctx, unsigned int state)
                                }
                        }
                        else {
-                               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+                               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                                _srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST);
-                               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+                               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                        }
                }
                else {
@@ -4393,19 +4393,19 @@ struct task *h1_timeout_task(struct task *t, void *context, unsigned int state)
 
        if (h1c) {
                 /* Make sure nobody stole the connection from us */
-               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
 
                /* Somebody already stole the connection from us, so we should not
                 * free it, we just have to free the task.
                 */
                if (!t->context) {
                        h1c = NULL;
-                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                        goto do_leave;
                }
 
                if (!expired) {
-                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                        TRACE_DEVEL("leaving (not expired)", H1_EV_H1C_WAKE, h1c->conn, h1c->h1s);
                        return t;
                }
@@ -4414,7 +4414,7 @@ struct task *h1_timeout_task(struct task *t, void *context, unsigned int state)
                 * stream's timeout
                 */
                if (h1c->state == H1_CS_RUNNING) {
-                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                        t->expire = TICK_ETERNITY;
                        TRACE_DEVEL("leaving (SC still attached)", H1_EV_H1C_WAKE, h1c->conn, h1c->h1s);
                        return t;
@@ -4427,7 +4427,7 @@ struct task *h1_timeout_task(struct task *t, void *context, unsigned int state)
                                h1_send(h1c);
                        if (b_data(&h1c->obuf) || (h1c->flags & H1C_F_ABRT_PENDING)) {
                                h1_refresh_timeout(h1c);
-                               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+                               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                                return t;
                        }
                }
@@ -4438,7 +4438,7 @@ struct task *h1_timeout_task(struct task *t, void *context, unsigned int state)
                        se_fl_set(h1c->h1s->sd, SE_FL_EOS | SE_FL_ERROR);
                        h1_alert(h1c->h1s);
                        h1_refresh_timeout(h1c);
-                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                        TRACE_DEVEL("waiting to release the SC before releasing the connection", H1_EV_H1C_WAKE);
                        return t;
                }
@@ -4449,7 +4449,7 @@ struct task *h1_timeout_task(struct task *t, void *context, unsigned int state)
                if (h1c->conn->flags & CO_FL_LIST_MASK)
                        conn_delete_from_tree(h1c->conn);
 
-               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
 
                h1c_report_term_evt(h1c, muxc_tevt_type_tout);
        }
index 16e86aff8c79fb3be1c95e0a286936385e5436c0..be605fe2bea71cc56216cdf0a171e6e3f517f6f5 100644 (file)
@@ -4946,13 +4946,13 @@ struct task *h2_io_cb(struct task *t, void *ctx, unsigned int state)
                /* the tasklet was idling on an idle connection, it might have
                 * been stolen, let's be careful!
                 */
-               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                if (t->context == NULL) {
                        /* The connection has been taken over by another thread,
                         * we're no longer responsible for it, so just free the
                         * tasklet, and do nothing.
                         */
-                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                        tasklet_free(tl);
                        t = NULL;
                        goto leave;
@@ -4971,7 +4971,7 @@ struct task *h2_io_cb(struct task *t, void *ctx, unsigned int state)
                                conn_delete_from_tree(conn);
                }
 
-               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
        } else {
                /* we're certain the connection was not in an idle list */
                conn = h2c->conn;
@@ -5009,9 +5009,9 @@ struct task *h2_io_cb(struct task *t, void *ctx, unsigned int state)
                                }
                        }
                        else {
-                               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+                               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                                _srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST);
-                               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+                               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                        }
                }
                else {
@@ -5135,17 +5135,17 @@ static int h2_process(struct h2c *h2c)
 
                /* connections in error must be removed from the idle lists */
                if (conn->flags & CO_FL_LIST_MASK) {
-                       HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+                       HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                        conn_delete_from_tree(conn);
-                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                }
        }
        else if (h2c->st0 == H2_CS_ERROR) {
                /* connections in error must be removed from the idle lists */
                if (conn->flags & CO_FL_LIST_MASK) {
-                       HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+                       HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                        conn_delete_from_tree(conn);
-                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                }
        }
 
@@ -5206,20 +5206,20 @@ struct task *h2_timeout_task(struct task *t, void *context, unsigned int state)
 
        if (h2c) {
                 /* Make sure nobody stole the connection from us */
-               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
 
                /* Somebody already stole the connection from us, so we should not
                 * free it, we just have to free the task.
                 */
                if (!t->context) {
                        h2c = NULL;
-                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                        goto do_leave;
                }
 
 
                if (!expired) {
-                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                        TRACE_DEVEL("leaving (not expired)", H2_EV_H2C_WAKE, h2c->conn);
                        return t;
                }
@@ -5228,7 +5228,7 @@ struct task *h2_timeout_task(struct task *t, void *context, unsigned int state)
                        /* we do still have streams but all of them are idle, waiting
                         * for the data layer, so we must not enforce the timeout here.
                         */
-                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                        t->expire = TICK_ETERNITY;
                        return t;
                }
@@ -5238,7 +5238,7 @@ struct task *h2_timeout_task(struct task *t, void *context, unsigned int state)
                        tasklet_wakeup(h2c->wait_event.tasklet);
                        TRACE_DEVEL("leaving (idle ping)", H2_EV_H2C_WAKE, h2c->conn);
                        t->expire = conn_idle_ping(h2c->conn);
-                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                        return t;
                }
 
@@ -5250,7 +5250,7 @@ struct task *h2_timeout_task(struct task *t, void *context, unsigned int state)
                else if (h2c->conn->flags & CO_FL_SESS_IDLE)
                        session_unown_conn(h2c->conn->owner, h2c->conn);
 
-               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
 
                if (h2c->flags & H2_CF_IDL_PING_SENT) {
                        TRACE_STATE("expired on idle ping", H2_EV_H2C_WAKE, h2c->conn);
@@ -5327,9 +5327,9 @@ do_leave:
 
        /* in any case this connection must not be considered idle anymore */
        if (h2c->conn->flags & CO_FL_LIST_MASK) {
-               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                conn_delete_from_tree(h2c->conn);
-               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
        }
 
        /* either we can release everything now or it will be done later once
index 6685dc8efa2bf381ee3776fae98bb025e5365196..4fe70f98f79f30b719c0831212f7d9e15106041f 100644 (file)
@@ -2541,13 +2541,13 @@ static struct task *spop_io_cb(struct task *t, void *ctx, unsigned int state)
                /* the tasklet was idling on an idle connection, it might have
                 * been stolen, let's be careful!
                 */
-               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                if (tl->context == NULL) {
                        /* The connection has been taken over by another thread,
                         * we're no longer responsible for it, so just free the
                         * tasklet, and do nothing.
                         */
-                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                        tasklet_free(tl);
                        return NULL;
                }
@@ -2562,7 +2562,7 @@ static struct task *spop_io_cb(struct task *t, void *ctx, unsigned int state)
                                conn_delete_from_tree(conn);
                }
 
-               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
        } else {
                /* we're certain the connection was not in an idle list */
                conn = spop_conn->conn;
@@ -2597,9 +2597,9 @@ static struct task *spop_io_cb(struct task *t, void *ctx, unsigned int state)
                                }
                        }
                        else {
-                               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+                               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                                _srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST);
-                               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+                               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                        }
                }
                else {
@@ -2666,9 +2666,9 @@ static int spop_process(struct spop_conn *spop_conn)
 
                /* connections in error must be removed from the idle lists */
                if (conn->flags & CO_FL_LIST_MASK) {
-                       HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+                       HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                        conn_delete_from_tree(conn);
-                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                }
        }
 
@@ -2769,19 +2769,19 @@ static struct task *spop_timeout_task(struct task *t, void *context, unsigned in
        TRACE_ENTER(SPOP_EV_SPOP_CONN_WAKE, (spop_conn ? spop_conn->conn : NULL));
 
        if (spop_conn) {
-               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
 
                /* Somebody already stole the connection from us, so we should not
                 * free it, we just have to free the task.
                 */
                if (!t->context) {
-                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                        spop_conn = NULL;
                        goto do_leave;
                }
 
                if (!expired) {
-                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                        TRACE_DEVEL("leaving (not expired)", SPOP_EV_SPOP_CONN_WAKE, spop_conn->conn);
                        return t;
                }
@@ -2794,7 +2794,7 @@ static struct task *spop_timeout_task(struct task *t, void *context, unsigned in
                else if (spop_conn->conn->flags & CO_FL_SESS_IDLE)
                        conn_delete_from_sess(spop_conn->conn);
 
-               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
 
                spop_conn_report_term_evt(spop_conn, muxc_tevt_type_tout);
        }
index 95560d59500479e54bf47dc0d492a5d741ee8e84..d7d5f244133767bdb8ed801d03ef6aad3ebdcbe4 100644 (file)
@@ -57,7 +57,7 @@
 
 static void srv_update_status(struct server *s, int type, int cause);
 static int srv_apply_lastaddr(struct server *srv, int *err_code);
-static void srv_cleanup_connections(struct server *srv);
+static void srv_purge_all_idle_conns(struct server *srv);
 
 /* extra keywords used as value for other arguments. They are used as
  * suggestions for mistyped words.
@@ -73,9 +73,11 @@ struct srv_kw_list srv_keywords = {
        .list = LIST_HEAD_INIT(srv_keywords.list)
 };
 
-__decl_thread(HA_SPINLOCK_T idle_conn_srv_lock);
-struct eb_root idle_conn_srv = EB_ROOT;
-struct task *idle_conn_task __read_mostly = NULL;
+/* Periodic idle conns purge elements. */
+__decl_thread(HA_SPINLOCK_T purge_conns_lock);
+struct eb_root servers_purge_tree = EB_ROOT;
+struct task *task_purge_servers __read_mostly = NULL;
+
 struct mt_list servers_list = MT_LIST_HEAD_INIT(servers_list);
 static struct task *server_atomic_sync_task = NULL;
 static event_hdl_async_equeue server_atomic_sync_queue;
@@ -318,7 +320,7 @@ static struct task *server_atomic_sync(struct task *task, void *context, unsigne
                                        send_log(srv->proxy, LOG_NOTICE, "%s.\n", trash.area);
                                }
                        }
-                       srv_cleanup_connections(srv);
+                       srv_purge_all_idle_conns(srv);
                        srv_set_dyncookie(srv);
                        srv_set_addr_desc(srv, 1);
                }
@@ -5565,7 +5567,7 @@ static int cli_parse_set_server(char **args, char *payload, struct appctx *appct
                        cli_err(appctx, "'set server <srv> ssl' expects 'on' or 'off'.\n");
                        goto out;
                }
-               srv_cleanup_connections(sv);
+               srv_purge_all_idle_conns(sv);
                HA_SPIN_UNLOCK(SERVER_LOCK, &sv->lock);
                cli_msg(appctx, LOG_NOTICE, "server ssl setting updated.\n");
 #else
@@ -6420,8 +6422,8 @@ static int cli_parse_delete_server(char **args, char *payload, struct appctx *ap
        ebpt_delete(&srv->conf.name);
        ebpt_delete(&srv->addr_node);
 
-       /* remove srv from idle_node tree for idle conn cleanup */
-       eb32_delete(&srv->idle_node);
+       /* remove srv from purge tree for idle conn cleanup */
+       eb32_delete(&srv->purge_node);
 
        /* flag the server as deleted
         * (despite the server being removed from primary server list,
@@ -6738,7 +6740,7 @@ static int _srv_update_status_adm(struct server *s, enum srv_adm_st_chg_cause ca
                                srv_shutdown_streams(s, SF_ERR_DOWN);
 
                        /* force connection cleanup on the given server */
-                       srv_cleanup_connections(s);
+                       srv_purge_all_idle_conns(s);
                        /* we might have streams queued on this server and waiting for
                         * a connection. Those which are redispatchable will be queued
                         * to another server or to the proxy itself.
@@ -7094,46 +7096,39 @@ static void srv_update_status(struct server *s, int type, int cause)
        }
 }
 
-struct task *srv_cleanup_toremove_conns(struct task *task, void *context, unsigned int state)
-{
-       struct connection *conn;
-
-       while ((conn = MT_LIST_POP(&idle_conns[tid].toremove_conns,
-                                      struct connection *, toremove_list)) != NULL) {
-               conn->mux->destroy(conn->ctx);
-       }
-
-       return task;
-}
-
-/* Move <toremove_nb> count connections from <list> storage to <toremove_list>
- * list storage. -1 means moving all of them.
+/* Move <count> connections attached on a server from <conns> list into the
+ * purgeable list of <t> thread. If <count> is negative, <conns> is emptied.
  *
- * Returns the number of connections moved.
+ * Must be called with IDLE_CONNS_LOCK held.
  *
- * Must be called with idle_conns_lock held.
+ * Returns the number of connections moved.
  */
-static int srv_migrate_conns_to_remove(struct list *list, struct mt_list *toremove_list, int toremove_nb)
+static int srv_purge_conns(struct list *conns, int t, int count)
 {
        struct connection *conn;
        int i = 0;
 
-       while (!LIST_ISEMPTY(list)) {
-               if (toremove_nb != -1 && i >= toremove_nb)
+       while (!LIST_ISEMPTY(conns)) {
+               if (count >= 0 && i >= count)
                        break;
 
-               conn = LIST_ELEM(list->n, struct connection *, idle_list);
+               conn = LIST_ELEM(conns->n, struct connection *, idle_list);
                conn_delete_from_tree(conn);
-               MT_LIST_APPEND(toremove_list, &conn->toremove_list);
+               MT_LIST_APPEND(&idle_conns[t].purged_list, &conn->purge_el);
                i++;
        }
 
        return i;
 }
-/* cleanup connections for a given server
- * might be useful when going on forced maintenance or live changing ip/port
+
+/* Mark as purgeable all idle backend connections on <srv> server. Purge task
+ * is immediately scheduled on necessary threads to remove them.
+ *
+ * This operation is useful when the server is going on forced maintenance or
+ * some of its network configuration such as IP/port are updated during
+ * runtime.
  */
-static void srv_cleanup_connections(struct server *srv)
+static void srv_purge_all_idle_conns(struct server *srv)
 {
        struct sess_priv_conns *sess_conns;
        int did_remove;
@@ -7146,10 +7141,10 @@ static void srv_cleanup_connections(struct server *srv)
        /* check all threads starting with ours */
        for (i = tid;;) {
                did_remove = 0;
-               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[i].idle_conns_lock);
+               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[i].lock);
 
                /* idle connections */
-               if (srv_migrate_conns_to_remove(&srv->per_thr[i].idle_conn_list, &idle_conns[i].toremove_conns, -1) > 0)
+               if (srv_purge_conns(&srv->per_thr[i].idle_conn_list, i, -1) > 0)
                        did_remove = 1;
 
                /* session attached connections */
@@ -7164,9 +7159,9 @@ static void srv_cleanup_connections(struct server *srv)
                        }
                }
 
-               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[i].idle_conns_lock);
+               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[i].lock);
                if (did_remove)
-                       task_wakeup(idle_conns[i].cleanup_task, TASK_WOKEN_OTHER);
+                       task_wakeup(idle_conns[i].task_free_purged, TASK_WOKEN_OTHER);
 
                if ((i = ((i + 1 == global.nbthread) ? 0 : i + 1)) == tid)
                        break;
@@ -7196,10 +7191,10 @@ void srv_release_conn(struct server *srv, struct connection *conn)
 
        /* Remove the connection from any tree (safe, idle or available) */
        if (conn->hash_node) {
-               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                conn_delete_from_tree(conn);
                conn->flags &= ~CO_FL_LIST_MASK;
-               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
        }
 }
 
@@ -7247,7 +7242,7 @@ struct connection *srv_lookup_conn_next(struct connection *conn)
  * on it before reinserting it with this function. In other context, prefer to
  * use the full feature srv_add_to_idle_list().
  *
- * Must be called with idle_conns_lock.
+ * Must be called with IDLE_CONNS_LOCK.
  */
 void _srv_add_idle(struct server *srv, struct connection *conn, int is_safe)
 {
@@ -7294,7 +7289,7 @@ int srv_add_to_idle_list(struct server *srv, struct connection *conn, int is_saf
                }
                _HA_ATOMIC_DEC(&srv->curr_used_conns);
 
-               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                conn_delete_from_tree(conn);
 
                if (is_safe) {
@@ -7306,24 +7301,28 @@ int srv_add_to_idle_list(struct server *srv, struct connection *conn, int is_saf
                        _srv_add_idle(srv, conn, 0);
                        _HA_ATOMIC_INC(&srv->curr_idle_nb);
                }
-               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                _HA_ATOMIC_INC(&srv->curr_idle_thr[tid]);
 
                __ha_barrier_full();
-               if ((volatile void *)srv->idle_node.node.leaf_p == NULL) {
-                       HA_SPIN_LOCK(OTHER_LOCK, &idle_conn_srv_lock);
-                       if ((volatile void *)srv->idle_node.node.leaf_p == NULL) {
-                               srv->idle_node.key = tick_add(srv->pool_purge_delay,
-                                                             now_ms);
-                               eb32_insert(&idle_conn_srv, &srv->idle_node);
-                               if (!task_in_wq(idle_conn_task) && !
-                                   task_in_rq(idle_conn_task)) {
-                                       task_schedule(idle_conn_task,
-                                                     srv->idle_node.key);
+
+               /* Register server for purge if not already the case. */
+               if ((volatile void *)srv->purge_node.node.leaf_p == NULL) {
+                       HA_SPIN_LOCK(OTHER_LOCK, &purge_conns_lock);
+                       if ((volatile void *)srv->purge_node.node.leaf_p == NULL) {
+                               srv->purge_node.key = tick_add(srv->pool_purge_delay,
+                                                              now_ms);
+                               eb32_insert(&servers_purge_tree, &srv->purge_node);
+
+                               /* Schedule task_purge_servers if needed. */
+                               if (!task_in_wq(task_purge_servers) &&
+                                   !task_in_rq(task_purge_servers)) {
+                                       task_schedule(task_purge_servers,
+                                                     srv->purge_node.key);
                                }
 
                        }
-                       HA_SPIN_UNLOCK(OTHER_LOCK, &idle_conn_srv_lock);
+                       HA_SPIN_UNLOCK(OTHER_LOCK, &purge_conns_lock);
                }
                return 1;
        }
@@ -7340,7 +7339,10 @@ void srv_add_to_avail_list(struct server *srv, struct connection *conn)
        eb64_insert(&srv->per_thr[tid].avail_conns, &conn->hash_node->node);
 }
 
-struct task *srv_cleanup_idle_conns(struct task *task, void *context, unsigned int state)
+/* Handler for <task_purge_servers>. Loop over registered servers and purge it
+ * if expired : detach some idle conns to reach current estimated needed level.
+ */
+struct task *do_servers_purge(struct task *task, void *context, unsigned int state)
 {
        struct server *srv;
        struct eb32_node *eb;
@@ -7348,20 +7350,20 @@ struct task *srv_cleanup_idle_conns(struct task *task, void *context, unsigned i
        unsigned int next_wakeup;
 
        next_wakeup = TICK_ETERNITY;
-       HA_SPIN_LOCK(OTHER_LOCK, &idle_conn_srv_lock);
+       HA_SPIN_LOCK(OTHER_LOCK, &purge_conns_lock);
        while (1) {
                int exceed_conns;
                int to_kill;
                int curr_idle;
 
-               eb = eb32_lookup_ge(&idle_conn_srv, now_ms - TIMER_LOOK_BACK);
+               eb = eb32_lookup_ge(&servers_purge_tree, now_ms - TIMER_LOOK_BACK);
                if (!eb) {
                        /* we might have reached the end of the tree, typically because
                         * <now_ms> is in the first half and we're first scanning the last
                        * half. Let's loop back to the beginning of the tree now.
                        */
 
-                       eb = eb32_first(&idle_conn_srv);
+                       eb = eb32_first(&servers_purge_tree);
                        if (likely(!eb))
                                break;
                }
@@ -7370,7 +7372,7 @@ struct task *srv_cleanup_idle_conns(struct task *task, void *context, unsigned i
                        next_wakeup = eb->key;
                        break;
                }
-               srv = eb32_entry(eb, struct server, idle_node);
+               srv = eb32_entry(eb, struct server, purge_node);
 
                /* Calculate how many idle connections we want to kill :
                 * we want to remove half the difference between the total
@@ -7401,31 +7403,31 @@ struct task *srv_cleanup_idle_conns(struct task *task, void *context, unsigned i
                        max_conn = (exceed_conns * srv->curr_idle_thr[i]) /
                                   curr_idle + 1;
 
-                       HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[i].idle_conns_lock);
-                       j = srv_migrate_conns_to_remove(&srv->per_thr[i].idle_conn_list, &idle_conns[i].toremove_conns, max_conn);
+                       HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[i].lock);
+                       j = srv_purge_conns(&srv->per_thr[i].idle_conn_list, i, max_conn);
                        if (j > 0)
                                did_remove = 1;
-                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[i].idle_conns_lock);
+                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[i].lock);
 
                        if (did_remove)
-                               task_wakeup(idle_conns[i].cleanup_task, TASK_WOKEN_OTHER);
+                               task_wakeup(idle_conns[i].task_free_purged, TASK_WOKEN_OTHER);
 
                        if ((i = ((i + 1 == global.nbthread) ? 0 : i + 1)) == tid)
                                break;
                }
 remove:
-               eb32_delete(&srv->idle_node);
+               eb32_delete(&srv->purge_node);
 
                if (srv->curr_idle_conns) {
                        /* There are still more idle connections, add the
                         * server back in the tree.
                         */
-                       srv->idle_node.key = tick_add(srv->pool_purge_delay, now_ms);
-                       eb32_insert(&idle_conn_srv, &srv->idle_node);
-                       next_wakeup = tick_first(next_wakeup, srv->idle_node.key);
+                       srv->purge_node.key = tick_add(srv->pool_purge_delay, now_ms);
+                       eb32_insert(&servers_purge_tree, &srv->purge_node);
+                       next_wakeup = tick_first(next_wakeup, srv->purge_node.key);
                }
        }
-       HA_SPIN_UNLOCK(OTHER_LOCK, &idle_conn_srv_lock);
+       HA_SPIN_UNLOCK(OTHER_LOCK, &purge_conns_lock);
 
        task->expire = next_wakeup;
        return task;
@@ -7522,6 +7524,20 @@ static struct cfg_kw_list cfg_kws = {ILH, {
 
 INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
 
+int alloc_servers_purge_task(void)
+{
+       task_purge_servers = task_new_anywhere();
+       if (!task_purge_servers) {
+               ha_alert("Failed to allocate purge servers global task.\n");
+               return ERR_FATAL|ERR_ABORT;
+       }
+
+       task_purge_servers->process = do_servers_purge;
+       task_purge_servers->context = NULL;
+       return ERR_NONE;
+}
+REGISTER_POST_CHECK(alloc_servers_purge_task);
+
 /*
  * Local variables:
  *  c-indent-level: 8
index b0e9fbefb5e26c3adee5fb3615760affdcf9761c..f82de2b5c402ed1e46f1f9aee71ab7aed7c62869 100644 (file)
@@ -134,7 +134,7 @@ void session_free(struct session *sess)
        if (conn != NULL && conn->mux)
                conn->mux->destroy(conn->ctx);
 
-       HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+       HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
        list_for_each_entry_safe(pconns, pconns_back, &sess->priv_conns, sess_el) {
                list_for_each_entry_safe(conn, conn_back, &pconns->conn_list, sess_el) {
                        LIST_DEL_INIT(&conn->sess_el);
@@ -144,7 +144,7 @@ void session_free(struct session *sess)
                MT_LIST_DELETE(&pconns->srv_el);
                pool_free(pool_head_sess_priv_conns, pconns);
        }
-       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
 
        /* Release connections outside of idle lock. */
        while (!LIST_ISEMPTY(&conn_tmp_list)) {
@@ -662,7 +662,7 @@ int session_add_conn(struct session *sess, struct connection *conn)
         */
        BUG_ON(conn->owner && conn->owner != sess);
 
-       HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+       HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
 
        /* Already attach to the session */
        if (!LIST_ISEMPTY(&conn->sess_el))
@@ -679,11 +679,11 @@ int session_add_conn(struct session *sess, struct connection *conn)
        conn->owner = sess;
 
  out:
-       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
        return 1;
 
  err:
-       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
        return 0;
 }
 
@@ -698,7 +698,7 @@ int session_reinsert_idle_conn(struct session *sess, struct connection *conn)
 {
        struct sess_priv_conns *pconns;
 
-       HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+       HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
 
        pconns = sess_get_sess_conns(sess, conn->target);
        if (!pconns)
@@ -707,13 +707,13 @@ int session_reinsert_idle_conn(struct session *sess, struct connection *conn)
        LIST_APPEND(&pconns->conn_list, &conn->sess_el);
        ++sess->idle_conns;
 
-       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
        return 1;
 
  err:
        /* Idle conn cannot be reinserted, hence session counter must be adjusted. */
        --sess->idle_conns;
-       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
        return 0;
 }
 
@@ -763,7 +763,7 @@ struct connection *session_get_conn(struct session *sess, void *target, int64_t
        struct sess_priv_conns *pconns;
        struct server *srv;
 
-       HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+       HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
 
        list_for_each_entry(pconns, &sess->priv_conns, sess_el) {
                if (pconns->target == target) {
@@ -789,7 +789,7 @@ struct connection *session_get_conn(struct session *sess, void *target, int64_t
        }
 
   end:
-       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
        return srv_conn;
 }
 
@@ -802,7 +802,7 @@ void session_unown_conn(struct session *sess, struct connection *conn)
 
        BUG_ON(objt_listener(conn->target));
 
-       HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+       HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
 
        /* WT: this currently is a workaround for an inconsistency between
         * the link status of the connection in the session list and the
@@ -832,7 +832,7 @@ void session_unown_conn(struct session *sess, struct connection *conn)
        }
 
  out:
-       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
 }
 
 int session_purge_conns(struct sess_priv_conns *sess_conns)
@@ -849,8 +849,8 @@ int session_purge_conns(struct sess_priv_conns *sess_conns)
                --((struct session *)conn->owner)->idle_conns;
 
                LIST_DEL_INIT(&conn->sess_el);
-               MT_LIST_APPEND(&idle_conns[conn_tid].toremove_conns,
-                              &conn->toremove_list);
+               MT_LIST_APPEND(&idle_conns[conn_tid].purged_list,
+                              &conn->purge_el);
                i++;
        }
 
index e06239efb10883a89a0a4d0c8c450152f27722e8..6928c717a166f75d185d9db06f3b3ac5a2bdb2ef 100644 (file)
@@ -5808,9 +5808,9 @@ struct task *ssl_sock_io_cb(struct task *t, void *context, unsigned int state)
                /* the tasklet was idling on an idle connection, it might have
                 * been stolen, let's be careful!
                 */
-               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                if (tl->context == NULL) {
-                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                        tasklet_free(tl);
                        return NULL;
                }
@@ -5819,7 +5819,7 @@ struct task *ssl_sock_io_cb(struct task *t, void *context, unsigned int state)
                conn_in_list = conn->flags & CO_FL_LIST_MASK;
                if (conn_in_list)
                        conn_delete_from_tree(conn);
-               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
        } else {
                ctx = context;
                conn = ctx->conn;
@@ -5888,9 +5888,9 @@ leave:
                struct server *srv = objt_server(conn->target);
 
                TRACE_DEVEL("adding conn back to idle list", SSL_EV_CONN_IO_CB, conn);
-               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
                _srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST);
-               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
        }
        TRACE_LEAVE(SSL_EV_CONN_IO_CB, conn);
        return t;