]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: proxy: simplify defaults proxies list storage
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Tue, 20 Jan 2026 13:33:46 +0000 (14:33 +0100)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 22 Jan 2026 16:57:09 +0000 (17:57 +0100)
Defaults proxies instance are stored in a global name tree. When there
is a name conflict and the older entry cannot be simply discarded as it
is already referenced, the older entry is instead removed from the name
tree and inserted into the orphaned list.

The purpose of the orphaned list was to guarantee that any remaining
unreferenced defaults are purged either on postparsing or deinit.
However, this is in fact completely useless. Indeed on postparsing,
orphaned entries are always referenced. On deinit instead, defaults are
already freed along the cleanup of all frontend/backend instances clean
up, thanks to their refcounting.

This patch streamlines this by removing orphaned list. Instead, a
defaults section is inserted into a new global defaults_list during
their whole lifetime. This is not strictly necessary but it ensures that
defaults instances can still be accessed easily in the future if needed
even if not present in the name tree. On deinit, a BUG_ON() is added to
ensure that defaults_list is indeed emptied.

Another benefit from this patch is to simplify the defaults deletion
procedure. Orphaned simple list is replaced by a proper double linked
list implementation, so a single LIST_DELETE() is now performed. This
will be notably useful as defaults may be removed at runtime in the
future if backends deletion at runtime is implemented.

include/haproxy/proxy-t.h
include/haproxy/proxy.h
src/cfgparse-listen.c
src/haproxy.c
src/proxy.c

index 0b8ce6d389db5961035c36dd13f5612c839af5b5..0ec1fae66ad854d4bdb38a0e1aa28a08786a55c2 100644 (file)
@@ -316,6 +316,7 @@ struct proxy {
        unsigned long last_change;              /* internal use only: last time the proxy state was changed */
 
        struct list global_list;                /* list member for global proxy list */
+       struct list el;                         /* attach point in various list - currently used only on defaults_list for defaults section */
 
        unsigned int maxconn;                   /* max # of active streams on the frontend */
 
index b0f10c99c760e17847b8777c75d2e9f8429817a6..ad6f6905b6544afdf83860a47ae73c7c0954537a 100644 (file)
@@ -39,6 +39,7 @@ extern struct list proxies;
 extern struct ceb_root *used_proxy_id;  /* list of proxy IDs in use */
 extern unsigned int error_snapshot_id;  /* global ID assigned to each error then incremented */
 extern struct ceb_root *proxy_by_name;    /* tree of proxies sorted by name */
+extern struct list defaults_list;       /* all defaults proxies list */
 
 extern const struct cfg_opt cfg_opts[];
 extern const struct cfg_opt cfg_opts2[];
index 0c811a6086ece95092bba83d745bf19f72d6802f..ebea793856203888bd46d8c655a3be19bba04d80 100644 (file)
@@ -569,6 +569,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
                }
 
                if (rc & PR_CAP_DEF) {
+                       LIST_APPEND(&defaults_list, &curproxy->el);
                        /* last and current proxies must be updated to this one */
                        curr_defproxy = last_defproxy = curproxy;
                } else {
index c012c9d5c4ac85e0f34b7d2cc2f89ad4eb49db74..95b2019d912bf5ec8d5fac05a1097f396209ae32 100644 (file)
@@ -2742,8 +2742,10 @@ void deinit(void)
         * they are respectively cleaned up in sink_deinit() and deinit_log_forward()
         */
 
-       /* destroy all referenced defaults proxies  */
-       defaults_px_destroy_all_unref();
+       /* All proxies are removed now, so every defaults should also be freed
+        * when their refcount reached zero.
+        */
+       BUG_ON(!LIST_ISEMPTY(&defaults_list));
 
        userlist_free(userlist);
 
index a5bd572ad017ef55b41ba12351dd9db21ba341af..b3aa601455f0e0151f814be704f0a7bd1faa50a4 100644 (file)
@@ -64,7 +64,7 @@ struct list proxies = LIST_HEAD_INIT(proxies); /* list of all proxies */
 struct ceb_root *used_proxy_id = NULL; /* list of proxy IDs in use */
 struct ceb_root *proxy_by_name = NULL; /* tree of proxies sorted by name */
 struct ceb_root *defproxy_by_name = NULL; /* tree of default proxies sorted by name (dups possible) */
-struct proxy *orphaned_default_proxies = NULL; /* deleted ones with refcount != 0 */
+struct list defaults_list = LIST_HEAD_INIT(defaults_list); /* list of all defaults proxies */
 unsigned int error_snapshot_id = 0;     /* global ID assigned to each error then incremented */
 
 /* CLI context used during "show servers {state|conn}" */
@@ -1500,6 +1500,7 @@ void init_new_proxy(struct proxy *p)
        memset(p, 0, sizeof(struct proxy));
        p->obj_type = OBJ_TYPE_PROXY;
        LIST_INIT(&p->global_list);
+       LIST_INIT(&p->el);
        LIST_INIT(&p->acl);
        LIST_INIT(&p->http_req_rules);
        LIST_INIT(&p->http_res_rules);
@@ -1628,29 +1629,11 @@ static void defaults_px_free(struct proxy *defproxy)
  */
 void defaults_px_destroy(struct proxy *px)
 {
-       struct proxy *prev;
-
        BUG_ON(!(px->cap & PR_CAP_DEF));
        BUG_ON(px->conf.refcount != 0);
 
        cebis_item_delete(&defproxy_by_name, conf.name_node, id, px);
-
-       /* If orphaned defaults list is not empty, it may contain <px> instance.
-        * In this case it is necessary to manually remove it from the list.
-        */
-       if (orphaned_default_proxies) {
-               if (orphaned_default_proxies == px) {
-                       orphaned_default_proxies = px->next;
-               }
-               else {
-                       for (prev = orphaned_default_proxies;
-                            prev && prev->next != px; prev = prev->next)
-                               ;
-                       if (prev)
-                               prev->next = px->next;
-               }
-               px->next = NULL;
-       }
+       LIST_DELETE(&px->el);
 
        defaults_px_free(px);
        free(px);
@@ -1669,35 +1652,19 @@ void defaults_px_destroy_all_unref(void)
                if (!px->conf.refcount)
                        defaults_px_destroy(px);
        }
-
-       px = orphaned_default_proxies;
-       while (px) {
-               BUG_ON(!(px->cap & PR_CAP_DEF));
-               nx = px->next;
-               if (!px->conf.refcount)
-                       defaults_px_destroy(px);
-               px = nx;
-       }
 }
 
 /* Removes <px> defaults from the name tree. This operation is useful when a
  * section is made invisible by a newer instance with the same name. If <px> is
- * not referenced it is freed immediately, else it is moved in defaults
- * orphaned list.
+ * not referenced it is freed immediately, else it is kept in defaults_list.
  */
 void defaults_px_detach(struct proxy *px)
 {
        BUG_ON(!(px->cap & PR_CAP_DEF));
-
        cebis_item_delete(&defproxy_by_name, conf.name_node, id, px);
-       if (px->conf.refcount) {
-               /* still referenced just append it to the orphaned list */
-               px->next = orphaned_default_proxies;
-               orphaned_default_proxies = px;
-       }
-       else {
+       if (!px->conf.refcount)
                defaults_px_destroy(px);
-       }
+       /* If not destroyed, <px> can still be accessed in <defaults_list>. */
 }
 
 /* Add a reference on the default proxy <defpx> for the proxy <px> Nothing is