diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 09:51:24 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 09:51:24 +0000 |
commit | f7548d6d28c313cf80e6f3ef89aed16a19815df1 (patch) | |
tree | a3f6f2a3f247293bee59ecd28e8cd8ceb6ca064a /src/lib-old-stats/stats.c | |
parent | Initial commit. (diff) | |
download | dovecot-f7548d6d28c313cf80e6f3ef89aed16a19815df1.tar.xz dovecot-f7548d6d28c313cf80e6f3ef89aed16a19815df1.zip |
Adding upstream version 1:2.3.19.1+dfsg1.upstream/1%2.3.19.1+dfsg1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/lib-old-stats/stats.c')
-rw-r--r-- | src/lib-old-stats/stats.c | 229 |
1 files changed, 229 insertions, 0 deletions
diff --git a/src/lib-old-stats/stats.c b/src/lib-old-stats/stats.c new file mode 100644 index 0000000..284de26 --- /dev/null +++ b/src/lib-old-stats/stats.c @@ -0,0 +1,229 @@ +/* Copyright (c) 2015-2018 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "array.h" +#include "stats.h" + +struct stats_item { + struct stats_vfuncs v; + size_t pos; +}; + +static ARRAY(struct stats_item *) stats_items = ARRAY_INIT; +static unsigned int stats_total_size = 0; +static bool stats_allocated = FALSE; + +struct stats_item *stats_register(const struct stats_vfuncs *vfuncs) +{ + struct stats_item *item; + + if (stats_allocated) + i_panic("stats_register() called after stats_alloc_size() was already called - this will break existing allocations"); + + if (!array_is_created(&stats_items)) + i_array_init(&stats_items, 8); + + item = i_new(struct stats_item, 1); + item->v = *vfuncs; + item->pos = stats_total_size; + array_push_back(&stats_items, &item); + + stats_total_size += vfuncs->alloc_size(); + return item; +} + +static bool stats_item_find(struct stats_item *item, unsigned int *idx_r) +{ + struct stats_item *const *itemp; + + array_foreach(&stats_items, itemp) { + if (*itemp == item) { + *idx_r = array_foreach_idx(&stats_items, itemp); + return TRUE; + } + } + return FALSE; +} + +static struct stats_item *stats_item_find_by_name(const char *name) +{ + struct stats_item *item; + + array_foreach_elem(&stats_items, item) { + if (strcmp(item->v.short_name, name) == 0) + return item; + } + return NULL; +} + +void stats_unregister(struct stats_item **_item) +{ + struct stats_item *item = *_item; + unsigned int idx; + + *_item = NULL; + + if (!stats_item_find(item, &idx)) + i_unreached(); + array_delete(&stats_items, idx, 1); + + i_free(item); + if (array_count(&stats_items) == 0) { + array_free(&stats_items); + /* all stats should have been freed by now. allow + re-registering and using stats. */ + stats_allocated = FALSE; + } +} + +struct stats *stats_alloc(pool_t pool) +{ + return p_malloc(pool, stats_alloc_size()); +} + +size_t stats_alloc_size(void) +{ + stats_allocated = TRUE; + return stats_total_size; +} + +void stats_copy(struct stats *dest, const struct stats *src) +{ + memcpy(dest, src, stats_total_size); +} + +unsigned int stats_field_count(void) +{ + struct stats_item *item; + unsigned int count = 0; + + array_foreach_elem(&stats_items, item) + count += item->v.field_count(); + return count; +} + +const char *stats_field_name(unsigned int n) +{ + struct stats_item *item; + unsigned int i = 0, count; + + array_foreach_elem(&stats_items, item) { + count = item->v.field_count(); + if (i + count > n) + return item->v.field_name(n - i); + i += count; + } + i_unreached(); +} + +void stats_field_value(string_t *str, const struct stats *stats, + unsigned int n) +{ + struct stats_item *item; + unsigned int i = 0, count; + + array_foreach_elem(&stats_items, item) { + count = item->v.field_count(); + if (i + count > n) { + const void *item_stats = + CONST_PTR_OFFSET(stats, item->pos); + item->v.field_value(str, item_stats, n - i); + return; + } + i += count; + } + i_unreached(); +} + +bool stats_diff(const struct stats *stats1, const struct stats *stats2, + struct stats *diff_stats_r, const char **error_r) +{ + struct stats_item *item; + bool ret = TRUE; + + array_foreach_elem(&stats_items, item) { + if (!item->v.diff(CONST_PTR_OFFSET(stats1, item->pos), + CONST_PTR_OFFSET(stats2, item->pos), + PTR_OFFSET(diff_stats_r, item->pos), + error_r)) + ret = FALSE; + } + return ret; +} + +void stats_add(struct stats *dest, const struct stats *src) +{ + struct stats_item *item; + + array_foreach_elem(&stats_items, item) { + item->v.add(PTR_OFFSET(dest, item->pos), + CONST_PTR_OFFSET(src, item->pos)); + } +} + +bool stats_have_changed(const struct stats *prev, const struct stats *cur) +{ + struct stats_item *item; + + array_foreach_elem(&stats_items, item) { + if (item->v.have_changed(CONST_PTR_OFFSET(prev, item->pos), + CONST_PTR_OFFSET(cur, item->pos))) + return TRUE; + } + return FALSE; +} + +void stats_export(buffer_t *buf, const struct stats *stats) +{ + struct stats_item *item; + + array_foreach_elem(&stats_items, item) { + buffer_append(buf, item->v.short_name, + strlen(item->v.short_name)+1); + item->v.export(buf, CONST_PTR_OFFSET(stats, item->pos)); + } +} + +bool stats_import(const unsigned char *data, size_t size, + const struct stats *old_stats, struct stats *stats, + const char **error_r) +{ + struct stats_item *item; + const unsigned char *p; + size_t pos; + + memcpy(stats, old_stats, stats_total_size); + while (size > 0) { + const char *next_name = (const void *)data; + + p = memchr(data, '\0', size); + if (p == NULL) { + *error_r = "Expected name, but NUL is missing"; + return FALSE; + } + item = stats_item_find_by_name(next_name); + if (item == NULL) { + *error_r = t_strdup_printf("Unknown stats name: '%s'", next_name); + return FALSE; + } + size -= (p+1) - data; + data = p+1; + if (!item->v.import(data, size, &pos, + PTR_OFFSET(stats, item->pos), error_r)) + return FALSE; + i_assert(pos <= size); + data += pos; + size -= pos; + } + return TRUE; +} + +void *stats_fill_ptr(struct stats *stats, struct stats_item *item) +{ + return PTR_OFFSET(stats, item->pos); +} + +void stats_reset(struct stats *stats) +{ + memset(stats, 0, stats_total_size); +} |