xref: /unit/src/nxt_log_moderation.c (revision 0:a63ceefd6ab0)
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_thread_t *thr, void *obj,
11     void *data);
12 
13 
14 nxt_bool_t
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->work_queue.main;
62         mod->timer.handler = nxt_log_moderate_timer_handler;
63         mod->timer.log = &nxt_main_log;
64 
65         nxt_event_timer_add(thr->engine, &mod->timer, 1000);
66     }
67 
68     return allow;
69 }
70 
71 
72 static void
73 nxt_log_moderate_timer_handler(nxt_thread_t *thr, void *obj, void *data)
74 {
75     nxt_bool_t            msg;
76     nxt_atomic_uint_t     n;
77     nxt_event_timer_t     *ev;
78     nxt_log_moderation_t  *mod;
79 
80     ev = obj;
81     mod = nxt_event_timer_data(ev, nxt_log_moderation_t, timer);
82 
83     nxt_thread_spin_lock(&mod->lock);
84 
85     mod->last = nxt_thread_time(thr);
86     n = mod->count;
87     mod->count = 0;
88     msg = (mod->pid == nxt_pid);
89 
90     nxt_thread_spin_unlock(&mod->lock);
91 
92     if (msg) {
93         nxt_log_error(mod->level, &nxt_main_log, "%s %uA times",
94                       mod->msg, n - mod->limit);
95     }
96 }
97