ce4ea486551bfc5041cc0dff779e328a9511c91f
[public/netxms.git] / src / server / core / hk.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003-2017 Victor Kirhenshtein
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 **
19 ** File: hk.cpp
20 **
21 **/
22
23 #include "nxcore.h"
24
25 /**
26 * Delete empty subnets from given list
27 */
28 static void DeleteEmptySubnetsFromList(ObjectArray<NetObj> *subnets)
29 {
30 for(int i = 0; i < subnets->size(); i++)
31 {
32 NetObj *object = subnets->get(i);
33 DbgPrintf(7, _T("DeleteEmptySubnets: checking subnet %s [%d] (refs: %d refs, children: %d, parents: %d)"),
34 object->getName(), object->getId(), object->getRefCount(), object->getChildCount(), object->getParentCount());
35 if (object->isEmpty())
36 {
37 DbgPrintf(5, _T("DeleteEmptySubnets: delete subnet %s [%d] (refs: %d, children: %d, parents: %d)"),
38 object->getName(), object->getId(), object->getRefCount(), object->getChildCount(), object->getParentCount());
39 object->deleteObject();
40 }
41 object->decRefCount();
42 }
43 }
44
45 /**
46 * Delete empty subnets
47 */
48 static void DeleteEmptySubnets()
49 {
50 if (IsZoningEnabled())
51 {
52 ObjectArray<NetObj> *zones = g_idxZoneByUIN.getObjects(true);
53 for(int i = 0; i < zones->size(); i++)
54 {
55 Zone *zone = (Zone *)zones->get(i);
56 ObjectArray<NetObj> *subnets = zone->getSubnets(true);
57 DeleteEmptySubnetsFromList(subnets);
58 delete subnets;
59 zone->decRefCount();
60 }
61 delete zones;
62 }
63 else
64 {
65 ObjectArray<NetObj> *subnets = g_idxSubnetByAddr.getObjects(true);
66 DeleteEmptySubnetsFromList(subnets);
67 delete subnets;
68 }
69 }
70
71 /**
72 * Delete notes for alarm
73 */
74 void DeleteAlarmNotes(DB_HANDLE hdb, UINT32 alarmId)
75 {
76 DB_STATEMENT hStmt = DBPrepare(hdb, _T("DELETE FROM alarm_notes WHERE alarm_id=?"));
77 if (hStmt == NULL)
78 return;
79
80 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, alarmId);
81 DBExecute(hStmt);
82 DBFreeStatement(hStmt);
83 }
84
85 /**
86 * Delete realted events for alarm
87 */
88 void DeleteAlarmEvents(DB_HANDLE hdb, UINT32 alarmId)
89 {
90 DB_STATEMENT hStmt = DBPrepare(hdb, _T("DELETE FROM alarm_events WHERE alarm_id=?"));
91 if (hStmt == NULL)
92 return;
93
94 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, alarmId);
95 DBExecute(hStmt);
96 DBFreeStatement(hStmt);
97 }
98
99 /**
100 * Remove outdated alarm records
101 */
102 static void CleanAlarmHistory(DB_HANDLE hdb)
103 {
104 UINT32 retentionTime = ConfigReadULong(_T("AlarmHistoryRetentionTime"), 180);
105 if (retentionTime == 0)
106 return;
107
108 retentionTime *= 86400; // Convert days to seconds
109 time_t ts = time(NULL) - (time_t)retentionTime;
110
111 DB_STATEMENT hStmt = DBPrepare(hdb, _T("SELECT alarm_id FROM alarms WHERE alarm_state=3 AND last_change_time<?"));
112 if (hStmt != NULL)
113 {
114 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, (UINT32)ts);
115 DB_RESULT hResult = DBSelectPrepared(hStmt);
116 if (hResult != NULL)
117 {
118 int count = DBGetNumRows(hResult);
119 for(int i = 0; i < count; i++)
120 {
121 UINT32 alarmId = DBGetFieldULong(hResult, i, 0);
122 DeleteAlarmNotes(hdb, alarmId);
123 DeleteAlarmEvents(hdb, alarmId);
124 }
125 DBFreeResult(hResult);
126 }
127 DBFreeStatement(hStmt);
128 }
129
130 hStmt = DBPrepare(hdb, _T("DELETE FROM alarms WHERE alarm_state=3 AND last_change_time<?"));
131 if (hStmt != NULL)
132 {
133 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, (UINT32)ts);
134 DBExecute(hStmt);
135 DBFreeStatement(hStmt);
136 }
137 }
138
139 /**
140 * Callback for cleaning expired DCI data on node
141 */
142 static void CleanDciData(NetObj *object, void *data)
143 {
144 ((DataCollectionTarget *)object)->cleanDCIData((DB_HANDLE)data);
145 }
146
147 /**
148 * Housekeeper wakeup condition
149 */
150 static CONDITION s_wakeupCondition = INVALID_CONDITION_HANDLE;
151
152 /**
153 * Housekeeper shutdown flag
154 */
155 static bool s_shutdown = false;
156
157 /**
158 * Housekeeper thread
159 */
160 static THREAD_RESULT THREAD_CALL HouseKeeper(void *pArg)
161 {
162 ThreadSetName("Housekeeper");
163
164 // Read housekeeping configuration
165 int hour;
166 int minute;
167
168 TCHAR buffer[64];
169 ConfigReadStr(_T("HousekeeperStartTime"), buffer, 64, _T("02:00"));
170 TCHAR *p = _tcschr(buffer, _T(':'));
171 if (p != NULL)
172 {
173 *p = 0;
174 p++;
175 minute = _tcstol(p, NULL, 10);
176 if ((minute < 0) || (minute > 59))
177 {
178 DbgPrintf(2, _T("Housekeeper: invalid minute value %s"), p);
179 minute = 0;
180 }
181 }
182 else
183 {
184 minute = 0;
185 }
186 hour = _tcstol(buffer, NULL, 10);
187 if ((hour < 0) || (hour > 23))
188 {
189 DbgPrintf(2, _T("Housekeeper: invalid hour value %s"), buffer);
190 hour = 0;
191 }
192 DbgPrintf(2, _T("Housekeeper: wakeup time is %02d:%02d"), hour, minute);
193
194 int sleepTime = GetSleepTime(hour, minute, 0);
195 DbgPrintf(4, _T("Housekeeper: sleeping for %d seconds"), sleepTime);
196
197 while(!s_shutdown)
198 {
199 ConditionWait(s_wakeupCondition, sleepTime * 1000);
200 if (s_shutdown)
201 break;
202
203 DbgPrintf(4, _T("Housekeeper: wakeup"));
204
205 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
206 CleanAlarmHistory(hdb);
207
208 time_t currTime = time(NULL);
209
210 // Remove outdated event log records
211 UINT32 dwRetentionTime = ConfigReadULong(_T("EventLogRetentionTime"), 90);
212 if (dwRetentionTime > 0)
213 {
214 dwRetentionTime *= 86400; // Convert days to seconds
215 TCHAR query[256];
216 _sntprintf(query, sizeof(query) / sizeof(TCHAR), _T("DELETE FROM event_log WHERE event_timestamp<%ld"), (long)(currTime - dwRetentionTime));
217 DBQuery(hdb, query);
218 }
219
220 // Remove outdated syslog records
221 dwRetentionTime = ConfigReadULong(_T("SyslogRetentionTime"), 90);
222 if (dwRetentionTime > 0)
223 {
224 dwRetentionTime *= 86400; // Convert days to seconds
225 TCHAR query[256];
226 _sntprintf(query, sizeof(query) / sizeof(TCHAR), _T("DELETE FROM syslog WHERE msg_timestamp<%ld"), (long)(currTime - dwRetentionTime));
227 DBQuery(hdb, query);
228 }
229
230 // Remove outdated audit log records
231 dwRetentionTime = ConfigReadULong(_T("AuditLogRetentionTime"), 90);
232 if (dwRetentionTime > 0)
233 {
234 dwRetentionTime *= 86400; // Convert days to seconds
235 TCHAR query[256];
236 _sntprintf(query, sizeof(query) / sizeof(TCHAR), _T("DELETE FROM audit_log WHERE timestamp<%ld"), (long)(currTime - dwRetentionTime));
237 DBQuery(hdb, query);
238 }
239
240 // Remove outdated SNMP trap log records
241 dwRetentionTime = ConfigReadULong(_T("SNMPTrapLogRetentionTime"), 90);
242 if (dwRetentionTime > 0)
243 {
244 dwRetentionTime *= 86400; // Convert days to seconds
245 TCHAR query[256];
246 _sntprintf(query, sizeof(query) / sizeof(TCHAR), _T("DELETE FROM snmp_trap_log WHERE trap_timestamp<%ld"), (long)(currTime - dwRetentionTime));
247 DBQuery(hdb, query);
248 }
249
250 // Delete empty subnets if needed
251 if (g_flags & AF_DELETE_EMPTY_SUBNETS)
252 DeleteEmptySubnets();
253
254 // Remove expired DCI data
255 g_idxNodeById.forEach(CleanDciData, hdb);
256 g_idxClusterById.forEach(CleanDciData, hdb);
257 g_idxMobileDeviceById.forEach(CleanDciData, hdb);
258 g_idxSensorById.forEach(CleanDciData, hdb);
259
260 DBConnectionPoolReleaseConnection(hdb);
261
262 // Call hooks in loaded modules
263 for(UINT32 i = 0; i < g_dwNumModules; i++)
264 {
265 if (g_pModuleList[i].pfHousekeeperHook != NULL)
266 {
267 DbgPrintf(5, _T("Housekeeper: calling hook in module %s"), g_pModuleList[i].szName);
268 g_pModuleList[i].pfHousekeeperHook();
269 }
270 }
271
272 SaveCurrentFreeId();
273
274 ThreadSleep(1); // to prevent multiple executions if processing took less then 1 second
275 sleepTime = GetSleepTime(hour, minute, 0);
276 DbgPrintf(4, _T("Housekeeper: sleeping for %d seconds"), sleepTime);
277 }
278
279 DbgPrintf(1, _T("Housekeeper thread terminated"));
280 return THREAD_OK;
281 }
282
283 /**
284 * Housekeeper thread handle
285 */
286 static THREAD s_thread = INVALID_THREAD_HANDLE;
287
288 /**
289 * Start housekeeper
290 */
291 void StartHouseKeeper()
292 {
293 s_wakeupCondition = ConditionCreate(FALSE);
294 s_thread = ThreadCreateEx(HouseKeeper, 0, NULL);
295 }
296
297 /**
298 * Stop housekeeper
299 */
300 void StopHouseKeeper()
301 {
302 s_shutdown = true;
303 ConditionSet(s_wakeupCondition);
304 ThreadJoin(s_thread);
305 ConditionDestroy(s_wakeupCondition);
306 }
307
308 /**
309 * Run housekeeper
310 */
311 void RunHouseKeeper()
312 {
313 ConditionSet(s_wakeupCondition);
314 }