]> git.kaiwu.me - haproxy.git/commitdiff
OPTIM/MINOR: server: restrict <all_servers> list usage
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 17 Sep 2026 09:54:41 +0000 (11:54 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 14 Oct 2026 09:15:39 +0000 (11:15 +0200)
<all_servers> global list usage is pretty limited. It is only useful at
postparsing to call srv_preinit() on each server instances. It is
possible to simplify it in two ways.

First, dynamic servers are not added anymore into it. For them,
srv_preinit() is called directly on the "add server" handler. Then,
servers are now removed from the global list once postparsing is over.
Thus, <all_servers> is now never used during runtime. This allows to
convert it from a mt-list to a simple list.

Note that log servers and haload servers are created after
check_config_validity(). They must be manually removed from
<all_servers>.

include/haproxy/server-t.h
include/haproxy/server.h
src/cfgparse.c
src/haload.c
src/server.c
src/sink.c

index 6e6288a216629a0cf4962c12819a61bf8f3a5659..4f89609237fd7e613bb82a9dbec6fa90eddb7a02 100644 (file)
@@ -351,7 +351,7 @@ struct server {
        signed char use_ssl;                    /* ssl enabled (1: on, 0: disabled, -1 forced off)  */
        unsigned int flags;                     /* server flags (SRV_F_*) */
        unsigned int pp_opts;                   /* proxy protocol options (SRV_PP_*) */
-       struct mt_list global_list;             /* attach point in the global servers */
+       struct list global_list;                /* attach point in the global servers */
        struct list el_px;                      /* attach point in parent proxy */
        int cklen;                              /* the len of the cookie, to speed up checks */
        int rdr_len;                            /* the length of the redirection prefix */
index 3c9667dfa2007e3060eb69c7f504ff7e95da3420..f4f8d9eda5f579795c0cd4b5f3a437ee6aa45f76 100644 (file)
@@ -44,7 +44,7 @@
 extern struct idle_conns idle_conns[MAX_THREADS];
 extern struct task *idle_conn_task[MAX_THREADS];
 extern struct eb_root idle_conn_srv[MAX_THREADS];
-extern struct mt_list all_servers;
+extern struct list all_servers;
 extern struct dict server_key_dict;
 
 int srv_downtime(const struct server *s);
@@ -399,6 +399,12 @@ static inline void srv_detach(struct server *srv)
        struct proxy *px = srv->proxy;
 
        LIST_DEL_INIT(&srv->el_px);
+
+       if (global.mode & MODE_STARTING) {
+               /* Necessary if startup is interrupted due to an early error before check_config_validity(). */
+               LIST_DEL_INIT(&srv->global_list);
+       }
+
        /* Reset the proxy's ready_srv if it was this one. */
        HA_ATOMIC_CAS(&px->ready_srv, &srv, NULL);
 }
index 81e52d87150436f3716d48d0ec3543226b70ce3d..5081dddbd1ba4017cc15bd2d81eae7cece26a2fa 100644 (file)
@@ -2287,8 +2287,7 @@ int check_config_validity()
        struct proxy *defpx;
        struct list *init_proxies_list = NULL;
        struct stktable *t;
-       struct server *newsrv = NULL, *defsrv;
-       struct mt_list back;
+       struct server *newsrv = NULL, *tmpsrv, *defsrv;
        int err_code = 0;
        /* Value forced to skip '1' due to an historical bug, see below for more details. */
        unsigned int next_pxid = 2;
@@ -2384,10 +2383,11 @@ int check_config_validity()
         * we must finish to initialize certain things on the servers,
         * as some of the fields may be accessed soon
         */
-       MT_LIST_FOR_EACH_ENTRY_LOCKED(newsrv, &all_servers, global_list, back) {
+       list_for_each_entry_safe(newsrv, tmpsrv, &all_servers, global_list) {
                err_code |= srv_preinit(newsrv);
                if (err_code & ERR_CODE)
                        goto out;
+               LIST_DEL_INIT(&newsrv->global_list);
        }
 
        list_for_each_entry(defpx, &defaults_list, el) {
index 0cb9c922c9fa2b54e6509a1d2f559474a2a13b9c..19b3c53288fe70139c63341c0f48a5c5a17feaa7 100644 (file)
@@ -2372,6 +2372,10 @@ static int hld_cfg_finalize(void)
 
                if (srv_preinit(srv))
                        goto leave;
+
+               /* No need to stay in <all_servers> as srv_preinit() is manually called. */
+               LIST_DEL_INIT(&srv->global_list);
+
 #if 0
                /* XXX Must this be done? XXX */
                if (!srv_alloc_lb(srv, &hld_proxy)) {
index d68ee1a595fbca2ebd890db9db41fc5df2047aad..211cb0209eef95bea16dd23eb33398a0b91d6cdb 100644 (file)
@@ -79,7 +79,7 @@ struct srv_kw_list srv_keywords = {
 
 struct eb_root idle_conn_srv[MAX_THREADS];
 struct task *idle_conn_task[MAX_THREADS] __read_mostly = {};
-struct mt_list all_servers = MT_LIST_HEAD_INIT(all_servers);
+struct list all_servers = LIST_HEAD_INIT(all_servers);
 static struct task *server_atomic_sync_task = NULL;
 static event_hdl_async_equeue server_atomic_sync_queue;
 
@@ -3159,10 +3159,9 @@ void srv_settings_cpy(struct server *srv, const struct server *src, int srv_tmpl
        }
 }
 
-/* Allocates a server, attaches it to the global <all_servers> list
- * and adds it to <proxy> server list. Before deleting the server with
- * srv_drop(), srv_detach() must be called to remove it from the parent
- * proxy list
+/* Allocates a server and adds it to <proxy> server list. Before deleting the
+ * server with srv_drop(), srv_detach() must be called to remove it from the
+ * parent proxy list
  *
  * Returns the server on success, otherwise NULL.
  */
@@ -3179,7 +3178,6 @@ struct server *new_server(struct proxy *proxy)
        srv->obj_type = OBJ_TYPE_SERVER;
        srv->proxy = proxy;
        LIST_APPEND(&proxy->servers, &srv->el_px);
-       MT_LIST_APPEND(&all_servers, &srv->global_list);
        LIST_INIT(&srv->srv_rec_item);
        LIST_INIT(&srv->ip_rec_item);
        LIST_INIT(&srv->pp_tlvs);
@@ -3211,6 +3209,10 @@ struct server *new_server(struct proxy *proxy)
 
        HA_RWLOCK_INIT(&srv->path_params.param_lock);
 
+       LIST_INIT(&srv->global_list);
+       if (global.mode & MODE_STARTING)
+               LIST_APPEND(&all_servers, &srv->global_list);
+
        return srv;
 }
 
@@ -3313,7 +3315,6 @@ void srv_drop(struct server *srv)
 
        HA_SPIN_DESTROY(&srv->lock);
 
-       MT_LIST_DELETE(&srv->global_list);
        event_hdl_sub_list_destroy(&srv->e_subs);
 
        srv_free(&srv);
index 887f4e047d25d3c16da472134aebb14da5771479..73d838ff4400f5fd95d19eaea6ddc503268b2efd 100644 (file)
@@ -1310,6 +1310,9 @@ struct sink *sink_new_from_logger(struct logger *logger)
        if (srv_preinit(srv) & ERR_CODE)
                goto error;
 
+       /* No need to stay in <all_servers> as srv_preinit() is manually called. */
+       LIST_DEL_INIT(&srv->global_list);
+
        /* Same thing for the forward proxy: check_config_validity() has
         * already walked over sink_proxies_list, so this one is never
         * initialized nor finalized. Keep the same order as there, as the