finished configuration API for tabular DCI; added "licenses" table
[public/netxms.git] / src / agent / subagents / oracle / main.cpp
CommitLineData
4d1753cd
VK
1/*\r
2** NetXMS subagent for Oracle monitoring\r
3** Copyright (C) 2009-2012 Raden Solutions\r
4**/\r
5\r
6#include "oracle_subagent.h"\r
7\r
8CONDITION g_shutdownCondition;\r
9MUTEX g_paramAccessMutex;\r
10int g_dbCount;\r
11DB_DRIVER g_driverHandle = NULL;\r
12DatabaseInfo g_dbInfo[MAX_DATABASES];\r
13DatabaseData g_dbData[MAX_DATABASES];\r
14\r
15THREAD_RESULT THREAD_CALL queryThread(void *arg);\r
16\r
17DBParameterGroup g_paramGroup[] = {\r
18 {\r
19 700, _T("Oracle.Sessions."),\r
20 _T("select ") DB_NULLARG_MAGIC _T(" ValueName, count(*) Count from v$session"),\r
21 2, { NULL }, 0\r
22 },\r
23 {\r
24 700, _T("Oracle.Cursors."),\r
25 _T("select ") DB_NULLARG_MAGIC _T(" ValueName, sum(a.value) Count from v$sesstat a, v$statname b, v$session s where a.statistic# = b.statistic# and s.sid=a.sid and b.name = 'opened cursors current'"),\r
26 2, { NULL }, 0\r
27 },\r
28 {\r
d6b34435
AK
29 700, _T("Oracle.Objects."),\r
30 _T("select ") DB_NULLARG_MAGIC _T(" ValueName, count(*) InvalidCount from dba_objects where status!='VALID'"),\r
31 2, { NULL }, 0\r
32 },\r
33 {\r
34 700, _T("Oracle.DBInfo."), \r
4d1753cd
VK
35 _T("select ") DB_NULLARG_MAGIC _T(" ValueName, name Name, to_char(created) CreateDate, log_mode LogMode, open_mode OpenMode from v$database"),\r
36 5, { NULL }, 0\r
37 },\r
38 {\r
39 700, _T("Oracle.Instance."),\r
40 _T("select ") DB_NULLARG_MAGIC _T(" ValueName, version Version, status Status, archiver ArchiverStatus, shutdown_pending ShutdownPending from v$instance"),\r
41 5, { NULL }, 0\r
42 },\r
43 {\r
44 1000, _T("Oracle.TableSpaces."),\r
45 _T("select d.tablespace_name ValueName, d.status Status, d.contents Type, to_char(round(used_percent,2)) UsedPct from dba_tablespaces d, dba_tablespace_usage_metrics m where d.tablespace_name=m.tablespace_name"),\r
46 3, { NULL }, 0\r
47 },\r
48 {\r
d6b34435 49 700, _T("Oracle.Dual."),\r
4d1753cd
VK
50 _T("select ") DB_NULLARG_MAGIC _T(" ValueName, decode(count(*),1,0,1) ExcessRows from dual"),\r
51 1, { NULL }, 0\r
52 },\r
53 {\r
d6b34435 54 700, _T("Oracle.Performance."),\r
4d1753cd 55 _T("select ") DB_NULLARG_MAGIC _T(" ValueName, (select s.value PhysReads from v$sysstat s, v$statname n where n.name='physical reads' and n.statistic#=s.statistic#) PhysReads, ")\r
2acc690f 56 _T("(select s.value LogicReads from v$sysstat s, v$statname n where n.name='session logical reads' and n.statistic#=s.statistic#) LogicReads, ")\r
d6b34435
AK
57 _T("(select round((sum(decode(name,'consistent gets',value,0))+sum(decode(name,'db block gets',value,0))-sum(decode(name,'physical reads',value, 0)))/(sum(decode(name,'consistent gets',value,0))+sum(decode(name,'db block gets',value,0)))*100,2) from v$sysstat) CacheHitRatio, ")\r
58 _T("(select round(sum(waits)*100/sum(gets),2) from v$rollstat) RollbackWaitRatio, ")\r
59 _T("(select round((1-(sum(getmisses)/sum(gets)))*100,2) from v$rowcache) DictCacheHitRatio, ")\r
60 _T("(select round(sum(pins)/(sum(pins)+sum(reloads))*100,2) from v$librarycache) LibCacheHitRatio ")\r
4d1753cd 61 _T("from DUAL "),\r
2acc690f 62 3, { NULL }, 0\r
4d1753cd
VK
63 },\r
64 {\r
d6b34435 65 700, _T("Oracle.CriticalStats."), \r
4d1753cd
VK
66 _T("select ") DB_NULLARG_MAGIC _T(" ValueName, (select count(*) TSOFF from DBA_TABLESPACES where status <> 'ONLINE') TSOffCount, ")\r
67 _T("(select count(*) DFOFF from V$DATAFILE where status not in ('ONLINE','SYSTEM')) DFOffCount, ")\r
68 _T("(select count(*) from DBA_SEGMENTS where max_extents = extents) FullSegmentsCount, ")\r
69 _T("(select count(*) from DBA_ROLLBACK_SEGS where status <> 'ONLINE') RBSegsNotOnlineCount, ")\r
70 _T("decode(sign(decode((select upper(log_mode) from v$database),'ARCHIVELOG',1,0)-")\r
71 _T("decode((select upper(value) from v$parameter where upper(name)='LOG_ARCHIVE_START'),'TRUE',1,0)),1, 1, 0) AutoArchivingOff, ")\r
72 _T("(SELECT count(file#) from v$datafile_header where recover ='YES') DatafilesNeedMediaRecovery, ")\r
73 _T("(SELECT count(*) FROM dba_jobs where NVL(failures,0) <> 0) FailedJobs ")\r
74 _T("from DUAL"), \r
75 5, { NULL }, 0\r
76 },\r
77 0\r
78};\r
79\r
80//\r
81// Handler functions\r
82//\r
83\r
84LONG getParameters(const TCHAR *parameter, const TCHAR *argument, TCHAR *value)\r
85{\r
86 LONG ret = SYSINFO_RC_UNSUPPORTED;\r
87 TCHAR dbId[MAX_STR];\r
88 TCHAR entity[MAX_STR];\r
89\r
90 // Get id of the database requested\r
91 if (!AgentGetParameterArg(parameter, 1, dbId, MAX_STR))\r
92 return ret;\r
93 if (!AgentGetParameterArg(parameter, 2, entity, MAX_STR) || entity[0] == _T('\0'))\r
94 nx_strncpy(entity, DB_NULLARG_MAGIC, MAX_STR);\r
95\r
a4be813d 96 AgentWriteDebugLog(7, _T("%s: got request for params: dbid='%s', param='%s'"), MYNAMESTR, dbId, parameter);\r
4d1753cd
VK
97\r
98 // Loop through databases and find an entry in g_dbInfo[] for this id\r
99 for (int i = 0; i <= g_dbCount; i++)\r
100 {\r
101 if (!_tcsnicmp(g_dbInfo[i].id, dbId, MAX_STR)) // found DB\r
102 {\r
6534de9b
AK
103 if (argument[0] == _T('R'))\r
104 {\r
105 ret_string(value, g_dbInfo[i].connected ? _T("YES") : _T("NO"));\r
106 ret = SYSINFO_RC_SUCCESS;\r
107 }\r
4d1753cd 108 // Loop through parameter groups and check whose prefix matches the parameter requested\r
6534de9b 109 for (int k = 0; argument[0] == _T('X') && g_paramGroup[k].prefix; k++)\r
4d1753cd
VK
110 {\r
111 if (!_tcsnicmp(g_paramGroup[k].prefix, parameter, _tcslen(g_paramGroup[k].prefix))) // found prefix\r
112 {\r
113 MutexLock(g_dbInfo[i].accessMutex);\r
114 // Loop through the values\r
a4be813d 115 AgentWriteDebugLog(9, _T("%s: valuecount %d"), MYNAMESTR, g_paramGroup[k].valueCount[i]);\r
4d1753cd
VK
116 for (int j = 0; j < g_paramGroup[k].valueCount[i]; j++)\r
117 {\r
118 StringMap* map = (g_paramGroup[k].values[i])[j].attrs;\r
119 TCHAR* name = (g_paramGroup[k].values[i])[j].name;\r
120 if (!_tcsnicmp(name, entity, MAX_STR)) // found value which matches the parameters argument\r
121 {\r
122 TCHAR key[MAX_STR];\r
123 nx_strncpy(key, parameter + _tcslen(g_paramGroup[k].prefix), MAX_STR);\r
124 TCHAR* place = _tcschr(key, _T('('));\r
125 if (place != NULL)\r
126 {\r
127 *place = _T('\0');\r
128 const TCHAR* dbval = map->get(key);\r
129 ret_string(value, dbval);\r
130 ret = SYSINFO_RC_SUCCESS;\r
131 }\r
132 break;\r
133 }\r
134 }\r
135 MutexUnlock(g_dbInfo[i].accessMutex);\r
136\r
137 break;\r
138 }\r
139 }\r
140 break;\r
141 }\r
142 }\r
143\r
144 return ret;\r
145}\r
146\r
147\r
148//\r
149// Subagent initialization\r
150//\r
151\r
152static BOOL SubAgentInit(Config *config)\r
153{\r
154 BOOL result = TRUE;\r
155 static DatabaseInfo info;\r
156 int i;\r
157 static NX_CFG_TEMPLATE configTemplate[] = \r
158 {\r
159 { _T("Id"), CT_STRING, 0, 0, MAX_STR, 0, info.id }, \r
160 { _T("Name"), CT_STRING, 0, 0, MAX_STR, 0, info.name }, \r
6534de9b 161 { _T("TnsName"), CT_STRING, 0, 0, MAX_STR, 0, info.name }, \r
4d1753cd
VK
162 { _T("UserName"), CT_STRING, 0, 0, MAX_USERNAME, 0, info.username }, \r
163 { _T("Password"), CT_STRING, 0, 0, MAX_PASSWORD, 0, info.password },\r
164 { _T(""), CT_END_OF_LIST, 0, 0, 0, 0, NULL }\r
165 };\r
166\r
167 // Init db driver\r
168#ifdef _WIN32\r
169 g_driverHandle = DBLoadDriver(_T("oracle.ddr"), NULL, TRUE, NULL, NULL);\r
170#else\r
171 g_driverHandle = DBLoadDriver(LIBDIR "/libnxddr_oracle.so", NULL, TRUE, NULL, NULL);\r
172#endif\r
173 if (g_driverHandle == NULL)\r
174 {\r
175 AgentWriteLog(EVENTLOG_ERROR_TYPE, _T("%s: failed to load db driver"), MYNAMESTR);\r
176 result = FALSE;\r
177 }\r
178\r
179 if (result)\r
180 {\r
181 g_shutdownCondition = ConditionCreate(TRUE);\r
182 }\r
183\r
04f06779
VK
184 // Load configuration from "oracle" section to allow simple configuration\r
185 // of one database without XML includes\r
186 memset(&info, 0, sizeof(info));\r
187 g_dbCount = -1;\r
188 if (config->parseTemplate(_T("ORACLE"), configTemplate))\r
189 {\r
2f67972d 190 if (info.name[0] != 0)\r
04f06779
VK
191 {\r
192 if (info.id[0] == 0)\r
2f67972d 193 _tcscpy(info.id, info.name);\r
04f06779
VK
194 memcpy(&g_dbInfo[++g_dbCount], &info, sizeof(DatabaseInfo));\r
195 g_dbInfo[g_dbCount].accessMutex = MutexCreate();\r
196 }\r
197 }\r
198\r
a4be813d
AK
199 // Load full-featured XML configuration\r
200 if (g_dbCount == -1) // Didn't load anything from the .conf file\r
4d1753cd 201 {\r
a4be813d 202 for (i = 1; result && i <= MAX_DATABASES; i++)\r
4d1753cd 203 {\r
a4be813d
AK
204 TCHAR section[MAX_STR];\r
205 memset((void*)&info, 0, sizeof(info));\r
206 _sntprintf(section, MAX_STR, _T("oracle/databases/database#%d"), i);\r
207 if ((result = config->parseTemplate(section, configTemplate)) != TRUE)\r
208 {\r
209 AgentWriteLog(EVENTLOG_ERROR_TYPE, _T("%s: error parsing configuration template"), MYNAMESTR);\r
210 return FALSE;\r
211 }\r
212 if (info.name[0] != _T('\0'))\r
213 memcpy((void*)&g_dbInfo[++g_dbCount], (void*)&info, sizeof(info));\r
214 else\r
215 continue;\r
216 if (info.username[0] == '\0' || info.password[0] == '\0')\r
217 {\r
218 AgentWriteLog(EVENTLOG_ERROR_TYPE, _T("%s: error getting username and/or password for "), MYNAMESTR);\r
219 result = FALSE;\r
220 }\r
221 if (result && (g_dbInfo[g_dbCount].accessMutex = MutexCreate()) == NULL)\r
222 {\r
223 AgentWriteLog(EVENTLOG_ERROR_TYPE, _T("%s: failed to create mutex (%d)"), MYNAMESTR, i);\r
224 result = FALSE;\r
225 }\r
4d1753cd
VK
226 }\r
227 }\r
228\r
229 // Exit if no usable configuration found\r
230 if (result && g_dbCount < 0)\r
231 {\r
232 AgentWriteLog(EVENTLOG_ERROR_TYPE, _T("%s: no databases to monitor"), MYNAMESTR);\r
233 result = FALSE;\r
234 }\r
235\r
236 // Run query thread for each database configured\r
237 for (i = 0; result && i <= g_dbCount; i++)\r
238 {\r
239 g_dbInfo[i].queryThreadHandle = ThreadCreateEx(queryThread, 0, CAST_TO_POINTER(i, void *));\r
240 }\r
241\r
242 return result;\r
243}\r
244\r
245\r
246//\r
247// Shutdown handler\r
248//\r
249\r
250static void SubAgentShutdown(void)\r
251{\r
252 AgentWriteLog(EVENTLOG_INFORMATION_TYPE, _T("%s: shutting down"), MYNAMESTR);\r
253 ConditionSet(g_shutdownCondition);\r
254 for (int i = 0; i <= g_dbCount; i++)\r
255 {\r
256 ThreadJoin(g_dbInfo[i].queryThreadHandle);\r
257 MutexDestroy(g_dbInfo[i].accessMutex);\r
258 }\r
259 ConditionDestroy(g_shutdownCondition);\r
260}\r
261\r
262//\r
263// Figure out Oracle DBMS version\r
264//\r
265\r
266static int getOracleVersion(DB_HANDLE handle) \r
267{\r
268 TCHAR versionString[32];\r
269\r
270 DB_RESULT result = DBSelect(handle,_T("select version from v$instance"));\r
271 if (result == NULL) \r
272 {\r
2f67972d 273 AgentWriteLog(EVENTLOG_WARNING_TYPE, _T("%s: query from v$instance failed"), MYNAMESTR);\r
4d1753cd
VK
274 return 700; // assume Oracle 7.0 by default\r
275 }\r
276\r
277 DBGetField(result, 0, 0, versionString, 32);\r
278 int major = 0, minor = 0;\r
279 _stscanf(versionString, _T("%d.%d"), &major, &minor);\r
280 DBFreeResult(result);\r
281\r
282 return major * 100 + minor * 10;\r
283}\r
284\r
285//\r
286// Thread for SQL queries\r
287//\r
288\r
289THREAD_RESULT THREAD_CALL queryThread(void* arg)\r
290{\r
291 int dbIndex = CAST_FROM_POINTER(arg, int);\r
292 DatabaseInfo& db = g_dbInfo[dbIndex];\r
293 const DWORD pollInterval = 60 * 1000L; // 1 minute\r
294 int waitTimeout;\r
295 QWORD startTimeMs;\r
296 TCHAR errorText[DBDRV_MAX_ERROR_TEXT];\r
297\r
298 while (true)\r
299 {\r
6534de9b 300 db.handle = DBConnect(g_driverHandle, db.name, NULL /* db.server */, db.username, db.password, NULL, errorText);\r
a4be813d 301 DBEnableReconnect(db.handle, false);\r
4d1753cd
VK
302 if (db.handle != NULL)\r
303 {\r
a4be813d 304 AgentWriteLog(EVENTLOG_INFORMATION_TYPE, _T("%s: connected to DB '%s'"), MYNAMESTR, db.name);\r
4d1753cd
VK
305 db.connected = true;\r
306 db.version = getOracleVersion(db.handle);\r
307 }\r
308\r
309 while (db.connected)\r
310 {\r
311 startTimeMs = GetCurrentTimeMs();\r
312\r
313 // Do queries\r
314 if (!(db.connected = getParametersFromDB(dbIndex)))\r
315 {\r
316 break;\r
317 }\r
318\r
319 waitTimeout = pollInterval - DWORD(GetCurrentTimeMs() - startTimeMs);\r
320 if (ConditionWait(g_shutdownCondition, waitTimeout < 0 ? 1 : waitTimeout))\r
321 goto finish;\r
322 }\r
323\r
324 // Try to reconnect every 30 secs\r
325 if (ConditionWait(g_shutdownCondition, DWORD(30 * 1000)))\r
326 break;\r
327 }\r
328\r
329finish:\r
330 if (db.connected && db.handle != NULL)\r
331 {\r
332 DBDisconnect(db.handle);\r
333 }\r
334\r
335 return THREAD_OK;\r
336}\r
337\r
338\r
339bool getParametersFromDB( int dbIndex )\r
340{\r
341 bool ret = true;\r
342 DatabaseInfo& info = g_dbInfo[dbIndex];\r
343\r
344 if (!info.connected)\r
345 {\r
346 return false;\r
347 }\r
348\r
349 MutexLock(info.accessMutex);\r
350\r
351 for (int i = 0; g_paramGroup[i].prefix; i++)\r
352 {\r
353 AgentWriteDebugLog(7, _T("%s: got entry for '%s'"), MYNAMESTR, g_paramGroup[i].prefix);\r
354\r
355 if (g_paramGroup[i].version > info.version) // this parameter group is not supported for this DB\r
356 continue; \r
357\r
358 // Release previously allocated array of values for this group\r
2acc690f 359 for (int j = 0; g_paramGroup[i].values[dbIndex] && j < g_paramGroup[i].valueCount[dbIndex]; j++)\r
4d1753cd 360 delete (g_paramGroup[i].values[dbIndex])[j].attrs;\r
2acc690f 361 safe_free_and_null(g_paramGroup[i].values[dbIndex]);\r
4d1753cd
VK
362\r
363 DB_RESULT queryResult = DBSelect(info.handle, g_paramGroup[i].query);\r
364 if (queryResult == NULL)\r
365 {\r
366 ret = false;\r
367 break;\r
368 }\r
369\r
370 int rows = DBGetNumRows(queryResult);\r
371 g_paramGroup[i].values[dbIndex] = (DBParameter*)malloc(sizeof(DBParameter) * rows);\r
372 g_paramGroup[i].valueCount[dbIndex] = rows;\r
373 for (int j = 0; j < rows; j++)\r
374 {\r
375 TCHAR colname[MAX_STR];\r
376 DBGetField(queryResult, j, 0, (g_paramGroup[i].values[dbIndex])[j].name, MAX_STR);\r
377 (g_paramGroup[i].values[dbIndex])[j].attrs = new StringMap;\r
378 for (int k = 1; DBGetColumnName(queryResult, k, colname, MAX_STR); k++) \r
379 {\r
380 TCHAR colval[MAX_STR];\r
381 DBGetField(queryResult, j, k, colval, MAX_STR);\r
382 // AgentWriteDebugLog(9, _T("%s: getParamsFromDB: colname '%s' ::: colval '%s'"), MYNAMESTR, colname, colval);\r
383 (g_paramGroup[i].values[dbIndex])[j].attrs->set(colname, colval);\r
384 }\r
385 }\r
386\r
387 DBFreeResult(queryResult);\r
388 }\r
389\r
390 MutexUnlock(info.accessMutex);\r
391\r
392 return ret;\r
393}\r
394\r
395//\r
396// Subagent information\r
397//\r
398\r
399\r
400static NETXMS_SUBAGENT_PARAM m_parameters[] =\r
401{\r
402 { _T("Oracle.Sessions.Count(*)"), getParameters, "X", DCI_DT_INT, _T("Oracle/Sessions: Number of sessions opened") },\r
403 { _T("Oracle.Cursors.Count(*)"), getParameters, "X", DCI_DT_INT, _T("Oracle/Cursors: Current number of opened cursors systemwide") },\r
6534de9b 404 { _T("Oracle.DBInfo.IsReachable(*)"), getParameters, "R", DCI_DT_STRING, _T("Oracle/Info: Database is reachable") },\r
4d1753cd
VK
405 { _T("Oracle.DBInfo.Name(*)"), getParameters, "X", DCI_DT_STRING, _T("Oracle/Info: Database name") },\r
406 { _T("Oracle.DBInfo.CreateDate(*)"), getParameters, "X", DCI_DT_STRING, _T("Oracle/Info: Database creation date") },\r
407 { _T("Oracle.DBInfo.LogMode(*)"), getParameters, "X", DCI_DT_STRING, _T("Oracle/Info: Database log mode") },\r
408 { _T("Oracle.DBInfo.OpenMode(*)"), getParameters, "X", DCI_DT_STRING, _T("Oracle/Info: Database open mode") },\r
409 { _T("Oracle.TableSpaces.Status(*)"), getParameters, "X", DCI_DT_STRING, _T("Oracle/Tablespaces: Status") },\r
410 { _T("Oracle.TableSpaces.Type(*)"), getParameters, "X", DCI_DT_STRING, _T("Oracle/Tablespaces: Type") },\r
411 { _T("Oracle.TableSpaces.UsedPct(*)"), getParameters, "X", DCI_DT_INT, _T("Oracle/Tablespaces: Percentage used") },\r
412 { _T("Oracle.Instance.Version(*)"), getParameters, "X", DCI_DT_STRING, _T("Oracle/Instance: DBMS Version") },\r
413 { _T("Oracle.Instance.Status(*)"), getParameters, "X", DCI_DT_STRING, _T("Oracle/Instance: Status") },\r
414 { _T("Oracle.Instance.ArchiverStatus(*)"), getParameters, "X", DCI_DT_STRING, _T("Oracle/Instance: Archiver status") },\r
415 { _T("Oracle.Instance.ShutdownPending(*)"), getParameters, "X", DCI_DT_STRING, _T("Oracle/Instance: Is shutdown pending") },\r
416 { _T("Oracle.CriticalStats.TSOffCount(*)"), getParameters, "X", DCI_DT_INT, _T("Oracle/CriticalStats: Number of offline tablespaces") },\r
417 { _T("Oracle.CriticalStats.DFOffCount(*)"), getParameters, "X", DCI_DT_INT, _T("Oracle/CriticalStats: Number of offline datafiles") },\r
418 { _T("Oracle.CriticalStats.FullSegmentsCount(*)"), getParameters, "X", DCI_DT_INT64, _T("Oracle/CriticalStats: Number of segments that cannot extend") },\r
419 { _T("Oracle.CriticalStats.RBSegsNotOnlineCount(*)"), getParameters, "X", DCI_DT_INT64, _T("Oracle/CriticalStats: Number of rollback segments not online") },\r
420 { _T("Oracle.CriticalStats.AutoArchivingOff(*)"), getParameters, "X", DCI_DT_STRING, _T("Oracle/CriticalStats: Archive logs enabled but auto archiving off ") },\r
421 { _T("Oracle.CriticalStats.DatafilesNeedMediaRecovery(*)"), getParameters, "X", DCI_DT_INT64, _T("Oracle/CriticalStats: Number of datafiles that need media recovery") },\r
422 { _T("Oracle.CriticalStats.FailedJobs(*)"), getParameters, "X", DCI_DT_INT64, _T("Oracle/CriticalStats: Number of failed jobs") },\r
423 { _T("Oracle.Dual.ExcessRows(*)"), getParameters, "X", DCI_DT_INT64, _T("Oracle/Dual: Excessive rows") },\r
424 { _T("Oracle.Performance.PhysReads(*)"), getParameters, "X", DCI_DT_INT64, _T("Oracle/Performance: Number of physical reads") },\r
2acc690f 425 { _T("Oracle.Performance.LogicReads(*)"), getParameters, "X", DCI_DT_INT64, _T("Oracle/Performance: Number of logical reads") },\r
d6b34435
AK
426 { _T("Oracle.Performance.CacheHitRatio(*)"), getParameters, "X", DCI_DT_INT64, _T("Oracle/Performance: Data buffer cache hit ratio") },\r
427 { _T("Oracle.Performance.LibCacheHitRatio(*)"), getParameters, "X", DCI_DT_INT64, _T("Oracle/Performance: Library cache hit ratio") },\r
428 { _T("Oracle.Performance.DictCacheHitRatio(*)"), getParameters, "X", DCI_DT_INT64, _T("Oracle/Performance: Dictionary cache hit ratio") },\r
429 { _T("Oracle.Performance.RollbackWaitRatio(*)"), getParameters, "X", DCI_DT_INT64, _T("Oracle/Performance: Ratio of waits for requests to rollback segments") },\r
430 { _T("Oracle.Objects.InvalidCount(*)"), getParameters, "X", DCI_DT_INT64, _T("Oracle/Objects: Number of invalid objects in DB") }\r
4d1753cd
VK
431};\r
432\r
433/*\r
434static NETXMS_SUBAGENT_ENUM m_enums[] =\r
435{\r
436};\r
437*/\r
438\r
439static NETXMS_SUBAGENT_INFO m_info =\r
440{\r
441 NETXMS_SUBAGENT_INFO_MAGIC,\r
442 _T("ORACLE"), NETXMS_VERSION_STRING,\r
443 SubAgentInit, SubAgentShutdown, NULL,\r
444 sizeof(m_parameters) / sizeof(NETXMS_SUBAGENT_PARAM), m_parameters,\r
445 0, NULL,\r
446 /*sizeof(m_parameters) / sizeof(NETXMS_SUBAGENT_PARAM),\r
447 m_parameters,\r
448 sizeof(m_enums) / sizeof(NETXMS_SUBAGENT_ENUM),\r
449 m_enums,*/\r
450 0, NULL\r
451};\r
452\r
453\r
454//\r
455// Entry point for NetXMS agent\r
456//\r
457\r
458DECLARE_SUBAGENT_ENTRY_POINT(ORACLE)\r
459{\r
460 *ppInfo = &m_info;\r
461 return TRUE;\r
462}\r
463\r
464\r
465//\r
466// DLL entry point\r
467//\r
468\r
469#ifdef _WIN32\r
470\r
471BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)\r
472{\r
473 if (dwReason == DLL_PROCESS_ATTACH)\r
474 DisableThreadLibraryCalls(hInstance);\r
475 return TRUE;\r
476}\r
477\r
478#endif\r