]> git.kaiwu.me - haproxy.git/commitdiff
MINOR: server: extract unregistering from "delete server" CLI parser
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 9 Sep 2026 14:36:46 +0000 (16:36 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 14 Oct 2026 09:15:39 +0000 (11:15 +0200)
Extract the code which performs the server deletion from the "del
server" CLI parser in a new function named srv_unregister(). Its purpose
is to ensure that a server is detached from any visible elements, most
notably the parent proxy list and name tree, and the global GUID tree.
This step is mandatory to remove a server at runtime but is skipped on
deinit.

This reorg allows to implement alternative method for server deletion at
runtime. This will be useful for the future "purge server" CLI command.

include/haproxy/server.h
src/server.c

index b0c9526c5ad9e2842629df084638fd37931ecdec..e5e7f2d9621c640c4b58aebaee76f56804b93c44 100644 (file)
@@ -94,7 +94,9 @@ int srv_set_ssl(struct server *s, int use_ssl);
 const char *srv_adm_st_chg_cause(enum srv_adm_st_chg_cause cause);
 const char *srv_op_st_chg_cause(enum srv_op_st_chg_cause cause);
 void srv_event_hdl_publish_check(struct server *srv, struct check *check);
+
 int srv_check_for_deletion(const char *bename, const char *svname, struct proxy **pb, struct server **ps, const char **pm);
+void srv_unregister(struct server *srv);
 
 /* functions related to server name resolution */
 int srv_prepare_for_resolution(struct server *srv, const char *hostname);
index 6bc9f34901927195604106069ca79ad15f294b70..bda1e856f955cfe6ae2ead3ceab2a7884449dd1d 100644 (file)
@@ -6979,41 +6979,28 @@ leave:
        return ret;
 }
 
-/* Parse a "del server" command
- * Returns 0 if the server has been successfully initialized, 1 on failure.
+/* Removes <srv> server from its various attach points in other objects, most
+ * notably in its parent proxy and global trees. This liberates the server name
+ * slot in the proxy and the global GUID value which can be reused by a newly
+ * added instance. This also schedules deletion of any active check and
+ * agent-check.
+ *
+ * This operation is mandatory prior the runtime removal of a server. Once
+ * detached, the server is flagged for deletion and the associated event is
+ * published. The server instance will be finally freed when its refcount
+ * reaches zero.
+ *
+ * This function cannot fail. This operation is not thread-safe and must only
+ * be called under thread isolation.
  */
-static int cli_parse_delete_server(char **args, char *payload, struct appctx *appctx, void *private)
+void srv_unregister(struct server *srv)
 {
-       struct proxy *be;
-       struct server *srv, *next;
+       struct server *next;
        struct watcher *srv_watch;
-       const char *be_name, *sv_name, *msg;
-       int ret;
-
-       if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
-               return 1;
-
-       ++args;
-
-       /* The proxy servers list is currently not protected by a lock so this
-        * requires thread isolation. In addition, any place referencing the
-        * server about to be deleted would be unsafe after our operation, so
-        * we must be certain to be alone so that no other thread has even
-        * started to grab a temporary reference to this server.
-        */
-       thread_isolate_full();
-
-       if (parse_be_srv(args[1], &be_name, &sv_name, &msg)) {
-               cli_err(appctx, msg);
-               goto out;
-       }
+       int i;
 
-       ret = srv_check_for_deletion(be_name, sv_name, &be, &srv, &msg);
-       if (ret <= 0) {
-               /* failure (recoverable or not) */
-               cli_err(appctx, msg);
-               goto out;
-       }
+       /* Only servers in maintenance can be deleted at runtime. */
+       BUG_ON(!(srv->cur_admin & SRV_ADMF_MAINT));
 
        /* removing cannot fail anymore when we reach this:
         * publishing EVENT_HDL_SUB_SERVER_DEL
@@ -7033,6 +7020,7 @@ static int cli_parse_delete_server(char **args, char *payload, struct appctx *ap
        if (srv->proxy->lbprm.ops && srv->proxy->lbprm.ops->server_deinit)
                srv->proxy->lbprm.ops->server_deinit(srv);
 
+       /* reattach all currently present watchers to the next proxy server */
        next = proxy_next_server(srv);
        BUG_ON(next && next->flags & SRV_F_DELETED);
        while (!MT_LIST_ISEMPTY(&srv->watcher_list)) {
@@ -7040,10 +7028,7 @@ static int cli_parse_delete_server(char **args, char *payload, struct appctx *ap
                watcher_next(srv_watch, next);
        }
 
-       /* detach the server from the proxy linked list
-        * The proxy servers list is currently not protected by a lock, so this
-        * requires thread_isolate/release.
-        */
+       /* detach the server from the proxy linked list */
        srv_detach(srv);
 
        /* Mark the server as being deleted (ie removed from its proxy list)
@@ -7057,22 +7042,59 @@ static int cli_parse_delete_server(char **args, char *payload, struct appctx *ap
        proxy_take(srv->proxy);
 
        /* remove srv from proxy trees (IDs, names and addresses) */
-       if (srv->puid < be->conf.first_unused_id)
-               be->conf.first_unused_id = srv->puid; // search from there for next add.
-       ceb32_item_delete(&be->conf.used_server_id, conf.puid_node, puid, srv);
-       cebuis_item_delete(&be->conf.used_server_name, conf.name_node, id, srv);
-       cebuis_item_delete(&be->used_server_addr, addr_node, addr_key, srv);
+       if (srv->puid < srv->proxy->conf.first_unused_id)
+               srv->proxy->conf.first_unused_id = srv->puid; // search from there for next add.
+       ceb32_item_delete(&srv->proxy->conf.used_server_id, conf.puid_node, puid, srv);
+       cebuis_item_delete(&srv->proxy->conf.used_server_name, conf.name_node, id, srv);
+       cebuis_item_delete(&srv->proxy->used_server_addr, addr_node, addr_key, srv);
 
        /* remove srv from global GUID tree */
        guid_remove(&srv->guid);
 
        /* remove srv from global tree for idle conn cleanup */
-       for (ret = 0; ret < global.nbthread; ret++)
-               eb32_delete(&srv->per_thr[ret].idle_node);
+       for (i = 0; i < global.nbthread; ++i)
+               eb32_delete(&srv->per_thr[i].idle_node);
 
        /* set LSB bit (odd bit) for reuse_cnt */
        srv_id_reuse_cnt |= 1;
+}
+
+/* Parse a "del server" command
+ * Returns 0 if the server has been successfully initialized, 1 on failure.
+ */
+static int cli_parse_delete_server(char **args, char *payload, struct appctx *appctx, void *private)
+{
+       struct proxy *be;
+       struct server *srv;
+       const char *be_name, *sv_name, *msg;
+       int ret;
+
+       if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
+               return 1;
+
+       ++args;
+
+       /* The proxy servers list is currently not protected by a lock so this
+        * requires thread isolation. In addition, any place referencing the
+        * server about to be deleted would be unsafe after our operation, so
+        * we must be certain to be alone so that no other thread has even
+        * started to grab a temporary reference to this server.
+        */
+       thread_isolate_full();
+
+       if (parse_be_srv(args[1], &be_name, &sv_name, &msg)) {
+               cli_err(appctx, msg);
+               goto out;
+       }
+
+       ret = srv_check_for_deletion(be_name, sv_name, &be, &srv, &msg);
+       if (ret <= 0) {
+               /* failure (recoverable or not) */
+               cli_err(appctx, msg);
+               goto out;
+       }
 
+       srv_unregister(srv);
        thread_release();
 
        ha_notice("Server deleted.\n");