diff --git a/include/haproxy/stats-t.h b/include/haproxy/stats-t.h index 1479c4efd..ffdd0b15a 100644 --- a/include/haproxy/stats-t.h +++ b/include/haproxy/stats-t.h @@ -578,6 +578,7 @@ struct show_stat_ctx { int iid, type, sid; /* proxy id, type and service id if bounding of stats is enabled */ int st_code; /* the status code returned by an action */ struct buffer chunk; /* temporary buffer which holds a single-line output */ + struct watcher px_watch; /* watcher to automatically update obj1 on backend deletion */ struct watcher srv_watch; /* watcher to automatically update obj2 on server deletion */ enum stat_state state; /* phase of output production */ }; diff --git a/src/http_ana.c b/src/http_ana.c index f004e41d9..fa061b698 100644 --- a/src/http_ana.c +++ b/src/http_ana.c @@ -4089,6 +4089,8 @@ static int http_handle_stats(struct stream *s, struct channel *req, struct proxy ctx->flags |= STAT_F_FMT_HTML; /* assume HTML mode by default */ if ((msg->flags & HTTP_MSGF_VER_11) && (txn->meth != HTTP_METH_HEAD)) ctx->flags |= STAT_F_CHUNKED; + + watcher_init(&ctx->px_watch, &ctx->obj1, offsetof(struct proxy, watcher_list)); watcher_init(&ctx->srv_watch, &ctx->obj2, offsetof(struct server, watcher_list)); htx = htxbuf(&req->buf); diff --git a/src/stats-html.c b/src/stats-html.c index 79ffc9731..cd9e37e9a 100644 --- a/src/stats-html.c +++ b/src/stats-html.c @@ -2116,6 +2116,8 @@ static size_t http_stats_fastfwd(struct appctx *appctx, struct buffer *buf, static void http_stats_release(struct appctx *appctx) { struct show_stat_ctx *ctx = appctx->svcctx; + if (ctx->domain == STATS_DOMAIN_PROXY && ctx->obj1) + watcher_detach(&ctx->px_watch); if (ctx->px_st == STAT_PX_ST_SV && ctx->obj2) watcher_detach(&ctx->srv_watch); } diff --git a/src/stats-proxy.c b/src/stats-proxy.c index 278a4bf9c..5b6a70628 100644 --- a/src/stats-proxy.c +++ b/src/stats-proxy.c @@ -1616,11 +1616,13 @@ int stats_dump_proxies(struct stconn *sc, struct buffer *buf, struct htx *htx) struct proxy *px; /* dump proxies */ - while (ctx->obj1) { + /* obj1 is updated and returned through watcher_next() */ + for (px = ctx->obj1; px; + px = watcher_next(&ctx->px_watch, px->next)) { + if (stats_is_full(appctx, buf, htx)) goto full; - px = ctx->obj1; /* Skip the global frontend proxies and non-networked ones. * Also skip proxies that were disabled in the configuration * This change allows retrieving stats from "old" proxies after a reload. @@ -1631,7 +1633,6 @@ int stats_dump_proxies(struct stconn *sc, struct buffer *buf, struct htx *htx) return 0; } - ctx->obj1 = px->next; ctx->px_st = STAT_PX_ST_INIT; ctx->field = 0; } diff --git a/src/stats.c b/src/stats.c index b4f29696e..4ce6d5e95 100644 --- a/src/stats.c +++ b/src/stats.c @@ -590,12 +590,13 @@ int stats_dump_stat_to_buffer(struct stconn *sc, struct buffer *buf, struct htx goto full; } - if (domain == STATS_DOMAIN_PROXY) - ctx->obj1 = proxies_list; - ctx->px_st = STAT_PX_ST_INIT; ctx->field = 0; ctx->state = STAT_STATE_LIST; + /* Update ctx->obj1 via watcher to point on the first proxy. */ + if (domain == STATS_DOMAIN_PROXY) + watcher_attach(&ctx->px_watch, proxies_list); + __fallthrough; case STAT_STATE_LIST: @@ -944,6 +945,8 @@ static int cli_parse_show_stat(char **args, char *payload, struct appctx *appctx ctx->scope_len = 0; ctx->http_px = NULL; // not under http context ctx->flags = STAT_F_SHNODE | STAT_F_SHDESC; + + watcher_init(&ctx->px_watch, &ctx->obj1, offsetof(struct proxy, watcher_list)); watcher_init(&ctx->srv_watch, &ctx->obj2, offsetof(struct server, watcher_list)); if ((strm_li(appctx_strm(appctx))->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) @@ -1028,8 +1031,12 @@ static int cli_io_handler_dump_stat(struct appctx *appctx) static void cli_io_handler_release_stat(struct appctx *appctx) { struct show_stat_ctx *ctx = appctx->svcctx; - if (ctx->px_st == STAT_PX_ST_SV && ctx->obj2) - watcher_detach(&ctx->srv_watch); + + if (ctx->state == STAT_STATE_LIST && ctx->domain == STATS_DOMAIN_PROXY) { + watcher_detach(&ctx->px_watch); + if (ctx->px_st == STAT_PX_ST_SV) + watcher_detach(&ctx->srv_watch); + } } static int cli_io_handler_dump_json_schema(struct appctx *appctx) @@ -1089,8 +1096,12 @@ static int cli_io_handler_dump_stat_file(struct appctx *appctx) static void cli_io_handler_release_dump_stat_file(struct appctx *appctx) { struct show_stat_ctx *ctx = appctx->svcctx; - if (ctx->px_st == STAT_PX_ST_SV && ctx->obj2) - watcher_detach(&ctx->srv_watch); + + if (ctx->state == STAT_STATE_LIST && ctx->domain == STATS_DOMAIN_PROXY) { + watcher_detach(&ctx->px_watch); + if (ctx->px_st == STAT_PX_ST_SV) + watcher_detach(&ctx->srv_watch); + } } int stats_allocate_proxy_counters_internal(struct extra_counters **counters,