forked from pi-hole/FTL
-
Notifications
You must be signed in to change notification settings - Fork 0
/
overTime.c
155 lines (130 loc) · 5.25 KB
/
overTime.c
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/* Pi-hole: A black hole for Internet advertisements
* (c) 2017 Pi-hole, LLC (https://pi-hole.net)
* Network-wide ad blocking via your own hardware.
*
* FTL Engine
* MessagePack serialization
*
* This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */
#include "FTL.h"
/**
* Initialize the overTime slot
*
* @param index The overTime slot index
* @param timestamp The timestamp of the slot
*/
static void initSlot(unsigned int index, time_t timestamp)
{
// Possible debug printing
if(config.debug & DEBUG_OVERTIME)
logg("initSlot(%u, %lu): Zeroing overTime slot", index, timestamp);
overTime[index].magic = MAGICBYTE;
overTime[index].timestamp = timestamp;
overTime[index].total = 0;
overTime[index].blocked = 0;
overTime[index].cached = 0;
overTime[index].forwarded = 0;
// Zero all query types
for(unsigned int queryType = 0; queryType < TYPE_MAX-1; queryType++)
overTime[index].querytypedata[queryType] = 0;
// Zero overTime counter for all known clients
for(int clientID = 0; clientID < counters->clients; clientID++)
clients[clientID].overTime[index] = 0;
}
void initOverTime(void)
{
// Get current timestamp
time_t now = time(NULL);
// The last timestamp (overTime[149]) should be the last interval of this hour
// If the current time is 09:35, the last interval is 09:50 - 10:00 (centered at 09:55)
time_t timestamp = now - now % 3600 + 3600 - (OVERTIME_INTERVAL / 2);
if(config.debug & DEBUG_OVERTIME)
logg("initOverTime(): Initializing %i slots from %lu to %lu", OVERTIME_SLOTS, timestamp-OVERTIME_SLOTS*OVERTIME_INTERVAL, timestamp);
// Iterate over overTime and initialize it
for(int i = OVERTIME_SLOTS-1; i >= 0 ; i--)
{
initSlot(i, timestamp);
// Prepare for next iteration
timestamp -= OVERTIME_INTERVAL;
}
}
unsigned int getOverTimeID(time_t timestamp)
{
// Center timestamp in OVERTIME_INTERVAL
timestamp -= timestamp % OVERTIME_INTERVAL;
timestamp += OVERTIME_INTERVAL/2;
// Get timestamp of first interval
time_t firstTimestamp = overTime[0].timestamp;
// Compute overTime ID
int id = (int) ((timestamp - firstTimestamp) / OVERTIME_INTERVAL);
// Check bounds manually
if(id < 0)
{
logg("WARN: getOverTimeID(%lu): %u is negative: %lu", timestamp, id, firstTimestamp);
// Return first timestamp in case negative timestamp was determined
return 0;
}
else if(id > OVERTIME_SLOTS-1)
{
logg("WARN: getOverTimeID(%lu): %i is too large: %lu", timestamp, id, firstTimestamp);
// Return last timestamp in case a too large timestamp was determined
return OVERTIME_SLOTS-1;
}
if(config.debug & DEBUG_OVERTIME)
logg("getOverTimeID(%lu): %i", timestamp, id);
return (unsigned int) id;
}
// This routine is called by garbage collection to rearrange the overTime structure for the next hour
void moveOverTimeMemory(time_t mintime)
{
time_t oldestOverTimeIS = overTime[0].timestamp;
// Shift SHOULD timestemp into the future by the amount GC is running earlier
time_t oldestOverTimeSHOULD = mintime;
// Center in interval
oldestOverTimeSHOULD -= oldestOverTimeSHOULD % OVERTIME_INTERVAL;
oldestOverTimeSHOULD += OVERTIME_INTERVAL / 2;
// Calculate the number of slots to be garbage collected, which is also the
// ID of the slot to move to the zero position
unsigned int moveOverTime = (unsigned int) ((oldestOverTimeSHOULD - oldestOverTimeIS) / OVERTIME_INTERVAL);
// The number of slots which will be moved (not garbage collected)
unsigned int remainingSlots = OVERTIME_SLOTS - moveOverTime;
if(config.debug & DEBUG_OVERTIME)
logg("moveOverTimeMemory(): IS: %lu, SHOULD: %lu, MOVING: %u", oldestOverTimeIS, oldestOverTimeSHOULD, moveOverTime);
// Check if the move over amount is valid. This prevents errors if the
// function is called before GC is necessary.
if(moveOverTime > 0 && moveOverTime < OVERTIME_SLOTS)
{
// Move overTime memory
if(config.debug & DEBUG_OVERTIME)
logg("moveOverTimeMemory(): Moving overTime %u - %u to 0 - %u", moveOverTime, moveOverTime+remainingSlots, remainingSlots);
memmove(&overTime[0], &overTime[moveOverTime], remainingSlots*sizeof(*overTime));
// Correct time indices of queries. This is necessary because we just moved the slot this index points to
for(int queryID = 0; queryID < counters->queries; queryID++)
{
// Check if the index would become negative if we adjusted it
if(((int)queries[queryID].timeidx - (int)moveOverTime) < 0)
{
// This should never happen, but we print a warning if it still happens
// We don't do anything in this case
logg("WARN: moveOverTimeMemory(): overTime time index correction failed (%i: %u / %u)", queryID, queries[queryID].timeidx, moveOverTime);
}
else
{
queries[queryID].timeidx -= moveOverTime;
}
}
// Move client-specific overTime memory
for(int clientID = 0; clientID < counters->clients; clientID++)
{
memmove(&clients[clientID].overTime[0], &clients[clientID].overTime[moveOverTime], remainingSlots*sizeof(int));
}
// Iterate over new overTime region and initialize it
for(unsigned int timeidx = remainingSlots; timeidx < OVERTIME_SLOTS ; timeidx++)
{
// This slot is OVERTIME_INTERVAL seconds after the previous slot
time_t timestamp = overTime[timeidx-1].timestamp + OVERTIME_INTERVAL;
initSlot(timeidx, timestamp);
}
}
}