1 /* Copyright (c) 2016-2018 Dovecot authors, see the included COPYING file */
2
3 #include "lib.h"
4 #include "ioloop.h"
5 #include "time-util.h"
6 #include "log-throttle.h"
7
8 struct log_throttle {
9 struct log_throttle_settings set;
10 log_throttle_callback_t *callback;
11 void *context;
12
13 struct timeval last_time;
14 unsigned int last_count;
15
16 struct timeout *to_throttled;
17 };
18
19 #undef log_throttle_init
20 struct log_throttle *
log_throttle_init(const struct log_throttle_settings * set,log_throttle_callback_t * callback,void * context)21 log_throttle_init(const struct log_throttle_settings *set,
22 log_throttle_callback_t *callback, void *context)
23 {
24 struct log_throttle *throttle;
25
26 i_assert(set->throttle_at_max_per_interval > 0);
27 i_assert(set->unthrottle_at_max_per_interval > 0);
28
29 throttle = i_new(struct log_throttle, 1);
30 throttle->set = *set;
31 if (throttle->set.interval_msecs == 0)
32 throttle->set.interval_msecs = 1000;
33 throttle->callback = callback;
34 throttle->context = context;
35 throttle->last_time = ioloop_timeval;
36 return throttle;
37 }
38
log_throttle_deinit(struct log_throttle ** _throttle)39 void log_throttle_deinit(struct log_throttle **_throttle)
40 {
41 struct log_throttle *throttle = *_throttle;
42
43 *_throttle = NULL;
44 timeout_remove(&throttle->to_throttled);
45 i_free(throttle);
46 }
47
log_throttle_callback(struct log_throttle * throttle)48 static void log_throttle_callback(struct log_throttle *throttle)
49 {
50 if (throttle->last_count > 0)
51 throttle->callback(throttle->last_count, throttle->context);
52 if (throttle->last_count < throttle->set.unthrottle_at_max_per_interval)
53 timeout_remove(&throttle->to_throttled);
54 throttle->last_count = 0;
55 }
56
log_throttle_accept(struct log_throttle * throttle)57 bool log_throttle_accept(struct log_throttle *throttle)
58 {
59 if (throttle->to_throttled != NULL) {
60 /* unthrottling and last_count resets are done only by
61 the callback */
62 throttle->last_count++;
63 return FALSE;
64 } else if (timeval_diff_msecs(&ioloop_timeval, &throttle->last_time) >=
65 (int)throttle->set.interval_msecs) {
66 throttle->last_time = ioloop_timeval;
67 throttle->last_count = 1;
68 return TRUE;
69 } else if (++throttle->last_count <= throttle->set.throttle_at_max_per_interval) {
70 return TRUE;
71 } else {
72 throttle->last_count = 1;
73 throttle->to_throttled =
74 timeout_add(throttle->set.interval_msecs,
75 log_throttle_callback, throttle);
76 return FALSE;
77 }
78 }
79