diff --git a/include/haproxy/stats-t.h b/include/haproxy/stats-t.h index af9b9711d..70d8b489a 100644 --- a/include/haproxy/stats-t.h +++ b/include/haproxy/stats-t.h @@ -509,11 +509,15 @@ enum stats_domain_px_cap { STATS_PX_CAP_MASK = 0xff }; +extern THREAD_LOCAL void *trash_counters; + #define EXTRA_COUNTERS(name) \ struct extra_counters *name #define EXTRA_COUNTERS_GET(counters, mod) \ - (void *)((counters)->data + (mod)->counters_off[(counters)->type]) + (likely(counters) ? \ + ((void *)((counters)->data + (mod)->counters_off[(counters)->type])) : \ + (trash_counters)) #define EXTRA_COUNTERS_REGISTER(counters, ctype, alloc_failed_label) \ do { \ diff --git a/src/listener.c b/src/listener.c index 7f038c4a3..c9f0c2de6 100644 --- a/src/listener.c +++ b/src/listener.c @@ -623,6 +623,8 @@ int create_listeners(struct bind_conf *bc, const struct sockaddr_storage *ss, if (fd != -1) l->rx.flags |= RX_F_INHERITED; + l->extra_counters = NULL; + HA_SPIN_INIT(&l->lock); _HA_ATOMIC_ADD(&jobs, 1); _HA_ATOMIC_ADD(&listeners, 1); diff --git a/src/proxy.c b/src/proxy.c index e469c7671..08140198f 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -1041,6 +1041,9 @@ void init_new_proxy(struct proxy *p) /* Default to only allow L4 retries */ p->retry_type = PR_RE_CONN_FAILED; + p->extra_counters_fe = NULL; + p->extra_counters_be = NULL; + HA_RWLOCK_INIT(&p->lock); } diff --git a/src/server.c b/src/server.c index 1e9f46ec7..d72e7e069 100644 --- a/src/server.c +++ b/src/server.c @@ -1742,6 +1742,8 @@ struct server *new_server(struct proxy *proxy) srv->agent.proxy = proxy; srv->xprt = srv->check.xprt = srv->agent.xprt = xprt_get(XPRT_RAW); + srv->extra_counters = NULL; + /* please don't put default server settings here, they are set in * init_default_instance(). */ diff --git a/src/stats.c b/src/stats.c index ad92d7159..3f314440d 100644 --- a/src/stats.c +++ b/src/stats.c @@ -269,6 +269,8 @@ static struct list stats_module_list[STATS_DOMAIN_COUNT] = { LIST_HEAD_INIT(stats_module_list[STATS_DOMAIN_DNS]), }; +THREAD_LOCAL void *trash_counters; + static inline uint8_t stats_get_domain(uint32_t domain) { return domain >> STATS_DOMAIN & STATS_DOMAIN_MASK; @@ -4548,6 +4550,34 @@ static int allocate_stats_dns_postcheck(void) REGISTER_CONFIG_POSTPARSER("allocate-stats-dns", allocate_stats_dns_postcheck); +static int allocate_trash_counters(void) +{ + struct stats_module *mod; + int domains[] = { STATS_DOMAIN_PROXY, STATS_DOMAIN_DNS }, i; + size_t max_counters_size = 0; + + /* calculate the greatest counters used by any stats modules */ + for (i = 0; i < STATS_DOMAIN_COUNT; ++i) { + list_for_each_entry(mod, &stats_module_list[domains[i]], list) { + max_counters_size = mod->counters_size > max_counters_size ? + mod->counters_size : max_counters_size; + } + } + + /* allocate the trash with the size of the greatest counters */ + if (max_counters_size) { + trash_counters = malloc(max_counters_size); + if (!trash_counters) { + ha_alert("stats: cannot allocate trash counters for statistics\n"); + return 0; + } + } + + return 1; +} + +REGISTER_PER_THREAD_ALLOC(allocate_trash_counters); + static void deinit_stats(void) { int domains[] = { STATS_DOMAIN_PROXY, STATS_DOMAIN_DNS }, i; @@ -4565,6 +4595,14 @@ static void deinit_stats(void) REGISTER_POST_DEINIT(deinit_stats); +static void free_trash_counters(void) +{ + if (trash_counters) + free(trash_counters); +} + +REGISTER_PER_THREAD_FREE(free_trash_counters); + /* register cli keywords */ static struct cli_kw_list cli_kws = {{ },{ { { "clear", "counters", NULL }, "clear counters : clear max statistics counters (add 'all' for all counters)", cli_parse_clear_counters, NULL, NULL },