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