From 4e9e841878d9bc09d171376cfcae2e9da671de4a Mon Sep 17 00:00:00 2001 From: Amaury Denoyelle Date: Mon, 29 Apr 2024 17:06:27 +0200 Subject: [PATCH] MINOR: stats: prepare stats-file support for values other than FN_COUNTER Currently, only FN_COUNTER are dumped and preloaded via a stats-file. Thus in several places we relied on the assumption that only FN_COUNTER are valid in stats-file context. New stats types will soon be implemented as they are also eligilible to statistics reloading on process startup. Thus, prepare stats-file functions to remove any FN_COUNTER restriction. As one of this change, generate_stat_tree() now uses stcol_is_generic() for stats name tree indexing before stats-file parsing. Also related to stats-file parsing, individual counter preloading step as been extracted from line parsing in a dedicated new function load_ctr(). This will allow to extend it to support multiple mechanism of counter preloading depending on the stats type. --- include/haproxy/stats.h | 6 ++++ src/stats-file.c | 61 ++++++++++++++++++++++++++++++----------- src/stats.c | 31 +++++++++++---------- 3 files changed, 68 insertions(+), 30 deletions(-) diff --git a/include/haproxy/stats.h b/include/haproxy/stats.h index 90141a331d..516529970a 100644 --- a/include/haproxy/stats.h +++ b/include/haproxy/stats.h @@ -74,6 +74,12 @@ int stats_emit_field_tags(struct buffer *out, const struct field *f, char delim); +/* Returns true if is fully defined, false if only used as name-desc. */ +static inline int stcol_is_generic(const struct stat_col *col) +{ + return !!(col->cap); +} + static inline enum field_format stcol_format(const struct stat_col *col) { return col->type & FF_MASK; diff --git a/src/stats-file.c b/src/stats-file.c index a41df828f4..828c0a1bf2 100644 --- a/src/stats-file.c +++ b/src/stats-file.c @@ -85,16 +85,20 @@ void stats_dump_file_header(int type, struct buffer *out) chunk_strcat(out, "#fe guid,"); for (i = 0; i < ST_I_PX_MAX; ++i) { col = &stat_cols_px[i]; - if (stcol_nature(col) == FN_COUNTER && (col->cap & (STATS_PX_CAP_FE|STATS_PX_CAP_LI))) + if (stcol_is_generic(col) && + col->cap & (STATS_PX_CAP_FE|STATS_PX_CAP_LI)) { chunk_appendf(out, "%s,", col->name); + } } } else { chunk_appendf(out, "#be guid,"); for (i = 0; i < ST_I_PX_MAX; ++i) { col = &stat_cols_px[i]; - if (stcol_nature(col) == FN_COUNTER && (col->cap & (STATS_PX_CAP_BE|STATS_PX_CAP_SRV))) + if (stcol_is_generic(col) && + col->cap & (STATS_PX_CAP_BE|STATS_PX_CAP_SRV)) { chunk_appendf(out, "%s,", col->name); + } } } @@ -189,6 +193,44 @@ static int parse_header_line(struct ist header, struct eb_root *st_tree, return 1; } +/* Preload an individual counter instance stored at with + * value> for the stat column. + * + * Returns 0 on success else non-zero if counter was not updated. + */ +static int load_ctr(const struct stat_col *col, const struct ist token, + void* counter) +{ + const enum field_nature fn = stcol_nature(col); + const enum field_format ff = stcol_format(col); + const char *ptr = istptr(token); + struct field value; + + switch (ff) { + case FF_U64: + value.u.u64 = read_uint64(&ptr, istend(token)); + break; + + default: + /* Unsupported field nature. */ + return 1; + } + + /* Do not load value if non numeric characters present. */ + if (ptr != istend(token)) + return 1; + + if (fn == FN_COUNTER && ff == FF_U64) { + *(uint64_t *)counter = value.u.u64; + } + else { + /* Unsupported field format/nature combination. */ + return 1; + } + + return 0; +} + /* Parse a non header stats-file line . Specify current parsing * and stats column matrix derived from the last header line. * @@ -269,7 +311,6 @@ static int parse_stat_line(struct ist line, i = 0; while (istlen(line) && i < STAT_FILE_MAX_COL_COUNT) { const struct stat_col *col = cols[i++]; - enum field_format ff; token = istsplit(&line, ','); if (!istlen(token)) @@ -278,19 +319,7 @@ static int parse_stat_line(struct ist line, if (!col) continue; - ff = stcol_format(col); - if (ff == FF_U64) { - uint64_t *offset, value; - const char *ptr; - - ptr = istptr(token); - value = read_uint64(&ptr, istend(token)); - /* Do not load value if non numeric characters present. */ - if (ptr == istend(token)) { - offset = (uint64_t *)(base_off + col->metric.offset[off]); - *offset = value; - } - } + load_ctr(col, token, base_off + col->metric.offset[off]); } return 0; diff --git a/src/stats.c b/src/stats.c index 3f3ee0fe3c..5ada0503ee 100644 --- a/src/stats.c +++ b/src/stats.c @@ -92,12 +92,6 @@ .cap = (cap_f), \ } -/* Returns true if is fully defined, false if only used as name-desc. */ -static int stcol_is_generic(const struct stat_col *col) -{ - return !!(col->cap); -} - /* Convert stat_col to old-style as name_desc. */ static void stcol2ndesc(struct name_desc *name, const struct stat_col *col) { @@ -338,7 +332,7 @@ struct list stats_module_list[STATS_DOMAIN_COUNT] = { THREAD_LOCAL void *trash_counters; -/* Insert into all stat columns from indexed by their name. */ +/* Insert generic stat columns into indexed by their name. */ int generate_stat_tree(struct eb_root *st_tree, const struct stat_col cols[]) { const struct stat_col *col; @@ -348,7 +342,8 @@ int generate_stat_tree(struct eb_root *st_tree, const struct stat_col cols[]) for (i = 0; i < ST_I_PX_MAX; ++i) { col = &cols[i]; - if (stcol_nature(col) == FN_COUNTER) { + + if (stcol_is_generic(col)) { len = strlen(col->name); node = malloc(sizeof(struct stcol_node) + len + 1); if (!node) @@ -739,6 +734,7 @@ static struct field me_generate_field(const struct stat_col *col, const void *counters, uint8_t cap, int stat_file) { + enum field_nature fn; struct field value; void *counter = NULL; int wrong_side = 0; @@ -794,12 +790,19 @@ static struct field me_generate_field(const struct stat_col *col, return (struct field){ .type = FF_EMPTY }; } - switch (stcol_format(col)) { - case FF_U64: - value = mkf_u64(stcol_nature(col), *(uint64_t *)counter); - break; - default: - /* only FF_U64 counters currently use generic metric calculation */ + fn = stcol_nature(col); + if (fn == FN_COUNTER) { + switch (stcol_format(col)) { + case FF_U64: + value = mkf_u64(FN_COUNTER, *(uint64_t *)counter); + break; + default: + /* only FF_U64 counters currently use generic metric calculation */ + ABORT_NOW(); + } + } + else { + /* No generic column available for other field nature. */ ABORT_NOW(); } -- 2.39.5