]> git.kaiwu.me - haproxy.git/commitdiff
MINOR: lua: handle proxy refcount
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 18 Feb 2026 08:55:13 +0000 (09:55 +0100)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Mon, 2 Mar 2026 13:08:30 +0000 (14:08 +0100)
Implement proxy refcount for Lua proxy class. This is similar to the
server class.

In summary, proxy_take() is used to increment refcount when a Lua proxy
is instantiated. proxy_drop() is called via Lua garbage collector. To
ensure a deleted backend is released asap, hlua_check_proxy() now
returns NULL if PR_FL_DELETED is set.

This approach is directly dependable on Lua GC execution. As such, it
probably suffers from the same limitations as the ones already described
in the previous commit. With the current patch, "del backend" is not
directly impacted though. However, the final proxy deinit may happen
after a long period of time, which could cause memory pressure increase.

One final observations regarding deinit : it is necessary to delay a
BUG_ON() which checks that defaults proxies list is empty. Now this must
be executed after Lua deinit (called via post_deinit_list). This should
guarantee that all proxies and their defaults refcount are null.

src/haproxy.c
src/hlua_fcn.c

index 2ea61c83609b694fd06ce9638362eb919f03f574..f6985f1b616df964aa3f252cad445be8adcf8072 100644 (file)
@@ -2824,10 +2824,6 @@ void deinit(void)
        /* If named defaults were preserved, ensure <def_ref> count is resetted. */
        if (!(global.tune.options & GTUNE_PURGE_DEFAULTS))
                defaults_px_unref_all();
-       /* All proxies are removed now, so every defaults should also be freed
-        * when their <def_ref> count reached zero.
-        */
-       BUG_ON(!LIST_ISEMPTY(&defaults_list));
 
        userlist_free(userlist);
 
@@ -2838,6 +2834,11 @@ void deinit(void)
        list_for_each_entry(pdf, &post_deinit_list, list)
                pdf->fct();
 
+       /* All proxies are removed now, so every defaults should also be freed
+        * when their <def_ref> count reached zero.
+        */
+       BUG_ON(!LIST_ISEMPTY(&defaults_list));
+
        ha_free(&global.log_send_hostname);
        chunk_destroy(&global.log_tag);
        ha_free(&global.chroot);
index 0566c886435b478565366584b8a7716fd1bd7f5c..ed374e24aa0eb937a2ae3028e92c32be31e1aafc 100644 (file)
@@ -1966,9 +1966,19 @@ void hlua_listable_servers(lua_State *L, struct proxy *px)
        lua_setmetatable(L, -2);
 }
 
+int hlua_proxy_gc(lua_State *L)
+{
+       struct proxy *px = hlua_checkudata(L, 1, class_proxy_ref);
+       proxy_drop(px);
+       return 0;
+}
+
 static struct proxy *hlua_check_proxy(lua_State *L, int ud)
 {
-       return hlua_checkudata(L, ud, class_proxy_ref);
+       struct proxy *px = hlua_checkudata(L, ud, class_proxy_ref);
+       if (px->flags & PR_FL_DELETED)
+               return NULL;
+       return px;
 }
 
 int hlua_proxy_get_name(lua_State *L)
@@ -1976,6 +1986,11 @@ int hlua_proxy_get_name(lua_State *L)
        struct proxy *px;
 
        px = hlua_check_proxy(L, 1);
+       if (px == NULL) {
+               lua_pushnil(L);
+               return 0;
+       }
+
        lua_pushstring(L, px->id);
        return 1;
 }
@@ -1986,6 +2001,11 @@ int hlua_proxy_get_uuid(lua_State *L)
        char buffer[17];
 
        px = hlua_check_proxy(L, 1);
+       if (px == NULL) {
+               lua_pushnil(L);
+               return 0;
+       }
+
        snprintf(buffer, sizeof(buffer), "%d", px->uuid);
        lua_pushstring(L, buffer);
        return 1;
@@ -2024,6 +2044,9 @@ int hlua_proxy_pause(lua_State *L)
        struct proxy *px;
 
        px = hlua_check_proxy(L, 1);
+       if (px == NULL)
+               return 0;
+
        /* safe to call without PROXY_LOCK - pause_proxy takes it */
        pause_proxy(px);
        return 0;
@@ -2034,6 +2057,9 @@ int hlua_proxy_resume(lua_State *L)
        struct proxy *px;
 
        px = hlua_check_proxy(L, 1);
+       if (px == NULL)
+               return 0;
+
        /* safe to call without PROXY_LOCK - resume_proxy takes it */
        resume_proxy(px);
        return 0;
@@ -2044,6 +2070,9 @@ int hlua_proxy_stop(lua_State *L)
        struct proxy *px;
 
        px = hlua_check_proxy(L, 1);
+       if (px == NULL)
+               return 0;
+
        /* safe to call without PROXY_LOCK - stop_proxy takes it */
        stop_proxy(px);
        return 0;
@@ -2055,6 +2084,11 @@ int hlua_proxy_get_cap(lua_State *L)
        const char *str;
 
        px = hlua_check_proxy(L, 1);
+       if (px == NULL) {
+               lua_pushnil(L);
+               return 0;
+       }
+
        str = proxy_cap_str(px->cap);
        lua_pushstring(L, str);
        return 1;
@@ -2066,6 +2100,11 @@ int hlua_proxy_get_stats(lua_State *L)
        int i;
 
        px = hlua_check_proxy(L, 1);
+       if (px == NULL) {
+               lua_pushnil(L);
+               return 0;
+       }
+
        if (px->cap & PR_CAP_BE)
                stats_fill_be_line(px, STAT_F_SHLGNDS, stats, STATS_LEN, NULL);
        else
@@ -2086,6 +2125,11 @@ int hlua_proxy_get_mode(lua_State *L)
        const char *str;
 
        px = hlua_check_proxy(L, 1);
+       if (px == NULL) {
+               lua_pushnil(L);
+               return 0;
+       }
+
        str = proxy_mode_str(px->mode);
        lua_pushstring(L, str);
        return 1;
@@ -2096,6 +2140,9 @@ int hlua_proxy_shut_bcksess(lua_State *L)
        struct proxy *px;
 
        px = hlua_check_proxy(L, 1);
+       if (px == NULL)
+               return 0;
+
        srv_shutdown_backup_streams(px, SF_ERR_KILLED);
        return 0;
 }
@@ -2105,6 +2152,11 @@ int hlua_proxy_get_srv_act(lua_State *L)
        struct proxy *px;
 
        px = hlua_check_proxy(L, 1);
+       if (px == NULL) {
+               lua_pushnil(L);
+               return 0;
+       }
+
        lua_pushinteger(L, px->srv_act);
        return 1;
 }
@@ -2114,6 +2166,11 @@ int hlua_proxy_get_srv_bck(lua_State *L)
        struct proxy *px;
 
        px = hlua_check_proxy(L, 1);
+       if (px == NULL) {
+               lua_pushnil(L);
+               return 0;
+       }
+
        lua_pushinteger(L, px->srv_bck);
        return 1;
 }
@@ -2128,6 +2185,10 @@ int hlua_proxy_get_mailers(lua_State *L)
        struct mailer *mailer;
 
        px = hlua_check_proxy(L, 1);
+       if (px == NULL) {
+               lua_pushnil(L);
+               return 0;
+       }
 
        if (!px->email_alert.mailers.m)
                return 0; /* email-alert mailers not found on proxy */
@@ -2208,6 +2269,8 @@ int hlua_fcn_new_proxy(lua_State *L, struct proxy *px)
        lua_pushlightuserdata(L, px);
        lua_rawseti(L, -2, 0);
 
+       proxy_take(px);
+
        /* set public methods */
        hlua_class_function(L, "get_name", hlua_proxy_get_name);
        hlua_class_function(L, "get_uuid", hlua_proxy_get_uuid);
@@ -3233,6 +3296,7 @@ void hlua_fcn_reg_core_fcn(lua_State *L)
 
        /* Create proxy object. */
        lua_newtable(L);
+       hlua_class_function(L, "__gc", hlua_proxy_gc);
        hlua_class_function(L, "__index", hlua_proxy_index);
        class_proxy_ref = hlua_register_metatable(L, CLASS_PROXY);