schema-related information (like schema version, DB syntax, etc.) moved from "config...
[public/netxms.git] / src / server / core / hk.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003, 2004, 2005 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 ** $module: hk.cpp
20 **
21 **/
22
23 #include "nxcore.h"
24
25
26 //
27 // Static data
28 //
29
30 static DB_HANDLE m_hdb;
31
32
33 //
34 // Remove deleted objects which are no longer referenced
35 //
36
37 static void CleanDeletedObjects(void)
38 {
39 DB_RESULT hResult;
40
41 hResult = DBSelect(m_hdb, "SELECT object_id FROM deleted_objects");
42 if (hResult != NULL)
43 {
44 DB_ASYNC_RESULT hAsyncResult;
45 char szQuery[256];
46 int i, iNumRows;
47 DWORD dwObjectId;
48
49 iNumRows = DBGetNumRows(hResult);
50 for(i = 0; i < iNumRows; i++)
51 {
52 dwObjectId = DBGetFieldULong(hResult, i, 0);
53
54 // Check if there are references to this object in event log
55 sprintf(szQuery, "SELECT event_source FROM event_log WHERE event_source=%d", dwObjectId);
56 hAsyncResult = DBAsyncSelect(m_hdb, szQuery);
57 if (hAsyncResult != NULL)
58 {
59 if (!DBFetch(hAsyncResult))
60 {
61 // No records with that source ID, so we can purge this object
62 sprintf(szQuery, "DELETE FROM deleted_objects WHERE object_id=%d", dwObjectId);
63 QueueSQLRequest(szQuery);
64 DbgPrintf(4, "*HK* Deleted object with id %d was purged", dwObjectId);
65 }
66 DBFreeAsyncResult(m_hdb, hAsyncResult);
67 }
68 }
69 DBFreeResult(hResult);
70 }
71 }
72
73
74 //
75 // Delete empty subnets
76 //
77
78 static void DeleteEmptySubnets(void)
79 {
80 DWORD i;
81
82 RWLockReadLock(g_rwlockIdIndex, INFINITE);
83
84 // Walk through subnets and delete empty ones
85 for(i = 0; i < g_dwIdIndexSize; i++)
86 if (((NetObj *)g_pIndexById[i].pObject)->Type() == OBJECT_SUBNET)
87 {
88 if (((NetObj *)g_pIndexById[i].pObject)->IsEmpty())
89 {
90 PostEvent(EVENT_SUBNET_DELETED, ((NetObj *)g_pIndexById[i].pObject)->Id(), NULL);
91 ((NetObj *)g_pIndexById[i].pObject)->Delete(TRUE);
92 }
93 }
94
95 RWLockUnlock(g_rwlockIdIndex);
96 }
97
98
99 //
100 // Maintenance tasks specific to PostgreSQL
101 //
102
103 static void PGSQLMaintenance(void)
104 {
105 if (!ConfigReadInt("DisableVacuum", 0))
106 DBQuery(m_hdb, "VACUUM ANALYZE");
107 }
108
109
110 //
111 // Housekeeper thread
112 //
113
114 THREAD_RESULT THREAD_CALL HouseKeeper(void *pArg)
115 {
116 time_t currTime;
117 char szQuery[256];
118 DWORD i, dwRetentionTime, dwInterval;
119
120 // Establish separate connection to database if needed
121 if (g_dwFlags & AF_ENABLE_MULTIPLE_DB_CONN)
122 {
123 m_hdb = DBConnect();
124 if (m_hdb == NULL)
125 {
126 nxlog_write(MSG_DB_CONNFAIL, EVENTLOG_ERROR_TYPE, NULL);
127 m_hdb = g_hCoreDB; // Switch to main DB connection
128 }
129 }
130 else
131 {
132 m_hdb = g_hCoreDB;
133 }
134
135 // Load configuration
136 dwInterval = ConfigReadULong("HouseKeepingInterval", 3600);
137
138 // Housekeeping loop
139 while(!ShutdownInProgress())
140 {
141 currTime = time(NULL);
142 if (SleepAndCheckForShutdown(dwInterval - (DWORD)(currTime % dwInterval)))
143 break; // Shutdown has arrived
144
145 // Remove outdated event log records
146 dwRetentionTime = ConfigReadULong("EventLogRetentionTime", 90);
147 if (dwRetentionTime > 0)
148 {
149 dwRetentionTime *= 86400; // Convert days to seconds
150 sprintf(szQuery, "DELETE FROM event_log WHERE event_timestamp<%ld", currTime - dwRetentionTime);
151 DBQuery(m_hdb, szQuery);
152 }
153
154 // Remove outdated syslog records
155 dwRetentionTime = ConfigReadULong("SyslogRetentionTime", 90);
156 if (dwRetentionTime > 0)
157 {
158 dwRetentionTime *= 86400; // Convert days to seconds
159 sprintf(szQuery, "DELETE FROM syslog WHERE msg_timestamp<%ld", currTime - dwRetentionTime);
160 DBQuery(m_hdb, szQuery);
161 }
162
163 // Remove outdated audit log records
164 dwRetentionTime = ConfigReadULong("AuditLogRetentionTime", 90);
165 if (dwRetentionTime > 0)
166 {
167 dwRetentionTime *= 86400; // Convert days to seconds
168 sprintf(szQuery, "DELETE FROM audit_log WHERE timestamp<%ld", currTime - dwRetentionTime);
169 DBQuery(m_hdb, szQuery);
170 }
171
172 // Delete empty subnets if needed
173 if (g_dwFlags & AF_DELETE_EMPTY_SUBNETS)
174 DeleteEmptySubnets();
175
176 // Remove deleted objects which are no longer referenced
177 CleanDeletedObjects();
178
179 // Remove expired DCI data
180 RWLockReadLock(g_rwlockNodeIndex, INFINITE);
181 for(i = 0; i < g_dwNodeAddrIndexSize; i++)
182 ((Node *)g_pNodeIndexByAddr[i].pObject)->CleanDCIData();
183 RWLockUnlock(g_rwlockNodeIndex);
184
185 // Run DB-specific maintenance tasks
186 if (g_nDBSyntax == DB_SYNTAX_PGSQL)
187 PGSQLMaintenance();
188 }
189
190 // Disconnect from database if using separate connection
191 if (m_hdb != g_hCoreDB)
192 {
193 DBDisconnect(m_hdb);
194 }
195 DbgPrintf(1, "Housekeeper thread terminated");
196 return THREAD_OK;
197 }