1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
|
/*
* Copyright (C) Igor Sysoev
* Copyright (C) NGINX, Inc.
*/
#include <nxt_main.h>
static void nxt_log_moderate_timer_handler(nxt_task_t *task, void *obj,
void *data);
nxt_bool_t
nxt_log_moderate_allow(nxt_log_moderation_t *mod)
{
nxt_uint_t n;
nxt_time_t now;
nxt_bool_t allow, timer;
nxt_thread_t *thr;
thr = nxt_thread();
now = nxt_thread_time(thr);
allow = 0;
timer = 0;
nxt_thread_spin_lock(&mod->lock);
n = mod->count++;
if (now != mod->last) {
if (n <= mod->limit) {
mod->last = now;
mod->count = 1;
allow = 1;
}
/* "n > mod->limit" means that timer has already been set. */
} else {
if (n < mod->limit) {
allow = 1;
} else if (n == mod->limit) {
/*
* There is a race condition on 32-bit many core system
* capable to fail an operation 2^32 times per second.
* This can be fixed by storing mod->count as uint64_t.
*/
timer = 1;
mod->pid = nxt_pid;
}
}
nxt_thread_spin_unlock(&mod->lock);
if (timer) {
mod->timer.work_queue = &thr->engine->fast_work_queue;
mod->timer.handler = nxt_log_moderate_timer_handler;
mod->timer.log = &nxt_main_log;
nxt_timer_add(thr->engine, &mod->timer, 1000);
}
return allow;
}
static void
nxt_log_moderate_timer_handler(nxt_task_t *task, void *obj, void *data)
{
nxt_bool_t msg;
nxt_timer_t *ev;
nxt_atomic_uint_t n;
nxt_log_moderation_t *mod;
ev = obj;
mod = nxt_timer_data(ev, nxt_log_moderation_t, timer);
nxt_thread_spin_lock(&mod->lock);
mod->last = nxt_thread_time(task->thread);
n = mod->count;
mod->count = 0;
msg = (mod->pid == nxt_pid);
nxt_thread_spin_unlock(&mod->lock);
if (msg) {
nxt_log_error(mod->level, &nxt_main_log, "%s %uA times",
mod->msg, n - mod->limit);
}
}
|