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