stats-metrics.c revision 5f08b0309190ec818d46bfe0e497468b30714a93
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher/* Copyright (c) 2017 Dovecot authors, see the included COPYING file */
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan#include "lib.h"
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan#include "array.h"
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher#include "stats-dist.h"
2cb6f28b3a12bb714bf14494d31eb6b6fff64b8bJakub Hrozek#include "time-util.h"
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek#include "event-filter.h"
2cb6f28b3a12bb714bf14494d31eb6b6fff64b8bJakub Hrozek#include "stats-settings.h"
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan#include "stats-metrics.h"
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagherstruct stats_metrics {
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan pool_t pool;
d6d50c17e94dc0d3000345e8a933311c14bbb828Jakub Hrozek struct event_filter *filter;
0172959f117b545c8a6b1893f5f56818d82dd624Jakub Hrozek ARRAY(struct metric *) metrics;
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher};
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagherstatic void
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivanstats_metric_settings_to_query(const struct stats_metric_settings *set,
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan struct event_filter_query *query_r)
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher{
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher i_zero(query_r);
7a14e8f66c0e932fe2954d792614a3b61d444bd1Jakub Hrozek
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan /* generate fields for event filter */
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher if (array_is_created(&set->filter)) {
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher struct event_filter_field *filter_fields;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher const char *const *filters;
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek unsigned int i, count;
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek filters = array_get(&set->filter, &count);
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek i_assert(count % 2 == 0);
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek count /= 2;
2ea6196484055397cc4bc011c5960f790431fa9dStephen Gallagher
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan filter_fields = t_new(struct event_filter_field, count + 1);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan for (i = 0; i < count; i++) {
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan filter_fields[i].key = filters[i*2];
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher filter_fields[i].value = filters[i*2+1];
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan }
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan query_r->fields = filter_fields;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan }
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher /* add query to the event filter */
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher query_r->categories = t_strsplit_spaces(set->categories, " ");
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher query_r->name = set->event_name;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher query_r->source_filename = t_strcut(set->source_location, ':');
2ea6196484055397cc4bc011c5960f790431fa9dStephen Gallagher query_r->source_linenum = set->parsed_source_linenum;
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek}
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivanstatic void stats_metrics_add_set(struct stats_metrics *metrics,
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan const struct stats_metric_settings *set)
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher{
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan struct event_filter_query query;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan struct metric *metric;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan const char *const *fields;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher metric = p_new(metrics->pool, struct metric, 1);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan metric->name = p_strdup(metrics->pool, set->name);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan metric->duration_stats = stats_dist_init();
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher fields = t_strsplit_spaces(set->fields, " ");
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher metric->fields_count = str_array_length(fields);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan if (metric->fields_count > 0) {
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher metric->fields = p_new(metrics->pool, struct metric_field,
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher metric->fields_count);
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher for (unsigned int i = 0; i < metric->fields_count; i++) {
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan metric->fields[i].field_key =
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher p_strdup(metrics->pool, fields[i]);
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher metric->fields[i].stats = stats_dist_init();
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher }
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek }
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek array_append(&metrics->metrics, &metric, 1);
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek stats_metric_settings_to_query(set, &query);
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek query.context = metric;
2ea6196484055397cc4bc011c5960f790431fa9dStephen Gallagher event_filter_add(metrics->filter, &query);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan}
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivanstatic void
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagherstats_metrics_add_from_settings(struct stats_metrics *metrics,
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan const struct stats_settings *set)
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan{
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan struct stats_metric_settings *const *metric_setp;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan if (!array_is_created(&set->metrics)) {
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan p_array_init(&metrics->metrics, metrics->pool, 0);
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan return;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan }
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher p_array_init(&metrics->metrics, metrics->pool,
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher array_count(&set->metrics));
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher array_foreach(&set->metrics, metric_setp) T_BEGIN {
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek stats_metrics_add_set(metrics, *metric_setp);
ea929f1b022fc2cb77dec89b0e12accef983ec85Jakub Hrozek } T_END;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan}
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivanstruct stats_metrics *stats_metrics_init(const struct stats_settings *set)
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher{
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan struct stats_metrics *metrics;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan pool_t pool = pool_alloconly_create("stats metrics", 1024);
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher metrics = p_new(pool, struct stats_metrics, 1);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan metrics->pool = pool;
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher metrics->filter = event_filter_create();
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher stats_metrics_add_from_settings(metrics, set);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan return metrics;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher}
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivanstatic void stats_metric_free(struct metric *metric)
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher{
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher stats_dist_deinit(&metric->duration_stats);
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher for (unsigned int i = 0; i < metric->fields_count; i++)
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan stats_dist_deinit(&metric->fields[i].stats);
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher}
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivanvoid stats_metrics_deinit(struct stats_metrics **_metrics)
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan{
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher struct stats_metrics *metrics = *_metrics;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan struct metric *const *metricp;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher *_metrics = NULL;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan array_foreach(&metrics->metrics, metricp)
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher stats_metric_free(*metricp);
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher event_filter_unref(&metrics->filter);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan pool_unref(&metrics->pool);
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher}
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivanvoid stats_metrics_reset(struct stats_metrics *metrics)
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher{
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher struct metric *const *metricp;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher array_foreach(&metrics->metrics, metricp) {
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher stats_dist_reset((*metricp)->duration_stats);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan for (unsigned int i = 0; i < (*metricp)->fields_count; i++)
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher stats_dist_reset((*metricp)->fields[i].stats);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan }
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan}
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivanstruct event_filter *
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagherstats_metrics_get_event_filter(struct stats_metrics *metrics)
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher{
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek return metrics->filter;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan}
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivanstatic void
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagherstats_metric_event(struct metric *metric, struct event *event)
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher{
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek struct timeval tv_start, tv_end;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan intmax_t duration = 0;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan if (event_get_last_send_time(event, &tv_end)) {
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher event_get_create_time(event, &tv_start);
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher duration = timeval_diff_usecs(&tv_end, &tv_start);
6463ed1dcdd45416468b3fa178bd856b5a9ed2c3Jakub Hrozek }
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan stats_dist_add(metric->duration_stats, duration);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan for (unsigned int i = 0; i < metric->fields_count; i++) {
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher const struct event_field *field =
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan event_find_field(event, metric->fields[i].field_key);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan if (field == NULL)
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan continue;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher intmax_t num = 0;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan switch (field->value_type) {
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan case EVENT_FIELD_VALUE_TYPE_STR:
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan break;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan case EVENT_FIELD_VALUE_TYPE_INTMAX:
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher num = field->value.intmax;
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher break;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan case EVENT_FIELD_VALUE_TYPE_TIMEVAL:
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan num = field->value.timeval.tv_sec * 1000000ULL +
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan field->value.timeval.tv_usec;
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher break;
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher }
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan stats_dist_add(metric->fields[i].stats, num);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan }
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher}
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivanvoid stats_metrics_event(struct stats_metrics *metrics, struct event *event)
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan{
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan struct event_filter_match_iter *iter;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher struct metric *metric;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan iter = event_filter_match_iter_init(metrics->filter, event);
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan while ((metric = event_filter_match_iter_next(iter)) != NULL)
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan stats_metric_event(metric, event);
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan event_filter_match_iter_deinit(&iter);
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher}
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivanstruct stats_metrics_iter {
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher struct stats_metrics *metrics;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan unsigned int idx;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan};
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivanstruct stats_metrics_iter *
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivanstats_metrics_iterate_init(struct stats_metrics *metrics)
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan{
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan struct stats_metrics_iter *iter;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher iter = i_new(struct stats_metrics_iter, 1);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan iter->metrics = metrics;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan return iter;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan}
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivanconst struct metric *stats_metrics_iterate(struct stats_metrics_iter *iter)
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher{
7797e361155f7ce937085fd98e360469d7baf1b6Jakub Hrozek struct metric *const *metrics;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan unsigned int count;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher metrics = array_get(&iter->metrics->metrics, &count);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan if (iter->idx >= count)
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan return NULL;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan return metrics[iter->idx++];
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan}
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallaghervoid stats_metrics_iterate_deinit(struct stats_metrics_iter **_iter)
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan{
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher struct stats_metrics_iter *iter = *_iter;
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan *_iter = NULL;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan i_free(iter);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan}
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan