From: Alexander Stephan Date: Thu, 16 Jul 2026 12:40:51 +0000 (+0000) Subject: MINOR: counters: add max-only reset helpers and use them for clear counters X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=5d7be73fa0e72df97f85c10e6cb52da426ea23c8;p=thirdparty%2Fhaproxy.git MINOR: counters: add max-only reset helpers and use them for clear counters The plain "clear counters" command (OPER level) resets only the max/peak gauges of each object's counters, leaving cumulative counters intact, while "clear counters all" (ADMIN) performs a full reset via the counters_{fe,be}_reset() helpers introduced earlier in this series. The max-only reset was open-coded inline in proxy_stats_clear_counters() with a hand-maintained list of fields, duplicated across the backend, server and listener branches. This is fragile: a new max gauge added to struct {fe,be}_counters can silently be forgotten here. Factor the max-only reset into counters_fe_reset_max() and counters_be_reset_max(), living next to the existing reset helpers, and call them from proxy_stats_clear_counters(). Unlike the full-reset helpers these cannot use a blanket memset because the max fields are interleaved with live cumulative fields, so the gauges are zeroed individually. While consolidating, the two open-coded lists turned out to disagree: the backend branch cleared conn_max / cps_max / rps_max but not cur_sess_max, while the server branch cleared cur_sess_max but none of the former. Both used the same struct be_counters, so these were latent gaps rather than intentional differences. counters_be_reset_max() now clears the union of all peak gauges, so plain "clear counters" consistently resets every max gauge for both backends and servers. No functional change for the full-reset ("all") path. --- diff --git a/include/haproxy/counters.h b/include/haproxy/counters.h index 1a8391bd0..d1ad04b3e 100644 --- a/include/haproxy/counters.h +++ b/include/haproxy/counters.h @@ -45,6 +45,15 @@ void counters_be_shared_drop(struct be_counters_shared *counters); void counters_fe_reset(struct fe_counters *counters); void counters_be_reset(struct be_counters *counters); +/* Reset only the max/peak fields of , leaving cumulative counters + * intact. This is what the plain "clear counters" command does (as opposed to + * "clear counters all" which performs a full reset via counters_*_reset()). + * The max fields are interleaved with live cumulative fields, so they are + * cleared individually rather than with a blanket memset. + */ +void counters_fe_reset_max(struct fe_counters *counters); +void counters_be_reset_max(struct be_counters *counters); + /* time oriented helper: get last time (relative to current time) on a given * array, for member (one member per thread group) which is * assumed to be unsigned long type. diff --git a/src/counters.c b/src/counters.c index 5473c5471..591e07e44 100644 --- a/src/counters.c +++ b/src/counters.c @@ -214,3 +214,45 @@ void counters_be_reset(struct be_counters *counters) memset((char *)counters + sizeof(counters->shared), 0, sizeof(*counters) - sizeof(counters->shared)); } + +/* Reset only the max/peak gauges of a frontend/listener struct, + * leaving cumulative counters intact. Used by the plain "clear counters" + * command (as opposed to "clear counters all" which resets everything via + * counters_fe_reset()). + */ +void counters_fe_reset_max(struct fe_counters *counters) +{ + if (!counters) + return; + + counters->conn_max = 0; + counters->cps_max = 0; + counters->sps_max = 0; + counters->p.http.rps_max = 0; +} + +/* Reset only the max/peak gauges of a backend/server struct, + * leaving cumulative counters intact. See counters_fe_reset_max(). + * + * Note: this clears the union of all max gauges present in the struct. The + * previous inline code cleared slightly different subsets for backends and + * servers (backends left cur_sess_max untouched, servers left conn_max / + * cps_max / rps_max untouched); those were latent gaps, so plain "clear + * counters" now consistently resets every peak gauge for both. + */ +void counters_be_reset_max(struct be_counters *counters) +{ + if (!counters) + return; + + counters->conn_max = 0; + counters->cps_max = 0; + counters->sps_max = 0; + counters->nbpend_max = 0; + counters->cur_sess_max = 0; + counters->qtime_max = 0; + counters->ctime_max = 0; + counters->dtime_max = 0; + counters->ttime_max = 0; + counters->p.http.rps_max = 0; +} diff --git a/src/stats-proxy.c b/src/stats-proxy.c index edc809885..f9aa3dcaa 100644 --- a/src/stats-proxy.c +++ b/src/stats-proxy.c @@ -1673,34 +1673,15 @@ void proxy_stats_clear_counters(int clrall, struct list *stat_modules) counters_fe_reset(&px->fe_counters); } else { - px->be_counters.conn_max = 0; - px->be_counters.p.http.rps_max = 0; - px->be_counters.sps_max = 0; - px->be_counters.cps_max = 0; - px->be_counters.nbpend_max = 0; - px->be_counters.qtime_max = 0; - px->be_counters.ctime_max = 0; - px->be_counters.dtime_max = 0; - px->be_counters.ttime_max = 0; - - px->fe_counters.conn_max = 0; - px->fe_counters.p.http.rps_max = 0; - px->fe_counters.sps_max = 0; - px->fe_counters.cps_max = 0; + counters_be_reset_max(&px->be_counters); + counters_fe_reset_max(&px->fe_counters); } list_for_each_entry(sv, &px->servers, el_px) { if (clrall) counters_be_reset(&sv->counters); - else { - sv->counters.cur_sess_max = 0; - sv->counters.nbpend_max = 0; - sv->counters.sps_max = 0; - sv->counters.qtime_max = 0; - sv->counters.ctime_max = 0; - sv->counters.dtime_max = 0; - sv->counters.ttime_max = 0; - } + else + counters_be_reset_max(&sv->counters); } list_for_each_entry(li, &px->conf.listeners, by_fe) @@ -1708,7 +1689,7 @@ void proxy_stats_clear_counters(int clrall, struct list *stat_modules) if (clrall) counters_fe_reset(li->counters); else - li->counters->conn_max = 0; + counters_fe_reset_max(li->counters); } }