bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2016-2018 Dovecot authors, see the included COPYING file */
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen#include "lib.h"
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen#include "ioloop.h"
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen#include "time-util.h"
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen#include "log-throttle.h"
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainenstruct log_throttle {
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen struct log_throttle_settings set;
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen log_throttle_callback_t *callback;
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen void *context;
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen struct timeval last_time;
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen unsigned int last_count;
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen struct timeout *to_throttled;
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen};
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen#undef log_throttle_init
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainenstruct log_throttle *
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainenlog_throttle_init(const struct log_throttle_settings *set,
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen log_throttle_callback_t *callback, void *context)
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen{
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen struct log_throttle *throttle;
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen i_assert(set->throttle_at_max_per_interval > 0);
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen i_assert(set->unthrottle_at_max_per_interval > 0);
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen throttle = i_new(struct log_throttle, 1);
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen throttle->set = *set;
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen if (throttle->set.interval_msecs == 0)
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen throttle->set.interval_msecs = 1000;
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen throttle->callback = callback;
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen throttle->context = context;
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen return throttle;
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen}
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainenvoid log_throttle_deinit(struct log_throttle **_throttle)
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen{
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen struct log_throttle *throttle = *_throttle;
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen *_throttle = NULL;
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&throttle->to_throttled);
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen i_free(throttle);
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen}
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainenstatic void log_throttle_callback(struct log_throttle *throttle)
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen{
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen if (throttle->last_count > 0)
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen throttle->callback(throttle->last_count, throttle->context);
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen if (throttle->last_count < throttle->set.unthrottle_at_max_per_interval)
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen timeout_remove(&throttle->to_throttled);
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen throttle->last_count = 0;
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen}
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainenbool log_throttle_accept(struct log_throttle *throttle)
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen{
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen if (throttle->to_throttled != NULL) {
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen /* unthrottling and last_count resets are done only by
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen the callback */
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen throttle->last_count++;
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen return FALSE;
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen } else if (timeval_diff_msecs(&ioloop_timeval, &throttle->last_time) >=
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen (int)throttle->set.interval_msecs) {
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen throttle->last_time = ioloop_timeval;
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen throttle->last_count = 1;
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen return TRUE;
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen } else if (++throttle->last_count <= throttle->set.throttle_at_max_per_interval) {
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen return TRUE;
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen } else {
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen throttle->last_count = 1;
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen throttle->to_throttled =
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen timeout_add(throttle->set.interval_msecs,
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen log_throttle_callback, throttle);
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen return FALSE;
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen }
ed1e909434714837f583c9d180c2a16a1c2675c2Timo Sirainen}