diff options
Diffstat (limited to '')
-rw-r--r-- | src/lib-old-stats/stats-parser.c | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/src/lib-old-stats/stats-parser.c b/src/lib-old-stats/stats-parser.c new file mode 100644 index 0000000..da009e9 --- /dev/null +++ b/src/lib-old-stats/stats-parser.c @@ -0,0 +1,178 @@ +/* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "str.h" +#include "time-util.h" +#include "stats-parser.h" + +#define USECS_PER_SEC 1000000 + +static bool stats_diff_timeval(struct timeval *dest, + const struct timeval *src1, + const struct timeval *src2) +{ + long long diff_usecs; + + diff_usecs = timeval_diff_usecs(src2, src1); + if (diff_usecs < 0) + return FALSE; + dest->tv_sec = diff_usecs / USECS_PER_SEC; + dest->tv_usec = diff_usecs % USECS_PER_SEC; + return TRUE; +} + +static bool +stats_diff_uint32(uint32_t *dest, const uint32_t *src1, const uint32_t *src2) +{ + if (*src1 > *src2) + return FALSE; + *dest = *src2 - *src1; + return TRUE; +} + +static bool +stats_diff_uint64(uint64_t *dest, const uint64_t *src1, const uint64_t *src2) +{ + if (*src1 > *src2) + return FALSE; + *dest = *src2 - *src1; + return TRUE; +} + +bool stats_parser_diff(const struct stats_parser_field *fields, + unsigned int fields_count, + const struct stats *stats1, const struct stats *stats2, + struct stats *diff_stats_r, const char **error_r) +{ + unsigned int i; + + for (i = 0; i < fields_count; i++) { + unsigned int offset = fields[i].offset; + void *dest = PTR_OFFSET(diff_stats_r, offset); + const void *src1 = CONST_PTR_OFFSET(stats1, offset); + const void *src2 = CONST_PTR_OFFSET(stats2, offset); + + switch (fields[i].type) { + case STATS_PARSER_TYPE_UINT: + switch (fields[i].size) { + case sizeof(uint32_t): + if (!stats_diff_uint32(dest, src1, src2)) { + *error_r = t_strdup_printf("%s %u < %u", + fields[i].name, + *(const uint32_t *)src2, + *(const uint32_t *)src1); + return FALSE; + } + break; + case sizeof(uint64_t): + if (!stats_diff_uint64(dest, src1, src2)) { + const uint64_t *n1 = src1, *n2 = src2; + + *error_r = t_strdup_printf("%s %"PRIu64" < %"PRIu64, + fields[i].name, *n2, *n1); + return FALSE; + } + break; + default: + i_unreached(); + } + break; + case STATS_PARSER_TYPE_TIMEVAL: + if (!stats_diff_timeval(dest, src1, src2)) { + const struct timeval *tv1 = src1, *tv2 = src2; + + *error_r = t_strdup_printf("%s %ld.%d < %ld.%d", + fields[i].name, + (long)tv2->tv_sec, (int)tv2->tv_usec, + (long)tv1->tv_sec, (int)tv1->tv_usec); + return FALSE; + } + break; + } + } + return TRUE; +} + +static void stats_timeval_add(struct timeval *dest, const struct timeval *src) +{ + dest->tv_sec += src->tv_sec; + dest->tv_usec += src->tv_usec; + if (dest->tv_usec > USECS_PER_SEC) { + dest->tv_usec -= USECS_PER_SEC; + dest->tv_sec++; + } +} + +void stats_parser_add(const struct stats_parser_field *fields, + unsigned int fields_count, + struct stats *dest, const struct stats *src) +{ + unsigned int i; + + for (i = 0; i < fields_count; i++) { + unsigned int offset = fields[i].offset; + void *f_dest = PTR_OFFSET(dest, offset); + const void *f_src = CONST_PTR_OFFSET(src, offset); + + switch (fields[i].type) { + case STATS_PARSER_TYPE_UINT: + switch (fields[i].size) { + case sizeof(uint32_t): { + uint32_t *n_dest = f_dest; + const uint32_t *n_src = f_src; + + *n_dest += *n_src; + break; + } + case sizeof(uint64_t): { + uint64_t *n_dest = f_dest; + const uint64_t *n_src = f_src; + + *n_dest += *n_src; + break; + } + default: + i_unreached(); + } + break; + case STATS_PARSER_TYPE_TIMEVAL: + stats_timeval_add(f_dest, f_src); + break; + } + } +} + +void stats_parser_value(string_t *str, + const struct stats_parser_field *field, + const void *data) +{ + const void *ptr = CONST_PTR_OFFSET(data, field->offset); + + switch (field->type) { + case STATS_PARSER_TYPE_UINT: + switch (field->size) { + case sizeof(uint32_t): { + const uint32_t *n = ptr; + + str_printfa(str, "%u", *n); + break; + } + case sizeof(uint64_t): { + const uint64_t *n = ptr; + + str_printfa(str, "%"PRIu64, *n); + break; + } + default: + i_unreached(); + } + break; + case STATS_PARSER_TYPE_TIMEVAL: { + const struct timeval *tv = ptr; + + str_printfa(str, "%"PRIdTIME_T".%u", + tv->tv_sec, (unsigned int)tv->tv_usec); + break; + } + } +} |