summaryrefslogtreecommitdiffstats
path: root/src/lib-old-stats/stats-parser.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/lib-old-stats/stats-parser.c178
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;
+ }
+ }
+}