Mercurial > dovecot > core-2.2
view src/stats/mail-stats.c @ 13558:4538030286f6
stats: Error message fix.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Tue, 27 Sep 2011 00:41:49 +0300 |
parents | 835891cf2eef |
children | ba770cba5598 |
line wrap: on
line source
/* Copyright (c) 2011 Dovecot authors, see the included COPYING file */ #include "lib.h" #include "time-util.h" #include "mail-stats.h" enum mail_stats_type { TYPE_NUM, TYPE_TIMEVAL }; struct mail_stats_parse_map { const char *name; unsigned int offset; unsigned int size; enum mail_stats_type type; } parse_map[] = { #define E(parsename, name, type) { parsename, offsetof(struct mail_stats, name), sizeof(((struct mail_stats *)0)->name), type } #define EN(parsename, name) E(parsename, name, TYPE_NUM) E("ucpu", user_cpu, TYPE_TIMEVAL), E("scpu", sys_cpu, TYPE_TIMEVAL), EN("minflt", min_faults), EN("majflt", maj_faults), EN("volcs", vol_cs), EN("involcs", invol_cs), EN("diskin", disk_input), EN("diskout", disk_output), EN("rchar", read_bytes), EN("wchar", write_bytes), EN("syscr", read_count), EN("syscw", write_count), EN("mlpath", mail_lookup_path), EN("mlattr", mail_lookup_attr), EN("mrcount", mail_read_count), EN("mrbytes", mail_read_bytes), EN("mcache", mail_cache_hits) }; static int mail_stats_parse_timeval(const char *value, struct timeval *tv) { const char *p, *secs_str; unsigned long secs, usecs; p = strchr(value, '.'); if (p == NULL) return -1; secs_str = t_strdup_until(value, p++); if (str_to_ulong(secs_str, &secs) < 0 || str_to_ulong(p, &usecs) < 0 || usecs > 1000000) return -1; tv->tv_sec = secs; tv->tv_usec = usecs; return 0; } static struct mail_stats_parse_map * parse_map_find(const char *name) { unsigned int i; for (i = 0; i < N_ELEMENTS(parse_map); i++) { if (strcmp(parse_map[i].name, name) == 0) return &parse_map[i]; } return NULL; } static int mail_stats_parse_one(const char *key, const char *value, struct mail_stats *stats, const char **error_r) { struct mail_stats_parse_map *map; void *dest; map = parse_map_find(key); if (map == NULL) return 0; dest = PTR_OFFSET(stats, map->offset); switch (map->type) { case TYPE_NUM: switch (map->size) { case sizeof(uint32_t): if (str_to_uint32(value, dest) < 0) { *error_r = "invalid number"; return -1; } break; case sizeof(uint64_t): if (str_to_uint64(value, dest) < 0) { *error_r = "invalid number"; return -1; } break; default: i_unreached(); } break; case TYPE_TIMEVAL: if (mail_stats_parse_timeval(value, dest) < 0) { *error_r = "invalid cpu parameter"; return -1; } break; } return 0; } int mail_stats_parse(const char *const *args, struct mail_stats *stats_r, const char **error_r) { const char *p, *key, *value; unsigned int i; memset(stats_r, 0, sizeof(*stats_r)); for (i = 0; args[i] != NULL; i++) { p = strchr(args[i], '='); if (p == NULL) { *error_r = "mail stats parameter missing '='"; return -1; } key = t_strdup_until(args[i], p); value = p + 1; if (mail_stats_parse_one(key, value, stats_r, error_r) < 0) return -1; } return 0; } static bool mail_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 / 1000000; dest->tv_usec = diff_usecs % 1000000; return TRUE; } static bool mail_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 mail_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 mail_stats_diff(const struct mail_stats *stats1, const struct mail_stats *stats2, struct mail_stats *diff_stats_r, const char **error_r) { unsigned int i; memset(diff_stats_r, 0, sizeof(*diff_stats_r)); for (i = 0; i < N_ELEMENTS(parse_map); i++) { unsigned int offset = parse_map[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 (parse_map[i].type) { case TYPE_NUM: switch (parse_map[i].size) { case sizeof(uint32_t): if (!mail_stats_diff_uint32(dest, src1, src2)) { *error_r = t_strdup_printf("%s %u < %u", parse_map[i].name, *(const uint32_t *)src2, *(const uint32_t *)src1); return FALSE; } break; case sizeof(uint64_t): if (!mail_stats_diff_uint64(dest, src1, src2)) { const uint64_t *n1 = src1, *n2 = src2; *error_r = t_strdup_printf("%s %llu < %llu", parse_map[i].name, (unsigned long long)*n2, (unsigned long long)*n1); return FALSE; } break; default: i_unreached(); } break; case TYPE_TIMEVAL: if (!mail_stats_diff_timeval(dest, src1, src2)) { const struct timeval *tv1 = src1, *tv2 = src2; *error_r = t_strdup_printf("%s %ld.%d < %ld.%d", parse_map[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 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 > 1000000) { dest->tv_usec -= 1000000; dest->tv_sec++; } } void mail_stats_add(struct mail_stats *dest, const struct mail_stats *src) { unsigned int i; for (i = 0; i < N_ELEMENTS(parse_map); i++) { unsigned int offset = parse_map[i].offset; void *f_dest = PTR_OFFSET(dest, offset); const void *f_src = CONST_PTR_OFFSET(src, offset); switch (parse_map[i].type) { case TYPE_NUM: switch (parse_map[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 TYPE_TIMEVAL: timeval_add(f_dest, f_src); break; } } }