Mercurial > dovecot > core-2.2
view src/lib-stats/stats.c @ 21390:2e2563132d5f
Updated copyright notices to include the year 2017.
author | Stephan Bosch <stephan.bosch@dovecot.fi> |
---|---|
date | Wed, 11 Jan 2017 02:51:13 +0100 |
parents | ca35aefb6c0e |
children | cb108f786fb4 |
line wrap: on
line source
/* Copyright (c) 2015-2017 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_append(&stats_items, &item, 1); 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 *const *itemp; array_foreach(&stats_items, itemp) { if (strcmp((*itemp)->v.short_name, name) == 0) return *itemp; } 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 *const *itemp; unsigned int count = 0; array_foreach(&stats_items, itemp) count += (*itemp)->v.field_count(); return count; } const char *stats_field_name(unsigned int n) { struct stats_item *const *itemp; unsigned int i = 0, count; array_foreach(&stats_items, itemp) { count = (*itemp)->v.field_count(); if (i + count > n) return (*itemp)->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 *const *itemp; unsigned int i = 0, count; array_foreach(&stats_items, itemp) { count = (*itemp)->v.field_count(); if (i + count > n) { const void *item_stats = CONST_PTR_OFFSET(stats, (*itemp)->pos); (*itemp)->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 *const *itemp; bool ret = TRUE; array_foreach(&stats_items, itemp) { if (!(*itemp)->v.diff(CONST_PTR_OFFSET(stats1, (*itemp)->pos), CONST_PTR_OFFSET(stats2, (*itemp)->pos), PTR_OFFSET(diff_stats_r, (*itemp)->pos), error_r)) ret = FALSE; } return ret; } void stats_add(struct stats *dest, const struct stats *src) { struct stats_item *const *itemp; array_foreach(&stats_items, itemp) { (*itemp)->v.add(PTR_OFFSET(dest, (*itemp)->pos), CONST_PTR_OFFSET(src, (*itemp)->pos)); } } bool stats_have_changed(const struct stats *prev, const struct stats *cur) { struct stats_item *const *itemp; array_foreach(&stats_items, itemp) { if ((*itemp)->v.have_changed(CONST_PTR_OFFSET(prev, (*itemp)->pos), CONST_PTR_OFFSET(cur, (*itemp)->pos))) return TRUE; } return FALSE; } void stats_export(buffer_t *buf, const struct stats *stats) { struct stats_item *const *itemp; array_foreach(&stats_items, itemp) { buffer_append(buf, (*itemp)->v.short_name, strlen((*itemp)->v.short_name)+1); (*itemp)->v.export(buf, CONST_PTR_OFFSET(stats, (*itemp)->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); }