@cryptotaxi247 / netdata-1 / commits / 959e74ef7

Reorganize MSSQL collection. (#21290)

thiagoftsm committed Nov 13, 2025 at 12:21 UTC 959e74ef7aa20a50394a199ad790c253f1a030ab
4 files changed +3652 -3637
CMakeLists.txt
+2 -1
@@ -1932,12 +1932,12 @@ set(WINDOWS_PLUGIN_FILES
1932 src/collectors/windows.plugin/GetServicesStatus.c
1933 src/collectors/windows.plugin/GetSensors.c
1934 src/collectors/windows.plugin/GetHardwareInfo.c
1935 + src/collectors/windows.plugin/MonitorSQL.c
1936 src/collectors/windows.plugin/perflib-adcs.c
1937 src/collectors/windows.plugin/perflib-adfs.c
1938 src/collectors/windows.plugin/perflib-rrd.c
1939 src/collectors/windows.plugin/perflib-rrd.h
1940 src/collectors/windows.plugin/perflib-ad.c
1940 - src/collectors/windows.plugin/perflib-mssql.c
1941 src/collectors/windows.plugin/perflib-mssql-queries.h
1942 src/collectors/windows.plugin/perflib-storage.c
1943 src/collectors/windows.plugin/perflib-processor.c
@@ -1945,6 +1945,7 @@ set(WINDOWS_PLUGIN_FILES
1945 src/collectors/windows.plugin/perflib-objects.c
1946 src/collectors/windows.plugin/perflib-network.c
1947 src/collectors/windows.plugin/perflib-netframework.c
1948 + src/collectors/windows.plugin/perflib-mssql.c
1949 src/collectors/windows.plugin/perflib-memory.c
1950 src/collectors/windows.plugin/perflib-processes.c
1951 src/collectors/windows.plugin/perflib-web-service.c
src/collectors/windows.plugin/MonitorSQL.c new
+3035
@@ -0,0 +1,3035 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#include "windows_plugin.h"
4 +#include "windows-internals.h"
5 +
6 +#include "perflib-mssql-queries.h"
7 +
8 +DICTIONARY *conn_options;
9 +
10 +static inline int netdata_mssql_check_result(SQLRETURN ret)
11 +{
12 + return (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO);
13 +}
14 +
15 +static char *netdata_MSSQL_error_text(enum netdata_mssql_odbc_errors val)
16 +{
17 + switch (val) {
18 + case NETDATA_MSSQL_ODBC_NO_ERROR:
19 + return "NO ERROR";
20 + case NETDATA_MSSQL_ODBC_CONNECT:
21 + return "CONNECTION";
22 + case NETDATA_MSSQL_ODBC_BIND:
23 + return "BIND PARAMETER";
24 + case NETDATA_MSSQL_ODBC_PREPARE:
25 + return "PREPARE PARAMETER";
26 + case NETDATA_MSSQL_ODBC_QUERY:
27 + return "QUERY PARAMETER";
28 + case NETDATA_MSSQL_ODBC_FETCH:
29 + default:
30 + return "QUERY FETCH";
31 + }
32 +}
33 +
34 +static char *netdata_MSSQL_type_text(uint32_t type)
35 +{
36 + switch (type) {
37 + case SQL_HANDLE_STMT:
38 + return "STMT";
39 + case SQL_HANDLE_DBC:
40 + default:
41 + return "DBC";
42 + }
43 +}
44 +
45 +// Connection and SQL
46 +static void netdata_MSSQL_error(uint32_t type, SQLHANDLE handle, enum netdata_mssql_odbc_errors step, char *instance)
47 +{
48 + SQLCHAR state[1024];
49 + SQLCHAR message[1024];
50 + if (likely(SQL_SUCCESS == SQLGetDiagRec((short)type, handle, 1, state, NULL, message, 1024, NULL))) {
51 + char *str_step = netdata_MSSQL_error_text(step);
52 + char *str_type = netdata_MSSQL_type_text(type);
53 + char *use_instance = (!instance) ? "no instance" : instance;
54 + nd_log(
55 + NDLS_COLLECTORS,
56 + NDLP_INFO,
57 + "MSSQL server error on %s using the handle %s running %s : %s, %s",
58 + use_instance,
59 + str_type,
60 + str_step,
61 + message,
62 + state);
63 + }
64 +}
65 +
66 +static inline void netdata_MSSQL_release_results(SQLHSTMT *stmt)
67 +{
68 + SQLCloseCursor(stmt);
69 +}
70 +
71 +static ULONGLONG netdata_MSSQL_fill_long_value(SQLHSTMT *stmt, const char *mask, const char *dbname, char *instance)
72 +{
73 + long db_size = 0;
74 + SQLLEN col_data_len = 0;
75 +
76 + SQLCHAR query[512];
77 + snprintfz((char *)query, 511, mask, dbname);
78 +
79 + SQLRETURN ret;
80 +
81 + ret = SQLExecDirect(stmt, query, SQL_NTS);
82 + if (likely(netdata_mssql_check_result(ret))) {
83 + netdata_MSSQL_error(SQL_HANDLE_STMT, stmt, NETDATA_MSSQL_ODBC_QUERY, instance);
84 + return (ULONGLONG)ULONG_LONG_MAX;
85 + }
86 +
87 + ret = SQLBindCol(stmt, 1, SQL_C_LONG, &db_size, sizeof(long), &col_data_len);
88 + if (likely(netdata_mssql_check_result(ret))) {
89 + netdata_MSSQL_error(SQL_HANDLE_STMT, stmt, NETDATA_MSSQL_ODBC_PREPARE, instance);
90 + return (ULONGLONG)ULONG_LONG_MAX;
91 + }
92 +
93 + ret = SQLFetch(stmt);
94 + if (likely(netdata_mssql_check_result(ret))) {
95 + netdata_MSSQL_error(SQL_HANDLE_STMT, stmt, NETDATA_MSSQL_ODBC_FETCH, instance);
96 + return (ULONGLONG)ULONG_LONG_MAX;
97 + }
98 +
99 + netdata_MSSQL_release_results(stmt);
100 + return (ULONGLONG)(db_size * MEGA_FACTOR);
101 +}
102 +
103 +#define NETDATA_MSSQL_BUFFER_PAGE_READS_METRIC "Page reads/sec"
104 +#define NETDATA_MSSQL_BUFFER_PAGE_WRITES_METRIC "Page writes/sec"
105 +#define NETDATA_MSSQL_BUFFER_PAGE_CACHE_METRIC "Buffer cache hit ratio"
106 +#define NETDATA_MSSQL_BUFFER_CHECKPOINT_METRIC "Checkpoint pages/sec"
107 +#define NETDATA_MSSQL_BUFFER_PAGE_LIFE_METRIC "Page life expectancy"
108 +#define NETDATA_MSSQL_BUFFER_LAZY_WRITES_METRIC "Lazy writes/sec"
109 +#define NETDATA_MSSQL_BUFFER_PAGE_LOOKUPS_METRIC "Page Lookups/sec"
110 +
111 +#define NETDATA_MSSQL_STATS_COMPILATIONS_METRIC "SQL Compilations/sec"
112 +#define NETDATA_MSSQL_STATS_RECOMPILATIONS_METRIC "SQL Re-Compilations/sec"
113 +
114 +void dict_mssql_fill_instance_transactions(struct mssql_db_instance *mdi)
115 +{
116 + char object_name[NETDATA_MAX_INSTANCE_OBJECT + 1] = {};
117 + long value = 0;
118 + SQLLEN col_object_len = 0, col_value_len = 0;
119 +
120 + SQLCHAR query[sizeof(NETDATA_QUERY_TRANSACTIONS_PER_INSTANCE_MASK) + NETDATA_MAX_INSTANCE_OBJECT + 1];
121 + snprintfz(
122 + (char *)query,
123 + sizeof(NETDATA_QUERY_TRANSACTIONS_PER_INSTANCE_MASK) + NETDATA_MAX_INSTANCE_OBJECT,
124 + NETDATA_QUERY_TRANSACTIONS_PER_INSTANCE_MASK,
125 + mdi->parent->instanceID);
126 +
127 + SQLRETURN ret = SQLExecDirect(mdi->parent->conn->dbInstanceTransactionSTMT, (SQLCHAR *)query, SQL_NTS);
128 + if (likely(netdata_mssql_check_result(ret))) {
129 + mdi->collecting_data = false;
130 + netdata_MSSQL_error(
131 + SQL_HANDLE_STMT,
132 + mdi->parent->conn->dbInstanceTransactionSTMT,
133 + NETDATA_MSSQL_ODBC_QUERY,
134 + mdi->parent->instanceID);
135 + goto enditransactions;
136 + }
137 +
138 + ret = SQLBindCol(
139 + mdi->parent->conn->dbInstanceTransactionSTMT, 1, SQL_C_CHAR, object_name, sizeof(object_name), &col_object_len);
140 + if (likely(netdata_mssql_check_result(ret))) {
141 + netdata_MSSQL_error(
142 + SQL_HANDLE_STMT,
143 + mdi->parent->conn->dbInstanceTransactionSTMT,
144 + NETDATA_MSSQL_ODBC_PREPARE,
145 + mdi->parent->instanceID);
146 + goto enditransactions;
147 + }
148 +
149 + ret =
150 + SQLBindCol(mdi->parent->conn->dbInstanceTransactionSTMT, 2, SQL_C_LONG, &value, sizeof(value), &col_value_len);
151 + if (likely(netdata_mssql_check_result(ret))) {
152 + netdata_MSSQL_error(
153 + SQL_HANDLE_STMT,
154 + mdi->parent->conn->dbInstanceTransactionSTMT,
155 + NETDATA_MSSQL_ODBC_PREPARE,
156 + mdi->parent->instanceID);
157 + goto enditransactions;
158 + }
159 +
160 + do {
161 + ret = SQLFetch(mdi->parent->conn->dbInstanceTransactionSTMT);
162 + switch (ret) {
163 + case SQL_SUCCESS:
164 + case SQL_SUCCESS_WITH_INFO:
165 + break;
166 + case SQL_NO_DATA:
167 + default:
168 + goto enditransactions;
169 + }
170 +
171 + // We cannot use strcmp, because buffer is filled with spaces instead NULL.
172 + if (unlikely(!strncmp(
173 + object_name, NETDATA_MSSQL_BUFFER_PAGE_READS_METRIC, sizeof(NETDATA_MSSQL_BUFFER_PAGE_READS_METRIC) - 1)))
174 + mdi->MSSQLBufferPageReads.current.Data = (ULONGLONG)value;
175 + else if (unlikely(!strncmp(
176 + object_name,
177 + NETDATA_MSSQL_BUFFER_PAGE_WRITES_METRIC,
178 + sizeof(NETDATA_MSSQL_BUFFER_PAGE_WRITES_METRIC) - 1)))
179 + mdi->MSSQLBufferPageWrites.current.Data = (ULONGLONG)value;
180 + else if (unlikely(!strncmp(
181 + object_name,
182 + NETDATA_MSSQL_BUFFER_PAGE_CACHE_METRIC,
183 + sizeof(NETDATA_MSSQL_BUFFER_PAGE_CACHE_METRIC) - 1)))
184 + mdi->MSSQLBufferCacheHits.current.Data = (ULONGLONG)value;
185 + else if (unlikely(!strncmp(
186 + object_name,
187 + NETDATA_MSSQL_BUFFER_CHECKPOINT_METRIC,
188 + sizeof(NETDATA_MSSQL_BUFFER_CHECKPOINT_METRIC) - 1)))
189 + mdi->MSSQLBufferCheckpointPages.current.Data = (ULONGLONG)value;
190 + else if (unlikely(!strncmp(
191 + object_name,
192 + NETDATA_MSSQL_BUFFER_PAGE_LIFE_METRIC,
193 + sizeof(NETDATA_MSSQL_BUFFER_PAGE_LIFE_METRIC) - 1)))
194 + mdi->MSSQLBufferPageLifeExpectancy.current.Data = (ULONGLONG)value;
195 + else if (unlikely(!strncmp(
196 + object_name,
197 + NETDATA_MSSQL_BUFFER_LAZY_WRITES_METRIC,
198 + sizeof(NETDATA_MSSQL_BUFFER_LAZY_WRITES_METRIC) - 1)))
199 + mdi->MSSQLBufferLazyWrite.current.Data = (ULONGLONG)value;
200 + else if (unlikely(!strncmp(
201 + object_name,
202 + NETDATA_MSSQL_BUFFER_PAGE_LOOKUPS_METRIC,
203 + sizeof(NETDATA_MSSQL_BUFFER_PAGE_LOOKUPS_METRIC) - 1)))
204 + mdi->MSSQLBufferPageLookups.current.Data = (ULONGLONG)value;
205 + else if (unlikely(!strncmp(
206 + object_name,
207 + NETDATA_MSSQL_STATS_COMPILATIONS_METRIC,
208 + sizeof(NETDATA_MSSQL_STATS_COMPILATIONS_METRIC) - 1)))
209 + mdi->MSSQLCompilations.current.Data = (ULONGLONG)value;
210 + else if (unlikely(!strncmp(
211 + object_name,
212 + NETDATA_MSSQL_STATS_RECOMPILATIONS_METRIC,
213 + sizeof(NETDATA_MSSQL_STATS_RECOMPILATIONS_METRIC) - 1)))
214 + mdi->MSSQLRecompilations.current.Data = (ULONGLONG)value;
215 + } while (true);
216 +
217 +enditransactions:
218 + netdata_MSSQL_release_results(mdi->parent->conn->dbInstanceTransactionSTMT);
219 +}
220 +
221 +#define NETDATA_MSSQL_ACTIVE_TRANSACTIONS_METRIC "Active Transactions"
222 +#define NETDATA_MSSQL_TRANSACTION_PER_SEC_METRIC "Transactions/sec"
223 +#define NETDATA_MSSQL_WRITE_TRANSACTIONS_METRIC "Write Transactions/sec"
224 +#define NETDATA_MSSQL_BACKUP_RESTORE_METRIC "Backup/Restore Throughput/sec"
225 +#define NETDATA_MSSQL_LOG_FLUSHED_METRIC "Log Bytes Flushed/sec"
226 +#define NETDATA_MSSQL_LOG_FLUSHES_METRIC "Log Flushes/sec"
227 +#define NETDATA_MSSQL_NUMBER_DEADLOCKS_METRIC "Number of Deadlocks/sec"
228 +#define NETDATA_MSSQL_LOCK_WAITS_METRIC "Lock Waits/sec"
229 +#define NETDATA_MSSQL_LOCK_TIMEOUTS_METRIC "Lock Timeouts/sec"
230 +#define NETDATA_MSSQL_LOCK_REQUESTS_METRIC "Lock Requests/sec"
231 +
232 +void dict_mssql_fill_transactions(struct mssql_db_instance *mdi, const char *dbname)
233 +{
234 + char object_name[NETDATA_MAX_INSTANCE_OBJECT + 1] = {};
235 + long value = 0;
236 + SQLLEN col_object_len = 0, col_value_len = 0;
237 +
238 + if (mdi->collect_instance)
239 + dict_mssql_fill_instance_transactions(mdi);
240 +
241 + SQLCHAR query[sizeof(NETDATA_QUERY_TRANSACTIONS_MASK) + 2 * NETDATA_MAX_INSTANCE_OBJECT + 1];
242 + snprintfz(
243 + (char *)query,
244 + sizeof(NETDATA_QUERY_TRANSACTIONS_MASK) + 2 * NETDATA_MAX_INSTANCE_OBJECT,
245 + NETDATA_QUERY_TRANSACTIONS_MASK,
246 + dbname,
247 + dbname);
248 +
249 + SQLRETURN ret = SQLExecDirect(mdi->parent->conn->dbTransactionSTMT, (SQLCHAR *)query, SQL_NTS);
250 + if (likely(netdata_mssql_check_result(ret))) {
251 + mdi->collecting_data = false;
252 + netdata_MSSQL_error(
253 + SQL_HANDLE_STMT, mdi->parent->conn->dbTransactionSTMT, NETDATA_MSSQL_ODBC_QUERY, mdi->parent->instanceID);
254 + goto endtransactions;
255 + }
256 +
257 + ret = SQLBindCol(
258 + mdi->parent->conn->dbTransactionSTMT, 1, SQL_C_CHAR, object_name, sizeof(object_name), &col_object_len);
259 + if (likely(netdata_mssql_check_result(ret))) {
260 + netdata_MSSQL_error(
261 + SQL_HANDLE_STMT, mdi->parent->conn->dbTransactionSTMT, NETDATA_MSSQL_ODBC_PREPARE, mdi->parent->instanceID);
262 + goto endtransactions;
263 + }
264 +
265 + ret = SQLBindCol(mdi->parent->conn->dbTransactionSTMT, 2, SQL_C_LONG, &value, sizeof(value), &col_value_len);
266 + if (likely(netdata_mssql_check_result(ret))) {
267 + netdata_MSSQL_error(
268 + SQL_HANDLE_STMT, mdi->parent->conn->dbTransactionSTMT, NETDATA_MSSQL_ODBC_PREPARE, mdi->parent->instanceID);
269 + goto endtransactions;
270 + }
271 +
272 + do {
273 + ret = SQLFetch(mdi->parent->conn->dbTransactionSTMT);
274 + switch (ret) {
275 + case SQL_SUCCESS:
276 + case SQL_SUCCESS_WITH_INFO:
277 + break;
278 + case SQL_NO_DATA:
279 + default:
280 + goto endtransactions;
281 + }
282 +
283 + // We cannot use strcmp, because buffer is filled with spaces instead NULL.
284 + if (unlikely(!strncmp(
285 + object_name,
286 + NETDATA_MSSQL_ACTIVE_TRANSACTIONS_METRIC,
287 + sizeof(NETDATA_MSSQL_ACTIVE_TRANSACTIONS_METRIC) - 1)))
288 + mdi->MSSQLDatabaseActiveTransactions.current.Data = (ULONGLONG)value;
289 + else if (unlikely(!strncmp(
290 + object_name,
291 + NETDATA_MSSQL_TRANSACTION_PER_SEC_METRIC,
292 + sizeof(NETDATA_MSSQL_TRANSACTION_PER_SEC_METRIC) - 1)))
293 + mdi->MSSQLDatabaseTransactions.current.Data = (ULONGLONG)value;
294 + else if (unlikely(!strncmp(
295 + object_name,
296 + NETDATA_MSSQL_WRITE_TRANSACTIONS_METRIC,
297 + sizeof(NETDATA_MSSQL_WRITE_TRANSACTIONS_METRIC) - 1)))
298 + mdi->MSSQLDatabaseWriteTransactions.current.Data = (ULONGLONG)value;
299 + else if (unlikely(!strncmp(
300 + object_name, NETDATA_MSSQL_BACKUP_RESTORE_METRIC, sizeof(NETDATA_MSSQL_BACKUP_RESTORE_METRIC) - 1)))
301 + mdi->MSSQLDatabaseBackupRestoreOperations.current.Data = (ULONGLONG)value;
302 + else if (unlikely(!strncmp(object_name, NETDATA_MSSQL_LOG_FLUSHED_METRIC, sizeof(NETDATA_MSSQL_LOG_FLUSHED_METRIC) - 1)))
303 + mdi->MSSQLDatabaseLogFlushed.current.Data = (ULONGLONG)value;
304 + else if (unlikely(!strncmp(object_name, NETDATA_MSSQL_LOG_FLUSHES_METRIC, sizeof(NETDATA_MSSQL_LOG_FLUSHES_METRIC) - 1)))
305 + mdi->MSSQLDatabaseLogFlushes.current.Data = (ULONGLONG)value;
306 + else if (unlikely(!strncmp(
307 + object_name,
308 + NETDATA_MSSQL_NUMBER_DEADLOCKS_METRIC,
309 + sizeof(NETDATA_MSSQL_NUMBER_DEADLOCKS_METRIC) - 1)))
310 + mdi->MSSQLDatabaseDeadLockSec.current.Data = (ULONGLONG)value;
311 + else if (unlikely(!strncmp(object_name, NETDATA_MSSQL_LOCK_WAITS_METRIC, sizeof(NETDATA_MSSQL_LOCK_WAITS_METRIC) - 1)))
312 + mdi->MSSQLDatabaseLockWaitSec.current.Data = (ULONGLONG)value;
313 + else if (unlikely(!strncmp(
314 + object_name, NETDATA_MSSQL_LOCK_TIMEOUTS_METRIC, sizeof(NETDATA_MSSQL_LOCK_TIMEOUTS_METRIC) - 1)))
315 + mdi->MSSQLDatabaseLockTimeoutsSec.current.Data = (ULONGLONG)value;
316 + else if (unlikely(!strncmp(
317 + object_name, NETDATA_MSSQL_LOCK_REQUESTS_METRIC, sizeof(NETDATA_MSSQL_LOCK_REQUESTS_METRIC) - 1)))
318 + mdi->MSSQLDatabaseLockRequestsSec.current.Data = (ULONGLONG)value;
319 +
320 + } while (true);
321 +
322 +endtransactions:
323 + netdata_MSSQL_release_results(mdi->parent->conn->dbTransactionSTMT);
324 +}
325 +
326 +void dict_mssql_fill_locks(struct mssql_db_instance *mdi, const char *dbname)
327 +{
328 +#define NETDATA_MSSQL_MAX_RESOURCE_TYPE (60)
329 + char resource_type[NETDATA_MSSQL_MAX_RESOURCE_TYPE + 1] = {};
330 + long value = 0;
331 + SQLLEN col_object_len = 0, col_value_len = 0;
332 +
333 + SQLCHAR query[sizeof(NETDATA_QUERY_LOCKS_MASK) + 2 * NETDATA_MAX_INSTANCE_OBJECT + 1];
334 + snprintfz(
335 + (char *)query,
336 + sizeof(NETDATA_QUERY_TRANSACTIONS_MASK) + 2 * NETDATA_MAX_INSTANCE_OBJECT,
337 + NETDATA_QUERY_LOCKS_MASK,
338 + dbname,
339 + dbname);
340 +
341 + SQLRETURN ret = SQLExecDirect(mdi->parent->conn->dbLocksSTMT, (SQLCHAR *)query, SQL_NTS);
342 + if (likely(netdata_mssql_check_result(ret))) {
343 + mdi->collecting_data = false;
344 + netdata_MSSQL_error(
345 + SQL_HANDLE_STMT, mdi->parent->conn->dbLocksSTMT, NETDATA_MSSQL_ODBC_QUERY, mdi->parent->instanceID);
346 + goto endlocks;
347 + }
348 +
349 + ret = SQLBindCol(
350 + mdi->parent->conn->dbLocksSTMT, 1, SQL_C_CHAR, resource_type, sizeof(resource_type), &col_object_len);
351 + if (likely(netdata_mssql_check_result(ret))) {
352 + netdata_MSSQL_error(
353 + SQL_HANDLE_STMT, mdi->parent->conn->dbLocksSTMT, NETDATA_MSSQL_ODBC_PREPARE, mdi->parent->instanceID);
354 + goto endlocks;
355 + }
356 +
357 + ret = SQLBindCol(mdi->parent->conn->dbLocksSTMT, 2, SQL_C_LONG, &value, sizeof(value), &col_value_len);
358 + if (likely(netdata_mssql_check_result(ret))) {
359 + netdata_MSSQL_error(
360 + SQL_HANDLE_STMT, mdi->parent->conn->dbLocksSTMT, NETDATA_MSSQL_ODBC_PREPARE, mdi->parent->instanceID);
361 + goto endlocks;
362 + }
363 +
364 + do {
365 + ret = SQLFetch(mdi->parent->conn->dbLocksSTMT);
366 + switch (ret) {
367 + case SQL_SUCCESS:
368 + case SQL_SUCCESS_WITH_INFO:
369 + break;
370 + case SQL_NO_DATA:
371 + default:
372 + goto endlocks;
373 + }
374 +
375 + char *space = strchr(resource_type, ' ');
376 + if (likely(space))
377 + *space = '\0';
378 +
379 + struct mssql_lock_instance *mli =
380 + dictionary_set(mdi->parent->locks_instances, resource_type, NULL, sizeof(*mli));
381 + if (unlikely(!mli))
382 + continue;
383 +
384 + mli->lockWait.current.Data = value;
385 + } while (true);
386 +
387 +endlocks:
388 + netdata_MSSQL_release_results(mdi->parent->conn->dbLocksSTMT);
389 +}
390 +
391 +int dict_mssql_fill_waits(struct mssql_instance *mi)
392 +{
393 + char wait_type[NETDATA_MAX_INSTANCE_OBJECT + 1] = {};
394 + char wait_category[NETDATA_MAX_INSTANCE_OBJECT + 1] = {};
395 + SQLBIGINT total_wait = 0;
396 + SQLBIGINT resource_wait = 0;
397 + SQLBIGINT signal_wait = 0;
398 + SQLBIGINT max_wait = 0;
399 + SQLBIGINT waiting_tasks = 0;
400 + int success = 0;
401 + SQLLEN col_wait_type_len = 0, col_total_wait_len = 0, col_resource_wait_len = 0, col_signal_wait_len = 0,
402 + col_max_wait_len = 0, col_waiting_tasks_len = 0, col_wait_category_len = 0;
403 +
404 + SQLRETURN ret = SQLExecDirect(mi->conn->dbWaitsSTMT, (SQLCHAR *)NETDATA_QUERY_CHECK_WAITS, SQL_NTS);
405 + if (likely(netdata_mssql_check_result(ret))) {
406 + netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->dbWaitsSTMT, NETDATA_MSSQL_ODBC_QUERY, mi->instanceID);
407 + goto endwait;
408 + }
409 +
410 + ret = SQLBindCol(mi->conn->dbWaitsSTMT, 1, SQL_C_CHAR, wait_type, sizeof(wait_type), &col_wait_type_len);
411 + if (likely(netdata_mssql_check_result(ret))) {
412 + netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->dbWaitsSTMT, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
413 + goto endwait;
414 + }
415 +
416 + ret = SQLBindCol(mi->conn->dbWaitsSTMT, 2, SQL_C_LONG, &total_wait, sizeof(total_wait), &col_total_wait_len);
417 + if (likely(netdata_mssql_check_result(ret))) {
418 + netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->dbWaitsSTMT, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
419 + goto endwait;
420 + }
421 +
422 + ret =
423 + SQLBindCol(mi->conn->dbWaitsSTMT, 3, SQL_C_LONG, &resource_wait, sizeof(resource_wait), &col_resource_wait_len);
424 + if (likely(netdata_mssql_check_result(ret))) {
425 + netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->dbWaitsSTMT, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
426 + goto endwait;
427 + }
428 +
429 + ret = SQLBindCol(mi->conn->dbWaitsSTMT, 4, SQL_C_LONG, &signal_wait, sizeof(signal_wait), &col_signal_wait_len);
430 + if (likely(netdata_mssql_check_result(ret))) {
431 + netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->dbWaitsSTMT, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
432 + goto endwait;
433 + }
434 +
435 + ret = SQLBindCol(mi->conn->dbWaitsSTMT, 5, SQL_C_LONG, &max_wait, sizeof(max_wait), &col_max_wait_len);
436 + if (likely(netdata_mssql_check_result(ret))) {
437 + netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->dbWaitsSTMT, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
438 + goto endwait;
439 + }
440 +
441 + ret =
442 + SQLBindCol(mi->conn->dbWaitsSTMT, 6, SQL_C_LONG, &waiting_tasks, sizeof(waiting_tasks), &col_waiting_tasks_len);
443 + if (likely(netdata_mssql_check_result(ret))) {
444 + netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->dbWaitsSTMT, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
445 + goto endwait;
446 + }
447 +
448 + ret =
449 + SQLBindCol(mi->conn->dbWaitsSTMT, 7, SQL_C_CHAR, wait_category, sizeof(wait_category), &col_wait_category_len);
450 + if (likely(netdata_mssql_check_result(ret))) {
451 + netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->dbWaitsSTMT, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
452 + goto endwait;
453 + }
454 +
455 + do {
456 + ret = SQLFetch(mi->conn->dbWaitsSTMT);
457 + switch (ret) {
458 + case SQL_SUCCESS:
459 + case SQL_SUCCESS_WITH_INFO:
460 + break;
461 + case SQL_NO_DATA:
462 + default:
463 + success = 1;
464 + goto endwait;
465 + }
466 +
467 + struct mssql_db_waits *mdw = dictionary_set(mi->waits, wait_type, NULL, sizeof(*mdw));
468 + if (!mdw)
469 + continue;
470 +
471 + mdw->MSSQLDatabaseTotalWait.current.Data = (ULONGLONG)total_wait;
472 + // Variable mdw->MSSQLDatabaseResourceWaitMSec.current.Data stores a mathematical operation
473 + // that can be negative sometimes. This is the reason we have this if
474 + if (likely(resource_wait > mdw->MSSQLDatabaseResourceWaitMSec.current.Data))
475 + mdw->MSSQLDatabaseResourceWaitMSec.current.Data = (ULONGLONG)resource_wait;
476 + mdw->MSSQLDatabaseSignalWaitMSec.current.Data = (ULONGLONG)signal_wait;
477 + mdw->MSSQLDatabaseMaxWaitTimeMSec.current.Data = (ULONGLONG)max_wait;
478 + mdw->MSSQLDatabaseWaitingTasks.current.Data = (ULONGLONG)waiting_tasks;
479 +
480 + if (unlikely(!mdw->wait_category))
481 + mdw->wait_category = strdupz(wait_category);
482 + } while (true);
483 +
484 +endwait:
485 + netdata_MSSQL_release_results(mi->conn->dbWaitsSTMT);
486 +
487 + return success;
488 +}
489 +
490 +int netdata_select_db(SQLHDBC hdbc, const char *database)
491 +{
492 + SQLHSTMT hstmt;
493 + SQLRETURN ret;
494 +
495 + ret = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
496 + if (likely(netdata_mssql_check_result(ret))) {
497 + return -1;
498 + }
499 +
500 + char query[512];
501 + snprintfz(query, sizeof(query), "USE %s", database);
502 + ret = SQLExecDirect(hstmt, (SQLCHAR *)query, SQL_NTS);
503 + int result = 0;
504 + if (likely(netdata_mssql_check_result(ret))) {
505 + result = -1;
506 + }
507 + SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
508 + return result;
509 +}
510 +
511 +void dict_mssql_fill_replication(struct mssql_db_instance *mdi)
512 +{
513 + char publisher[NETDATA_MAX_INSTANCE_OBJECT + 1] = {};
514 + char publisher_db[NETDATA_MAX_INSTANCE_OBJECT + 1] = {};
515 + char publication[NETDATA_MAX_INSTANCE_OBJECT + 1] = {};
516 + char key[NETDATA_MAX_INSTANCE_OBJECT * 2 + 2];
517 + int type = 0, status = 0, warning = 0, avg_latency = 0, retention = 0, subscriptioncount = 0,
518 + runningdistagentcount = 0, average_runspeedPerf = 0;
519 + SQLLEN publisher_len = 0, publisherdb_len = 0, publication_len = 0, type_len = 0, status_len = 0, warning_len = 0,
520 + avg_latency_len = 0, retention_len = 0, subscriptioncount_len = 0, runningagentcount_len = 0,
521 + average_runspeedperf_len = 0;
522 +
523 + if (likely(netdata_select_db(mdi->parent->conn->netdataSQLHDBc, NETDATA_REPLICATION_DB))) {
524 + return;
525 + }
526 +
527 + SQLRETURN ret =
528 + SQLExecDirect(mdi->parent->conn->dbReplicationPublisher, (SQLCHAR *)NETDATA_REPLICATION_MONITOR_QUERY, SQL_NTS);
529 + if (likely(netdata_mssql_check_result(ret))) {
530 + mdi->collecting_data = false;
531 + netdata_MSSQL_error(
532 + SQL_HANDLE_STMT,
533 + mdi->parent->conn->dbReplicationPublisher,
534 + NETDATA_MSSQL_ODBC_QUERY,
535 + mdi->parent->instanceID);
536 + goto endreplication;
537 + }
538 +
539 + ret = SQLBindCol(
540 + mdi->parent->conn->dbReplicationPublisher, 1, SQL_C_CHAR, publisher_db, sizeof(publisher_db), &publisherdb_len);
541 + if (likely(netdata_mssql_check_result(ret))) {
542 + netdata_MSSQL_error(
543 + SQL_HANDLE_STMT,
544 + mdi->parent->conn->dbReplicationPublisher,
545 + NETDATA_MSSQL_ODBC_PREPARE,
546 + mdi->parent->instanceID);
547 + goto endreplication;
548 + }
549 +
550 + ret = SQLBindCol(
551 + mdi->parent->conn->dbReplicationPublisher, 2, SQL_C_CHAR, publication, sizeof(publication), &publication_len);
552 + if (likely(netdata_mssql_check_result(ret))) {
553 + netdata_MSSQL_error(
554 + SQL_HANDLE_STMT,
555 + mdi->parent->conn->dbReplicationPublisher,
556 + NETDATA_MSSQL_ODBC_PREPARE,
557 + mdi->parent->instanceID);
558 + goto endreplication;
559 + }
560 +
561 + ret = SQLBindCol(mdi->parent->conn->dbReplicationPublisher, 4, SQL_C_LONG, &type, sizeof(type), &type_len);
562 + if (likely(netdata_mssql_check_result(ret))) {
563 + netdata_MSSQL_error(
564 + SQL_HANDLE_STMT,
565 + mdi->parent->conn->dbReplicationPublisher,
566 + NETDATA_MSSQL_ODBC_PREPARE,
567 + mdi->parent->instanceID);
568 + goto endreplication;
569 + }
570 +
571 + ret = SQLBindCol(mdi->parent->conn->dbReplicationPublisher, 5, SQL_C_LONG, &status, sizeof(status), &status_len);
572 + if (likely(netdata_mssql_check_result(ret))) {
573 + netdata_MSSQL_error(
574 + SQL_HANDLE_STMT,
575 + mdi->parent->conn->dbReplicationPublisher,
576 + NETDATA_MSSQL_ODBC_PREPARE,
577 + mdi->parent->instanceID);
578 + goto endreplication;
579 + }
580 +
581 + ret = SQLBindCol(mdi->parent->conn->dbReplicationPublisher, 6, SQL_C_LONG, &warning, sizeof(warning), &warning_len);
582 + if (likely(netdata_mssql_check_result(ret))) {
583 + netdata_MSSQL_error(
584 + SQL_HANDLE_STMT,
585 + mdi->parent->conn->dbReplicationPublisher,
586 + NETDATA_MSSQL_ODBC_PREPARE,
587 + mdi->parent->instanceID);
588 + goto endreplication;
589 + }
590 +
591 + ret = SQLBindCol(
592 + mdi->parent->conn->dbReplicationPublisher, 9, SQL_C_LONG, &avg_latency, sizeof(avg_latency), &avg_latency_len);
593 + if (likely(netdata_mssql_check_result(ret))) {
594 + // It is still a NULL value
595 + avg_latency = 0;
596 + }
597 +
598 + ret = SQLBindCol(
599 + mdi->parent->conn->dbReplicationPublisher, 11, SQL_C_LONG, &retention, sizeof(retention), &retention_len);
600 + if (likely(netdata_mssql_check_result(ret))) {
601 + netdata_MSSQL_error(
602 + SQL_HANDLE_STMT,
603 + mdi->parent->conn->dbReplicationPublisher,
604 + NETDATA_MSSQL_ODBC_PREPARE,
605 + mdi->parent->instanceID);
606 + goto endreplication;
607 + }
608 +
609 + ret = SQLBindCol(
610 + mdi->parent->conn->dbReplicationPublisher,
611 + 15,
612 + SQL_C_LONG,
613 + &subscriptioncount,
614 + sizeof(subscriptioncount),
615 + &subscriptioncount_len);
616 + if (likely(netdata_mssql_check_result(ret))) {
617 + netdata_MSSQL_error(
618 + SQL_HANDLE_STMT,
619 + mdi->parent->conn->dbReplicationPublisher,
620 + NETDATA_MSSQL_ODBC_PREPARE,
621 + mdi->parent->instanceID);
622 + goto endreplication;
623 + }
624 +
625 + ret = SQLBindCol(
626 + mdi->parent->conn->dbReplicationPublisher,
627 + 16,
628 + SQL_C_LONG,
629 + &runningdistagentcount,
630 + sizeof(runningdistagentcount),
631 + &runningagentcount_len);
632 + if (likely(netdata_mssql_check_result(ret))) {
633 + netdata_MSSQL_error(
634 + SQL_HANDLE_STMT,
635 + mdi->parent->conn->dbReplicationPublisher,
636 + NETDATA_MSSQL_ODBC_PREPARE,
637 + mdi->parent->instanceID);
638 + goto endreplication;
639 + }
640 +
641 + ret = SQLBindCol(
642 + mdi->parent->conn->dbReplicationPublisher,
643 + 22,
644 + SQL_C_LONG,
645 + &average_runspeedPerf,
646 + sizeof(average_runspeedPerf),
647 + &average_runspeedperf_len);
648 + if (likely(netdata_mssql_check_result(ret))) {
649 + netdata_MSSQL_error(
650 + SQL_HANDLE_STMT,
651 + mdi->parent->conn->dbReplicationPublisher,
652 + NETDATA_MSSQL_ODBC_PREPARE,
653 + mdi->parent->instanceID);
654 + goto endreplication;
655 + }
656 +
657 + ret = SQLBindCol(
658 + mdi->parent->conn->dbReplicationPublisher, 24, SQL_C_CHAR, publisher, sizeof(publisher), &publisher_len);
659 + if (likely(netdata_mssql_check_result(ret))) {
660 + netdata_MSSQL_error(
661 + SQL_HANDLE_STMT,
662 + mdi->parent->conn->dbReplicationPublisher,
663 + NETDATA_MSSQL_ODBC_PREPARE,
664 + mdi->parent->instanceID);
665 + goto endreplication;
666 + }
667 +
668 + do {
669 + ret = SQLFetch(mdi->parent->conn->dbReplicationPublisher);
670 + switch (ret) {
671 + case SQL_SUCCESS:
672 + case SQL_SUCCESS_WITH_INFO:
673 + break;
674 + case SQL_NO_DATA:
675 + default:
676 + goto endreplication;
677 + }
678 +
679 + snprintfz(key, sizeof(key) - 1, "%s:%s", publisher_db, publication);
680 + struct mssql_publisher_publication *mpp =
681 + dictionary_set(mdi->parent->publisher_publication, key, NULL, sizeof(*mpp));
682 +
683 + if (unlikely(!mpp->publisher)) {
684 + mpp->publisher = strdupz(publisher);
685 + mpp->parent = mdi->parent;
686 + }
687 +
688 + if (unlikely(!mpp->publication))
689 + mpp->publication = strdupz(publication);
690 +
691 + if (unlikely(!mpp->db))
692 + mpp->db = strdupz(publisher_db);
693 +
694 + mpp->type = type;
695 + mpp->status = status;
696 + mpp->warning = warning;
697 +
698 + mpp->avg_latency = avg_latency;
699 +
700 + mpp->retention = retention;
701 +
702 + mpp->subscriptioncount = subscriptioncount;
703 + mpp->runningdistagentcount = runningdistagentcount;
704 +
705 + mpp->average_runspeedPerf = average_runspeedPerf;
706 + } while (true);
707 +
708 +endreplication:
709 + (void)netdata_select_db(mdi->parent->conn->netdataSQLHDBc, "master");
710 + netdata_MSSQL_release_results(mdi->parent->conn->dbReplicationPublisher);
711 +}
712 +int dict_mssql_databases_run_queries(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
713 +{
714 + struct mssql_db_instance *mdi = value;
715 + const char *dbname = dictionary_acquired_item_name((DICTIONARY_ITEM *)item);
716 +
717 + if (unlikely(!mdi->collecting_data || !mdi->parent || !mdi->parent->conn)) {
718 + goto enddrunquery;
719 + }
720 +
721 + // We failed to collect this for the database, so we are not going to try again
722 + if (unlikely(mdi->MSSQLDatabaseDataFileSize.current.Data != ULONG_LONG_MAX))
723 + mdi->MSSQLDatabaseDataFileSize.current.Data = netdata_MSSQL_fill_long_value(
724 + mdi->parent->conn->dataFileSizeSTMT, NETDATA_QUERY_DATA_FILE_SIZE_MASK, dbname, mdi->parent->instanceID);
725 + else {
726 + mdi->collecting_data = false;
727 + goto enddrunquery;
728 + }
729 +
730 + dict_mssql_fill_transactions(mdi, dbname);
731 + dict_mssql_fill_locks(mdi, dbname);
732 +
733 + if (likely(mdi->running_replication))
734 + dict_mssql_fill_replication(mdi);
735 +
736 +enddrunquery:
737 + return 1;
738 +}
739 +
740 +long metdata_mssql_check_permission(struct mssql_instance *mi)
741 +{
742 + static int next_try = NETDATA_MSSQL_NEXT_TRY - 1;
743 + long perm = 0;
744 + SQLLEN col_data_len = 0;
745 +
746 + if (++next_try != NETDATA_MSSQL_NEXT_TRY)
747 + return 1;
748 +
749 + next_try = 0;
750 +
751 + SQLRETURN ret;
752 +
753 + ret = SQLExecDirect(mi->conn->checkPermSTMT, (SQLCHAR *)NETDATA_QUERY_CHECK_PERM, SQL_NTS);
754 + if (likely(netdata_mssql_check_result(ret))) {
755 + netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->checkPermSTMT, NETDATA_MSSQL_ODBC_QUERY, mi->instanceID);
756 + perm = LONG_MAX;
757 + goto endperm;
758 + }
759 +
760 + ret = SQLBindCol(mi->conn->checkPermSTMT, 1, SQL_C_LONG, &perm, sizeof(perm), &col_data_len);
761 +
762 + if (likely(netdata_mssql_check_result(ret))) {
763 + netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->checkPermSTMT, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
764 + perm = LONG_MAX;
765 + goto endperm;
766 + }
767 +
768 + ret = SQLFetch(mi->conn->checkPermSTMT);
769 + if (likely(netdata_mssql_check_result(ret))) {
770 + netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->checkPermSTMT, NETDATA_MSSQL_ODBC_FETCH, mi->instanceID);
771 + perm = LONG_MAX;
772 + goto endperm;
773 + }
774 +
775 +endperm:
776 + netdata_MSSQL_release_results(mi->conn->checkPermSTMT);
777 + return perm;
778 +}
779 +
780 +void metdata_mssql_fill_mssql_status(struct mssql_instance *mi)
781 +{
782 + char dbname[SQLSERVER_MAX_NAME_LENGTH + 1];
783 + int readonly = 0;
784 + BYTE state = 0;
785 + SQLLEN col_data_len = 0;
786 +
787 + static int next_try = NETDATA_MSSQL_NEXT_TRY - 1;
788 +
789 + if (unlikely(++next_try != NETDATA_MSSQL_NEXT_TRY))
790 + return;
791 +
792 + next_try = 0;
793 +
794 + SQLRETURN ret;
795 +
796 + ret = SQLExecDirect(mi->conn->dbSQLState, (SQLCHAR *)NETDATA_QUERY_DATABASE_STATUS, SQL_NTS);
797 + if (likely(netdata_mssql_check_result(ret))) {
798 + netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->dbSQLState, NETDATA_MSSQL_ODBC_QUERY, mi->instanceID);
799 + goto enddbstate;
800 + }
801 +
802 + ret = SQLBindCol(mi->conn->dbSQLState, 1, SQL_C_TINYINT, &state, sizeof(state), &col_data_len);
803 + if (likely(netdata_mssql_check_result(ret))) {
804 + netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->dbSQLState, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
805 + goto enddbstate;
806 + }
807 +
808 + ret = SQLBindCol(mi->conn->dbSQLState, 3, SQL_C_BIT, &readonly, sizeof(readonly), &col_data_len);
809 + if (likely(netdata_mssql_check_result(ret))) {
810 + netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->dbWaitsSTMT, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
811 + goto enddbstate;
812 + }
813 +
814 + do {
815 + ret = SQLFetch(mi->conn->dbSQLState);
816 + if (likely(netdata_mssql_check_result(ret))) {
817 + goto enddbstate;
818 + }
819 +
820 + struct mssql_db_instance *mdi = dictionary_set(mi->databases, dbname, NULL, sizeof(*mdi));
821 + if (unlikely(!mdi))
822 + continue;
823 +
824 + mdi->MSSQLDBState.current.Data = (ULONGLONG)state;
825 + mdi->MSSQLDBIsReadonly.current.Data = (ULONGLONG)readonly;
826 + } while (true);
827 +
828 +enddbstate:
829 + netdata_MSSQL_release_results(mi->conn->dbSQLState);
830 +}
831 +
832 +void metdata_mssql_fill_job_status(struct mssql_instance *mi)
833 +{
834 + char job[SQLSERVER_MAX_NAME_LENGTH + 1];
835 + BYTE state = 0;
836 + SQLLEN col_job_len = 0;
837 + SQLLEN col_state_len = 0;
838 +
839 + static int next_try = NETDATA_MSSQL_NEXT_TRY - 1;
840 +
841 + if (unlikely(++next_try != NETDATA_MSSQL_NEXT_TRY))
842 + return;
843 +
844 + next_try = 0;
845 +
846 + SQLRETURN ret;
847 +
848 + ret = SQLExecDirect(mi->conn->dbSQLJobs, (SQLCHAR *)NETDATA_QUERY_JOBS_STATUS, SQL_NTS);
849 + if (likely(netdata_mssql_check_result(ret))) {
850 + netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->dbSQLJobs, NETDATA_MSSQL_ODBC_QUERY, mi->instanceID);
851 + goto enddbjobs;
852 + }
853 +
854 + ret = SQLBindCol(mi->conn->dbSQLJobs, 1, SQL_C_CHAR, job, sizeof(job), &col_job_len);
855 + if (likely(netdata_mssql_check_result(ret))) {
856 + netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->dbSQLJobs, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
857 + goto enddbjobs;
858 + }
859 +
860 + ret = SQLBindCol(mi->conn->dbSQLJobs, 2, SQL_C_TINYINT, &state, sizeof(state), &col_state_len);
861 + if (likely(netdata_mssql_check_result(ret))) {
862 + netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->dbSQLJobs, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
863 + goto enddbjobs;
864 + }
865 +
866 + do {
867 + ret = SQLFetch(mi->conn->dbSQLJobs);
868 + if (likely(netdata_mssql_check_result(ret))) {
869 + goto enddbjobs;
870 + }
871 +
872 + struct mssql_db_jobs *mdj = dictionary_set(mi->sysjobs, job, NULL, sizeof(*mdj));
873 + if (unlikely(!mdj))
874 + continue;
875 +
876 + mdj->MSSQLJOBState.current.Data = (ULONGLONG)state;
877 + } while (true);
878 +
879 +enddbjobs:
880 + netdata_MSSQL_release_results(mi->conn->dbSQLJobs);
881 +}
882 +
883 +void metdata_mssql_fill_dictionary_from_db(struct mssql_instance *mi)
884 +{
885 + char dbname[SQLSERVER_MAX_NAME_LENGTH + 1];
886 + SQLLEN col_data_len = 0;
887 +
888 + static int next_try = NETDATA_MSSQL_NEXT_TRY - 1;
889 +
890 + if (unlikely(++next_try != NETDATA_MSSQL_NEXT_TRY))
891 + return;
892 +
893 + next_try = 0;
894 +
895 + SQLRETURN ret;
896 +
897 + ret = SQLExecDirect(mi->conn->databaseListSTMT, (SQLCHAR *)NETDATA_QUERY_LIST_DB, SQL_NTS);
898 + if (likely(netdata_mssql_check_result(ret))) {
899 + netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->databaseListSTMT, NETDATA_MSSQL_ODBC_QUERY, mi->instanceID);
900 + goto enddblist;
901 + }
902 +
903 + ret = SQLBindCol(mi->conn->databaseListSTMT, 1, SQL_C_CHAR, dbname, sizeof(dbname), &col_data_len);
904 +
905 + if (likely(netdata_mssql_check_result(ret))) {
906 + netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->databaseListSTMT, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
907 + goto enddblist;
908 + }
909 +
910 + int i = 0;
911 + do {
912 + ret = SQLFetch(mi->conn->databaseListSTMT);
913 + if (likely(netdata_mssql_check_result(ret))) {
914 + goto enddblist;
915 + }
916 +
917 + struct mssql_db_instance *mdi = dictionary_set(mi->databases, dbname, NULL, sizeof(*mdi));
918 + if (!mdi)
919 + continue;
920 +
921 + mdi->updated = 0;
922 + if (unlikely(!mdi->parent)) {
923 + mdi->parent = mi;
924 + }
925 +
926 + if (mi->conn && !strncmp(dbname, NETDATA_REPLICATION_DB, sizeof(NETDATA_REPLICATION_DB) - 1)) {
927 + mdi->running_replication = true;
928 + }
929 +
930 + if (unlikely(!i)) {
931 + mdi->collect_instance = true;
932 + }
933 + } while (true);
934 +
935 +enddblist:
936 + netdata_MSSQL_release_results(mi->conn->databaseListSTMT);
937 +}
938 +
939 +static bool netdata_MSSQL_initialize_connection(struct netdata_mssql_conn *nmc)
940 +{
941 + SQLRETURN ret;
942 + if (unlikely(!nmc->netdataSQLEnv)) {
943 + ret = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &nmc->netdataSQLEnv);
944 + if (likely(netdata_mssql_check_result(ret)))
945 + return FALSE;
946 +
947 + ret = SQLSetEnvAttr(nmc->netdataSQLEnv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0);
948 + if (likely(netdata_mssql_check_result(ret))) {
949 + return FALSE;
950 + }
951 + }
952 +
953 + ret = SQLAllocHandle(SQL_HANDLE_DBC, nmc->netdataSQLEnv, &nmc->netdataSQLHDBc);
954 + if (likely(netdata_mssql_check_result(ret))) {
955 + return FALSE;
956 + }
957 +
958 + ret = SQLSetConnectAttr(nmc->netdataSQLHDBc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0);
959 + if (likely(netdata_mssql_check_result(ret))) {
960 + return FALSE;
961 + }
962 +
963 + ret = SQLSetConnectAttr(nmc->netdataSQLHDBc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)TRUE, 0);
964 + if (likely(netdata_mssql_check_result(ret))) {
965 + return FALSE;
966 + }
967 +
968 + SQLCHAR ret_conn_str[1024];
969 + ret = SQLDriverConnect(
970 + nmc->netdataSQLHDBc, NULL, nmc->connectionString, SQL_NTS, ret_conn_str, 1024, NULL, SQL_DRIVER_NOPROMPT);
971 +
972 + BOOL retConn;
973 + switch (ret) {
974 + case SQL_NO_DATA_FOUND:
975 + case SQL_INVALID_HANDLE:
976 + case SQL_ERROR:
977 + default:
978 + netdata_MSSQL_error(SQL_HANDLE_DBC, nmc->netdataSQLHDBc, NETDATA_MSSQL_ODBC_CONNECT, NULL);
979 + retConn = FALSE;
980 + break;
981 + case SQL_SUCCESS:
982 + case SQL_SUCCESS_WITH_INFO:
983 + retConn = TRUE;
984 + break;
985 + }
986 +
987 + if (likely(retConn)) {
988 + SQLSetConnectAttr(nmc->netdataSQLHDBc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_ON, 0);
989 +
990 + ret = SQLAllocHandle(SQL_HANDLE_STMT, nmc->netdataSQLHDBc, &nmc->checkPermSTMT);
991 + if (likely(netdata_mssql_check_result(ret))) {
992 + retConn = FALSE;
993 + goto endMSSQLInitializationConnection;
994 + }
995 +
996 + ret = SQLAllocHandle(SQL_HANDLE_STMT, nmc->netdataSQLHDBc, &nmc->databaseListSTMT);
997 + if (likely(netdata_mssql_check_result(ret))) {
998 + retConn = FALSE;
999 + goto endMSSQLInitializationConnection;
1000 + }
1001 +
1002 + ret = SQLAllocHandle(SQL_HANDLE_STMT, nmc->netdataSQLHDBc, &nmc->dataFileSizeSTMT);
1003 + if (likely(netdata_mssql_check_result(ret))) {
1004 + retConn = FALSE;
1005 + goto endMSSQLInitializationConnection;
1006 + }
1007 +
1008 + ret = SQLAllocHandle(SQL_HANDLE_STMT, nmc->netdataSQLHDBc, &nmc->dbTransactionSTMT);
1009 + if (likely(netdata_mssql_check_result(ret))) {
1010 + retConn = FALSE;
1011 + goto endMSSQLInitializationConnection;
1012 + }
1013 +
1014 + ret = SQLAllocHandle(SQL_HANDLE_STMT, nmc->netdataSQLHDBc, &nmc->dbInstanceTransactionSTMT);
1015 + if (likely(netdata_mssql_check_result(ret))) {
1016 + retConn = FALSE;
1017 + goto endMSSQLInitializationConnection;
1018 + }
1019 +
1020 + ret = SQLAllocHandle(SQL_HANDLE_STMT, nmc->netdataSQLHDBc, &nmc->dbLocksSTMT);
1021 + if (likely(netdata_mssql_check_result(ret))) {
1022 + retConn = FALSE;
1023 + goto endMSSQLInitializationConnection;
1024 + }
1025 +
1026 + ret = SQLAllocHandle(SQL_HANDLE_STMT, nmc->netdataSQLHDBc, &nmc->dbWaitsSTMT);
1027 + if (likely(netdata_mssql_check_result(ret))) {
1028 + retConn = FALSE;
1029 + goto endMSSQLInitializationConnection;
1030 + }
1031 +
1032 + ret = SQLAllocHandle(SQL_HANDLE_STMT, nmc->netdataSQLHDBc, &nmc->dbSQLState);
1033 + if (likely(netdata_mssql_check_result(ret))) {
1034 + retConn = FALSE;
1035 + goto endMSSQLInitializationConnection;
1036 + }
1037 +
1038 + ret = SQLAllocHandle(SQL_HANDLE_STMT, nmc->netdataSQLHDBc, &nmc->dbSQLJobs);
1039 + if (likely(netdata_mssql_check_result(ret))) {
1040 + retConn = FALSE;
1041 + goto endMSSQLInitializationConnection;
1042 + }
1043 +
1044 + ret = SQLAllocHandle(SQL_HANDLE_STMT, nmc->netdataSQLHDBc, &nmc->dbReplicationPublisher);
1045 + if (likely(netdata_mssql_check_result(ret))) {
1046 + retConn = FALSE;
1047 + goto endMSSQLInitializationConnection;
1048 + }
1049 + }
1050 +
1051 +endMSSQLInitializationConnection:
1052 + return retConn;
1053 +}
1054 +
1055 +// Dictionary
1056 +static DICTIONARY *mssql_instances = NULL;
1057 +
1058 +static void initialize_mssql_objects(struct mssql_instance *mi, const char *instance)
1059 +{
1060 + char prefix[NETDATA_MAX_INSTANCE_NAME];
1061 + if (unlikely(!strcmp(instance, "MSSQLSERVER"))) {
1062 + strncpyz(prefix, "SQLServer:", sizeof(prefix) - 1);
1063 + } else if (unlikely(!strcmp(instance, "SQLEXPRESS"))) {
1064 + strncpyz(prefix, "MSSQL$SQLEXPRESS:", sizeof(prefix) - 1);
1065 + if (mi->conn)
1066 + mi->conn->is_sqlexpress = true;
1067 + } else {
1068 + char *express = (mi->conn && mi->conn->is_sqlexpress) ? "SQLEXPRESS:" : "";
1069 + snprintfz(prefix, sizeof(prefix) - 1, "MSSQL$%s%s:", express, instance);
1070 + }
1071 +
1072 + size_t length = strlen(prefix);
1073 + char name[NETDATA_MAX_INSTANCE_OBJECT];
1074 + snprintfz(name, sizeof(name) - 1, "%s%s", prefix, "General Statistics");
1075 + mi->objectName[NETDATA_MSSQL_GENERAL_STATS] = strdupz(name);
1076 +
1077 + strncpyz(&name[length], "SQL Errors", sizeof(name) - length);
1078 + mi->objectName[NETDATA_MSSQL_SQL_ERRORS] = strdupz(name);
1079 +
1080 + strncpyz(&name[length], "Databases", sizeof(name) - length);
1081 + mi->objectName[NETDATA_MSSQL_DATABASE] = strdupz(name);
1082 +
1083 + strncpyz(&name[length], "SQL Statistics", sizeof(name) - length);
1084 + mi->objectName[NETDATA_MSSQL_SQL_STATS] = strdupz(name);
1085 +
1086 + strncpyz(&name[length], "Buffer Manager", sizeof(name) - length);
1087 + mi->objectName[NETDATA_MSSQL_BUFFER_MANAGEMENT] = strdupz(name);
1088 +
1089 + strncpyz(&name[length], "SystemJobs", sizeof(name) - length);
1090 + mi->objectName[NETDATA_MSSQL_JOBS] = strdupz(name);
1091 +
1092 + strncpyz(&name[length], "Memory Manager", sizeof(name) - length);
1093 + mi->objectName[NETDATA_MSSQL_MEMORY] = strdupz(name);
1094 +
1095 + strncpyz(&name[length], "Locks", sizeof(name) - length);
1096 + mi->objectName[NETDATA_MSSQL_LOCKS] = strdupz(name);
1097 +
1098 + strncpyz(&name[length], "Wait Statistics", sizeof(name) - length);
1099 + mi->objectName[NETDATA_MSSQL_WAITS] = strdupz(name);
1100 +
1101 + strncpyz(&name[length], "Access Methods", sizeof(name) - length);
1102 + mi->objectName[NETDATA_MSSQL_ACCESS_METHODS] = strdupz(name);
1103 +
1104 + mi->instanceID = strdupz(instance);
1105 +}
1106 +
1107 +static inline void initialize_mssql_keys(struct mssql_instance *mi)
1108 +{
1109 + // General Statistics (https://learn.microsoft.com/en-us/sql/relational-databases/performance-monitor/sql-server-general-statistics-object)
1110 + mi->MSSQLUserConnections.key = "User Connections";
1111 + mi->MSSQLBlockedProcesses.key = "Processes blocked";
1112 +
1113 + // SQL Statistics (https://learn.microsoft.com/en-us/sql/relational-databases/performance-monitor/sql-server-sql-statistics-object)
1114 + mi->MSSQLStatsAutoParameterization.key = "Auto-Param Attempts/sec";
1115 + mi->MSSQLStatsBatchRequests.key = "Batch Requests/sec";
1116 + mi->MSSQLStatSafeAutoParameterization.key = "Safe Auto-Params/sec";
1117 +
1118 + // Access Methods (https://learn.microsoft.com/en-us/sql/relational-databases/performance-monitor/sql-server-access-methods-object)
1119 + mi->MSSQLAccessMethodPageSplits.key = "Page Splits/sec";
1120 +
1121 + // Errors (https://learn.microsoft.com/en-us/sql/relational-databases/performance-monitor/sql-server-sql-errors-object)
1122 + mi->MSSQLSQLErrorsTotal.key = "Errors/sec";
1123 +
1124 + // Memory Management (https://learn.microsoft.com/en-us/sql/relational-databases/performance-monitor/sql-server-memory-manager-object)
1125 + mi->MSSQLConnectionMemoryBytes.key = "Connection Memory (KB)";
1126 + mi->MSSQLExternalBenefitOfMemory.key = "External benefit of memory";
1127 + mi->MSSQLPendingMemoryGrants.key = "Memory Grants Pending";
1128 + mi->MSSQLTotalServerMemory.key = "Total Server Memory (KB)";
1129 +}
1130 +
1131 +void dict_mssql_insert_locks_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
1132 +{
1133 + const char *resource = dictionary_acquired_item_name((DICTIONARY_ITEM *)item);
1134 +
1135 + // https://learn.microsoft.com/en-us/sql/relational-databases/performance-monitor/sql-server-locks-object
1136 + struct mssql_lock_instance *ptr = value;
1137 + ptr->resourceID = strdupz(resource);
1138 + ptr->deadLocks.key = "Number of Deadlocks/sec";
1139 + ptr->lockWait.key = "Lock Waits/sec";
1140 +}
1141 +
1142 +void dict_mssql_insert_wait_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
1143 +{
1144 + const char *type = dictionary_acquired_item_name((DICTIONARY_ITEM *)item);
1145 +
1146 + struct mssql_db_waits *mdw = value;
1147 +
1148 + mdw->wait_type = strdupz(type);
1149 + mdw->wait_category = NULL;
1150 + mdw->rd_total_wait = mdw->rd_max_wait_time_msec = mdw->rd_resource_wait_msec = mdw->rd_signal_wait_msec =
1151 + mdw->rd_waiting_tasks = NULL;
1152 +}
1153 +
1154 +void dict_mssql_insert_databases_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
1155 +{
1156 + struct mssql_db_instance *mdi = value;
1157 +
1158 + mdi->collecting_data = true;
1159 +}
1160 +
1161 +void dict_mssql_insert_replication_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
1162 +{
1163 + UNUSED(value);
1164 +}
1165 +
1166 +void dict_mssql_insert_jobs_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
1167 +{
1168 + UNUSED(value);
1169 +}
1170 +
1171 +// Options
1172 +void netdata_mount_mssql_connection_string(struct netdata_mssql_conn *dbInput)
1173 +{
1174 + SQLCHAR conn[1024];
1175 + const char *serverAddress;
1176 + const char *serverAddressArg;
1177 + if (unlikely(!dbInput)) {
1178 + return;
1179 + }
1180 +
1181 + char auth[512];
1182 + if (likely(dbInput->server && dbInput->address)) {
1183 + nd_log(
1184 + NDLS_COLLECTORS,
1185 + NDLP_ERR,
1186 + "Collector is not expecting server and address defined together, please, select one of them.");
1187 + dbInput->connectionString = NULL;
1188 + return;
1189 + }
1190 +
1191 + if (likely(dbInput->server)) {
1192 + serverAddress = "Server";
1193 + serverAddressArg = dbInput->server;
1194 + } else {
1195 + serverAddressArg = "Address";
1196 + serverAddress = dbInput->address;
1197 + }
1198 +
1199 + if (likely(dbInput->windows_auth))
1200 + snprintfz(auth, sizeof(auth) - 1, "Trusted_Connection = yes");
1201 + else if (unlikely(!dbInput->username || !dbInput->password)) {
1202 + nd_log(
1203 + NDLS_COLLECTORS,
1204 + NDLP_ERR,
1205 + "You are not using Windows Authentication. Thus, it is necessary to specify user and password.");
1206 + dbInput->connectionString = NULL;
1207 + return;
1208 + } else {
1209 + snprintfz(auth, sizeof(auth) - 1, "UID=%s;PWD=%s;", dbInput->username, dbInput->password);
1210 + }
1211 +
1212 + snprintfz(
1213 + (char *)conn, sizeof(conn) - 1, "Driver={%s};%s=%s;%s", dbInput->driver, serverAddress, serverAddressArg, auth);
1214 + dbInput->connectionString = (SQLCHAR *)strdupz((char *)conn);
1215 +}
1216 +
1217 +static void netdata_read_config_options()
1218 +{
1219 +#define NETDATA_MAX_MSSSQL_SECTION_LENGTH (40)
1220 +#define NETDATA_DEFAULT_MSSQL_SECTION "plugin:windows:PerflibMSSQL"
1221 + uint16_t expected_instances = 1;
1222 + uint16_t total_instances = 0;
1223 + for (; total_instances < expected_instances; total_instances++) {
1224 + char section_name[NETDATA_MAX_MSSSQL_SECTION_LENGTH + 1];
1225 + char upper_instance[NETDATA_MAX_INSTANCE_OBJECT + 1];
1226 + strncpyz(section_name, NETDATA_DEFAULT_MSSQL_SECTION, sizeof(NETDATA_DEFAULT_MSSQL_SECTION));
1227 + if (likely(total_instances)) {
1228 + snprintfz(&section_name[sizeof(NETDATA_DEFAULT_MSSQL_SECTION) - 1], 5, "%d", total_instances);
1229 + }
1230 + const char *instance = inicfg_get(&netdata_config, section_name, "instance", NULL);
1231 + int additional_instances = (int)inicfg_get_number(&netdata_config, section_name, "additional instances", 0);
1232 + if (!instance || strlen(instance) > NETDATA_MAX_INSTANCE_OBJECT) {
1233 + nd_log(
1234 + NDLS_COLLECTORS,
1235 + NDLP_ERR,
1236 + "You must specify a valid 'instance' name to collect data from database in section %s.",
1237 + section_name);
1238 + continue;
1239 + }
1240 +
1241 + if (!total_instances && additional_instances) {
1242 + if (additional_instances > 64) {
1243 + nd_log(NDLS_COLLECTORS, NDLP_ERR, "Number of instances is bigger than expected (64)");
1244 + expected_instances = 64;
1245 + }
1246 + expected_instances = additional_instances + 1;
1247 + }
1248 +
1249 + const char *move = instance;
1250 + int i;
1251 + for (i = 0; *move; move++, i++) {
1252 + upper_instance[i] = toupper(*move);
1253 + }
1254 + upper_instance[i] = '\0';
1255 +
1256 + struct netdata_mssql_conn *dbconn = dictionary_set(conn_options, upper_instance, NULL, sizeof(*dbconn));
1257 +
1258 + dbconn->instance = strdupz(upper_instance);
1259 + dbconn->driver = inicfg_get(&netdata_config, section_name, "driver", "SQL Server");
1260 + dbconn->server = inicfg_get(&netdata_config, section_name, "server", NULL);
1261 + dbconn->address = inicfg_get(&netdata_config, section_name, "address", NULL);
1262 + dbconn->username = inicfg_get(&netdata_config, section_name, "uid", NULL);
1263 + dbconn->password = inicfg_get(&netdata_config, section_name, "pwd", NULL);
1264 + dbconn->instances = additional_instances;
1265 + dbconn->windows_auth = inicfg_get_boolean(&netdata_config, section_name, "windows authentication", false);
1266 + dbconn->is_sqlexpress = inicfg_get_boolean(&netdata_config, section_name, "express", false);
1267 + dbconn->is_connected = FALSE;
1268 +
1269 + netdata_mount_mssql_connection_string(dbconn);
1270 + }
1271 +}
1272 +
1273 +static inline struct netdata_mssql_conn *netdata_mssql_get_conn_option(const char *instance)
1274 +{
1275 + return (struct netdata_mssql_conn *)dictionary_get(conn_options, instance);
1276 +}
1277 +
1278 +void mssql_fill_initial_instances(struct mssql_instance *mi)
1279 +{
1280 + // https://learn.microsoft.com/en-us/sql/relational-databases/performance-monitor/sql-server-locks-object?view=sql-server-ver17
1281 + char *keys[] = {
1282 + "AllocUnit",
1283 + "Application",
1284 + "Database",
1285 + "Extent",
1286 + "File",
1287 + "HoBT",
1288 + "Key",
1289 + "Metadata",
1290 + "OIB",
1291 + "Object",
1292 + "Page",
1293 + "RID",
1294 + "RowGroup",
1295 + "Xact",
1296 + NULL};
1297 + for (int i = 0; keys[i]; i++) {
1298 + (void)dictionary_set(mi->locks_instances, keys[i], NULL, sizeof(struct mssql_lock_instance));
1299 + }
1300 +}
1301 +
1302 +void dict_mssql_insert_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
1303 +{
1304 + struct mssql_instance *mi = value;
1305 + const char *instance = dictionary_acquired_item_name((DICTIONARY_ITEM *)item);
1306 + bool *create_thread = data;
1307 +
1308 + if (unlikely(!mi->locks_instances)) {
1309 + mi->locks_instances = dictionary_create_advanced(
1310 + DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE, NULL, sizeof(struct mssql_lock_instance));
1311 + dictionary_register_insert_callback(mi->locks_instances, dict_mssql_insert_locks_cb, NULL);
1312 + mssql_fill_initial_instances(mi);
1313 + }
1314 +
1315 + if (unlikely(!mi->databases)) {
1316 + mi->databases = dictionary_create_advanced(
1317 + DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE, NULL, sizeof(struct mssql_db_instance));
1318 + dictionary_register_insert_callback(mi->databases, dict_mssql_insert_databases_cb, NULL);
1319 + }
1320 +
1321 + if (unlikely(!mi->publisher_publication)) {
1322 + mi->publisher_publication = dictionary_create_advanced(
1323 + DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE,
1324 + NULL,
1325 + sizeof(struct mssql_publisher_publication));
1326 + dictionary_register_insert_callback(mi->publisher_publication, dict_mssql_insert_replication_cb, NULL);
1327 + }
1328 +
1329 + if (unlikely(!mi->sysjobs)) {
1330 + mi->sysjobs = dictionary_create_advanced(
1331 + DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE, NULL, sizeof(struct mssql_db_jobs));
1332 + dictionary_register_insert_callback(mi->sysjobs, dict_mssql_insert_jobs_cb, NULL);
1333 + }
1334 +
1335 + if (unlikely(!mi->waits)) {
1336 + mi->waits = dictionary_create_advanced(
1337 + DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE, NULL, sizeof(struct mssql_db_waits));
1338 + dictionary_register_insert_callback(mi->waits, dict_mssql_insert_wait_cb, NULL);
1339 + }
1340 +
1341 + initialize_mssql_objects(mi, instance);
1342 + initialize_mssql_keys(mi);
1343 + mi->conn = netdata_mssql_get_conn_option(instance);
1344 +
1345 + if (likely(mi->conn && mi->conn->connectionString)) {
1346 + mi->conn->is_connected = netdata_MSSQL_initialize_connection(mi->conn);
1347 + if (mi->conn->is_connected)
1348 + *create_thread = true;
1349 + }
1350 +}
1351 +
1352 +void dict_mssql_insert_conn_option(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
1353 +{
1354 + ;
1355 +}
1356 +
1357 +static void mssql_fill_dictionary(int update_every)
1358 +{
1359 + HKEY hKey;
1360 + LSTATUS ret = RegOpenKeyExA(
1361 + HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Microsoft SQL Server\\Instance Names\\SQL", 0, KEY_READ, &hKey);
1362 + if (ret != ERROR_SUCCESS)
1363 + return;
1364 +
1365 + DWORD values = 0;
1366 +
1367 + ret = RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL, &values, NULL, NULL, NULL, NULL);
1368 + if (likely(ret != ERROR_SUCCESS)) {
1369 + goto endMSSQLFillDict;
1370 + }
1371 +
1372 + if (unlikely(!values)) {
1373 + ret = ERROR_PATH_NOT_FOUND;
1374 + goto endMSSQLFillDict;
1375 + }
1376 +
1377 +// https://learn.microsoft.com/en-us/windows/win32/sysinfo/enumerating-registry-subkeys
1378 +#define REGISTRY_MAX_VALUE 16383
1379 +
1380 + DWORD i;
1381 + char avalue[REGISTRY_MAX_VALUE] = {'\0'};
1382 + for (i = 0; i < values; i++) {
1383 + avalue[0] = '\0';
1384 + DWORD length = REGISTRY_MAX_VALUE;
1385 +
1386 + ret = RegEnumValue(hKey, i, avalue, &length, NULL, NULL, NULL, NULL);
1387 + if (likely(ret != ERROR_SUCCESS))
1388 + continue;
1389 +
1390 + struct mssql_instance *p = dictionary_set(mssql_instances, avalue, NULL, sizeof(*p));
1391 + p->update_every = update_every;
1392 + }
1393 +
1394 +endMSSQLFillDict:
1395 + RegCloseKey(hKey);
1396 +}
1397 +
1398 +int netdata_mssql_reset_value(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
1399 +{
1400 + struct mssql_db_instance *mdi = value;
1401 +
1402 + mdi->collecting_data = false;
1403 +
1404 + return 1;
1405 +}
1406 +
1407 +int dict_mssql_query_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
1408 +{
1409 + struct mssql_instance *mi = value;
1410 + static long collecting = 1;
1411 +
1412 + if (likely(mi->conn && mi->conn->is_connected && collecting)) {
1413 + collecting = metdata_mssql_check_permission(mi);
1414 + if (!collecting) {
1415 + nd_log(
1416 + NDLS_COLLECTORS,
1417 + NDLP_ERR,
1418 + "User %s does not have permission to run queries on %s",
1419 + mi->conn->username,
1420 + mi->instanceID);
1421 + } else {
1422 + metdata_mssql_fill_dictionary_from_db(mi);
1423 + metdata_mssql_fill_mssql_status(mi);
1424 + metdata_mssql_fill_job_status(mi);
1425 + dictionary_sorted_walkthrough_read(mi->databases, dict_mssql_databases_run_queries, NULL);
1426 + }
1427 +
1428 + collecting = dict_mssql_fill_waits(mi);
1429 + } else {
1430 + dictionary_sorted_walkthrough_read(mi->databases, netdata_mssql_reset_value, NULL);
1431 + }
1432 +
1433 + return 1;
1434 +}
1435 +
1436 +static void netdata_mssql_queries(void *ptr __maybe_unused)
1437 +{
1438 + heartbeat_t hb;
1439 + heartbeat_init(&hb, USEC_PER_SEC);
1440 + int update_every = UPDATE_EVERY_MIN;
1441 +
1442 + while (service_running(SERVICE_COLLECTORS)) {
1443 + (void)heartbeat_next(&hb);
1444 +
1445 + if (unlikely(!service_running(SERVICE_COLLECTORS)))
1446 + break;
1447 +
1448 + dictionary_sorted_walkthrough_read(mssql_instances, dict_mssql_query_cb, &update_every);
1449 + }
1450 +}
1451 +
1452 +static ND_THREAD *mssql_queries_thread = NULL;
1453 +
1454 +static int initialize(int update_every)
1455 +{
1456 + static bool create_thread = false;
1457 + mssql_instances = dictionary_create_advanced(
1458 + DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE, NULL, sizeof(struct mssql_instance));
1459 +
1460 + dictionary_register_insert_callback(mssql_instances, dict_mssql_insert_cb, &create_thread);
1461 +
1462 + conn_options = dictionary_create_advanced(
1463 + DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE, NULL, sizeof(struct netdata_mssql_conn));
1464 + dictionary_register_insert_callback(conn_options, dict_mssql_insert_conn_option, NULL);
1465 +
1466 + netdata_read_config_options();
1467 + mssql_fill_dictionary(update_every);
1468 +
1469 + if (likely(create_thread)) {
1470 + mssql_queries_thread =
1471 + nd_thread_create("mssql_queries", NETDATA_THREAD_OPTION_DEFAULT, netdata_mssql_queries, &update_every);
1472 + }
1473 +
1474 + return 0;
1475 +}
1476 +
1477 +void dict_mssql_locks_wait_charts(struct mssql_instance *mi, struct mssql_lock_instance *mli, const char *resource)
1478 +{
1479 + if (unlikely(!mli->st_lockWait)) {
1480 + char id[RRD_ID_LENGTH_MAX + 1];
1481 +
1482 + snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_resource_%s_lock_wait", mi->instanceID, resource);
1483 + netdata_fix_chart_name(id);
1484 + mli->st_lockWait = rrdset_create_localhost(
1485 + "mssql",
1486 + id,
1487 + NULL,
1488 + "locks",
1489 + "mssql.instance_resource_lock_waits",
1490 + "Lock requests that required the caller to wait per resource",
1491 + "locks/s",
1492 + PLUGIN_WINDOWS_NAME,
1493 + "PerflibMSSQL",
1494 + PRIO_MSSQL_LOCKS_WAIT,
1495 + mi->update_every,
1496 + RRDSET_TYPE_LINE);
1497 +
1498 + rrdlabels_add(mli->st_lockWait->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
1499 + rrdlabels_add(mli->st_lockWait->rrdlabels, "resource", resource, RRDLABEL_SRC_AUTO);
1500 + mli->rd_lockWait = rrddim_add(mli->st_lockWait, "locks", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1501 + }
1502 +
1503 + rrddim_set_by_pointer(mli->st_lockWait, mli->rd_lockWait, (collected_number)mli->lockWait.current.Data);
1504 + rrdset_done(mli->st_lockWait);
1505 +}
1506 +
1507 +void dict_mssql_dead_locks_charts(struct mssql_instance *mi, struct mssql_lock_instance *mli, const char *resource)
1508 +{
1509 + if (unlikely(!mli->st_deadLocks)) {
1510 + char id[RRD_ID_LENGTH_MAX + 1];
1511 +
1512 + snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_resource_%s_deadlocks", mi->instanceID, resource);
1513 + netdata_fix_chart_name(id);
1514 + mli->st_deadLocks = rrdset_create_localhost(
1515 + "mssql",
1516 + id,
1517 + NULL,
1518 + "locks",
1519 + "mssql.instance_resource_deadlocks",
1520 + "Active lock requests that resulted in deadlock per resource",
1521 + "deadlocks/s",
1522 + PLUGIN_WINDOWS_NAME,
1523 + "PerflibMSSQL",
1524 + PRIO_MSSQL_LOCKS_DEADLOCK_PER_RESOURCE,
1525 + mi->update_every,
1526 + RRDSET_TYPE_LINE);
1527 +
1528 + rrdlabels_add(mli->st_deadLocks->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
1529 + rrdlabels_add(mli->st_deadLocks->rrdlabels, "resource", resource, RRDLABEL_SRC_AUTO);
1530 + mli->rd_deadLocks = rrddim_add(mli->st_deadLocks, "deadlocks", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1531 + }
1532 +
1533 + rrddim_set_by_pointer(mli->st_deadLocks, mli->rd_deadLocks, (collected_number)mli->deadLocks.current.Data);
1534 + rrdset_done(mli->st_deadLocks);
1535 +}
1536 +
1537 +int dict_mssql_locks_charts_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
1538 +{
1539 + const char *dimension = dictionary_acquired_item_name((DICTIONARY_ITEM *)item);
1540 + struct mssql_lock_instance *mli = value;
1541 + struct mssql_instance *mi = data;
1542 +
1543 + dict_mssql_locks_wait_charts(mi, mli, dimension);
1544 + dict_mssql_dead_locks_charts(mi, mli, dimension);
1545 +
1546 + return 1;
1547 +}
1548 +
1549 +static void do_mssql_locks(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *mi, int update_every __maybe_unused)
1550 +{
1551 + if (unlikely(!pDataBlock))
1552 + goto end_mssql_locks;
1553 +
1554 + PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, mi->objectName[NETDATA_MSSQL_LOCKS]);
1555 + if (likely(pObjectType)) {
1556 + if (likely(pObjectType->NumInstances)) {
1557 + PERF_INSTANCE_DEFINITION *pi = NULL;
1558 + for (LONG i = 0; i < pObjectType->NumInstances; i++) {
1559 + pi = perflibForEachInstance(pDataBlock, pObjectType, pi);
1560 + if (unlikely(!pi))
1561 + break;
1562 +
1563 + if (unlikely(!getInstanceName(pDataBlock, pObjectType, pi, windows_shared_buffer, sizeof(windows_shared_buffer))))
1564 + strncpyz(windows_shared_buffer, "[unknown]", sizeof(windows_shared_buffer) - 1);
1565 +
1566 + if (unlikely(!strcasecmp(windows_shared_buffer, "_Total")))
1567 + continue;
1568 +
1569 + struct mssql_lock_instance *mli =
1570 + dictionary_set(mi->locks_instances, windows_shared_buffer, NULL, sizeof(*mli));
1571 + if (unlikely(!mli))
1572 + continue;
1573 +
1574 + perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &mli->deadLocks);
1575 + perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &mli->lockWait);
1576 + }
1577 + }
1578 + }
1579 +
1580 +end_mssql_locks:
1581 + dictionary_sorted_walkthrough_read(mi->locks_instances, dict_mssql_locks_charts_cb, mi);
1582 +}
1583 +
1584 +void mssql_total_wait_charts(struct mssql_instance *mi, struct mssql_db_waits *mdw, const char *type)
1585 +{
1586 + if (unlikely(!mdw->st_total_wait)) {
1587 + char id[RRD_ID_LENGTH_MAX + 1];
1588 +
1589 + snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_%s_total_wait", mi->instanceID, type);
1590 + netdata_fix_chart_name(id);
1591 + mdw->st_total_wait = rrdset_create_localhost(
1592 + "mssql",
1593 + id,
1594 + NULL,
1595 + "locks",
1596 + "mssql.instance_total_wait_time",
1597 + "Wait time for each wait type and category",
1598 + "ms",
1599 + PLUGIN_WINDOWS_NAME,
1600 + "PerflibMSSQL",
1601 + PRIO_MSSQL_WAITS_TOTAL,
1602 + mi->update_every,
1603 + RRDSET_TYPE_LINE);
1604 +
1605 + rrdlabels_add(mdw->st_total_wait->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
1606 + rrdlabels_add(mdw->st_total_wait->rrdlabels, "wait_type", mdw->wait_type, RRDLABEL_SRC_AUTO);
1607 + rrdlabels_add(mdw->st_total_wait->rrdlabels, "wait_category", mdw->wait_category, RRDLABEL_SRC_AUTO);
1608 + mdw->rd_total_wait = rrddim_add(mdw->st_total_wait, "duration", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1609 + }
1610 +
1611 + rrddim_set_by_pointer(
1612 + mdw->st_total_wait, mdw->rd_total_wait, (collected_number)mdw->MSSQLDatabaseTotalWait.current.Data);
1613 +
1614 + rrdset_done(mdw->st_total_wait);
1615 +}
1616 +
1617 +void mssql_resource_wait_charts(struct mssql_instance *mi, struct mssql_db_waits *mdw, const char *type)
1618 +{
1619 + if (unlikely(!mdw->st_resource_wait_msec)) {
1620 + char id[RRD_ID_LENGTH_MAX + 1];
1621 +
1622 + snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_%s_resource_wait", mi->instanceID, type);
1623 + netdata_fix_chart_name(id);
1624 + mdw->st_resource_wait_msec = rrdset_create_localhost(
1625 + "mssql",
1626 + id,
1627 + NULL,
1628 + "locks",
1629 + "mssql.instance_resource_wait_time",
1630 + "Wait time for threads waiting on specific resource types for each wait type and category",
1631 + "ms",
1632 + PLUGIN_WINDOWS_NAME,
1633 + "PerflibMSSQL",
1634 + PRIO_MSSQL_RESOURCE_WAIT,
1635 + mi->update_every,
1636 + RRDSET_TYPE_LINE);
1637 +
1638 + rrdlabels_add(mdw->st_resource_wait_msec->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
1639 + rrdlabels_add(mdw->st_resource_wait_msec->rrdlabels, "wait_type", mdw->wait_type, RRDLABEL_SRC_AUTO);
1640 + rrdlabels_add(mdw->st_resource_wait_msec->rrdlabels, "wait_category", mdw->wait_category, RRDLABEL_SRC_AUTO);
1641 + mdw->rd_resource_wait_msec =
1642 + rrddim_add(mdw->st_resource_wait_msec, "duration", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1643 + }
1644 +
1645 + rrddim_set_by_pointer(
1646 + mdw->st_resource_wait_msec,
1647 + mdw->rd_resource_wait_msec,
1648 + (collected_number)mdw->MSSQLDatabaseResourceWaitMSec.current.Data);
1649 +
1650 + rrdset_done(mdw->st_resource_wait_msec);
1651 +}
1652 +
1653 +void mssql_signal_wait_charts(struct mssql_instance *mi, struct mssql_db_waits *mdw, const char *type)
1654 +{
1655 + if (unlikely(!mdw->st_signal_wait_msec)) {
1656 + char id[RRD_ID_LENGTH_MAX + 1];
1657 +
1658 + snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_%s_signal_wait", mi->instanceID, type);
1659 + netdata_fix_chart_name(id);
1660 + mdw->st_signal_wait_msec = rrdset_create_localhost(
1661 + "mssql",
1662 + id,
1663 + NULL,
1664 + "locks",
1665 + "mssql.instance_signal_wait_time",
1666 + "Delay between thread wakeup signal and actual execution start for each wait type and category",
1667 + "ms",
1668 + PLUGIN_WINDOWS_NAME,
1669 + "PerflibMSSQL",
1670 + PRIO_MSSQL_SIGNAL_WAIT,
1671 + mi->update_every,
1672 + RRDSET_TYPE_LINE);
1673 +
1674 + rrdlabels_add(mdw->st_signal_wait_msec->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
1675 + rrdlabels_add(mdw->st_signal_wait_msec->rrdlabels, "wait_type", mdw->wait_type, RRDLABEL_SRC_AUTO);
1676 + rrdlabels_add(mdw->st_signal_wait_msec->rrdlabels, "wait_category", mdw->wait_category, RRDLABEL_SRC_AUTO);
1677 + mdw->rd_signal_wait_msec =
1678 + rrddim_add(mdw->st_signal_wait_msec, "duration", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1679 + }
1680 +
1681 + rrddim_set_by_pointer(
1682 + mdw->st_signal_wait_msec,
1683 + mdw->rd_signal_wait_msec,
1684 + (collected_number)mdw->MSSQLDatabaseSignalWaitMSec.current.Data);
1685 +
1686 + rrdset_done(mdw->st_signal_wait_msec);
1687 +}
1688 +
1689 +void mssql_max_wait_charts(struct mssql_instance *mi, struct mssql_db_waits *mdw, const char *type)
1690 +{
1691 + if (unlikely(!mdw->st_max_wait_time_msec)) {
1692 + char id[RRD_ID_LENGTH_MAX + 1];
1693 +
1694 + snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_%s_max_wait", mi->instanceID, type);
1695 + netdata_fix_chart_name(id);
1696 + mdw->st_max_wait_time_msec = rrdset_create_localhost(
1697 + "mssql",
1698 + id,
1699 + NULL,
1700 + "locks",
1701 + "mssql.instance_max_wait_time",
1702 + "Maximum wait time for each wait type and category",
1703 + "ms",
1704 + PLUGIN_WINDOWS_NAME,
1705 + "PerflibMSSQL",
1706 + PRIO_MSSQL_MAX_WAIT_TIME,
1707 + mi->update_every,
1708 + RRDSET_TYPE_LINE);
1709 +
1710 + rrdlabels_add(mdw->st_max_wait_time_msec->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
1711 + rrdlabels_add(mdw->st_max_wait_time_msec->rrdlabels, "wait_type", mdw->wait_type, RRDLABEL_SRC_AUTO);
1712 + rrdlabels_add(mdw->st_max_wait_time_msec->rrdlabels, "wait_category", mdw->wait_category, RRDLABEL_SRC_AUTO);
1713 + mdw->rd_max_wait_time_msec =
1714 + rrddim_add(mdw->st_max_wait_time_msec, "duration", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1715 + }
1716 +
1717 + rrddim_set_by_pointer(
1718 + mdw->st_max_wait_time_msec,
1719 + mdw->rd_max_wait_time_msec,
1720 + (collected_number)mdw->MSSQLDatabaseMaxWaitTimeMSec.current.Data);
1721 +
1722 + rrdset_done(mdw->st_max_wait_time_msec);
1723 +}
1724 +
1725 +void mssql_waiting_count_charts(struct mssql_instance *mi, struct mssql_db_waits *mdw, const char *type)
1726 +{
1727 + if (unlikely(!mdw->st_waiting_tasks)) {
1728 + char id[RRD_ID_LENGTH_MAX + 1];
1729 +
1730 + snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_%s_waiting_count", mi->instanceID, type);
1731 + netdata_fix_chart_name(id);
1732 + mdw->st_waiting_tasks = rrdset_create_localhost(
1733 + "mssql",
1734 + id,
1735 + NULL,
1736 + "locks",
1737 + "mssql.instance_waits",
1738 + "Number of waits for each wait type and category",
1739 + "waits/s",
1740 + PLUGIN_WINDOWS_NAME,
1741 + "PerflibMSSQL",
1742 + PRIO_MSSQL_WAITING_COUNT,
1743 + mi->update_every,
1744 + RRDSET_TYPE_LINE);
1745 +
1746 + rrdlabels_add(mdw->st_waiting_tasks->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
1747 + rrdlabels_add(mdw->st_waiting_tasks->rrdlabels, "wait_type", mdw->wait_type, RRDLABEL_SRC_AUTO);
1748 + rrdlabels_add(mdw->st_waiting_tasks->rrdlabels, "wait_category", mdw->wait_category, RRDLABEL_SRC_AUTO);
1749 + mdw->rd_waiting_tasks = rrddim_add(mdw->st_waiting_tasks, "waits", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1750 + }
1751 +
1752 + rrddim_set_by_pointer(
1753 + mdw->st_waiting_tasks, mdw->rd_waiting_tasks, (collected_number)mdw->MSSQLDatabaseWaitingTasks.current.Data);
1754 +
1755 + rrdset_done(mdw->st_waiting_tasks);
1756 +}
1757 +
1758 +int dict_mssql_waits_charts_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
1759 +{
1760 + const char *dimension = dictionary_acquired_item_name((DICTIONARY_ITEM *)item);
1761 + struct mssql_db_waits *mdw = value;
1762 + struct mssql_instance *mi = data;
1763 +
1764 + mssql_total_wait_charts(mi, mdw, dimension);
1765 + mssql_resource_wait_charts(mi, mdw, dimension);
1766 + mssql_signal_wait_charts(mi, mdw, dimension);
1767 + mssql_max_wait_charts(mi, mdw, dimension);
1768 + mssql_waiting_count_charts(mi, mdw, dimension);
1769 +
1770 + return 1;
1771 +}
1772 +
1773 +static void do_mssql_waits(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *mi, int update_every)
1774 +{
1775 + dictionary_sorted_walkthrough_read(mi->waits, dict_mssql_waits_charts_cb, mi);
1776 +}
1777 +
1778 +void mssql_buffman_iops_chart(struct mssql_db_instance *mdi, struct mssql_instance *mi)
1779 +{
1780 + if (unlikely(!mdi->st_buff_page_iops)) {
1781 + char id[RRD_ID_LENGTH_MAX + 1];
1782 + snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_bufman_iops", mi->instanceID);
1783 + netdata_fix_chart_name(id);
1784 + mdi->st_buff_page_iops = rrdset_create_localhost(
1785 + "mssql",
1786 + id,
1787 + NULL,
1788 + "buffer cache",
1789 + "mssql.instance_bufman_iops",
1790 + "Number of pages input and output",
1791 + "pages/s",
1792 + PLUGIN_WINDOWS_NAME,
1793 + "PerflibMSSQL",
1794 + PRIO_MSSQL_BUFF_MAN_IOPS,
1795 + mi->update_every,
1796 + RRDSET_TYPE_LINE);
1797 +
1798 + mdi->rd_buff_page_reads = rrddim_add(mdi->st_buff_page_iops, "read", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1799 + mdi->rd_buff_page_writes =
1800 + rrddim_add(mdi->st_buff_page_iops, "written", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
1801 +
1802 + rrdlabels_add(mdi->st_buff_page_iops->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
1803 + }
1804 +
1805 + rrddim_set_by_pointer(
1806 + mdi->st_buff_page_iops, mdi->rd_buff_page_reads, (collected_number)mdi->MSSQLBufferPageReads.current.Data);
1807 + rrddim_set_by_pointer(
1808 + mdi->st_buff_page_iops, mdi->rd_buff_page_writes, (collected_number)mdi->MSSQLBufferPageWrites.current.Data);
1809 +
1810 + rrdset_done(mdi->st_buff_page_iops);
1811 +}
1812 +
1813 +void mssql_buffman_cache_hit_ratio_chart(struct mssql_db_instance *mdi, struct mssql_instance *mi)
1814 +{
1815 + if (unlikely(!mdi->st_buff_cache_hits)) {
1816 + char id[RRD_ID_LENGTH_MAX + 1];
1817 + snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_cache_hit_ratio", mi->instanceID);
1818 + netdata_fix_chart_name(id);
1819 + mdi->st_buff_cache_hits = rrdset_create_localhost(
1820 + "mssql",
1821 + id,
1822 + NULL,
1823 + "buffer cache",
1824 + "mssql.instance_cache_hit_ratio",
1825 + "Buffer Cache hit ratio",
1826 + "percentage",
1827 + PLUGIN_WINDOWS_NAME,
1828 + "PerflibMSSQL",
1829 + PRIO_MSSQL_BUFF_CACHE_HIT_RATIO,
1830 + mi->update_every,
1831 + RRDSET_TYPE_LINE);
1832 +
1833 + mdi->rd_buff_cache_hits = rrddim_add(mdi->st_buff_cache_hits, "hit_ratio", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
1834 +
1835 + rrdlabels_add(mdi->st_buff_cache_hits->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
1836 + }
1837 +
1838 + rrddim_set_by_pointer(
1839 + mdi->st_buff_cache_hits, mdi->rd_buff_cache_hits, (collected_number)mdi->MSSQLBufferCacheHits.current.Data);
1840 + rrdset_done(mdi->st_buff_cache_hits);
1841 +}
1842 +
1843 +void mssql_buffman_checkpoints_pages_chart(struct mssql_db_instance *mdi, struct mssql_instance *mi)
1844 +{
1845 + if (unlikely(!mdi->st_buff_checkpoint_pages)) {
1846 + char id[RRD_ID_LENGTH_MAX + 1];
1847 + snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_bufman_checkpoint_pages", mi->instanceID);
1848 + netdata_fix_chart_name(id);
1849 + mdi->st_buff_checkpoint_pages = rrdset_create_localhost(
1850 + "mssql",
1851 + id,
1852 + NULL,
1853 + "buffer cache",
1854 + "mssql.instance_bufman_checkpoint_pages",
1855 + "Flushed pages",
1856 + "pages/s",
1857 + PLUGIN_WINDOWS_NAME,
1858 + "PerflibMSSQL",
1859 + PRIO_MSSQL_BUFF_CHECKPOINT_PAGES,
1860 + mi->update_every,
1861 + RRDSET_TYPE_LINE);
1862 +
1863 + mdi->rd_buff_checkpoint_pages =
1864 + rrddim_add(mdi->st_buff_checkpoint_pages, "log", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1865 +
1866 + rrdlabels_add(mdi->st_buff_checkpoint_pages->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
1867 + }
1868 +
1869 + rrddim_set_by_pointer(
1870 + mdi->st_buff_checkpoint_pages,
1871 + mdi->rd_buff_checkpoint_pages,
1872 + (collected_number)mdi->MSSQLBufferCheckpointPages.current.Data);
1873 + rrdset_done(mdi->st_buff_checkpoint_pages);
1874 +}
1875 +
1876 +void mssql_buffman_page_life_expectancy_chart(struct mssql_db_instance *mdi, struct mssql_instance *mi)
1877 +{
1878 + if (unlikely(!mdi->st_buff_cache_page_life_expectancy)) {
1879 + char id[RRD_ID_LENGTH_MAX + 1];
1880 + snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_bufman_page_life_expectancy", mi->instanceID);
1881 + netdata_fix_chart_name(id);
1882 + mdi->st_buff_cache_page_life_expectancy = rrdset_create_localhost(
1883 + "mssql",
1884 + id,
1885 + NULL,
1886 + "buffer cache",
1887 + "mssql.instance_bufman_page_life_expectancy",
1888 + "Page life expectancy",
1889 + "seconds",
1890 + PLUGIN_WINDOWS_NAME,
1891 + "PerflibMSSQL",
1892 + PRIO_MSSQL_BUFF_PAGE_LIFE_EXPECTANCY,
1893 + mi->update_every,
1894 + RRDSET_TYPE_LINE);
1895 +
1896 + mdi->rd_buff_cache_page_life_expectancy =
1897 + rrddim_add(mdi->st_buff_cache_page_life_expectancy, "life_expectancy", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
1898 +
1899 + rrdlabels_add(
1900 + mdi->st_buff_cache_page_life_expectancy->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
1901 + }
1902 +
1903 + rrddim_set_by_pointer(
1904 + mdi->st_buff_cache_page_life_expectancy,
1905 + mdi->rd_buff_cache_page_life_expectancy,
1906 + (collected_number)mdi->MSSQLBufferPageLifeExpectancy.current.Data);
1907 + rrdset_done(mdi->st_buff_cache_page_life_expectancy);
1908 +}
1909 +
1910 +void mssql_buffman_lazy_write_chart(struct mssql_db_instance *mdi, struct mssql_instance *mi)
1911 +{
1912 + if (unlikely(!mdi->st_buff_lazy_write)) {
1913 + char id[RRD_ID_LENGTH_MAX + 1];
1914 + snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_bufman_lazy_write", mi->instanceID);
1915 + netdata_fix_chart_name(id);
1916 + mdi->st_buff_lazy_write = rrdset_create_localhost(
1917 + "mssql",
1918 + id,
1919 + NULL,
1920 + "buffer cache",
1921 + "mssql.instance_bufman_lazy_write",
1922 + "Buffers written by buffer manager's lazy writer",
1923 + "writes/s",
1924 + PLUGIN_WINDOWS_NAME,
1925 + "PerflibMSSQL",
1926 + PRIO_MSSQL_BUFF_LAZY_WRITE,
1927 + mi->update_every,
1928 + RRDSET_TYPE_LINE);
1929 +
1930 + mdi->rd_buff_lazy_write = rrddim_add(mdi->st_buff_lazy_write, "writes", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1931 +
1932 + rrdlabels_add(mdi->st_buff_lazy_write->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
1933 + }
1934 +
1935 + rrddim_set_by_pointer(
1936 + mdi->st_buff_lazy_write, mdi->rd_buff_lazy_write, (collected_number)mdi->MSSQLBufferLazyWrite.current.Data);
1937 + rrdset_done(mdi->st_buff_lazy_write);
1938 +}
1939 +
1940 +void mssql_buffman_page_lookups_chart(struct mssql_db_instance *mdi, struct mssql_instance *mi)
1941 +{
1942 + if (unlikely(!mdi->st_buff_page_lookups)) {
1943 + char id[RRD_ID_LENGTH_MAX + 1];
1944 + snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_bufman_page_lookups", mi->instanceID);
1945 + netdata_fix_chart_name(id);
1946 + mdi->st_buff_page_lookups = rrdset_create_localhost(
1947 + "mssql",
1948 + id,
1949 + NULL,
1950 + "buffer cache",
1951 + "mssql.instance_bufman_page_lookups",
1952 + "Requests to find a page in the buffer pool.",
1953 + "lookups/s",
1954 + PLUGIN_WINDOWS_NAME,
1955 + "PerflibMSSQL",
1956 + PRIO_MSSQL_BUFF_PAGE_LOOKUPS,
1957 + mi->update_every,
1958 + RRDSET_TYPE_LINE);
1959 +
1960 + mdi->rd_buff_page_lookups =
1961 + rrddim_add(mdi->st_buff_page_lookups, "lookups", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1962 +
1963 + rrdlabels_add(mdi->st_buff_page_lookups->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
1964 + }
1965 +
1966 + rrddim_set_by_pointer(
1967 + mdi->st_buff_page_lookups,
1968 + mdi->rd_buff_page_lookups,
1969 + (collected_number)mdi->MSSQLBufferPageLookups.current.Data);
1970 + rrdset_done(mdi->st_buff_page_lookups);
1971 +}
1972 +
1973 +static void netdata_mssql_compilations(struct mssql_db_instance *mdi, struct mssql_instance *mi)
1974 +{
1975 + if (unlikely(!mdi->st_stats_compilation)) {
1976 + char id[RRD_ID_LENGTH_MAX + 1];
1977 + snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_sqlstats_sql_compilations", mi->instanceID);
1978 + netdata_fix_chart_name(id);
1979 + mdi->st_stats_compilation = rrdset_create_localhost(
1980 + "mssql",
1981 + id,
1982 + NULL,
1983 + "sql activity",
1984 + "mssql.instance_sqlstats_sql_compilations",
1985 + "SQL compilations",
1986 + "compilations/s",
1987 + PLUGIN_WINDOWS_NAME,
1988 + "PerflibMSSQL",
1989 + PRIO_MSSQL_STATS_COMPILATIONS,
1990 + mi->update_every,
1991 + RRDSET_TYPE_LINE);
1992 +
1993 + mdi->rd_stats_compilation =
1994 + rrddim_add(mdi->st_stats_compilation, "compilations", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1995 +
1996 + rrdlabels_add(mdi->st_stats_compilation->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
1997 + }
1998 +
1999 + rrddim_set_by_pointer(
2000 + mdi->st_stats_compilation, mdi->rd_stats_compilation, (collected_number)mdi->MSSQLCompilations.current.Data);
2001 + rrdset_done(mdi->st_stats_compilation);
2002 +}
2003 +
2004 +static void netdata_mssql_recompilations(struct mssql_db_instance *mdi, struct mssql_instance *mi)
2005 +{
2006 + if (unlikely(!mdi->st_stats_recompiles)) {
2007 + char id[RRD_ID_LENGTH_MAX + 1];
2008 + snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_sqlstats_sql_recompilations", mi->instanceID);
2009 + netdata_fix_chart_name(id);
2010 + mdi->st_stats_recompiles = rrdset_create_localhost(
2011 + "mssql",
2012 + id,
2013 + NULL,
2014 + "sql activity",
2015 + "mssql.instance_sqlstats_sql_recompilations",
2016 + "SQL re-compilations",
2017 + "recompiles/s",
2018 + PLUGIN_WINDOWS_NAME,
2019 + "PerflibMSSQL",
2020 + PRIO_MSSQL_STATS_RECOMPILATIONS,
2021 + mi->update_every,
2022 + RRDSET_TYPE_LINE);
2023 +
2024 + mdi->rd_stats_recompiles =
2025 + rrddim_add(mdi->st_stats_recompiles, "recompiles", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
2026 +
2027 + rrdlabels_add(mdi->st_stats_recompiles->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
2028 + }
2029 +
2030 + rrddim_set_by_pointer(
2031 + mdi->st_stats_recompiles, mdi->rd_stats_recompiles, (collected_number)mdi->MSSQLRecompilations.current.Data);
2032 + rrdset_done(mdi->st_stats_recompiles);
2033 +}
2034 +
2035 +int dict_mssql_buffman_stats_charts_cb(
2036 + const DICTIONARY_ITEM *item __maybe_unused,
2037 + void *value,
2038 + void *data __maybe_unused)
2039 +{
2040 + struct mssql_db_instance *mdi = value;
2041 + struct mssql_instance *mi = data;
2042 +
2043 + if (unlikely(!mdi->collect_instance))
2044 + return 1;
2045 +
2046 + mssql_buffman_iops_chart(mdi, mi);
2047 + mssql_buffman_cache_hit_ratio_chart(mdi, mi);
2048 + mssql_buffman_checkpoints_pages_chart(mdi, mi);
2049 + mssql_buffman_page_life_expectancy_chart(mdi, mi);
2050 + mssql_buffman_lazy_write_chart(mdi, mi);
2051 + mssql_buffman_page_lookups_chart(mdi, mi);
2052 +
2053 + netdata_mssql_compilations(mdi, mi);
2054 + netdata_mssql_recompilations(mdi, mi);
2055 +
2056 + return 1;
2057 +}
2058 +
2059 +static void do_mssql_bufferman_stats_sql(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *mi, int update_every)
2060 +{
2061 + dictionary_sorted_walkthrough_read(mi->databases, dict_mssql_buffman_stats_charts_cb, mi);
2062 +}
2063 +
2064 +static void netdata_mssql_jobs_status(struct mssql_db_jobs *mdj, struct mssql_instance *mi, const char *job)
2065 +{
2066 + if (unlikely(!mdj->st_status)) {
2067 + char id[RRD_ID_LENGTH_MAX + 1];
2068 + snprintfz(id, RRD_ID_LENGTH_MAX, "job_%s_instance_%s_status", job, mi->instanceID);
2069 + netdata_fix_chart_name(id);
2070 + mdj->st_status = rrdset_create_localhost(
2071 + "mssql",
2072 + id,
2073 + NULL,
2074 + "jobs",
2075 + "mssql.instance_jobs_status",
2076 + "Jobs running",
2077 + "status",
2078 + PLUGIN_WINDOWS_NAME,
2079 + "PerflibMSSQL",
2080 + PRIO_MSSQL_DATABASE_JOBS_STATUS,
2081 + mi->update_every,
2082 + RRDSET_TYPE_LINE);
2083 +
2084 + mdj->rd_status_enabled = rrddim_add(mdj->st_status, "enabled", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2085 +
2086 + mdj->rd_status_disabled = rrddim_add(mdj->st_status, "disabled", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2087 +
2088 + rrdlabels_add(mdj->st_status->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
2089 + rrdlabels_add(mdj->st_status->rrdlabels, "job_name", job, RRDLABEL_SRC_AUTO);
2090 + }
2091 +
2092 + rrddim_set_by_pointer(
2093 + mdj->st_status, mdj->rd_status_enabled, (collected_number)(mdj->MSSQLJOBState.current.Data == 1));
2094 + rrddim_set_by_pointer(
2095 + mdj->st_status, mdj->rd_status_disabled, (collected_number)(mdj->MSSQLJOBState.current.Data == 0));
2096 + rrdset_done(mdj->st_status);
2097 +}
2098 +
2099 +int dict_mssql_sysjobs_chart_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
2100 +{
2101 + const char *job = dictionary_acquired_item_name((DICTIONARY_ITEM *)item);
2102 + struct mssql_db_jobs *mdj = value;
2103 + struct mssql_instance *mi = data;
2104 +
2105 + netdata_mssql_jobs_status(mdj, mi, job);
2106 +}
2107 +
2108 +static void do_mssql_job_status_sql(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *mi, int update_every)
2109 +{
2110 + dictionary_sorted_walkthrough_read(mi->sysjobs, dict_mssql_sysjobs_chart_cb, mi);
2111 +}
2112 +
2113 +void dict_mssql_replication_status(struct mssql_publisher_publication *mpp, int update_every)
2114 +{
2115 + if (unlikely(!mpp->st_publisher_status)) {
2116 + char id[RRD_ID_LENGTH_MAX + 1];
2117 +
2118 + snprintfz(
2119 + id,
2120 + RRD_ID_LENGTH_MAX,
2121 + "instance_%s_replication_%s_%s_status",
2122 + mpp->parent->instanceID,
2123 + mpp->publication,
2124 + mpp->db);
2125 + netdata_fix_chart_name(id);
2126 + mpp->st_publisher_status = rrdset_create_localhost(
2127 + "mssql",
2128 + id,
2129 + NULL,
2130 + "replication",
2131 + "mssql.replication_status",
2132 + "Current replication status",
2133 + "status",
2134 + PLUGIN_WINDOWS_NAME,
2135 + "PerflibMSSQL",
2136 + PRIO_MSSQL_REPLICATION_STATUS,
2137 + update_every,
2138 + RRDSET_TYPE_LINE);
2139 +
2140 + rrdlabels_add(
2141 + mpp->st_publisher_status->rrdlabels, "mssql_instance", mpp->parent->instanceID, RRDLABEL_SRC_AUTO);
2142 + rrdlabels_add(mpp->st_publisher_status->rrdlabels, "publisher", mpp->publisher, RRDLABEL_SRC_AUTO);
2143 + rrdlabels_add(mpp->st_publisher_status->rrdlabels, "database", mpp->db, RRDLABEL_SRC_AUTO);
2144 + rrdlabels_add(mpp->st_publisher_status->rrdlabels, "publication", mpp->publication, RRDLABEL_SRC_AUTO);
2145 +
2146 + mpp->rd_publisher_status_started =
2147 + rrddim_add(mpp->st_publisher_status, "started", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2148 + mpp->rd_publisher_status_successed =
2149 + rrddim_add(mpp->st_publisher_status, "succeeded", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2150 + mpp->rd_publisher_status_in_progress =
2151 + rrddim_add(mpp->st_publisher_status, "in_progress", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2152 + mpp->rd_publisher_status_idle =
2153 + rrddim_add(mpp->st_publisher_status, "idle", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2154 + mpp->rd_publisher_status_retrying =
2155 + rrddim_add(mpp->st_publisher_status, "retrying", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2156 + mpp->rd_publisher_status_failed =
2157 + rrddim_add(mpp->st_publisher_status, "failed", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2158 + }
2159 +
2160 + int status = mpp->status;
2161 + rrddim_set_by_pointer(mpp->st_publisher_status, mpp->rd_publisher_status_started, (collected_number)(status == 1));
2162 + rrddim_set_by_pointer(
2163 + mpp->st_publisher_status, mpp->rd_publisher_status_successed, (collected_number)(status == 2));
2164 + rrddim_set_by_pointer(
2165 + mpp->st_publisher_status, mpp->rd_publisher_status_in_progress, (collected_number)(status == 3));
2166 + rrddim_set_by_pointer(mpp->st_publisher_status, mpp->rd_publisher_status_idle, (collected_number)(status == 4));
2167 + rrddim_set_by_pointer(mpp->st_publisher_status, mpp->rd_publisher_status_retrying, (collected_number)(status == 5));
2168 + rrddim_set_by_pointer(mpp->st_publisher_status, mpp->rd_publisher_status_failed, (collected_number)(status == 6));
2169 + rrdset_done(mpp->st_publisher_status);
2170 +}
2171 +
2172 +void dict_mssql_replication_warning(struct mssql_publisher_publication *mpp, int update_every)
2173 +{
2174 + if (unlikely(!mpp->st_warning)) {
2175 + char id[RRD_ID_LENGTH_MAX + 1];
2176 +
2177 + snprintfz(
2178 + id,
2179 + RRD_ID_LENGTH_MAX,
2180 + "instance_%s_replication_%s_%s_warning",
2181 + mpp->parent->instanceID,
2182 + mpp->publication,
2183 + mpp->db);
2184 + netdata_fix_chart_name(id);
2185 + mpp->st_warning = rrdset_create_localhost(
2186 + "mssql",
2187 + id,
2188 + NULL,
2189 + "replication",
2190 + "mssql.replication_warning",
2191 + "Maximum threshold warning.",
2192 + "status",
2193 + PLUGIN_WINDOWS_NAME,
2194 + "PerflibMSSQL",
2195 + PRIO_MSSQL_REPLICATION_WARNING,
2196 + update_every,
2197 + RRDSET_TYPE_LINE);
2198 +
2199 + rrdlabels_add(mpp->st_warning->rrdlabels, "mssql_instance", mpp->parent->instanceID, RRDLABEL_SRC_AUTO);
2200 + rrdlabels_add(mpp->st_warning->rrdlabels, "publisher", mpp->publisher, RRDLABEL_SRC_AUTO);
2201 + rrdlabels_add(mpp->st_warning->rrdlabels, "database", mpp->db, RRDLABEL_SRC_AUTO);
2202 + rrdlabels_add(mpp->st_warning->rrdlabels, "publication", mpp->publication, RRDLABEL_SRC_AUTO);
2203 +
2204 + mpp->rd_warning_expiration = rrddim_add(mpp->st_warning, "expiration", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2205 + mpp->rd_warning_latency = rrddim_add(mpp->st_warning, "latency", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2206 + mpp->rd_warning_mergeeexpiration =
2207 + rrddim_add(mpp->st_warning, "merge expiration", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2208 + mpp->rd_warning_mergefastduration =
2209 + rrddim_add(mpp->st_warning, "fast duration", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2210 + mpp->rd_warning_mergelowduration =
2211 + rrddim_add(mpp->st_warning, "low duration", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2212 + mpp->rd_warning_mergefastrunspeed =
2213 + rrddim_add(mpp->st_warning, "fast run speed", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2214 + mpp->rd_warning_mergelowrunspeed =
2215 + rrddim_add(mpp->st_warning, "low run speed", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2216 + }
2217 +
2218 + int warning = mpp->warning;
2219 + rrddim_set_by_pointer(
2220 + mpp->st_warning, mpp->rd_warning_expiration, (collected_number)(warning & MSSQL_REPLICATON_EXPIRATION));
2221 + rrddim_set_by_pointer(
2222 + mpp->st_warning, mpp->rd_warning_latency, (collected_number)(warning & MSSQL_REPLICATON_LATENCY));
2223 + rrddim_set_by_pointer(
2224 + mpp->st_warning,
2225 + mpp->rd_warning_mergeeexpiration,
2226 + (collected_number)(warning & MSSQL_REPLICATON_MERGEEXPIRATION));
2227 + rrddim_set_by_pointer(
2228 + mpp->st_warning,
2229 + mpp->rd_warning_mergefastduration,
2230 + (collected_number)(warning & MSSQL_REPLICATON_MERGEFASTDURATION));
2231 + rrddim_set_by_pointer(
2232 + mpp->st_warning,
2233 + mpp->rd_warning_mergelowduration,
2234 + (collected_number)(warning & MSSQL_REPLICATON_MERGELOWDURATION));
2235 + rrddim_set_by_pointer(
2236 + mpp->st_warning,
2237 + mpp->rd_warning_mergefastrunspeed,
2238 + (collected_number)(warning & MSSQL_REPLICATON_MERGEFASTRUNSPEED));
2239 + rrddim_set_by_pointer(
2240 + mpp->st_warning,
2241 + mpp->rd_warning_mergelowrunspeed,
2242 + (collected_number)(warning & MSSQL_REPLICATON_MERGELOWRUNSPEED));
2243 + rrdset_done(mpp->st_warning);
2244 +}
2245 +
2246 +void dict_mssql_replication_avg_latency(struct mssql_publisher_publication *mpp, int update_every)
2247 +{
2248 + if (unlikely(!mpp->st_avg_latency)) {
2249 + char id[RRD_ID_LENGTH_MAX + 1];
2250 +
2251 + snprintfz(
2252 + id,
2253 + RRD_ID_LENGTH_MAX,
2254 + "instance_%s_replication_%s_%s_avg_latency",
2255 + mpp->parent->instanceID,
2256 + mpp->publication,
2257 + mpp->db);
2258 + netdata_fix_chart_name(id);
2259 + mpp->st_avg_latency = rrdset_create_localhost(
2260 + "mssql",
2261 + id,
2262 + NULL,
2263 + "replication",
2264 + "mssql.replication_avg_latency",
2265 + "Average latency for a transactional publication.",
2266 + "seconds",
2267 + PLUGIN_WINDOWS_NAME,
2268 + "PerflibMSSQL",
2269 + PRIO_MSSQL_REPLICATION_AVG_LATENCY,
2270 + update_every,
2271 + RRDSET_TYPE_LINE);
2272 +
2273 + rrdlabels_add(mpp->st_avg_latency->rrdlabels, "mssql_instance", mpp->parent->instanceID, RRDLABEL_SRC_AUTO);
2274 + rrdlabels_add(mpp->st_avg_latency->rrdlabels, "publisher", mpp->publisher, RRDLABEL_SRC_AUTO);
2275 + rrdlabels_add(mpp->st_avg_latency->rrdlabels, "database", mpp->db, RRDLABEL_SRC_AUTO);
2276 + rrdlabels_add(mpp->st_avg_latency->rrdlabels, "publication", mpp->publication, RRDLABEL_SRC_AUTO);
2277 +
2278 + mpp->rd_avg_latency = rrddim_add(mpp->st_avg_latency, "latency", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2279 + }
2280 +
2281 + rrddim_set_by_pointer(mpp->st_avg_latency, mpp->rd_avg_latency, (collected_number)mpp->avg_latency);
2282 + rrdset_done(mpp->st_avg_latency);
2283 +}
2284 +
2285 +void dict_mssql_replication_subscription(struct mssql_publisher_publication *mpp, int update_every)
2286 +{
2287 + if (unlikely(!mpp->st_subscription_count)) {
2288 + char id[RRD_ID_LENGTH_MAX + 1];
2289 +
2290 + snprintfz(
2291 + id,
2292 + RRD_ID_LENGTH_MAX,
2293 + "instance_%s_replication_%s_%s_subscription",
2294 + mpp->parent->instanceID,
2295 + mpp->publication,
2296 + mpp->db);
2297 + netdata_fix_chart_name(id);
2298 + mpp->st_subscription_count = rrdset_create_localhost(
2299 + "mssql",
2300 + id,
2301 + NULL,
2302 + "replication",
2303 + "mssql.replication_subscription",
2304 + "Number of subscriptions to a publication.",
2305 + "subscription",
2306 + PLUGIN_WINDOWS_NAME,
2307 + "PerflibMSSQL",
2308 + PRIO_MSSQL_REPLICATION_SUBSCRIPTION_COUNT,
2309 + update_every,
2310 + RRDSET_TYPE_LINE);
2311 +
2312 + rrdlabels_add(
2313 + mpp->st_subscription_count->rrdlabels, "mssql_instance", mpp->parent->instanceID, RRDLABEL_SRC_AUTO);
2314 + rrdlabels_add(mpp->st_subscription_count->rrdlabels, "publisher", mpp->publisher, RRDLABEL_SRC_AUTO);
2315 + rrdlabels_add(mpp->st_subscription_count->rrdlabels, "database", mpp->db, RRDLABEL_SRC_AUTO);
2316 + rrdlabels_add(mpp->st_subscription_count->rrdlabels, "publication", mpp->publication, RRDLABEL_SRC_AUTO);
2317 +
2318 + mpp->rd_subscription_count =
2319 + rrddim_add(mpp->st_subscription_count, "subscription", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2320 + }
2321 +
2322 + rrddim_set_by_pointer(
2323 + mpp->st_subscription_count, mpp->rd_subscription_count, (collected_number)mpp->subscriptioncount);
2324 + rrdset_done(mpp->st_subscription_count);
2325 +}
2326 +
2327 +void dict_mssql_replication_dist_agent_running(struct mssql_publisher_publication *mpp, int update_every)
2328 +{
2329 + if (unlikely(!mpp->st_running_agent)) {
2330 + char id[RRD_ID_LENGTH_MAX + 1];
2331 +
2332 + snprintfz(
2333 + id,
2334 + RRD_ID_LENGTH_MAX,
2335 + "instance_%s_replication_%s_%s_agent_running",
2336 + mpp->parent->instanceID,
2337 + mpp->publication,
2338 + mpp->db);
2339 + netdata_fix_chart_name(id);
2340 + mpp->st_running_agent = rrdset_create_localhost(
2341 + "mssql",
2342 + id,
2343 + NULL,
2344 + "replication",
2345 + "mssql.replication_agent_running",
2346 + "Distribution agents running.",
2347 + "agents",
2348 + PLUGIN_WINDOWS_NAME,
2349 + "PerflibMSSQL",
2350 + PRIO_MSSQL_REPLICATION_AGENT_RUNNING,
2351 + update_every,
2352 + RRDSET_TYPE_LINE);
2353 +
2354 + rrdlabels_add(mpp->st_running_agent->rrdlabels, "mssql_instance", mpp->parent->instanceID, RRDLABEL_SRC_AUTO);
2355 + rrdlabels_add(mpp->st_running_agent->rrdlabels, "publisher", mpp->publisher, RRDLABEL_SRC_AUTO);
2356 + rrdlabels_add(mpp->st_running_agent->rrdlabels, "database", mpp->db, RRDLABEL_SRC_AUTO);
2357 + rrdlabels_add(mpp->st_running_agent->rrdlabels, "publication", mpp->publication, RRDLABEL_SRC_AUTO);
2358 +
2359 + mpp->rd_running_agent = rrddim_add(mpp->st_running_agent, "agents", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2360 + }
2361 +
2362 + rrddim_set_by_pointer(mpp->st_running_agent, mpp->rd_running_agent, (collected_number)mpp->runningdistagentcount);
2363 + rrdset_done(mpp->st_running_agent);
2364 +}
2365 +
2366 +void dict_mssql_replication_sync_time(struct mssql_publisher_publication *mpp, int update_every)
2367 +{
2368 + if (unlikely(!mpp->st_synchronization_time)) {
2369 + char id[RRD_ID_LENGTH_MAX + 1];
2370 +
2371 + snprintfz(
2372 + id,
2373 + RRD_ID_LENGTH_MAX,
2374 + "instance_%s_replication_%s_%s_synchronization",
2375 + mpp->parent->instanceID,
2376 + mpp->publication,
2377 + mpp->db);
2378 + netdata_fix_chart_name(id);
2379 + mpp->st_synchronization_time = rrdset_create_localhost(
2380 + "mssql",
2381 + id,
2382 + NULL,
2383 + "replication",
2384 + "mssql.replication_synchronization",
2385 + "The shortest synchronization.",
2386 + "seconds",
2387 + PLUGIN_WINDOWS_NAME,
2388 + "PerflibMSSQL",
2389 + PRIO_MSSQL_REPLICATION_SYNC_TIME,
2390 + update_every,
2391 + RRDSET_TYPE_LINE);
2392 +
2393 + rrdlabels_add(
2394 + mpp->st_synchronization_time->rrdlabels, "mssql_instance", mpp->parent->instanceID, RRDLABEL_SRC_AUTO);
2395 + rrdlabels_add(mpp->st_synchronization_time->rrdlabels, "publisher", mpp->publisher, RRDLABEL_SRC_AUTO);
2396 + rrdlabels_add(mpp->st_synchronization_time->rrdlabels, "database", mpp->db, RRDLABEL_SRC_AUTO);
2397 + rrdlabels_add(mpp->st_synchronization_time->rrdlabels, "publication", mpp->publication, RRDLABEL_SRC_AUTO);
2398 +
2399 + mpp->rd_synchronization_time =
2400 + rrddim_add(mpp->st_synchronization_time, "seconds", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2401 + }
2402 +
2403 + rrddim_set_by_pointer(
2404 + mpp->st_synchronization_time, mpp->rd_synchronization_time, (collected_number)mpp->runningdistagentcount);
2405 + rrdset_done(mpp->st_synchronization_time);
2406 +}
2407 +
2408 +int dict_mssql_replication_chart_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
2409 +{
2410 + struct mssql_publisher_publication *mpp = value;
2411 + int *update_every = data;
2412 +
2413 + dict_mssql_replication_status(mpp, *update_every);
2414 + dict_mssql_replication_warning(mpp, *update_every);
2415 + dict_mssql_replication_avg_latency(mpp, *update_every);
2416 + dict_mssql_replication_subscription(mpp, *update_every);
2417 + dict_mssql_replication_dist_agent_running(mpp, *update_every);
2418 + dict_mssql_replication_sync_time(mpp, *update_every);
2419 +}
2420 +
2421 +static void do_mssql_replication(struct mssql_instance *mi, int update_every)
2422 +{
2423 + dictionary_sorted_walkthrough_read(mi->publisher_publication, dict_mssql_replication_chart_cb, &update_every);
2424 +}
2425 +
2426 +static void mssql_database_backup_restore_chart(struct mssql_db_instance *mdi, const char *db, int update_every)
2427 +{
2428 + char id[RRD_ID_LENGTH_MAX + 1];
2429 +
2430 + if (unlikely(!mdi->st_db_backup_restore_operations)) {
2431 + snprintfz(id, RRD_ID_LENGTH_MAX, "db_%s_instance_%s_backup_restore_operations", db, mdi->parent->instanceID);
2432 + netdata_fix_chart_name(id);
2433 + mdi->st_db_backup_restore_operations = rrdset_create_localhost(
2434 + "mssql",
2435 + id,
2436 + NULL,
2437 + "transactions",
2438 + "mssql.database_backup_restore_operations",
2439 + "Backup IO per database",
2440 + "operations/s",
2441 + PLUGIN_WINDOWS_NAME,
2442 + "PerflibMSSQL",
2443 + PRIO_MSSQL_DATABASE_BACKUP_RESTORE_OPERATIONS,
2444 + update_every,
2445 + RRDSET_TYPE_LINE);
2446 +
2447 + rrdlabels_add(
2448 + mdi->st_db_backup_restore_operations->rrdlabels,
2449 + "mssql_instance",
2450 + mdi->parent->instanceID,
2451 + RRDLABEL_SRC_AUTO);
2452 + rrdlabels_add(mdi->st_db_backup_restore_operations->rrdlabels, "database", db, RRDLABEL_SRC_AUTO);
2453 +
2454 + mdi->rd_db_backup_restore_operations =
2455 + rrddim_add(mdi->st_db_backup_restore_operations, "backup", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
2456 + }
2457 +
2458 + rrddim_set_by_pointer(
2459 + mdi->st_db_backup_restore_operations,
2460 + mdi->rd_db_backup_restore_operations,
2461 + (collected_number)mdi->MSSQLDatabaseBackupRestoreOperations.current.Data);
2462 +
2463 + rrdset_done(mdi->st_db_backup_restore_operations);
2464 +}
2465 +
2466 +static void mssql_database_log_flushes_chart(struct mssql_db_instance *mdi, const char *db, int update_every)
2467 +{
2468 + char id[RRD_ID_LENGTH_MAX + 1];
2469 +
2470 + if (unlikely(!mdi->st_db_log_flushes)) {
2471 + snprintfz(id, RRD_ID_LENGTH_MAX, "db_%s_instance_%s_log_flushes", db, mdi->parent->instanceID);
2472 + netdata_fix_chart_name(id);
2473 + mdi->st_db_log_flushes = rrdset_create_localhost(
2474 + "mssql",
2475 + id,
2476 + NULL,
2477 + "transactions",
2478 + "mssql.database_log_flushes",
2479 + "Log flushes",
2480 + "flushes/s",
2481 + PLUGIN_WINDOWS_NAME,
2482 + "PerflibMSSQL",
2483 + PRIO_MSSQL_DATABASE_LOG_FLUSHES,
2484 + update_every,
2485 + RRDSET_TYPE_LINE);
2486 +
2487 + rrdlabels_add(mdi->st_db_log_flushes->rrdlabels, "mssql_instance", mdi->parent->instanceID, RRDLABEL_SRC_AUTO);
2488 + rrdlabels_add(mdi->st_db_log_flushes->rrdlabels, "database", db, RRDLABEL_SRC_AUTO);
2489 + }
2490 +
2491 + if (unlikely(!mdi->rd_db_log_flushes)) {
2492 + mdi->rd_db_log_flushes = rrddim_add(mdi->st_db_log_flushes, "flushes", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
2493 + }
2494 +
2495 + rrddim_set_by_pointer(
2496 + mdi->st_db_log_flushes, mdi->rd_db_log_flushes, (collected_number)mdi->MSSQLDatabaseLogFlushes.current.Data);
2497 +
2498 + rrdset_done(mdi->st_db_log_flushes);
2499 +}
2500 +
2501 +static void mssql_database_log_flushed_chart(struct mssql_db_instance *mdi, const char *db, int update_every)
2502 +{
2503 + char id[RRD_ID_LENGTH_MAX + 1];
2504 +
2505 + if (unlikely(!mdi->st_db_log_flushed)) {
2506 + snprintfz(id, RRD_ID_LENGTH_MAX, "db_%s_instance_%s_log_flushed", db, mdi->parent->instanceID);
2507 + netdata_fix_chart_name(id);
2508 + mdi->st_db_log_flushed = rrdset_create_localhost(
2509 + "mssql",
2510 + id,
2511 + NULL,
2512 + "transactions",
2513 + "mssql.database_log_flushed",
2514 + "Log flushed",
2515 + "bytes/s",
2516 + PLUGIN_WINDOWS_NAME,
2517 + "PerflibMSSQL",
2518 + PRIO_MSSQL_DATABASE_LOG_FLUSHED,
2519 + update_every,
2520 + RRDSET_TYPE_LINE);
2521 +
2522 + rrdlabels_add(mdi->st_db_log_flushed->rrdlabels, "mssql_instance", mdi->parent->instanceID, RRDLABEL_SRC_AUTO);
2523 + rrdlabels_add(mdi->st_db_log_flushed->rrdlabels, "database", db, RRDLABEL_SRC_AUTO);
2524 +
2525 + mdi->rd_db_log_flushed = rrddim_add(mdi->st_db_log_flushed, "flushed", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
2526 + }
2527 +
2528 + rrddim_set_by_pointer(
2529 + mdi->st_db_log_flushed, mdi->rd_db_log_flushed, (collected_number)mdi->MSSQLDatabaseLogFlushed.current.Data);
2530 +
2531 + rrdset_done(mdi->st_db_log_flushed);
2532 +}
2533 +
2534 +static void mssql_transactions_chart(struct mssql_db_instance *mdi, const char *db, int update_every)
2535 +{
2536 + char id[RRD_ID_LENGTH_MAX + 1];
2537 +
2538 + if (unlikely(!mdi->st_db_transactions)) {
2539 + snprintfz(id, RRD_ID_LENGTH_MAX, "db_%s_instance_%s_transactions", db, mdi->parent->instanceID);
2540 + netdata_fix_chart_name(id);
2541 + mdi->st_db_transactions = rrdset_create_localhost(
2542 + "mssql",
2543 + id,
2544 + NULL,
2545 + "transactions",
2546 + "mssql.database_transactions",
2547 + "Transactions",
2548 + "transactions/s",
2549 + PLUGIN_WINDOWS_NAME,
2550 + "PerflibMSSQL",
2551 + PRIO_MSSQL_DATABASE_TRANSACTIONS,
2552 + update_every,
2553 + RRDSET_TYPE_LINE);
2554 +
2555 + rrdlabels_add(mdi->st_db_transactions->rrdlabels, "mssql_instance", mdi->parent->instanceID, RRDLABEL_SRC_AUTO);
2556 + rrdlabels_add(mdi->st_db_transactions->rrdlabels, "database", db, RRDLABEL_SRC_AUTO);
2557 +
2558 + mdi->rd_db_transactions =
2559 + rrddim_add(mdi->st_db_transactions, "transactions", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
2560 + }
2561 +
2562 + rrddim_set_by_pointer(
2563 + mdi->st_db_transactions,
2564 + mdi->rd_db_transactions,
2565 + (collected_number)mdi->MSSQLDatabaseTransactions.current.Data);
2566 +
2567 + rrdset_done(mdi->st_db_transactions);
2568 +}
2569 +
2570 +static void mssql_write_transactions_chart(struct mssql_db_instance *mdi, const char *db, int update_every)
2571 +{
2572 + char id[RRD_ID_LENGTH_MAX + 1];
2573 +
2574 + if (unlikely(!mdi->st_db_write_transactions)) {
2575 + snprintfz(id, RRD_ID_LENGTH_MAX, "db_%s_instance_%s_write_transactions", db, mdi->parent->instanceID);
2576 + netdata_fix_chart_name(id);
2577 + mdi->st_db_write_transactions = rrdset_create_localhost(
2578 + "mssql",
2579 + id,
2580 + NULL,
2581 + "transactions",
2582 + "mssql.database_write_transactions",
2583 + "Write transactions",
2584 + "transactions/s",
2585 + PLUGIN_WINDOWS_NAME,
2586 + "PerflibMSSQL",
2587 + PRIO_MSSQL_DATABASE_WRITE_TRANSACTIONS,
2588 + update_every,
2589 + RRDSET_TYPE_LINE);
2590 +
2591 + rrdlabels_add(
2592 + mdi->st_db_write_transactions->rrdlabels, "mssql_instance", mdi->parent->instanceID, RRDLABEL_SRC_AUTO);
2593 + rrdlabels_add(mdi->st_db_write_transactions->rrdlabels, "database", db, RRDLABEL_SRC_AUTO);
2594 +
2595 + mdi->rd_db_write_transactions =
2596 + rrddim_add(mdi->st_db_write_transactions, "write", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
2597 + }
2598 +
2599 + rrddim_set_by_pointer(
2600 + mdi->st_db_write_transactions,
2601 + mdi->rd_db_write_transactions,
2602 + (collected_number)mdi->MSSQLDatabaseWriteTransactions.current.Data);
2603 +
2604 + rrdset_done(mdi->st_db_write_transactions);
2605 +}
2606 +
2607 +static void mssql_lockwait_chart(struct mssql_db_instance *mdi, const char *db, int update_every)
2608 +{
2609 + char id[RRD_ID_LENGTH_MAX + 1];
2610 +
2611 + if (unlikely(!mdi->st_db_lockwait)) {
2612 + snprintfz(id, RRD_ID_LENGTH_MAX, "db_%s_instance_%s_lockwait", db, mdi->parent->instanceID);
2613 + netdata_fix_chart_name(id);
2614 + mdi->st_db_lockwait = rrdset_create_localhost(
2615 + "mssql",
2616 + id,
2617 + NULL,
2618 + "locks",
2619 + "mssql.database_lockwait",
2620 + "Lock requests that required the caller to wait.",
2621 + "locks/s",
2622 + PLUGIN_WINDOWS_NAME,
2623 + "PerflibMSSQL",
2624 + PRIO_MSSQL_DATABASE_LOCKWAIT_PER_SECOND,
2625 + update_every,
2626 + RRDSET_TYPE_LINE);
2627 +
2628 + rrdlabels_add(mdi->st_db_lockwait->rrdlabels, "mssql_instance", mdi->parent->instanceID, RRDLABEL_SRC_AUTO);
2629 + rrdlabels_add(mdi->st_db_lockwait->rrdlabels, "database", db, RRDLABEL_SRC_AUTO);
2630 +
2631 + mdi->rd_db_lockwait = rrddim_add(mdi->st_db_lockwait, "lock", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
2632 + }
2633 +
2634 + rrddim_set_by_pointer(
2635 + mdi->st_db_lockwait, mdi->rd_db_lockwait, (collected_number)mdi->MSSQLDatabaseLockWaitSec.current.Data);
2636 +
2637 + rrdset_done(mdi->st_db_lockwait);
2638 +}
2639 +
2640 +static void mssql_deadlock_chart(struct mssql_db_instance *mdi, const char *db, int update_every)
2641 +{
2642 + char id[RRD_ID_LENGTH_MAX + 1];
2643 +
2644 + if (unlikely(!mdi->st_db_deadlock)) {
2645 + snprintfz(id, RRD_ID_LENGTH_MAX, "db_%s_instance_%s_deadlocks", db, mdi->parent->instanceID);
2646 + netdata_fix_chart_name(id);
2647 + mdi->st_db_deadlock = rrdset_create_localhost(
2648 + "mssql",
2649 + id,
2650 + NULL,
2651 + "locks",
2652 + "mssql.database_deadlocks",
2653 + "Lock requests that resulted in deadlock.",
2654 + "deadlocks/s",
2655 + PLUGIN_WINDOWS_NAME,
2656 + "PerflibMSSQL",
2657 + PRIO_MSSQL_DATABASE_DEADLOCKS_PER_SECOND,
2658 + update_every,
2659 + RRDSET_TYPE_LINE);
2660 +
2661 + rrdlabels_add(mdi->st_db_deadlock->rrdlabels, "mssql_instance", mdi->parent->instanceID, RRDLABEL_SRC_AUTO);
2662 + rrdlabels_add(mdi->st_db_deadlock->rrdlabels, "database", db, RRDLABEL_SRC_AUTO);
2663 +
2664 + mdi->rd_db_deadlock = rrddim_add(mdi->st_db_deadlock, "deadlocks", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
2665 + }
2666 +
2667 + rrddim_set_by_pointer(
2668 + mdi->st_db_deadlock, mdi->rd_db_deadlock, (collected_number)mdi->MSSQLDatabaseDeadLockSec.current.Data);
2669 +
2670 + rrdset_done(mdi->st_db_deadlock);
2671 +}
2672 +
2673 +static void mssql_is_readonly_chart(struct mssql_db_instance *mdi, const char *db, int update_every)
2674 +{
2675 + if (unlikely(!mdi->st_db_readonly)) {
2676 + char id[RRD_ID_LENGTH_MAX + 1];
2677 + snprintfz(id, RRD_ID_LENGTH_MAX, "db_%s_instance_%s_readonly", db, mdi->parent->instanceID);
2678 + netdata_fix_chart_name(id);
2679 + mdi->st_db_readonly = rrdset_create_localhost(
2680 + "mssql",
2681 + id,
2682 + NULL,
2683 + "locks",
2684 + "mssql.database_readonly",
2685 + "Current database write status.",
2686 + "status",
2687 + PLUGIN_WINDOWS_NAME,
2688 + "PerflibMSSQL",
2689 + PRIO_MSSQL_DATABASE_READONLY,
2690 + update_every,
2691 + RRDSET_TYPE_LINE);
2692 +
2693 + rrdlabels_add(mdi->st_db_readonly->rrdlabels, "mssql_instance", mdi->parent->instanceID, RRDLABEL_SRC_AUTO);
2694 + rrdlabels_add(mdi->st_db_readonly->rrdlabels, "database", db, RRDLABEL_SRC_AUTO);
2695 +
2696 + mdi->rd_db_readonly_yes = rrddim_add(mdi->st_db_readonly, "writable", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2697 + mdi->rd_db_readonly_no = rrddim_add(mdi->st_db_readonly, "readonly", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2698 + }
2699 +
2700 + rrddim_set_by_pointer(
2701 + mdi->st_db_readonly, mdi->rd_db_readonly_no, (collected_number)mdi->MSSQLDBIsReadonly.current.Data);
2702 +
2703 + collected_number opposite = (mdi->MSSQLDBIsReadonly.current.Data) ? 0 : 1;
2704 + rrddim_set_by_pointer(mdi->st_db_readonly, mdi->rd_db_readonly_yes, (collected_number)opposite);
2705 +
2706 + rrdset_done(mdi->st_db_readonly);
2707 +}
2708 +
2709 +static void mssql_db_states_chart(struct mssql_db_instance *mdi, const char *db, int update_every)
2710 +{
2711 + if (unlikely(!mdi->st_db_state)) {
2712 + char id[RRD_ID_LENGTH_MAX + 1];
2713 + snprintfz(id, RRD_ID_LENGTH_MAX, "db_%s_instance_%s_state", db, mdi->parent->instanceID);
2714 + netdata_fix_chart_name(id);
2715 + mdi->st_db_state = rrdset_create_localhost(
2716 + "mssql",
2717 + id,
2718 + NULL,
2719 + "locks",
2720 + "mssql.database_state",
2721 + "Current database state.",
2722 + "status",
2723 + PLUGIN_WINDOWS_NAME,
2724 + "PerflibMSSQL",
2725 + PRIO_MSSQL_DATABASE_STATE,
2726 + update_every,
2727 + RRDSET_TYPE_LINE);
2728 +
2729 + rrdlabels_add(mdi->st_db_state->rrdlabels, "mssql_instance", mdi->parent->instanceID, RRDLABEL_SRC_AUTO);
2730 + rrdlabels_add(mdi->st_db_state->rrdlabels, "database", db, RRDLABEL_SRC_AUTO);
2731 +
2732 + mdi->rd_db_state[0] = rrddim_add(mdi->st_db_state, "online", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2733 + mdi->rd_db_state[1] = rrddim_add(mdi->st_db_state, "restoring", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2734 + mdi->rd_db_state[2] = rrddim_add(mdi->st_db_state, "recovering", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2735 + mdi->rd_db_state[3] = rrddim_add(mdi->st_db_state, "recovering_pending", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2736 + mdi->rd_db_state[4] = rrddim_add(mdi->st_db_state, "suspect", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2737 + mdi->rd_db_state[5] = rrddim_add(mdi->st_db_state, "offline", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2738 + }
2739 +}
2740 +
2741 +static void mssql_db_state_chart_loop(struct mssql_db_instance *mdi, const char *db, int update_every)
2742 +{
2743 + collected_number set_value =
2744 + (mdi->MSSQLDBState.current.Data < 5) ? (collected_number)mdi->MSSQLDBState.current.Data : 5;
2745 + mssql_db_states_chart(mdi, db, update_every);
2746 + for (collected_number i; i < NETDATA_DB_STATES; i++) {
2747 + rrddim_set_by_pointer(mdi->st_db_state, mdi->rd_db_state[i], i == set_value);
2748 + }
2749 + rrdset_done(mdi->st_db_state);
2750 +}
2751 +
2752 +static void mssql_lock_request_chart(struct mssql_db_instance *mdi, const char *db, int update_every)
2753 +{
2754 + char id[RRD_ID_LENGTH_MAX + 1];
2755 +
2756 + if (unlikely(!mdi->st_lock_requests)) {
2757 + snprintfz(id, RRD_ID_LENGTH_MAX, "db_%s_instance_%s_lock_requests", db, mdi->parent->instanceID);
2758 + netdata_fix_chart_name(id);
2759 + mdi->st_lock_requests = rrdset_create_localhost(
2760 + "mssql",
2761 + id,
2762 + NULL,
2763 + "locks",
2764 + "mssql.database_lock_requests",
2765 + "Number of new locks and lock conversions requested.",
2766 + "requests/s",
2767 + PLUGIN_WINDOWS_NAME,
2768 + "PerflibMSSQL",
2769 + PRIO_MSSQL_DATABASE_LOCK_REQUESTS_SEC,
2770 + update_every,
2771 + RRDSET_TYPE_LINE);
2772 +
2773 + rrdlabels_add(mdi->st_lock_requests->rrdlabels, "mssql_instance", mdi->parent->instanceID, RRDLABEL_SRC_AUTO);
2774 + rrdlabels_add(mdi->st_lock_requests->rrdlabels, "database", db, RRDLABEL_SRC_AUTO);
2775 +
2776 + mdi->rd_lock_requests = rrddim_add(mdi->st_lock_requests, "requests", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
2777 + }
2778 +
2779 + rrddim_set_by_pointer(
2780 + mdi->st_lock_requests, mdi->rd_lock_requests, (collected_number)mdi->MSSQLDatabaseLockRequestsSec.current.Data);
2781 +
2782 + rrdset_done(mdi->st_lock_requests);
2783 +}
2784 +
2785 +static void mssql_lock_timeout_chart(struct mssql_db_instance *mdi, const char *db, int update_every)
2786 +{
2787 + char id[RRD_ID_LENGTH_MAX + 1];
2788 +
2789 + if (unlikely(!mdi->st_lock_timeouts)) {
2790 + snprintfz(id, RRD_ID_LENGTH_MAX, "db_%s_instance_%s_lock_timeouts", db, mdi->parent->instanceID);
2791 + netdata_fix_chart_name(id);
2792 + mdi->st_lock_timeouts = rrdset_create_localhost(
2793 + "mssql",
2794 + id,
2795 + NULL,
2796 + "locks",
2797 + "mssql.database_lock_timeouts",
2798 + "Lock that timed out.",
2799 + "timeouts/s",
2800 + PLUGIN_WINDOWS_NAME,
2801 + "PerflibMSSQL",
2802 + PRIO_MSSQL_DATABASE_LOCKS_TIMEOUT_PER_SECOND,
2803 + update_every,
2804 + RRDSET_TYPE_LINE);
2805 +
2806 + rrdlabels_add(mdi->st_lock_timeouts->rrdlabels, "mssql_instance", mdi->parent->instanceID, RRDLABEL_SRC_AUTO);
2807 + rrdlabels_add(mdi->st_lock_timeouts->rrdlabels, "database", db, RRDLABEL_SRC_AUTO);
2808 +
2809 + mdi->rd_lock_timeouts = rrddim_add(mdi->st_lock_timeouts, "timeouts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
2810 + }
2811 +
2812 + rrddim_set_by_pointer(
2813 + mdi->st_lock_timeouts, mdi->rd_lock_timeouts, (collected_number)mdi->MSSQLDatabaseLockTimeoutsSec.current.Data);
2814 +
2815 + rrdset_done(mdi->st_lock_timeouts);
2816 +}
2817 +
2818 +static void mssql_active_transactions_chart(struct mssql_db_instance *mdi, const char *db, int update_every)
2819 +{
2820 + char id[RRD_ID_LENGTH_MAX + 1];
2821 +
2822 + if (unlikely(!mdi->st_db_active_transactions)) {
2823 + snprintfz(id, RRD_ID_LENGTH_MAX, "db_%s_instance_%s_active_transactions", db, mdi->parent->instanceID);
2824 + netdata_fix_chart_name(id);
2825 + mdi->st_db_active_transactions = rrdset_create_localhost(
2826 + "mssql",
2827 + id,
2828 + NULL,
2829 + "transactions",
2830 + "mssql.database_active_transactions",
2831 + "Active transactions per database",
2832 + "transactions",
2833 + PLUGIN_WINDOWS_NAME,
2834 + "PerflibMSSQL",
2835 + PRIO_MSSQL_DATABASE_ACTIVE_TRANSACTIONS,
2836 + update_every,
2837 + RRDSET_TYPE_LINE);
2838 +
2839 + rrdlabels_add(
2840 + mdi->st_db_active_transactions->rrdlabels, "mssql_instance", mdi->parent->instanceID, RRDLABEL_SRC_AUTO);
2841 + rrdlabels_add(mdi->st_db_active_transactions->rrdlabels, "database", db, RRDLABEL_SRC_AUTO);
2842 +
2843 + mdi->rd_db_active_transactions =
2844 + rrddim_add(mdi->st_db_active_transactions, "active", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2845 + }
2846 +
2847 + rrddim_set_by_pointer(
2848 + mdi->st_db_active_transactions,
2849 + mdi->rd_db_active_transactions,
2850 + (collected_number)mdi->MSSQLDatabaseActiveTransactions.current.Data);
2851 +
2852 + rrdset_done(mdi->st_db_active_transactions);
2853 +}
2854 +
2855 +static inline void mssql_data_file_size_chart(struct mssql_db_instance *mdi, const char *db, int update_every)
2856 +{
2857 + char id[RRD_ID_LENGTH_MAX + 1];
2858 +
2859 + if (unlikely(!mdi->st_db_data_file_size)) {
2860 + snprintfz(id, RRD_ID_LENGTH_MAX, "db_%s_instance_%s_data_files_size", db, mdi->parent->instanceID);
2861 + netdata_fix_chart_name(id);
2862 + mdi->st_db_data_file_size = rrdset_create_localhost(
2863 + "mssql",
2864 + id,
2865 + NULL,
2866 + "size",
2867 + "mssql.database_data_files_size",
2868 + "Current database size.",
2869 + "bytes",
2870 + PLUGIN_WINDOWS_NAME,
2871 + "PerflibMSSQL",
2872 + PRIO_MSSQL_DATABASE_DATA_FILE_SIZE,
2873 + update_every,
2874 + RRDSET_TYPE_LINE);
2875 +
2876 + rrdlabels_add(
2877 + mdi->st_db_data_file_size->rrdlabels, "mssql_instance", mdi->parent->instanceID, RRDLABEL_SRC_AUTO);
2878 + rrdlabels_add(mdi->st_db_data_file_size->rrdlabels, "database", db, RRDLABEL_SRC_AUTO);
2879 +
2880 + mdi->rd_db_data_file_size = rrddim_add(mdi->st_db_data_file_size, "size", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2881 + }
2882 +
2883 + collected_number data = mdi->MSSQLDatabaseDataFileSize.current.Data;
2884 + rrddim_set_by_pointer(mdi->st_db_data_file_size, mdi->rd_db_data_file_size, data);
2885 +
2886 + rrdset_done(mdi->st_db_data_file_size);
2887 +}
2888 +
2889 +int dict_mssql_databases_charts_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
2890 +{
2891 + struct mssql_db_instance *mdi = value;
2892 + const char *db = dictionary_acquired_item_name((DICTIONARY_ITEM *)item);
2893 +
2894 + if (unlikely(!mdi->collecting_data)) {
2895 + goto endchartcb;
2896 + }
2897 +
2898 + int *update_every = data;
2899 +
2900 + void (*transaction_chart[])(struct mssql_db_instance *, const char *, int) = {
2901 + mssql_data_file_size_chart,
2902 + mssql_transactions_chart,
2903 + mssql_database_backup_restore_chart,
2904 + mssql_database_log_flushed_chart,
2905 + mssql_database_log_flushes_chart,
2906 + mssql_active_transactions_chart,
2907 + mssql_write_transactions_chart,
2908 + mssql_lockwait_chart,
2909 + mssql_deadlock_chart,
2910 + mssql_is_readonly_chart,
2911 + mssql_db_state_chart_loop,
2912 + mssql_lock_timeout_chart,
2913 + mssql_lock_request_chart,
2914 +
2915 + // Last function pointer must be NULL
2916 + NULL};
2917 +
2918 + int i;
2919 + for (i = 0; transaction_chart[i]; i++) {
2920 + transaction_chart[i](mdi, db, *update_every);
2921 + }
2922 +
2923 +endchartcb:
2924 + return 1;
2925 +}
2926 +
2927 +static void do_mssql_databases(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *mi, int update_every)
2928 +{
2929 + if (unlikely(!pDataBlock))
2930 + goto end_mssql_databases;
2931 +
2932 + PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, mi->objectName[NETDATA_MSSQL_DATABASE]);
2933 + if (unlikely(!pObjectType))
2934 + return;
2935 +
2936 + PERF_INSTANCE_DEFINITION *pi = NULL;
2937 + for (LONG i = 0; i < pObjectType->NumInstances; i++) {
2938 + pi = perflibForEachInstance(pDataBlock, pObjectType, pi);
2939 + if (unlikely(!pi))
2940 + break;
2941 +
2942 + if (unlikely(!getInstanceName(pDataBlock, pObjectType, pi, windows_shared_buffer, sizeof(windows_shared_buffer))))
2943 + strncpyz(windows_shared_buffer, "[unknown]", sizeof(windows_shared_buffer) - 1);
2944 +
2945 + if (unlikely(!strcasecmp(windows_shared_buffer, "_Total")))
2946 + continue;
2947 +
2948 + struct mssql_db_instance *mdi = dictionary_set(mi->databases, windows_shared_buffer, NULL, sizeof(*mdi));
2949 + if (unlikely(!mdi))
2950 + continue;
2951 +
2952 + if (unlikely(!mdi->parent)) {
2953 + mdi->parent = mi;
2954 + }
2955 +
2956 + if (unlikely(!i))
2957 + mdi->collect_instance = true;
2958 + }
2959 +
2960 +end_mssql_databases:
2961 + dictionary_sorted_walkthrough_read(mi->databases, dict_mssql_databases_charts_cb, &update_every);
2962 +}
2963 +
2964 +int dict_mssql_charts_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
2965 +{
2966 + struct mssql_instance *mi = value;
2967 + int *update_every = data;
2968 +
2969 + static void (*doMSSQL[])(PERF_DATA_BLOCK *, struct mssql_instance *, int) = {
2970 + do_mssql_general_stats,
2971 + do_mssql_errors,
2972 + do_mssql_memory_mgr,
2973 + do_mssql_statistics_perflib,
2974 + do_mssql_access_methods,
2975 +
2976 + do_mssql_databases,
2977 + do_mssql_locks,
2978 + do_mssql_waits,
2979 + do_mssql_bufferman_stats_sql,
2980 + do_mssql_job_status_sql,
2981 +
2982 + NULL};
2983 +
2984 + DWORD i;
2985 + PERF_DATA_BLOCK *pDataBlock;
2986 + static bool collect_perflib[NETDATA_MSSQL_METRICS_END] = {
2987 + true, true, true, true, true, true, true, true, true, true};
2988 + for (i = 0; i < NETDATA_MSSQL_ACCESS_METHODS; i++) {
2989 + if (unlikely(!collect_perflib[i]))
2990 + continue;
2991 +
2992 + pDataBlock = netdata_mssql_get_perf_data_block(collect_perflib, mi, i);
2993 + if (unlikely(!pDataBlock))
2994 + continue;
2995 +
2996 + doMSSQL[i](pDataBlock, mi, *update_every);
2997 + }
2998 +
2999 + if (unlikely(unlikely(!mi->conn || !mi->conn->is_connected)))
3000 + return 1;
3001 +
3002 + for (i = NETDATA_MSSQL_DATABASE; doMSSQL[i]; i++) {
3003 + pDataBlock = (collect_perflib[i]) ? netdata_mssql_get_perf_data_block(collect_perflib, mi, i) : NULL;
3004 +
3005 + doMSSQL[i](pDataBlock, mi, *update_every);
3006 + }
3007 +
3008 + do_mssql_replication(mi, *update_every);
3009 +
3010 + return 1;
3011 +}
3012 +
3013 +// Entry point
3014 +
3015 +int do_PerflibMSSQL(int update_every, usec_t dt __maybe_unused)
3016 +{
3017 + static bool initialized = false;
3018 +
3019 + if (unlikely(!initialized)) {
3020 + if (initialize(update_every))
3021 + return -1;
3022 +
3023 + initialized = true;
3024 + }
3025 +
3026 + dictionary_sorted_walkthrough_read(mssql_instances, dict_mssql_charts_cb, &update_every);
3027 +
3028 + return 0;
3029 +}
3030 +
3031 +void do_PerflibMSSQL_cleanup()
3032 +{
3033 + if (likely(nd_thread_join(mssql_queries_thread)))
3034 + nd_log_daemon(NDLP_ERR, "Failed to join mssql queries thread");
3035 +}
src/collectors/windows.plugin/perflib-mssql-queries.h
+348
@@ -3,6 +3,10 @@
3 #ifndef NETDATA_PERFLIB_MSSQL_QUERIES_H
4 #define NETDATA_PERFLIB_MSSQL_QUERIES_H
5
6 +#include <sqlext.h>
7 +#include <sqltypes.h>
8 +#include <sql.h>
9 +
10 // https://learn.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-tran-locks-transact-sql?view=sql-server-ver16
11 #define NETDATA_QUERY_LOCKS_MASK \
12 "SELECT resource_type, count(*) FROM %s.sys.dm_tran_locks WHERE DB_NAME(resource_database_id) = '%s' group by resource_type;"
@@ -631,4 +635,348 @@
635 N'SOS_WORK_DISPATCHER', \
636 'RESERVED_MEMORY_ALLOCATION_EXT') AND ws.[waiting_tasks_count] > 0 AND ws.[wait_time_ms] > 100;"
637
638 +#ifndef MEGA_FACTOR
639 +#define MEGA_FACTOR (1048576) // 1024 * 1024
640 +#endif
641 +// https://learn.microsoft.com/en-us/sql/sql-server/install/instance-configuration?view=sql-server-ver16
642 +#define NETDATA_MAX_INSTANCE_NAME (32)
643 +#define NETDATA_MAX_INSTANCE_OBJECT (128)
644 +// https://learn.microsoft.com/en-us/previous-versions/sql/sql-server-2008-r2/ms191240(v=sql.105)#sysname
645 +#define SQLSERVER_MAX_NAME_LENGTH NETDATA_MAX_INSTANCE_OBJECT
646 +#define NETDATA_MSSQL_NEXT_TRY (60)
647 +
648 +struct netdata_mssql_conn {
649 + const char *instance;
650 + const char *driver;
651 + const char *server;
652 + const char *address;
653 + const char *username;
654 + const char *password;
655 + int instances;
656 + bool windows_auth;
657 + bool is_sqlexpress;
658 +
659 + SQLCHAR *connectionString;
660 +
661 + SQLHENV netdataSQLEnv;
662 + SQLHDBC netdataSQLHDBc;
663 +
664 + SQLHSTMT checkPermSTMT;
665 + SQLHSTMT databaseListSTMT;
666 + SQLHSTMT dataFileSizeSTMT;
667 + SQLHSTMT dbTransactionSTMT;
668 + SQLHSTMT dbInstanceTransactionSTMT;
669 + SQLHSTMT dbWaitsSTMT;
670 + SQLHSTMT dbLocksSTMT;
671 + SQLHSTMT dbSQLState;
672 + SQLHSTMT dbSQLJobs;
673 + SQLHSTMT dbReplicationPublisher;
674 +
675 + BOOL is_connected;
676 +};
677 +
678 +enum netdata_mssql_metrics {
679 + NETDATA_MSSQL_GENERAL_STATS,
680 + NETDATA_MSSQL_SQL_ERRORS,
681 + NETDATA_MSSQL_MEMORY,
682 + NETDATA_MSSQL_SQL_STATS,
683 + NETDATA_MSSQL_ACCESS_METHODS,
684 +
685 + NETDATA_MSSQL_DATABASE,
686 + NETDATA_MSSQL_LOCKS,
687 + NETDATA_MSSQL_WAITS,
688 + NETDATA_MSSQL_BUFFER_MANAGEMENT,
689 + NETDATA_MSSQL_JOBS,
690 +
691 + NETDATA_MSSQL_METRICS_END
692 +};
693 +
694 +struct mssql_db_waits {
695 + const char *wait_type;
696 + const char *wait_category;
697 +
698 + RRDSET *st_total_wait;
699 + RRDDIM *rd_total_wait;
700 +
701 + RRDSET *st_resource_wait_msec;
702 + RRDDIM *rd_resource_wait_msec;
703 +
704 + RRDSET *st_signal_wait_msec;
705 + RRDDIM *rd_signal_wait_msec;
706 +
707 + RRDSET *st_max_wait_time_msec;
708 + RRDDIM *rd_max_wait_time_msec;
709 +
710 + RRDSET *st_waiting_tasks;
711 + RRDDIM *rd_waiting_tasks;
712 +
713 + COUNTER_DATA MSSQLDatabaseTotalWait;
714 + COUNTER_DATA MSSQLDatabaseResourceWaitMSec;
715 + COUNTER_DATA MSSQLDatabaseSignalWaitMSec;
716 + COUNTER_DATA MSSQLDatabaseMaxWaitTimeMSec;
717 + COUNTER_DATA MSSQLDatabaseWaitingTasks;
718 +};
719 +
720 +// https://learn.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-replmonitorhelppublication-transact-sql?view=sql-server-ver17
721 +struct mssql_publisher_publication {
722 + struct mssql_instance *parent;
723 +
724 + // Lables
725 + char *publisher;
726 + char *publication;
727 + char *db;
728 + int type;
729 +
730 + // Charts
731 + int status;
732 + int warning;
733 +
734 + int avg_latency;
735 +
736 + int retention;
737 +
738 + int subscriptioncount;
739 + int runningdistagentcount;
740 +
741 + int average_runspeedPerf;
742 +
743 + RRDSET *st_publisher_status;
744 + RRDDIM *rd_publisher_status_started;
745 + RRDDIM *rd_publisher_status_successed;
746 + RRDDIM *rd_publisher_status_in_progress;
747 + RRDDIM *rd_publisher_status_idle;
748 + RRDDIM *rd_publisher_status_retrying;
749 + RRDDIM *rd_publisher_status_failed;
750 +
751 + RRDSET *st_warning;
752 + RRDDIM *rd_warning_expiration;
753 + RRDDIM *rd_warning_latency;
754 + RRDDIM *rd_warning_mergeeexpiration;
755 + RRDDIM *rd_warning_mergefastduration;
756 + RRDDIM *rd_warning_mergelowduration;
757 + RRDDIM *rd_warning_mergefastrunspeed;
758 + RRDDIM *rd_warning_mergelowrunspeed;
759 +
760 + RRDSET *st_avg_latency;
761 + RRDDIM *rd_avg_latency;
762 +
763 + RRDSET *st_retention;
764 + RRDDIM *rd_retention;
765 +
766 + RRDSET *st_subscription_count;
767 + RRDDIM *rd_subscription_count;
768 +
769 + RRDSET *st_running_agent;
770 + RRDDIM *rd_running_agent;
771 +
772 + RRDSET *st_synchronization_time;
773 + RRDDIM *rd_synchronization_time;
774 +};
775 +
776 +struct mssql_instance {
777 + char *instanceID;
778 + int update_every;
779 +
780 + struct netdata_mssql_conn *conn;
781 +
782 + char *objectName[NETDATA_MSSQL_METRICS_END];
783 +
784 + RRDSET *st_user_connections;
785 + RRDDIM *rd_user_connections;
786 +
787 + RRDSET *st_process_blocked;
788 + RRDDIM *rd_process_blocked;
789 +
790 + RRDSET *st_stats_auto_param;
791 + RRDDIM *rd_stats_auto_param;
792 +
793 + RRDSET *st_stats_batch_request;
794 + RRDDIM *rd_stats_batch_request;
795 +
796 + RRDSET *st_stats_safe_auto;
797 + RRDDIM *rd_stats_safe_auto;
798 +
799 + RRDSET *st_access_method_page_splits;
800 + RRDDIM *rd_access_method_page_splits;
801 +
802 + RRDSET *st_sql_errors;
803 + RRDDIM *rd_sql_errors;
804 +
805 + DICTIONARY *locks_instances;
806 +
807 + DICTIONARY *databases;
808 + DICTIONARY *sysjobs;
809 + DICTIONARY *publisher_publication;
810 +
811 + RRDSET *st_conn_memory;
812 + RRDDIM *rd_conn_memory;
813 +
814 + RRDSET *st_ext_benefit_mem;
815 + RRDDIM *rd_ext_benefit_mem;
816 +
817 + RRDSET *st_pending_mem_grant;
818 + RRDDIM *rd_pending_mem_grant;
819 +
820 + RRDSET *st_mem_tot_server;
821 + RRDDIM *rd_mem_tot_server;
822 +
823 + DICTIONARY *waits;
824 +
825 + COUNTER_DATA MSSQLAccessMethodPageSplits;
826 + COUNTER_DATA MSSQLBlockedProcesses;
827 + COUNTER_DATA MSSQLUserConnections;
828 + COUNTER_DATA MSSQLConnectionMemoryBytes;
829 + COUNTER_DATA MSSQLExternalBenefitOfMemory;
830 + COUNTER_DATA MSSQLPendingMemoryGrants;
831 + COUNTER_DATA MSSQLSQLErrorsTotal;
832 + COUNTER_DATA MSSQLTotalServerMemory;
833 + COUNTER_DATA MSSQLStatsAutoParameterization;
834 + COUNTER_DATA MSSQLStatsBatchRequests;
835 + COUNTER_DATA MSSQLStatSafeAutoParameterization;
836 +};
837 +
838 +struct mssql_lock_instance {
839 + struct mssql_instance *parent;
840 +
841 + char *resourceID;
842 +
843 + COUNTER_DATA lockWait;
844 + COUNTER_DATA deadLocks;
845 +
846 + RRDSET *st_deadLocks;
847 + RRDDIM *rd_lockWait;
848 +
849 + RRDSET *st_lockWait;
850 + RRDDIM *rd_deadLocks;
851 +};
852 +
853 +struct mssql_db_jobs {
854 + bool enabled;
855 +
856 + RRDSET *st_status;
857 + RRDDIM *rd_status_enabled;
858 + RRDDIM *rd_status_disabled;
859 +
860 + COUNTER_DATA MSSQLJOBState;
861 +};
862 +
863 +struct mssql_db_instance {
864 + struct mssql_instance *parent;
865 +
866 + bool collecting_data;
867 + bool collect_instance;
868 + bool running_replication;
869 +
870 + RRDSET *st_db_data_file_size;
871 + RRDSET *st_db_active_transactions;
872 + RRDSET *st_db_backup_restore_operations;
873 + RRDSET *st_db_log_flushed;
874 + RRDSET *st_db_log_flushes;
875 + RRDSET *st_db_transactions;
876 + RRDSET *st_db_write_transactions;
877 + RRDSET *st_db_lockwait;
878 + RRDSET *st_db_deadlock;
879 + RRDSET *st_db_readonly;
880 + RRDSET *st_db_state;
881 + RRDSET *st_lock_timeouts;
882 + RRDSET *st_lock_requests;
883 + RRDSET *st_buff_page_iops;
884 + RRDSET *st_buff_cache_hits;
885 + RRDSET *st_buff_checkpoint_pages;
886 + RRDSET *st_buff_cache_page_life_expectancy;
887 + RRDSET *st_buff_lazy_write;
888 + RRDSET *st_buff_page_lookups;
889 +
890 + RRDSET *st_stats_compilation;
891 + RRDSET *st_stats_recompiles;
892 +
893 + RRDDIM *rd_db_data_file_size;
894 + RRDDIM *rd_db_active_transactions;
895 + RRDDIM *rd_db_backup_restore_operations;
896 + RRDDIM *rd_db_log_flushed;
897 + RRDDIM *rd_db_log_flushes;
898 + RRDDIM *rd_db_transactions;
899 + RRDDIM *rd_db_write_transactions;
900 + RRDDIM *rd_db_lockwait;
901 + RRDDIM *rd_db_deadlock;
902 + RRDDIM *rd_db_readonly_yes;
903 + RRDDIM *rd_db_readonly_no;
904 + RRDDIM *rd_db_state[NETDATA_DB_STATES];
905 + RRDDIM *rd_lock_timeouts;
906 + RRDDIM *rd_lock_requests;
907 + RRDDIM *rd_buff_page_reads;
908 + RRDDIM *rd_buff_page_writes;
909 + RRDDIM *rd_buff_cache_hits;
910 + RRDDIM *rd_buff_checkpoint_pages;
911 + RRDDIM *rd_buff_cache_page_life_expectancy;
912 + RRDDIM *rd_buff_lazy_write;
913 + RRDDIM *rd_buff_page_lookups;
914 +
915 + RRDDIM *rd_stats_compilation;
916 + RRDDIM *rd_stats_recompiles;
917 +
918 + COUNTER_DATA MSSQLDatabaseDataFileSize;
919 +
920 + COUNTER_DATA MSSQLDatabaseActiveTransactions;
921 + COUNTER_DATA MSSQLDatabaseBackupRestoreOperations;
922 + COUNTER_DATA MSSQLDatabaseLogFlushed;
923 + COUNTER_DATA MSSQLDatabaseLogFlushes;
924 + COUNTER_DATA MSSQLDatabaseTransactions;
925 + COUNTER_DATA MSSQLDatabaseWriteTransactions;
926 +
927 + COUNTER_DATA MSSQLDatabaseLockWaitSec;
928 + COUNTER_DATA MSSQLDatabaseDeadLockSec;
929 + COUNTER_DATA MSSQLDatabaseLockTimeoutsSec;
930 + COUNTER_DATA MSSQLDatabaseLockRequestsSec;
931 +
932 + // Buffer Management (https://learn.microsoft.com/en-us/sql/relational-databases/performance-monitor/sql-server-buffer-manager-object)
933 + COUNTER_DATA MSSQLBufferPageReads;
934 + COUNTER_DATA MSSQLBufferPageWrites;
935 + COUNTER_DATA MSSQLBufferCacheHits;
936 + COUNTER_DATA MSSQLBufferCheckpointPages;
937 + COUNTER_DATA MSSQLBufferPageLifeExpectancy;
938 + COUNTER_DATA MSSQLBufferLazyWrite;
939 + COUNTER_DATA MSSQLBufferPageLookups;
940 +
941 + COUNTER_DATA MSSQLCompilations;
942 + COUNTER_DATA MSSQLRecompilations;
943 +
944 + COUNTER_DATA MSSQLDBIsReadonly;
945 + COUNTER_DATA MSSQLDBState;
946 +
947 + uint32_t updated;
948 +};
949 +
950 +enum netdata_mssql_odbc_errors {
951 + NETDATA_MSSQL_ODBC_NO_ERROR,
952 + NETDATA_MSSQL_ODBC_CONNECT,
953 + NETDATA_MSSQL_ODBC_BIND,
954 + NETDATA_MSSQL_ODBC_PREPARE,
955 + NETDATA_MSSQL_ODBC_QUERY,
956 + NETDATA_MSSQL_ODBC_FETCH
957 +};
958 +
959 +static inline PERF_DATA_BLOCK *
960 +netdata_mssql_get_perf_data_block(bool *collect_perflib, struct mssql_instance *mi, DWORD idx)
961 +{
962 + DWORD id = RegistryFindIDByName(mi->objectName[idx]);
963 + if (id == PERFLIB_REGISTRY_NAME_NOT_FOUND) {
964 + collect_perflib[idx] = false;
965 + return NULL;
966 + }
967 +
968 + PERF_DATA_BLOCK *pDataBlock = perflibGetPerformanceData(id);
969 + if (!pDataBlock) {
970 + collect_perflib[idx] = true;
971 + return NULL;
972 + }
973 +
974 + return pDataBlock;
975 +}
976 +
977 +void do_mssql_general_stats(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *mi, int update_every);
978 +void do_mssql_errors(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *mi, int update_every);
979 +void do_mssql_memory_mgr(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *mi, int update_every);
980 +void do_mssql_statistics_perflib(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *mi, int update_every);
981 +void do_mssql_access_methods(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *mi, int update_every);
982 #endif
src/collectors/windows.plugin/perflib-mssql.c
+267 -3636
@@ -5,3557 +5,175 @@
5
6 #include "perflib-mssql-queries.h"
7
8 -#include <sqlext.h>
9 -#include <sqltypes.h>
10 -#include <sql.h>
11 -
12 -#define MEGA_FACTOR (1048576) // 1024 * 1024
13 -// https://learn.microsoft.com/en-us/sql/sql-server/install/instance-configuration?view=sql-server-ver16
14 -#define NETDATA_MAX_INSTANCE_NAME (32)
15 -#define NETDATA_MAX_INSTANCE_OBJECT (128)
16 -// https://learn.microsoft.com/en-us/previous-versions/sql/sql-server-2008-r2/ms191240(v=sql.105)#sysname
17 -#define SQLSERVER_MAX_NAME_LENGTH NETDATA_MAX_INSTANCE_OBJECT
18 -#define NETDATA_MSSQL_NEXT_TRY (60)
19 -
20 -struct netdata_mssql_conn {
21 - const char *instance;
22 - const char *driver;
23 - const char *server;
24 - const char *address;
25 - const char *username;
26 - const char *password;
27 - int instances;
28 - bool windows_auth;
29 - bool is_sqlexpress;
30 -
31 - SQLCHAR *connectionString;
32 -
33 - SQLHENV netdataSQLEnv;
34 - SQLHDBC netdataSQLHDBc;
35 -
36 - SQLHSTMT checkPermSTMT;
37 - SQLHSTMT databaseListSTMT;
38 - SQLHSTMT dataFileSizeSTMT;
39 - SQLHSTMT dbTransactionSTMT;
40 - SQLHSTMT dbInstanceTransactionSTMT;
41 - SQLHSTMT dbWaitsSTMT;
42 - SQLHSTMT dbLocksSTMT;
43 - SQLHSTMT dbSQLState;
44 - SQLHSTMT dbSQLJobs;
45 - SQLHSTMT dbReplicationPublisher;
46 -
47 - BOOL is_connected;
48 -};
49 -
50 -DICTIONARY *conn_options;
51 -
52 -enum netdata_mssql_metrics {
53 - NETDATA_MSSQL_GENERAL_STATS,
54 - NETDATA_MSSQL_SQL_ERRORS,
55 - NETDATA_MSSQL_MEMORY,
56 - NETDATA_MSSQL_SQL_STATS,
57 - NETDATA_MSSQL_ACCESS_METHODS,
58 -
59 - NETDATA_MSSQL_DATABASE,
60 - NETDATA_MSSQL_LOCKS,
61 - NETDATA_MSSQL_WAITS,
62 - NETDATA_MSSQL_BUFFER_MANAGEMENT,
63 - NETDATA_MSSQL_JOBS,
64 -
65 - NETDATA_MSSQL_METRICS_END
66 -};
67 -
68 -struct mssql_db_waits {
69 - const char *wait_type;
70 - const char *wait_category;
71 -
72 - RRDSET *st_total_wait;
73 - RRDDIM *rd_total_wait;
74 -
75 - RRDSET *st_resource_wait_msec;
76 - RRDDIM *rd_resource_wait_msec;
77 -
78 - RRDSET *st_signal_wait_msec;
79 - RRDDIM *rd_signal_wait_msec;
80 -
81 - RRDSET *st_max_wait_time_msec;
82 - RRDDIM *rd_max_wait_time_msec;
83 -
84 - RRDSET *st_waiting_tasks;
85 - RRDDIM *rd_waiting_tasks;
86 -
87 - COUNTER_DATA MSSQLDatabaseTotalWait;
88 - COUNTER_DATA MSSQLDatabaseResourceWaitMSec;
89 - COUNTER_DATA MSSQLDatabaseSignalWaitMSec;
90 - COUNTER_DATA MSSQLDatabaseMaxWaitTimeMSec;
91 - COUNTER_DATA MSSQLDatabaseWaitingTasks;
92 -};
93 -
94 -// https://learn.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-replmonitorhelppublication-transact-sql?view=sql-server-ver17
95 -struct mssql_publisher_publication {
96 - struct mssql_instance *parent;
97 -
98 - // Lables
99 - char *publisher;
100 - char *publication;
101 - char *db;
102 - int type;
103 -
104 - // Charts
105 - int status;
106 - int warning;
107 -
108 - int avg_latency;
109 -
110 - int retention;
111 -
112 - int subscriptioncount;
113 - int runningdistagentcount;
114 -
115 - int average_runspeedPerf;
116 -
117 - RRDSET *st_publisher_status;
118 - RRDDIM *rd_publisher_status_started;
119 - RRDDIM *rd_publisher_status_successed;
120 - RRDDIM *rd_publisher_status_in_progress;
121 - RRDDIM *rd_publisher_status_idle;
122 - RRDDIM *rd_publisher_status_retrying;
123 - RRDDIM *rd_publisher_status_failed;
124 -
125 - RRDSET *st_warning;
126 - RRDDIM *rd_warning_expiration;
127 - RRDDIM *rd_warning_latency;
128 - RRDDIM *rd_warning_mergeeexpiration;
129 - RRDDIM *rd_warning_mergefastduration;
130 - RRDDIM *rd_warning_mergelowduration;
131 - RRDDIM *rd_warning_mergefastrunspeed;
132 - RRDDIM *rd_warning_mergelowrunspeed;
133 -
134 - RRDSET *st_avg_latency;
135 - RRDDIM *rd_avg_latency;
136 -
137 - RRDSET *st_retention;
138 - RRDDIM *rd_retention;
139 -
140 - RRDSET *st_subscription_count;
141 - RRDDIM *rd_subscription_count;
142 -
143 - RRDSET *st_running_agent;
144 - RRDDIM *rd_running_agent;
145 -
146 - RRDSET *st_synchronization_time;
147 - RRDDIM *rd_synchronization_time;
148 -};
149 -
150 -struct mssql_instance {
151 - char *instanceID;
152 - int update_every;
153 -
154 - struct netdata_mssql_conn *conn;
155 -
156 - char *objectName[NETDATA_MSSQL_METRICS_END];
157 -
158 - RRDSET *st_user_connections;
159 - RRDDIM *rd_user_connections;
160 -
161 - RRDSET *st_process_blocked;
162 - RRDDIM *rd_process_blocked;
163 -
164 - RRDSET *st_stats_auto_param;
165 - RRDDIM *rd_stats_auto_param;
166 -
167 - RRDSET *st_stats_batch_request;
168 - RRDDIM *rd_stats_batch_request;
169 -
170 - RRDSET *st_stats_safe_auto;
171 - RRDDIM *rd_stats_safe_auto;
172 -
173 - RRDSET *st_access_method_page_splits;
174 - RRDDIM *rd_access_method_page_splits;
175 -
176 - RRDSET *st_sql_errors;
177 - RRDDIM *rd_sql_errors;
178 -
179 - DICTIONARY *locks_instances;
180 -
181 - DICTIONARY *databases;
182 - DICTIONARY *sysjobs;
183 - DICTIONARY *publisher_publication;
184 -
185 - RRDSET *st_conn_memory;
186 - RRDDIM *rd_conn_memory;
187 -
188 - RRDSET *st_ext_benefit_mem;
189 - RRDDIM *rd_ext_benefit_mem;
190 -
191 - RRDSET *st_pending_mem_grant;
192 - RRDDIM *rd_pending_mem_grant;
193 -
194 - RRDSET *st_mem_tot_server;
195 - RRDDIM *rd_mem_tot_server;
196 -
197 - DICTIONARY *waits;
198 -
199 - COUNTER_DATA MSSQLAccessMethodPageSplits;
200 - COUNTER_DATA MSSQLBlockedProcesses;
201 - COUNTER_DATA MSSQLUserConnections;
202 - COUNTER_DATA MSSQLConnectionMemoryBytes;
203 - COUNTER_DATA MSSQLExternalBenefitOfMemory;
204 - COUNTER_DATA MSSQLPendingMemoryGrants;
205 - COUNTER_DATA MSSQLSQLErrorsTotal;
206 - COUNTER_DATA MSSQLTotalServerMemory;
207 - COUNTER_DATA MSSQLStatsAutoParameterization;
208 - COUNTER_DATA MSSQLStatsBatchRequests;
209 - COUNTER_DATA MSSQLStatSafeAutoParameterization;
210 -};
211 -
212 -struct mssql_lock_instance {
213 - struct mssql_instance *parent;
214 -
215 - char *resourceID;
216 -
217 - COUNTER_DATA lockWait;
218 - COUNTER_DATA deadLocks;
219 -
220 - RRDSET *st_deadLocks;
221 - RRDDIM *rd_lockWait;
222 -
223 - RRDSET *st_lockWait;
224 - RRDDIM *rd_deadLocks;
225 -};
226 -
227 -struct mssql_db_jobs {
228 - bool enabled;
229 -
230 - RRDSET *st_status;
231 - RRDDIM *rd_status_enabled;
232 - RRDDIM *rd_status_disabled;
233 -
234 - COUNTER_DATA MSSQLJOBState;
235 -};
236 -
237 -struct mssql_db_instance {
238 - struct mssql_instance *parent;
239 -
240 - bool collecting_data;
241 - bool collect_instance;
242 - bool running_replication;
243 -
244 - RRDSET *st_db_data_file_size;
245 - RRDSET *st_db_active_transactions;
246 - RRDSET *st_db_backup_restore_operations;
247 - RRDSET *st_db_log_flushed;
248 - RRDSET *st_db_log_flushes;
249 - RRDSET *st_db_transactions;
250 - RRDSET *st_db_write_transactions;
251 - RRDSET *st_db_lockwait;
252 - RRDSET *st_db_deadlock;
253 - RRDSET *st_db_readonly;
254 - RRDSET *st_db_state;
255 - RRDSET *st_lock_timeouts;
256 - RRDSET *st_lock_requests;
257 - RRDSET *st_buff_page_iops;
258 - RRDSET *st_buff_cache_hits;
259 - RRDSET *st_buff_checkpoint_pages;
260 - RRDSET *st_buff_cache_page_life_expectancy;
261 - RRDSET *st_buff_lazy_write;
262 - RRDSET *st_buff_page_lookups;
263 -
264 - RRDSET *st_stats_compilation;
265 - RRDSET *st_stats_recompiles;
266 -
267 - RRDDIM *rd_db_data_file_size;
268 - RRDDIM *rd_db_active_transactions;
269 - RRDDIM *rd_db_backup_restore_operations;
270 - RRDDIM *rd_db_log_flushed;
271 - RRDDIM *rd_db_log_flushes;
272 - RRDDIM *rd_db_transactions;
273 - RRDDIM *rd_db_write_transactions;
274 - RRDDIM *rd_db_lockwait;
275 - RRDDIM *rd_db_deadlock;
276 - RRDDIM *rd_db_readonly_yes;
277 - RRDDIM *rd_db_readonly_no;
278 - RRDDIM *rd_db_state[NETDATA_DB_STATES];
279 - RRDDIM *rd_lock_timeouts;
280 - RRDDIM *rd_lock_requests;
281 - RRDDIM *rd_buff_page_reads;
282 - RRDDIM *rd_buff_page_writes;
283 - RRDDIM *rd_buff_cache_hits;
284 - RRDDIM *rd_buff_checkpoint_pages;
285 - RRDDIM *rd_buff_cache_page_life_expectancy;
286 - RRDDIM *rd_buff_lazy_write;
287 - RRDDIM *rd_buff_page_lookups;
288 -
289 - RRDDIM *rd_stats_compilation;
290 - RRDDIM *rd_stats_recompiles;
291 -
292 - COUNTER_DATA MSSQLDatabaseDataFileSize;
293 -
294 - COUNTER_DATA MSSQLDatabaseActiveTransactions;
295 - COUNTER_DATA MSSQLDatabaseBackupRestoreOperations;
296 - COUNTER_DATA MSSQLDatabaseLogFlushed;
297 - COUNTER_DATA MSSQLDatabaseLogFlushes;
298 - COUNTER_DATA MSSQLDatabaseTransactions;
299 - COUNTER_DATA MSSQLDatabaseWriteTransactions;
300 -
301 - COUNTER_DATA MSSQLDatabaseLockWaitSec;
302 - COUNTER_DATA MSSQLDatabaseDeadLockSec;
303 - COUNTER_DATA MSSQLDatabaseLockTimeoutsSec;
304 - COUNTER_DATA MSSQLDatabaseLockRequestsSec;
305 -
306 - // Buffer Management (https://learn.microsoft.com/en-us/sql/relational-databases/performance-monitor/sql-server-buffer-manager-object)
307 - COUNTER_DATA MSSQLBufferPageReads;
308 - COUNTER_DATA MSSQLBufferPageWrites;
309 - COUNTER_DATA MSSQLBufferCacheHits;
310 - COUNTER_DATA MSSQLBufferCheckpointPages;
311 - COUNTER_DATA MSSQLBufferPageLifeExpectancy;
312 - COUNTER_DATA MSSQLBufferLazyWrite;
313 - COUNTER_DATA MSSQLBufferPageLookups;
314 -
315 - COUNTER_DATA MSSQLCompilations;
316 - COUNTER_DATA MSSQLRecompilations;
317 -
318 - COUNTER_DATA MSSQLDBIsReadonly;
319 - COUNTER_DATA MSSQLDBState;
320 -
321 - uint32_t updated;
322 -};
323 -
324 -enum netdata_mssql_odbc_errors {
325 - NETDATA_MSSQL_ODBC_NO_ERROR,
326 - NETDATA_MSSQL_ODBC_CONNECT,
327 - NETDATA_MSSQL_ODBC_BIND,
328 - NETDATA_MSSQL_ODBC_PREPARE,
329 - NETDATA_MSSQL_ODBC_QUERY,
330 - NETDATA_MSSQL_ODBC_FETCH
331 -};
332 -
333 -static inline int netdata_mssql_check_result(SQLRETURN ret)
334 -{
335 - return (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO);
336 -}
337 -
338 -static char *netdata_MSSQL_error_text(enum netdata_mssql_odbc_errors val)
339 -{
340 - switch (val) {
341 - case NETDATA_MSSQL_ODBC_NO_ERROR:
342 - return "NO ERROR";
343 - case NETDATA_MSSQL_ODBC_CONNECT:
344 - return "CONNECTION";
345 - case NETDATA_MSSQL_ODBC_BIND:
346 - return "BIND PARAMETER";
347 - case NETDATA_MSSQL_ODBC_PREPARE:
348 - return "PREPARE PARAMETER";
349 - case NETDATA_MSSQL_ODBC_QUERY:
350 - return "QUERY PARAMETER";
351 - case NETDATA_MSSQL_ODBC_FETCH:
352 - default:
353 - return "QUERY FETCH";
354 - }
355 -}
356 -
357 -static char *netdata_MSSQL_type_text(uint32_t type)
358 -{
359 - switch (type) {
360 - case SQL_HANDLE_STMT:
361 - return "STMT";
362 - case SQL_HANDLE_DBC:
363 - default:
364 - return "DBC";
365 - }
366 -}
367 -
368 -// Connection and SQL
369 -static void netdata_MSSQL_error(uint32_t type, SQLHANDLE handle, enum netdata_mssql_odbc_errors step, char *instance)
370 -{
371 - SQLCHAR state[1024];
372 - SQLCHAR message[1024];
373 - if (SQL_SUCCESS == SQLGetDiagRec((short)type, handle, 1, state, NULL, message, 1024, NULL)) {
374 - char *str_step = netdata_MSSQL_error_text(step);
375 - char *str_type = netdata_MSSQL_type_text(type);
376 - char *use_instance = (!instance) ? "no instance" : instance;
377 - nd_log(
378 - NDLS_COLLECTORS,
379 - NDLP_INFO,
380 - "MSSQL server error on %s using the handle %s running %s : %s, %s",
381 - use_instance,
382 - str_type,
383 - str_step,
384 - message,
385 - state);
386 - }
387 -}
388 -
389 -static inline void netdata_MSSQL_release_results(SQLHSTMT *stmt)
390 -{
391 - SQLCloseCursor(stmt);
392 -}
393 -
394 -static ULONGLONG netdata_MSSQL_fill_long_value(SQLHSTMT *stmt, const char *mask, const char *dbname, char *instance)
395 -{
396 - long db_size = 0;
397 - SQLLEN col_data_len = 0;
398 -
399 - SQLCHAR query[512];
400 - snprintfz((char *)query, 511, mask, dbname);
401 -
402 - SQLRETURN ret;
403 -
404 - ret = SQLExecDirect(stmt, query, SQL_NTS);
405 - if (netdata_mssql_check_result(ret)) {
406 - netdata_MSSQL_error(SQL_HANDLE_STMT, stmt, NETDATA_MSSQL_ODBC_QUERY, instance);
407 - return (ULONGLONG)ULONG_LONG_MAX;
408 - }
409 -
410 - ret = SQLBindCol(stmt, 1, SQL_C_LONG, &db_size, sizeof(long), &col_data_len);
411 - if (netdata_mssql_check_result(ret)) {
412 - netdata_MSSQL_error(SQL_HANDLE_STMT, stmt, NETDATA_MSSQL_ODBC_PREPARE, instance);
413 - return (ULONGLONG)ULONG_LONG_MAX;
414 - }
415 -
416 - ret = SQLFetch(stmt);
417 - if (netdata_mssql_check_result(ret)) {
418 - netdata_MSSQL_error(SQL_HANDLE_STMT, stmt, NETDATA_MSSQL_ODBC_FETCH, instance);
419 - return (ULONGLONG)ULONG_LONG_MAX;
420 - }
421 -
422 - netdata_MSSQL_release_results(stmt);
423 - return (ULONGLONG)(db_size * MEGA_FACTOR);
424 -}
425 -
426 -#define NETDATA_MSSQL_BUFFER_PAGE_READS_METRIC "Page reads/sec"
427 -#define NETDATA_MSSQL_BUFFER_PAGE_WRITES_METRIC "Page writes/sec"
428 -#define NETDATA_MSSQL_BUFFER_PAGE_CACHE_METRIC "Buffer cache hit ratio"
429 -#define NETDATA_MSSQL_BUFFER_CHECKPOINT_METRIC "Checkpoint pages/sec"
430 -#define NETDATA_MSSQL_BUFFER_PAGE_LIFE_METRIC "Page life expectancy"
431 -#define NETDATA_MSSQL_BUFFER_LAZY_WRITES_METRIC "Lazy writes/sec"
432 -#define NETDATA_MSSQL_BUFFER_PAGE_LOOKUPS_METRIC "Page Lookups/sec"
433 -
434 -#define NETDATA_MSSQL_STATS_COMPILATIONS_METRIC "SQL Compilations/sec"
435 -#define NETDATA_MSSQL_STATS_RECOMPILATIONS_METRIC "SQL Re-Compilations/sec"
436 -
437 -void dict_mssql_fill_instance_transactions(struct mssql_db_instance *mdi)
438 -{
439 - char object_name[NETDATA_MAX_INSTANCE_OBJECT + 1] = {};
440 - long value = 0;
441 - SQLLEN col_object_len = 0, col_value_len = 0;
442 -
443 - SQLCHAR query[sizeof(NETDATA_QUERY_TRANSACTIONS_PER_INSTANCE_MASK) + NETDATA_MAX_INSTANCE_OBJECT + 1];
444 - snprintfz(
445 - (char *)query,
446 - sizeof(NETDATA_QUERY_TRANSACTIONS_PER_INSTANCE_MASK) + NETDATA_MAX_INSTANCE_OBJECT,
447 - NETDATA_QUERY_TRANSACTIONS_PER_INSTANCE_MASK,
448 - mdi->parent->instanceID);
449 -
450 - SQLRETURN ret = SQLExecDirect(mdi->parent->conn->dbInstanceTransactionSTMT, (SQLCHAR *)query, SQL_NTS);
451 - if (netdata_mssql_check_result(ret)) {
452 - mdi->collecting_data = false;
453 - netdata_MSSQL_error(
454 - SQL_HANDLE_STMT,
455 - mdi->parent->conn->dbInstanceTransactionSTMT,
456 - NETDATA_MSSQL_ODBC_QUERY,
457 - mdi->parent->instanceID);
458 - goto enditransactions;
459 - }
460 -
461 - ret = SQLBindCol(
462 - mdi->parent->conn->dbInstanceTransactionSTMT, 1, SQL_C_CHAR, object_name, sizeof(object_name), &col_object_len);
463 - if (netdata_mssql_check_result(ret)) {
464 - netdata_MSSQL_error(
465 - SQL_HANDLE_STMT,
466 - mdi->parent->conn->dbInstanceTransactionSTMT,
467 - NETDATA_MSSQL_ODBC_PREPARE,
468 - mdi->parent->instanceID);
469 - goto enditransactions;
470 - }
471 -
472 - ret =
473 - SQLBindCol(mdi->parent->conn->dbInstanceTransactionSTMT, 2, SQL_C_LONG, &value, sizeof(value), &col_value_len);
474 - if (netdata_mssql_check_result(ret)) {
475 - netdata_MSSQL_error(
476 - SQL_HANDLE_STMT,
477 - mdi->parent->conn->dbInstanceTransactionSTMT,
478 - NETDATA_MSSQL_ODBC_PREPARE,
479 - mdi->parent->instanceID);
480 - goto enditransactions;
481 - }
482 -
483 - do {
484 - ret = SQLFetch(mdi->parent->conn->dbInstanceTransactionSTMT);
485 - switch (ret) {
486 - case SQL_SUCCESS:
487 - case SQL_SUCCESS_WITH_INFO:
488 - break;
489 - case SQL_NO_DATA:
490 - default:
491 - goto enditransactions;
492 - }
493 -
494 - // We cannot use strcmp, because buffer is filled with spaces instead NULL.
495 - if (!strncmp(
496 - object_name, NETDATA_MSSQL_BUFFER_PAGE_READS_METRIC, sizeof(NETDATA_MSSQL_BUFFER_PAGE_READS_METRIC) - 1))
497 - mdi->MSSQLBufferPageReads.current.Data = (ULONGLONG)value;
498 - else if (!strncmp(
499 - object_name,
500 - NETDATA_MSSQL_BUFFER_PAGE_WRITES_METRIC,
501 - sizeof(NETDATA_MSSQL_BUFFER_PAGE_WRITES_METRIC) - 1))
502 - mdi->MSSQLBufferPageWrites.current.Data = (ULONGLONG)value;
503 - else if (!strncmp(
504 - object_name,
505 - NETDATA_MSSQL_BUFFER_PAGE_CACHE_METRIC,
506 - sizeof(NETDATA_MSSQL_BUFFER_PAGE_CACHE_METRIC) - 1))
507 - mdi->MSSQLBufferCacheHits.current.Data = (ULONGLONG)value;
508 - else if (!strncmp(
509 - object_name,
510 - NETDATA_MSSQL_BUFFER_CHECKPOINT_METRIC,
511 - sizeof(NETDATA_MSSQL_BUFFER_CHECKPOINT_METRIC) - 1))
512 - mdi->MSSQLBufferCheckpointPages.current.Data = (ULONGLONG)value;
513 - else if (!strncmp(
514 - object_name,
515 - NETDATA_MSSQL_BUFFER_PAGE_LIFE_METRIC,
516 - sizeof(NETDATA_MSSQL_BUFFER_PAGE_LIFE_METRIC) - 1))
517 - mdi->MSSQLBufferPageLifeExpectancy.current.Data = (ULONGLONG)value;
518 - else if (!strncmp(
519 - object_name,
520 - NETDATA_MSSQL_BUFFER_LAZY_WRITES_METRIC,
521 - sizeof(NETDATA_MSSQL_BUFFER_LAZY_WRITES_METRIC) - 1))
522 - mdi->MSSQLBufferLazyWrite.current.Data = (ULONGLONG)value;
523 - else if (!strncmp(
524 - object_name,
525 - NETDATA_MSSQL_BUFFER_PAGE_LOOKUPS_METRIC,
526 - sizeof(NETDATA_MSSQL_BUFFER_PAGE_LOOKUPS_METRIC) - 1))
527 - mdi->MSSQLBufferPageLookups.current.Data = (ULONGLONG)value;
528 - else if (!strncmp(
529 - object_name,
530 - NETDATA_MSSQL_STATS_COMPILATIONS_METRIC,
531 - sizeof(NETDATA_MSSQL_STATS_COMPILATIONS_METRIC) - 1))
532 - mdi->MSSQLCompilations.current.Data = (ULONGLONG)value;
533 - else if (!strncmp(
534 - object_name,
535 - NETDATA_MSSQL_STATS_RECOMPILATIONS_METRIC,
536 - sizeof(NETDATA_MSSQL_STATS_RECOMPILATIONS_METRIC) - 1))
537 - mdi->MSSQLRecompilations.current.Data = (ULONGLONG)value;
538 - } while (true);
539 -
540 -enditransactions:
541 - netdata_MSSQL_release_results(mdi->parent->conn->dbInstanceTransactionSTMT);
542 -}
543 -
544 -#define NETDATA_MSSQL_ACTIVE_TRANSACTIONS_METRIC "Active Transactions"
545 -#define NETDATA_MSSQL_TRANSACTION_PER_SEC_METRIC "Transactions/sec"
546 -#define NETDATA_MSSQL_WRITE_TRANSACTIONS_METRIC "Write Transactions/sec"
547 -#define NETDATA_MSSQL_BACKUP_RESTORE_METRIC "Backup/Restore Throughput/sec"
548 -#define NETDATA_MSSQL_LOG_FLUSHED_METRIC "Log Bytes Flushed/sec"
549 -#define NETDATA_MSSQL_LOG_FLUSHES_METRIC "Log Flushes/sec"
550 -#define NETDATA_MSSQL_NUMBER_DEADLOCKS_METRIC "Number of Deadlocks/sec"
551 -#define NETDATA_MSSQL_LOCK_WAITS_METRIC "Lock Waits/sec"
552 -#define NETDATA_MSSQL_LOCK_TIMEOUTS_METRIC "Lock Timeouts/sec"
553 -#define NETDATA_MSSQL_LOCK_REQUESTS_METRIC "Lock Requests/sec"
554 -
555 -void dict_mssql_fill_transactions(struct mssql_db_instance *mdi, const char *dbname)
556 -{
557 - char object_name[NETDATA_MAX_INSTANCE_OBJECT + 1] = {};
558 - long value = 0;
559 - SQLLEN col_object_len = 0, col_value_len = 0;
560 -
561 - if (mdi->collect_instance)
562 - dict_mssql_fill_instance_transactions(mdi);
563 -
564 - SQLCHAR query[sizeof(NETDATA_QUERY_TRANSACTIONS_MASK) + 2 * NETDATA_MAX_INSTANCE_OBJECT + 1];
565 - snprintfz(
566 - (char *)query,
567 - sizeof(NETDATA_QUERY_TRANSACTIONS_MASK) + 2 * NETDATA_MAX_INSTANCE_OBJECT,
568 - NETDATA_QUERY_TRANSACTIONS_MASK,
569 - dbname,
570 - dbname);
571 -
572 - SQLRETURN ret = SQLExecDirect(mdi->parent->conn->dbTransactionSTMT, (SQLCHAR *)query, SQL_NTS);
573 - if (netdata_mssql_check_result(ret)) {
574 - mdi->collecting_data = false;
575 - netdata_MSSQL_error(
576 - SQL_HANDLE_STMT, mdi->parent->conn->dbTransactionSTMT, NETDATA_MSSQL_ODBC_QUERY, mdi->parent->instanceID);
577 - goto endtransactions;
578 - }
579 -
580 - ret = SQLBindCol(
581 - mdi->parent->conn->dbTransactionSTMT, 1, SQL_C_CHAR, object_name, sizeof(object_name), &col_object_len);
582 - if (netdata_mssql_check_result(ret)) {
583 - netdata_MSSQL_error(
584 - SQL_HANDLE_STMT, mdi->parent->conn->dbTransactionSTMT, NETDATA_MSSQL_ODBC_PREPARE, mdi->parent->instanceID);
585 - goto endtransactions;
586 - }
587 -
588 - ret = SQLBindCol(mdi->parent->conn->dbTransactionSTMT, 2, SQL_C_LONG, &value, sizeof(value), &col_value_len);
589 - if (netdata_mssql_check_result(ret)) {
590 - netdata_MSSQL_error(
591 - SQL_HANDLE_STMT, mdi->parent->conn->dbTransactionSTMT, NETDATA_MSSQL_ODBC_PREPARE, mdi->parent->instanceID);
592 - goto endtransactions;
593 - }
594 -
595 - do {
596 - ret = SQLFetch(mdi->parent->conn->dbTransactionSTMT);
597 - switch (ret) {
598 - case SQL_SUCCESS:
599 - case SQL_SUCCESS_WITH_INFO:
600 - break;
601 - case SQL_NO_DATA:
602 - default:
603 - goto endtransactions;
604 - }
605 -
606 - // We cannot use strcmp, because buffer is filled with spaces instead NULL.
607 - if (!strncmp(
608 - object_name,
609 - NETDATA_MSSQL_ACTIVE_TRANSACTIONS_METRIC,
610 - sizeof(NETDATA_MSSQL_ACTIVE_TRANSACTIONS_METRIC) - 1))
611 - mdi->MSSQLDatabaseActiveTransactions.current.Data = (ULONGLONG)value;
612 - else if (!strncmp(
613 - object_name,
614 - NETDATA_MSSQL_TRANSACTION_PER_SEC_METRIC,
615 - sizeof(NETDATA_MSSQL_TRANSACTION_PER_SEC_METRIC) - 1))
616 - mdi->MSSQLDatabaseTransactions.current.Data = (ULONGLONG)value;
617 - else if (!strncmp(
618 - object_name,
619 - NETDATA_MSSQL_WRITE_TRANSACTIONS_METRIC,
620 - sizeof(NETDATA_MSSQL_WRITE_TRANSACTIONS_METRIC) - 1))
621 - mdi->MSSQLDatabaseWriteTransactions.current.Data = (ULONGLONG)value;
622 - else if (!strncmp(
623 - object_name, NETDATA_MSSQL_BACKUP_RESTORE_METRIC, sizeof(NETDATA_MSSQL_BACKUP_RESTORE_METRIC) - 1))
624 - mdi->MSSQLDatabaseBackupRestoreOperations.current.Data = (ULONGLONG)value;
625 - else if (!strncmp(object_name, NETDATA_MSSQL_LOG_FLUSHED_METRIC, sizeof(NETDATA_MSSQL_LOG_FLUSHED_METRIC) - 1))
626 - mdi->MSSQLDatabaseLogFlushed.current.Data = (ULONGLONG)value;
627 - else if (!strncmp(object_name, NETDATA_MSSQL_LOG_FLUSHES_METRIC, sizeof(NETDATA_MSSQL_LOG_FLUSHES_METRIC) - 1))
628 - mdi->MSSQLDatabaseLogFlushes.current.Data = (ULONGLONG)value;
629 - else if (!strncmp(
630 - object_name,
631 - NETDATA_MSSQL_NUMBER_DEADLOCKS_METRIC,
632 - sizeof(NETDATA_MSSQL_NUMBER_DEADLOCKS_METRIC) - 1))
633 - mdi->MSSQLDatabaseDeadLockSec.current.Data = (ULONGLONG)value;
634 - else if (!strncmp(object_name, NETDATA_MSSQL_LOCK_WAITS_METRIC, sizeof(NETDATA_MSSQL_LOCK_WAITS_METRIC) - 1))
635 - mdi->MSSQLDatabaseLockWaitSec.current.Data = (ULONGLONG)value;
636 - else if (!strncmp(
637 - object_name, NETDATA_MSSQL_LOCK_TIMEOUTS_METRIC, sizeof(NETDATA_MSSQL_LOCK_TIMEOUTS_METRIC) - 1))
638 - mdi->MSSQLDatabaseLockTimeoutsSec.current.Data = (ULONGLONG)value;
639 - else if (!strncmp(
640 - object_name, NETDATA_MSSQL_LOCK_REQUESTS_METRIC, sizeof(NETDATA_MSSQL_LOCK_REQUESTS_METRIC) - 1))
641 - mdi->MSSQLDatabaseLockRequestsSec.current.Data = (ULONGLONG)value;
642 -
643 - } while (true);
644 -
645 -endtransactions:
646 - netdata_MSSQL_release_results(mdi->parent->conn->dbTransactionSTMT);
647 -}
648 -
649 -void dict_mssql_fill_locks(struct mssql_db_instance *mdi, const char *dbname)
650 -{
651 -#define NETDATA_MSSQL_MAX_RESOURCE_TYPE (60)
652 - char resource_type[NETDATA_MSSQL_MAX_RESOURCE_TYPE + 1] = {};
653 - long value = 0;
654 - SQLLEN col_object_len = 0, col_value_len = 0;
655 -
656 - SQLCHAR query[sizeof(NETDATA_QUERY_LOCKS_MASK) + 2 * NETDATA_MAX_INSTANCE_OBJECT + 1];
657 - snprintfz(
658 - (char *)query,
659 - sizeof(NETDATA_QUERY_TRANSACTIONS_MASK) + 2 * NETDATA_MAX_INSTANCE_OBJECT,
660 - NETDATA_QUERY_LOCKS_MASK,
661 - dbname,
662 - dbname);
663 -
664 - SQLRETURN ret = SQLExecDirect(mdi->parent->conn->dbLocksSTMT, (SQLCHAR *)query, SQL_NTS);
665 - if (netdata_mssql_check_result(ret)) {
666 - mdi->collecting_data = false;
667 - netdata_MSSQL_error(
668 - SQL_HANDLE_STMT, mdi->parent->conn->dbLocksSTMT, NETDATA_MSSQL_ODBC_QUERY, mdi->parent->instanceID);
669 - goto endlocks;
670 - }
671 -
672 - ret = SQLBindCol(
673 - mdi->parent->conn->dbLocksSTMT, 1, SQL_C_CHAR, resource_type, sizeof(resource_type), &col_object_len);
674 - if (netdata_mssql_check_result(ret)) {
675 - netdata_MSSQL_error(
676 - SQL_HANDLE_STMT, mdi->parent->conn->dbLocksSTMT, NETDATA_MSSQL_ODBC_PREPARE, mdi->parent->instanceID);
677 - goto endlocks;
678 - }
679 -
680 - ret = SQLBindCol(mdi->parent->conn->dbLocksSTMT, 2, SQL_C_LONG, &value, sizeof(value), &col_value_len);
681 - if (netdata_mssql_check_result(ret)) {
682 - netdata_MSSQL_error(
683 - SQL_HANDLE_STMT, mdi->parent->conn->dbLocksSTMT, NETDATA_MSSQL_ODBC_PREPARE, mdi->parent->instanceID);
684 - goto endlocks;
685 - }
686 -
687 - do {
688 - ret = SQLFetch(mdi->parent->conn->dbLocksSTMT);
689 - switch (ret) {
690 - case SQL_SUCCESS:
691 - case SQL_SUCCESS_WITH_INFO:
692 - break;
693 - case SQL_NO_DATA:
694 - default:
695 - goto endlocks;
696 - }
697 -
698 - char *space = strchr(resource_type, ' ');
699 - if (space)
700 - *space = '\0';
701 -
702 - struct mssql_lock_instance *mli =
703 - dictionary_set(mdi->parent->locks_instances, resource_type, NULL, sizeof(*mli));
704 - if (!mli)
705 - continue;
706 -
707 - mli->lockWait.current.Data = value;
708 - } while (true);
709 -
710 -endlocks:
711 - netdata_MSSQL_release_results(mdi->parent->conn->dbLocksSTMT);
712 -}
713 -
714 -int dict_mssql_fill_waits(struct mssql_instance *mi)
715 -{
716 - char wait_type[NETDATA_MAX_INSTANCE_OBJECT + 1] = {};
717 - char wait_category[NETDATA_MAX_INSTANCE_OBJECT + 1] = {};
718 - SQLBIGINT total_wait = 0;
719 - SQLBIGINT resource_wait = 0;
720 - SQLBIGINT signal_wait = 0;
721 - SQLBIGINT max_wait = 0;
722 - SQLBIGINT waiting_tasks = 0;
723 - int success = 0;
724 - SQLLEN col_wait_type_len = 0, col_total_wait_len = 0, col_resource_wait_len = 0, col_signal_wait_len = 0,
725 - col_max_wait_len = 0, col_waiting_tasks_len = 0, col_wait_category_len = 0;
726 -
727 - SQLRETURN ret = SQLExecDirect(mi->conn->dbWaitsSTMT, (SQLCHAR *)NETDATA_QUERY_CHECK_WAITS, SQL_NTS);
728 - if (netdata_mssql_check_result(ret)) {
729 - netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->dbWaitsSTMT, NETDATA_MSSQL_ODBC_QUERY, mi->instanceID);
730 - goto endwait;
731 - }
732 -
733 - ret = SQLBindCol(mi->conn->dbWaitsSTMT, 1, SQL_C_CHAR, wait_type, sizeof(wait_type), &col_wait_type_len);
734 - if (netdata_mssql_check_result(ret)) {
735 - netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->dbWaitsSTMT, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
736 - goto endwait;
737 - }
738 -
739 - ret = SQLBindCol(mi->conn->dbWaitsSTMT, 2, SQL_C_LONG, &total_wait, sizeof(total_wait), &col_total_wait_len);
740 - if (netdata_mssql_check_result(ret)) {
741 - netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->dbWaitsSTMT, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
742 - goto endwait;
743 - }
744 -
745 - ret =
746 - SQLBindCol(mi->conn->dbWaitsSTMT, 3, SQL_C_LONG, &resource_wait, sizeof(resource_wait), &col_resource_wait_len);
747 - if (netdata_mssql_check_result(ret)) {
748 - netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->dbWaitsSTMT, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
749 - goto endwait;
750 - }
751 -
752 - ret = SQLBindCol(mi->conn->dbWaitsSTMT, 4, SQL_C_LONG, &signal_wait, sizeof(signal_wait), &col_signal_wait_len);
753 - if (netdata_mssql_check_result(ret)) {
754 - netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->dbWaitsSTMT, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
755 - goto endwait;
756 - }
757 -
758 - ret = SQLBindCol(mi->conn->dbWaitsSTMT, 5, SQL_C_LONG, &max_wait, sizeof(max_wait), &col_max_wait_len);
759 - if (netdata_mssql_check_result(ret)) {
760 - netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->dbWaitsSTMT, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
761 - goto endwait;
762 - }
763 -
764 - ret =
765 - SQLBindCol(mi->conn->dbWaitsSTMT, 6, SQL_C_LONG, &waiting_tasks, sizeof(waiting_tasks), &col_waiting_tasks_len);
766 - if (netdata_mssql_check_result(ret)) {
767 - netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->dbWaitsSTMT, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
768 - goto endwait;
769 - }
770 -
771 - ret =
772 - SQLBindCol(mi->conn->dbWaitsSTMT, 7, SQL_C_CHAR, wait_category, sizeof(wait_category), &col_wait_category_len);
773 - if (netdata_mssql_check_result(ret)) {
774 - netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->dbWaitsSTMT, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
775 - goto endwait;
776 - }
777 -
778 - do {
779 - ret = SQLFetch(mi->conn->dbWaitsSTMT);
780 - switch (ret) {
781 - case SQL_SUCCESS:
782 - case SQL_SUCCESS_WITH_INFO:
783 - break;
784 - case SQL_NO_DATA:
785 - default:
786 - success = 1;
787 - goto endwait;
788 - }
789 -
790 - struct mssql_db_waits *mdw = dictionary_set(mi->waits, wait_type, NULL, sizeof(*mdw));
791 - if (!mdw)
792 - continue;
793 -
794 - mdw->MSSQLDatabaseTotalWait.current.Data = (ULONGLONG)total_wait;
795 - // Variable mdw->MSSQLDatabaseResourceWaitMSec.current.Data stores a mathematical operation
796 - // that can be negative sometimes. This is the reason we have this if
797 - if (resource_wait > mdw->MSSQLDatabaseResourceWaitMSec.current.Data)
798 - mdw->MSSQLDatabaseResourceWaitMSec.current.Data = (ULONGLONG)resource_wait;
799 - mdw->MSSQLDatabaseSignalWaitMSec.current.Data = (ULONGLONG)signal_wait;
800 - mdw->MSSQLDatabaseMaxWaitTimeMSec.current.Data = (ULONGLONG)max_wait;
801 - mdw->MSSQLDatabaseWaitingTasks.current.Data = (ULONGLONG)waiting_tasks;
802 -
803 - if (!mdw->wait_category)
804 - mdw->wait_category = strdupz(wait_category);
805 - } while (true);
806 -
807 -endwait:
808 - netdata_MSSQL_release_results(mi->conn->dbWaitsSTMT);
809 -
810 - return success;
811 -}
812 -
813 -int netdata_select_db(SQLHDBC hdbc, const char *database)
814 -{
815 - SQLHSTMT hstmt;
816 - SQLRETURN ret;
817 -
818 - ret = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
819 - if (netdata_mssql_check_result(ret)) {
820 - return -1;
821 - }
822 -
823 - char query[512];
824 - snprintfz(query, sizeof(query), "USE %s", database);
825 - ret = SQLExecDirect(hstmt, (SQLCHAR *)query, SQL_NTS);
826 - int result = 0;
827 - if (netdata_mssql_check_result(ret)) {
828 - result = -1;
829 - }
830 - SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
831 - return result;
832 -}
833 -
834 -void dict_mssql_fill_replication(struct mssql_db_instance *mdi)
835 -{
836 - char publisher[NETDATA_MAX_INSTANCE_OBJECT + 1] = {};
837 - char publisher_db[NETDATA_MAX_INSTANCE_OBJECT + 1] = {};
838 - char publication[NETDATA_MAX_INSTANCE_OBJECT + 1] = {};
839 - char key[NETDATA_MAX_INSTANCE_OBJECT * 2 + 2];
840 - int type = 0, status = 0, warning = 0, avg_latency = 0, retention = 0, subscriptioncount = 0,
841 - runningdistagentcount = 0, average_runspeedPerf = 0;
842 - SQLLEN publisher_len = 0, publisherdb_len = 0, publication_len = 0, type_len = 0, status_len = 0, warning_len = 0,
843 - avg_latency_len = 0, retention_len = 0, subscriptioncount_len = 0, runningagentcount_len = 0,
844 - average_runspeedperf_len = 0;
845 -
846 - if (netdata_select_db(mdi->parent->conn->netdataSQLHDBc, NETDATA_REPLICATION_DB)) {
847 - return;
848 - }
849 -
850 - SQLRETURN ret =
851 - SQLExecDirect(mdi->parent->conn->dbReplicationPublisher, (SQLCHAR *)NETDATA_REPLICATION_MONITOR_QUERY, SQL_NTS);
852 - if (netdata_mssql_check_result(ret)) {
853 - mdi->collecting_data = false;
854 - netdata_MSSQL_error(
855 - SQL_HANDLE_STMT,
856 - mdi->parent->conn->dbReplicationPublisher,
857 - NETDATA_MSSQL_ODBC_QUERY,
858 - mdi->parent->instanceID);
859 - goto endreplication;
860 - }
861 -
862 - ret = SQLBindCol(
863 - mdi->parent->conn->dbReplicationPublisher, 1, SQL_C_CHAR, publisher_db, sizeof(publisher_db), &publisherdb_len);
864 - if (netdata_mssql_check_result(ret)) {
865 - netdata_MSSQL_error(
866 - SQL_HANDLE_STMT,
867 - mdi->parent->conn->dbReplicationPublisher,
868 - NETDATA_MSSQL_ODBC_PREPARE,
869 - mdi->parent->instanceID);
870 - goto endreplication;
871 - }
872 -
873 - ret = SQLBindCol(
874 - mdi->parent->conn->dbReplicationPublisher, 2, SQL_C_CHAR, publication, sizeof(publication), &publication_len);
875 - if (netdata_mssql_check_result(ret)) {
876 - netdata_MSSQL_error(
877 - SQL_HANDLE_STMT,
878 - mdi->parent->conn->dbReplicationPublisher,
879 - NETDATA_MSSQL_ODBC_PREPARE,
880 - mdi->parent->instanceID);
881 - goto endreplication;
882 - }
883 -
884 - ret = SQLBindCol(mdi->parent->conn->dbReplicationPublisher, 4, SQL_C_LONG, &type, sizeof(type), &type_len);
885 - if (netdata_mssql_check_result(ret)) {
886 - netdata_MSSQL_error(
887 - SQL_HANDLE_STMT,
888 - mdi->parent->conn->dbReplicationPublisher,
889 - NETDATA_MSSQL_ODBC_PREPARE,
890 - mdi->parent->instanceID);
891 - goto endreplication;
892 - }
893 -
894 - ret = SQLBindCol(mdi->parent->conn->dbReplicationPublisher, 5, SQL_C_LONG, &status, sizeof(status), &status_len);
895 - if (netdata_mssql_check_result(ret)) {
896 - netdata_MSSQL_error(
897 - SQL_HANDLE_STMT,
898 - mdi->parent->conn->dbReplicationPublisher,
899 - NETDATA_MSSQL_ODBC_PREPARE,
900 - mdi->parent->instanceID);
901 - goto endreplication;
902 - }
903 -
904 - ret = SQLBindCol(mdi->parent->conn->dbReplicationPublisher, 6, SQL_C_LONG, &warning, sizeof(warning), &warning_len);
905 - if (netdata_mssql_check_result(ret)) {
906 - netdata_MSSQL_error(
907 - SQL_HANDLE_STMT,
908 - mdi->parent->conn->dbReplicationPublisher,
909 - NETDATA_MSSQL_ODBC_PREPARE,
910 - mdi->parent->instanceID);
911 - goto endreplication;
912 - }
913 -
914 - ret = SQLBindCol(
915 - mdi->parent->conn->dbReplicationPublisher, 9, SQL_C_LONG, &avg_latency, sizeof(avg_latency), &avg_latency_len);
916 - if (netdata_mssql_check_result(ret)) {
917 - // It is still a NULL value
918 - avg_latency = 0;
919 - }
920 -
921 - ret = SQLBindCol(
922 - mdi->parent->conn->dbReplicationPublisher, 11, SQL_C_LONG, &retention, sizeof(retention), &retention_len);
923 - if (netdata_mssql_check_result(ret)) {
924 - netdata_MSSQL_error(
925 - SQL_HANDLE_STMT,
926 - mdi->parent->conn->dbReplicationPublisher,
927 - NETDATA_MSSQL_ODBC_PREPARE,
928 - mdi->parent->instanceID);
929 - goto endreplication;
930 - }
931 -
932 - ret = SQLBindCol(
933 - mdi->parent->conn->dbReplicationPublisher,
934 - 15,
935 - SQL_C_LONG,
936 - &subscriptioncount,
937 - sizeof(subscriptioncount),
938 - &subscriptioncount_len);
939 - if (netdata_mssql_check_result(ret)) {
940 - netdata_MSSQL_error(
941 - SQL_HANDLE_STMT,
942 - mdi->parent->conn->dbReplicationPublisher,
943 - NETDATA_MSSQL_ODBC_PREPARE,
944 - mdi->parent->instanceID);
945 - goto endreplication;
946 - }
947 -
948 - ret = SQLBindCol(
949 - mdi->parent->conn->dbReplicationPublisher,
950 - 16,
951 - SQL_C_LONG,
952 - &runningdistagentcount,
953 - sizeof(runningdistagentcount),
954 - &runningagentcount_len);
955 - if (netdata_mssql_check_result(ret)) {
956 - netdata_MSSQL_error(
957 - SQL_HANDLE_STMT,
958 - mdi->parent->conn->dbReplicationPublisher,
959 - NETDATA_MSSQL_ODBC_PREPARE,
960 - mdi->parent->instanceID);
961 - goto endreplication;
962 - }
963 -
964 - ret = SQLBindCol(
965 - mdi->parent->conn->dbReplicationPublisher,
966 - 22,
967 - SQL_C_LONG,
968 - &average_runspeedPerf,
969 - sizeof(average_runspeedPerf),
970 - &average_runspeedperf_len);
971 - if (netdata_mssql_check_result(ret)) {
972 - netdata_MSSQL_error(
973 - SQL_HANDLE_STMT,
974 - mdi->parent->conn->dbReplicationPublisher,
975 - NETDATA_MSSQL_ODBC_PREPARE,
976 - mdi->parent->instanceID);
977 - goto endreplication;
978 - }
979 -
980 - ret = SQLBindCol(
981 - mdi->parent->conn->dbReplicationPublisher, 24, SQL_C_CHAR, publisher, sizeof(publisher), &publisher_len);
982 - if (netdata_mssql_check_result(ret)) {
983 - netdata_MSSQL_error(
984 - SQL_HANDLE_STMT,
985 - mdi->parent->conn->dbReplicationPublisher,
986 - NETDATA_MSSQL_ODBC_PREPARE,
987 - mdi->parent->instanceID);
988 - goto endreplication;
989 - }
990 -
991 - do {
992 - ret = SQLFetch(mdi->parent->conn->dbReplicationPublisher);
993 - switch (ret) {
994 - case SQL_SUCCESS:
995 - case SQL_SUCCESS_WITH_INFO:
996 - break;
997 - case SQL_NO_DATA:
998 - default:
999 - goto endreplication;
1000 - }
1001 -
1002 - snprintfz(key, sizeof(key) - 1, "%s:%s", publisher_db, publication);
1003 - struct mssql_publisher_publication *mpp =
1004 - dictionary_set(mdi->parent->publisher_publication, key, NULL, sizeof(*mpp));
1005 -
1006 - if (!mpp->publisher) {
1007 - mpp->publisher = strdupz(publisher);
1008 - mpp->parent = mdi->parent;
1009 - }
1010 -
1011 - if (!mpp->publication)
1012 - mpp->publication = strdupz(publication);
1013 -
1014 - if (!mpp->db)
1015 - mpp->db = strdupz(publisher_db);
1016 -
1017 - mpp->type = type;
1018 - mpp->status = status;
1019 - mpp->warning = warning;
1020 -
1021 - mpp->avg_latency = avg_latency;
1022 -
1023 - mpp->retention = retention;
1024 -
1025 - mpp->subscriptioncount = subscriptioncount;
1026 - mpp->runningdistagentcount = runningdistagentcount;
1027 -
1028 - mpp->average_runspeedPerf = average_runspeedPerf;
1029 - } while (true);
1030 -
1031 -endreplication:
1032 - (void)netdata_select_db(mdi->parent->conn->netdataSQLHDBc, "master");
1033 - netdata_MSSQL_release_results(mdi->parent->conn->dbReplicationPublisher);
1034 -}
1035 -int dict_mssql_databases_run_queries(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
1036 -{
1037 - struct mssql_db_instance *mdi = value;
1038 - const char *dbname = dictionary_acquired_item_name((DICTIONARY_ITEM *)item);
1039 -
1040 - if (!mdi->collecting_data || !mdi->parent || !mdi->parent->conn) {
1041 - goto enddrunquery;
1042 - }
1043 -
1044 - // We failed to collect this for the database, so we are not going to try again
1045 - if (mdi->MSSQLDatabaseDataFileSize.current.Data != ULONG_LONG_MAX)
1046 - mdi->MSSQLDatabaseDataFileSize.current.Data = netdata_MSSQL_fill_long_value(
1047 - mdi->parent->conn->dataFileSizeSTMT, NETDATA_QUERY_DATA_FILE_SIZE_MASK, dbname, mdi->parent->instanceID);
1048 - else {
1049 - mdi->collecting_data = false;
1050 - goto enddrunquery;
1051 - }
1052 -
1053 - dict_mssql_fill_transactions(mdi, dbname);
1054 - dict_mssql_fill_locks(mdi, dbname);
1055 -
1056 - if (mdi->running_replication)
1057 - dict_mssql_fill_replication(mdi);
1058 -
1059 -enddrunquery:
1060 - return 1;
1061 -}
1062 -
1063 -long metdata_mssql_check_permission(struct mssql_instance *mi)
1064 -{
1065 - static int next_try = NETDATA_MSSQL_NEXT_TRY - 1;
1066 - long perm = 0;
1067 - SQLLEN col_data_len = 0;
1068 -
1069 - if (++next_try != NETDATA_MSSQL_NEXT_TRY)
1070 - return 1;
1071 -
1072 - next_try = 0;
1073 -
1074 - SQLRETURN ret;
1075 -
1076 - ret = SQLExecDirect(mi->conn->checkPermSTMT, (SQLCHAR *)NETDATA_QUERY_CHECK_PERM, SQL_NTS);
1077 - if (netdata_mssql_check_result(ret)) {
1078 - netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->checkPermSTMT, NETDATA_MSSQL_ODBC_QUERY, mi->instanceID);
1079 - perm = LONG_MAX;
1080 - goto endperm;
1081 - }
1082 -
1083 - ret = SQLBindCol(mi->conn->checkPermSTMT, 1, SQL_C_LONG, &perm, sizeof(perm), &col_data_len);
1084 -
1085 - if (netdata_mssql_check_result(ret)) {
1086 - netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->checkPermSTMT, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
1087 - perm = LONG_MAX;
1088 - goto endperm;
1089 - }
1090 -
1091 - ret = SQLFetch(mi->conn->checkPermSTMT);
1092 - if (netdata_mssql_check_result(ret)) {
1093 - netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->checkPermSTMT, NETDATA_MSSQL_ODBC_FETCH, mi->instanceID);
1094 - perm = LONG_MAX;
1095 - goto endperm;
1096 - }
1097 -
1098 -endperm:
1099 - netdata_MSSQL_release_results(mi->conn->checkPermSTMT);
1100 - return perm;
1101 -}
1102 -
1103 -void metdata_mssql_fill_mssql_status(struct mssql_instance *mi)
1104 -{
1105 - char dbname[SQLSERVER_MAX_NAME_LENGTH + 1];
1106 - int readonly = 0;
1107 - BYTE state = 0;
1108 - SQLLEN col_data_len = 0;
1109 -
1110 - static int next_try = NETDATA_MSSQL_NEXT_TRY - 1;
1111 -
1112 - if (++next_try != NETDATA_MSSQL_NEXT_TRY)
1113 - return;
1114 -
1115 - next_try = 0;
1116 -
1117 - SQLRETURN ret;
1118 -
1119 - ret = SQLExecDirect(mi->conn->dbSQLState, (SQLCHAR *)NETDATA_QUERY_DATABASE_STATUS, SQL_NTS);
1120 - if (netdata_mssql_check_result(ret)) {
1121 - netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->dbSQLState, NETDATA_MSSQL_ODBC_QUERY, mi->instanceID);
1122 - goto enddbstate;
1123 - }
1124 -
1125 - ret = SQLBindCol(mi->conn->dbSQLState, 1, SQL_C_TINYINT, &state, sizeof(state), &col_data_len);
1126 - if (netdata_mssql_check_result(ret)) {
1127 - netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->dbSQLState, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
1128 - goto enddbstate;
1129 - }
1130 -
1131 - ret = SQLBindCol(mi->conn->dbSQLState, 3, SQL_C_BIT, &readonly, sizeof(readonly), &col_data_len);
1132 - if (netdata_mssql_check_result(ret)) {
1133 - netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->dbWaitsSTMT, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
1134 - goto enddbstate;
1135 - }
1136 -
1137 - int i = 0;
1138 - do {
1139 - ret = SQLFetch(mi->conn->dbSQLState);
1140 - if (netdata_mssql_check_result(ret)) {
1141 - goto enddbstate;
1142 - }
1143 -
1144 - struct mssql_db_instance *mdi = dictionary_set(mi->databases, dbname, NULL, sizeof(*mdi));
1145 - if (!mdi)
1146 - continue;
1147 -
1148 - mdi->MSSQLDBState.current.Data = (ULONGLONG)state;
1149 - mdi->MSSQLDBIsReadonly.current.Data = (ULONGLONG)readonly;
1150 - } while (true);
1151 -
1152 -enddbstate:
1153 - netdata_MSSQL_release_results(mi->conn->dbSQLState);
1154 -}
1155 -
1156 -void metdata_mssql_fill_job_status(struct mssql_instance *mi)
1157 -{
1158 - char job[SQLSERVER_MAX_NAME_LENGTH + 1];
1159 - BYTE state = 0;
1160 - SQLLEN col_job_len = 0;
1161 - SQLLEN col_state_len = 0;
1162 -
1163 - static int next_try = NETDATA_MSSQL_NEXT_TRY - 1;
1164 -
1165 - if (++next_try != NETDATA_MSSQL_NEXT_TRY)
1166 - return;
1167 -
1168 - next_try = 0;
1169 -
1170 - SQLRETURN ret;
1171 -
1172 - ret = SQLExecDirect(mi->conn->dbSQLJobs, (SQLCHAR *)NETDATA_QUERY_JOBS_STATUS, SQL_NTS);
1173 - if (netdata_mssql_check_result(ret)) {
1174 - netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->dbSQLJobs, NETDATA_MSSQL_ODBC_QUERY, mi->instanceID);
1175 - goto enddbjobs;
1176 - }
1177 -
1178 - ret = SQLBindCol(mi->conn->dbSQLJobs, 1, SQL_C_CHAR, job, sizeof(job), &col_job_len);
1179 - if (netdata_mssql_check_result(ret)) {
1180 - netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->dbSQLJobs, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
1181 - goto enddbjobs;
1182 - }
1183 -
1184 - ret = SQLBindCol(mi->conn->dbSQLJobs, 2, SQL_C_TINYINT, &state, sizeof(state), &col_state_len);
1185 - if (netdata_mssql_check_result(ret)) {
1186 - netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->dbSQLJobs, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
1187 - goto enddbjobs;
1188 - }
1189 -
1190 - do {
1191 - ret = SQLFetch(mi->conn->dbSQLJobs);
1192 - if (netdata_mssql_check_result(ret)) {
1193 - goto enddbjobs;
1194 - }
1195 -
1196 - struct mssql_db_jobs *mdj = dictionary_set(mi->sysjobs, job, NULL, sizeof(*mdj));
1197 - if (!mdj)
1198 - continue;
1199 -
1200 - mdj->MSSQLJOBState.current.Data = (ULONGLONG)state;
1201 - } while (true);
1202 -
1203 -enddbjobs:
1204 - netdata_MSSQL_release_results(mi->conn->dbSQLJobs);
1205 -}
1206 -
1207 -void metdata_mssql_fill_dictionary_from_db(struct mssql_instance *mi)
1208 -{
1209 - char dbname[SQLSERVER_MAX_NAME_LENGTH + 1];
1210 - SQLLEN col_data_len = 0;
1211 -
1212 - static int next_try = NETDATA_MSSQL_NEXT_TRY - 1;
1213 -
1214 - if (++next_try != NETDATA_MSSQL_NEXT_TRY)
1215 - return;
1216 -
1217 - next_try = 0;
1218 -
1219 - SQLRETURN ret;
1220 -
1221 - ret = SQLExecDirect(mi->conn->databaseListSTMT, (SQLCHAR *)NETDATA_QUERY_LIST_DB, SQL_NTS);
1222 - if (netdata_mssql_check_result(ret)) {
1223 - netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->databaseListSTMT, NETDATA_MSSQL_ODBC_QUERY, mi->instanceID);
1224 - goto enddblist;
1225 - }
1226 -
1227 - ret = SQLBindCol(mi->conn->databaseListSTMT, 1, SQL_C_CHAR, dbname, sizeof(dbname), &col_data_len);
1228 -
1229 - if (netdata_mssql_check_result(ret)) {
1230 - netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->databaseListSTMT, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
1231 - goto enddblist;
1232 - }
1233 -
1234 - int i = 0;
1235 - do {
1236 - ret = SQLFetch(mi->conn->databaseListSTMT);
1237 - if (netdata_mssql_check_result(ret)) {
1238 - goto enddblist;
1239 - }
1240 -
1241 - struct mssql_db_instance *mdi = dictionary_set(mi->databases, dbname, NULL, sizeof(*mdi));
1242 - if (!mdi)
1243 - continue;
1244 -
1245 - mdi->updated = 0;
1246 - if (!mdi->parent) {
1247 - mdi->parent = mi;
1248 - }
1249 -
1250 - if (mi->conn && !strncmp(dbname, NETDATA_REPLICATION_DB, sizeof(NETDATA_REPLICATION_DB) - 1)) {
1251 - mdi->running_replication = true;
1252 - }
1253 -
1254 - if (!i) {
1255 - mdi->collect_instance = true;
1256 - }
1257 - } while (true);
1258 -
1259 -enddblist:
1260 - netdata_MSSQL_release_results(mi->conn->databaseListSTMT);
1261 -}
1262 -
1263 -static bool netdata_MSSQL_initialize_connection(struct netdata_mssql_conn *nmc)
1264 -{
1265 - SQLRETURN ret;
1266 - if (nmc->netdataSQLEnv == NULL) {
1267 - ret = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &nmc->netdataSQLEnv);
1268 - if (netdata_mssql_check_result(ret))
1269 - return FALSE;
1270 -
1271 - ret = SQLSetEnvAttr(nmc->netdataSQLEnv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0);
1272 - if (netdata_mssql_check_result(ret)) {
1273 - return FALSE;
1274 - }
1275 - }
1276 -
1277 - ret = SQLAllocHandle(SQL_HANDLE_DBC, nmc->netdataSQLEnv, &nmc->netdataSQLHDBc);
1278 - if (netdata_mssql_check_result(ret)) {
1279 - return FALSE;
1280 - }
1281 -
1282 - ret = SQLSetConnectAttr(nmc->netdataSQLHDBc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0);
1283 - if (netdata_mssql_check_result(ret)) {
1284 - return FALSE;
1285 - }
1286 -
1287 - ret = SQLSetConnectAttr(nmc->netdataSQLHDBc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)TRUE, 0);
1288 - if (netdata_mssql_check_result(ret)) {
1289 - return FALSE;
1290 - }
1291 -
1292 - SQLCHAR ret_conn_str[1024];
1293 - ret = SQLDriverConnect(
1294 - nmc->netdataSQLHDBc, NULL, nmc->connectionString, SQL_NTS, ret_conn_str, 1024, NULL, SQL_DRIVER_NOPROMPT);
1295 -
1296 - BOOL retConn;
1297 - switch (ret) {
1298 - case SQL_NO_DATA_FOUND:
1299 - case SQL_INVALID_HANDLE:
1300 - case SQL_ERROR:
1301 - default:
1302 - netdata_MSSQL_error(SQL_HANDLE_DBC, nmc->netdataSQLHDBc, NETDATA_MSSQL_ODBC_CONNECT, NULL);
1303 - retConn = FALSE;
1304 - break;
1305 - case SQL_SUCCESS:
1306 - case SQL_SUCCESS_WITH_INFO:
1307 - retConn = TRUE;
1308 - break;
1309 - }
1310 -
1311 - if (retConn) {
1312 - SQLSetConnectAttr(nmc->netdataSQLHDBc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_ON, 0);
1313 -
1314 - ret = SQLAllocHandle(SQL_HANDLE_STMT, nmc->netdataSQLHDBc, &nmc->checkPermSTMT);
1315 - if (netdata_mssql_check_result(ret)) {
1316 - retConn = FALSE;
1317 - goto endMSSQLInitializationConnection;
1318 - }
1319 -
1320 - ret = SQLAllocHandle(SQL_HANDLE_STMT, nmc->netdataSQLHDBc, &nmc->databaseListSTMT);
1321 - if (netdata_mssql_check_result(ret)) {
1322 - retConn = FALSE;
1323 - goto endMSSQLInitializationConnection;
1324 - }
1325 -
1326 - ret = SQLAllocHandle(SQL_HANDLE_STMT, nmc->netdataSQLHDBc, &nmc->dataFileSizeSTMT);
1327 - if (netdata_mssql_check_result(ret)) {
1328 - retConn = FALSE;
1329 - goto endMSSQLInitializationConnection;
1330 - }
1331 -
1332 - ret = SQLAllocHandle(SQL_HANDLE_STMT, nmc->netdataSQLHDBc, &nmc->dbTransactionSTMT);
1333 - if (netdata_mssql_check_result(ret)) {
1334 - retConn = FALSE;
1335 - goto endMSSQLInitializationConnection;
1336 - }
1337 -
1338 - ret = SQLAllocHandle(SQL_HANDLE_STMT, nmc->netdataSQLHDBc, &nmc->dbInstanceTransactionSTMT);
1339 - if (netdata_mssql_check_result(ret)) {
1340 - retConn = FALSE;
1341 - goto endMSSQLInitializationConnection;
1342 - }
1343 -
1344 - ret = SQLAllocHandle(SQL_HANDLE_STMT, nmc->netdataSQLHDBc, &nmc->dbLocksSTMT);
1345 - if (netdata_mssql_check_result(ret)) {
1346 - retConn = FALSE;
1347 - goto endMSSQLInitializationConnection;
1348 - }
1349 -
1350 - ret = SQLAllocHandle(SQL_HANDLE_STMT, nmc->netdataSQLHDBc, &nmc->dbWaitsSTMT);
1351 - if (netdata_mssql_check_result(ret)) {
1352 - retConn = FALSE;
1353 - goto endMSSQLInitializationConnection;
1354 - }
1355 -
1356 - ret = SQLAllocHandle(SQL_HANDLE_STMT, nmc->netdataSQLHDBc, &nmc->dbSQLState);
1357 - if (netdata_mssql_check_result(ret)) {
1358 - retConn = FALSE;
1359 - goto endMSSQLInitializationConnection;
1360 - }
1361 -
1362 - ret = SQLAllocHandle(SQL_HANDLE_STMT, nmc->netdataSQLHDBc, &nmc->dbSQLJobs);
1363 - if (netdata_mssql_check_result(ret)) {
1364 - retConn = FALSE;
1365 - goto endMSSQLInitializationConnection;
1366 - }
1367 -
1368 - ret = SQLAllocHandle(SQL_HANDLE_STMT, nmc->netdataSQLHDBc, &nmc->dbReplicationPublisher);
1369 - if (netdata_mssql_check_result(ret)) {
1370 - retConn = FALSE;
1371 - goto endMSSQLInitializationConnection;
1372 - }
1373 - }
1374 -
1375 -endMSSQLInitializationConnection:
1376 - return retConn;
1377 -}
1378 -
1379 -// Dictionary
1380 -static DICTIONARY *mssql_instances = NULL;
1381 -
1382 -static void initialize_mssql_objects(struct mssql_instance *mi, const char *instance)
1383 -{
1384 - char prefix[NETDATA_MAX_INSTANCE_NAME];
1385 - if (!strcmp(instance, "MSSQLSERVER")) {
1386 - strncpyz(prefix, "SQLServer:", sizeof(prefix) - 1);
1387 - } else if (!strcmp(instance, "SQLEXPRESS")) {
1388 - strncpyz(prefix, "MSSQL$SQLEXPRESS:", sizeof(prefix) - 1);
1389 - if (mi->conn)
1390 - mi->conn->is_sqlexpress = true;
1391 - } else {
1392 - char *express = (mi->conn && mi->conn->is_sqlexpress) ? "SQLEXPRESS:" : "";
1393 - snprintfz(prefix, sizeof(prefix) - 1, "MSSQL$%s%s:", express, instance);
1394 - }
1395 -
1396 - size_t length = strlen(prefix);
1397 - char name[NETDATA_MAX_INSTANCE_OBJECT];
1398 - snprintfz(name, sizeof(name) - 1, "%s%s", prefix, "General Statistics");
1399 - mi->objectName[NETDATA_MSSQL_GENERAL_STATS] = strdupz(name);
1400 -
1401 - strncpyz(&name[length], "SQL Errors", sizeof(name) - length);
1402 - mi->objectName[NETDATA_MSSQL_SQL_ERRORS] = strdupz(name);
1403 -
1404 - strncpyz(&name[length], "Databases", sizeof(name) - length);
1405 - mi->objectName[NETDATA_MSSQL_DATABASE] = strdupz(name);
1406 -
1407 - strncpyz(&name[length], "SQL Statistics", sizeof(name) - length);
1408 - mi->objectName[NETDATA_MSSQL_SQL_STATS] = strdupz(name);
1409 -
1410 - strncpyz(&name[length], "Buffer Manager", sizeof(name) - length);
1411 - mi->objectName[NETDATA_MSSQL_BUFFER_MANAGEMENT] = strdupz(name);
1412 -
1413 - strncpyz(&name[length], "SystemJobs", sizeof(name) - length);
1414 - mi->objectName[NETDATA_MSSQL_JOBS] = strdupz(name);
1415 -
1416 - strncpyz(&name[length], "Memory Manager", sizeof(name) - length);
1417 - mi->objectName[NETDATA_MSSQL_MEMORY] = strdupz(name);
1418 -
1419 - strncpyz(&name[length], "Locks", sizeof(name) - length);
1420 - mi->objectName[NETDATA_MSSQL_LOCKS] = strdupz(name);
1421 -
1422 - strncpyz(&name[length], "Wait Statistics", sizeof(name) - length);
1423 - mi->objectName[NETDATA_MSSQL_WAITS] = strdupz(name);
1424 -
1425 - strncpyz(&name[length], "Access Methods", sizeof(name) - length);
1426 - mi->objectName[NETDATA_MSSQL_ACCESS_METHODS] = strdupz(name);
1427 -
1428 - mi->instanceID = strdupz(instance);
1429 -}
1430 -
1431 -static inline void initialize_mssql_keys(struct mssql_instance *mi)
1432 -{
1433 - // General Statistics (https://learn.microsoft.com/en-us/sql/relational-databases/performance-monitor/sql-server-general-statistics-object)
1434 - mi->MSSQLUserConnections.key = "User Connections";
1435 - mi->MSSQLBlockedProcesses.key = "Processes blocked";
1436 -
1437 - // SQL Statistics (https://learn.microsoft.com/en-us/sql/relational-databases/performance-monitor/sql-server-sql-statistics-object)
1438 - mi->MSSQLStatsAutoParameterization.key = "Auto-Param Attempts/sec";
1439 - mi->MSSQLStatsBatchRequests.key = "Batch Requests/sec";
1440 - mi->MSSQLStatSafeAutoParameterization.key = "Safe Auto-Params/sec";
1441 -
1442 - // Access Methods (https://learn.microsoft.com/en-us/sql/relational-databases/performance-monitor/sql-server-access-methods-object)
1443 - mi->MSSQLAccessMethodPageSplits.key = "Page Splits/sec";
1444 -
1445 - // Errors (https://learn.microsoft.com/en-us/sql/relational-databases/performance-monitor/sql-server-sql-errors-object)
1446 - mi->MSSQLSQLErrorsTotal.key = "Errors/sec";
1447 -
1448 - // Memory Management (https://learn.microsoft.com/en-us/sql/relational-databases/performance-monitor/sql-server-memory-manager-object)
1449 - mi->MSSQLConnectionMemoryBytes.key = "Connection Memory (KB)";
1450 - mi->MSSQLExternalBenefitOfMemory.key = "External benefit of memory";
1451 - mi->MSSQLPendingMemoryGrants.key = "Memory Grants Pending";
1452 - mi->MSSQLTotalServerMemory.key = "Total Server Memory (KB)";
1453 -}
1454 -
1455 -void dict_mssql_insert_locks_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
1456 -{
1457 - const char *resource = dictionary_acquired_item_name((DICTIONARY_ITEM *)item);
1458 -
1459 - // https://learn.microsoft.com/en-us/sql/relational-databases/performance-monitor/sql-server-locks-object
1460 - struct mssql_lock_instance *ptr = value;
1461 - ptr->resourceID = strdupz(resource);
1462 - ptr->deadLocks.key = "Number of Deadlocks/sec";
1463 - ptr->lockWait.key = "Lock Waits/sec";
1464 -}
1465 -
1466 -void dict_mssql_insert_wait_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
1467 -{
1468 - const char *type = dictionary_acquired_item_name((DICTIONARY_ITEM *)item);
1469 -
1470 - struct mssql_db_waits *mdw = value;
1471 -
1472 - mdw->wait_type = strdupz(type);
1473 - mdw->wait_category = NULL;
1474 - mdw->rd_total_wait = mdw->rd_max_wait_time_msec = mdw->rd_resource_wait_msec = mdw->rd_signal_wait_msec =
1475 - mdw->rd_waiting_tasks = NULL;
1476 -}
1477 -
1478 -void dict_mssql_insert_databases_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
1479 -{
1480 - struct mssql_db_instance *mdi = value;
1481 -
1482 - mdi->collecting_data = true;
1483 -}
1484 -
1485 -void dict_mssql_insert_replication_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
1486 -{
1487 - UNUSED(value);
1488 -}
1489 -
1490 -void dict_mssql_insert_jobs_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
1491 -{
1492 - UNUSED(value);
1493 -}
1494 -
1495 -// Options
1496 -void netdata_mount_mssql_connection_string(struct netdata_mssql_conn *dbInput)
1497 -{
1498 - SQLCHAR conn[1024];
1499 - const char *serverAddress;
1500 - const char *serverAddressArg;
1501 - if (!dbInput) {
1502 - return;
1503 - }
1504 -
1505 - char auth[512];
1506 - if (dbInput->server && dbInput->address) {
1507 - nd_log(
1508 - NDLS_COLLECTORS,
1509 - NDLP_ERR,
1510 - "Collector is not expecting server and address defined together, please, select one of them.");
1511 - dbInput->connectionString = NULL;
1512 - return;
1513 - }
1514 -
1515 - if (dbInput->server) {
1516 - serverAddress = "Server";
1517 - serverAddressArg = dbInput->server;
1518 - } else {
1519 - serverAddressArg = "Address";
1520 - serverAddress = dbInput->address;
1521 - }
1522 -
1523 - if (dbInput->windows_auth)
1524 - snprintfz(auth, sizeof(auth) - 1, "Trusted_Connection = yes");
1525 - else if (!dbInput->username || !dbInput->password) {
1526 - nd_log(
1527 - NDLS_COLLECTORS,
1528 - NDLP_ERR,
1529 - "You are not using Windows Authentication. Thus, it is necessary to specify user and password.");
1530 - dbInput->connectionString = NULL;
1531 - return;
1532 - } else {
1533 - snprintfz(auth, sizeof(auth) - 1, "UID=%s;PWD=%s;", dbInput->username, dbInput->password);
1534 - }
1535 -
1536 - snprintfz(
1537 - (char *)conn, sizeof(conn) - 1, "Driver={%s};%s=%s;%s", dbInput->driver, serverAddress, serverAddressArg, auth);
1538 - dbInput->connectionString = (SQLCHAR *)strdupz((char *)conn);
1539 -}
1540 -
1541 -static void netdata_read_config_options()
1542 -{
1543 -#define NETDATA_MAX_MSSSQL_SECTION_LENGTH (40)
1544 -#define NETDATA_DEFAULT_MSSQL_SECTION "plugin:windows:PerflibMSSQL"
1545 - uint16_t expected_instances = 1;
1546 - uint16_t total_instances = 0;
1547 - for (; total_instances < expected_instances; total_instances++) {
1548 - char section_name[NETDATA_MAX_MSSSQL_SECTION_LENGTH + 1];
1549 - char upper_instance[NETDATA_MAX_INSTANCE_OBJECT + 1];
1550 - strncpyz(section_name, NETDATA_DEFAULT_MSSQL_SECTION, sizeof(NETDATA_DEFAULT_MSSQL_SECTION));
1551 - if (total_instances) {
1552 - snprintfz(&section_name[sizeof(NETDATA_DEFAULT_MSSQL_SECTION) - 1], 5, "%d", total_instances);
1553 - }
1554 - const char *instance = inicfg_get(&netdata_config, section_name, "instance", NULL);
1555 - int additional_instances = (int)inicfg_get_number(&netdata_config, section_name, "additional instances", 0);
1556 - if (!instance || strlen(instance) > NETDATA_MAX_INSTANCE_OBJECT) {
1557 - nd_log(
1558 - NDLS_COLLECTORS,
1559 - NDLP_ERR,
1560 - "You must specify a valid 'instance' name to collect data from database in section %s.",
1561 - section_name);
1562 - continue;
1563 - }
1564 -
1565 - if (!total_instances && additional_instances) {
1566 - if (additional_instances > 64) {
1567 - nd_log(NDLS_COLLECTORS, NDLP_ERR, "Number of instances is bigger than expected (64)");
1568 - expected_instances = 64;
1569 - }
1570 - expected_instances = additional_instances + 1;
1571 - }
1572 -
1573 - const char *move = instance;
1574 - int i;
1575 - for (i = 0; *move; move++, i++) {
1576 - upper_instance[i] = toupper(*move);
1577 - }
1578 - upper_instance[i] = '\0';
1579 -
1580 - struct netdata_mssql_conn *dbconn = dictionary_set(conn_options, upper_instance, NULL, sizeof(*dbconn));
1581 -
1582 - dbconn->instance = strdupz(upper_instance);
1583 - dbconn->driver = inicfg_get(&netdata_config, section_name, "driver", "SQL Server");
1584 - dbconn->server = inicfg_get(&netdata_config, section_name, "server", NULL);
1585 - dbconn->address = inicfg_get(&netdata_config, section_name, "address", NULL);
1586 - dbconn->username = inicfg_get(&netdata_config, section_name, "uid", NULL);
1587 - dbconn->password = inicfg_get(&netdata_config, section_name, "pwd", NULL);
1588 - dbconn->instances = additional_instances;
1589 - dbconn->windows_auth = inicfg_get_boolean(&netdata_config, section_name, "windows authentication", false);
1590 - dbconn->is_sqlexpress = inicfg_get_boolean(&netdata_config, section_name, "express", false);
1591 - dbconn->is_connected = FALSE;
1592 -
1593 - netdata_mount_mssql_connection_string(dbconn);
1594 - }
1595 -}
1596 -
1597 -static inline struct netdata_mssql_conn *netdata_mssql_get_conn_option(const char *instance)
1598 -{
1599 - return (struct netdata_mssql_conn *)dictionary_get(conn_options, instance);
1600 -}
1601 -
1602 -void mssql_fill_initial_instances(struct mssql_instance *mi)
1603 -{
1604 - // https://learn.microsoft.com/en-us/sql/relational-databases/performance-monitor/sql-server-locks-object?view=sql-server-ver17
1605 - char *keys[] = {
1606 - "AllocUnit",
1607 - "Application",
1608 - "Database",
1609 - "Extent",
1610 - "File",
1611 - "HoBT",
1612 - "Key",
1613 - "Metadata",
1614 - "OIB",
1615 - "Object",
1616 - "Page",
1617 - "RID",
1618 - "RowGroup",
1619 - "Xact",
1620 - NULL};
1621 - for (int i = 0; keys[i]; i++) {
1622 - (void)dictionary_set(mi->locks_instances, keys[i], NULL, sizeof(struct mssql_lock_instance));
1623 - }
1624 -}
1625 -
1626 -void dict_mssql_insert_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
1627 -{
1628 - struct mssql_instance *mi = value;
1629 - const char *instance = dictionary_acquired_item_name((DICTIONARY_ITEM *)item);
1630 - bool *create_thread = data;
1631 -
1632 - if (!mi->locks_instances) {
1633 - mi->locks_instances = dictionary_create_advanced(
1634 - DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE, NULL, sizeof(struct mssql_lock_instance));
1635 - dictionary_register_insert_callback(mi->locks_instances, dict_mssql_insert_locks_cb, NULL);
1636 - mssql_fill_initial_instances(mi);
1637 - }
1638 -
1639 - if (!mi->databases) {
1640 - mi->databases = dictionary_create_advanced(
1641 - DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE, NULL, sizeof(struct mssql_db_instance));
1642 - dictionary_register_insert_callback(mi->databases, dict_mssql_insert_databases_cb, NULL);
1643 - }
1644 -
1645 - if (!mi->publisher_publication) {
1646 - mi->publisher_publication = dictionary_create_advanced(
1647 - DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE,
1648 - NULL,
1649 - sizeof(struct mssql_publisher_publication));
1650 - dictionary_register_insert_callback(mi->publisher_publication, dict_mssql_insert_replication_cb, NULL);
1651 - }
1652 -
1653 - if (!mi->sysjobs) {
1654 - mi->sysjobs = dictionary_create_advanced(
1655 - DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE, NULL, sizeof(struct mssql_db_jobs));
1656 - dictionary_register_insert_callback(mi->sysjobs, dict_mssql_insert_jobs_cb, NULL);
1657 - }
1658 -
1659 - if (!mi->waits) {
1660 - mi->waits = dictionary_create_advanced(
1661 - DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE, NULL, sizeof(struct mssql_db_waits));
1662 - dictionary_register_insert_callback(mi->waits, dict_mssql_insert_wait_cb, NULL);
1663 - }
1664 -
1665 - initialize_mssql_objects(mi, instance);
1666 - initialize_mssql_keys(mi);
1667 - mi->conn = netdata_mssql_get_conn_option(instance);
1668 -
1669 - if (mi->conn && mi->conn->connectionString) {
1670 - mi->conn->is_connected = netdata_MSSQL_initialize_connection(mi->conn);
1671 - if (mi->conn->is_connected)
1672 - *create_thread = true;
1673 - }
1674 -}
1675 -
1676 -void dict_mssql_insert_conn_option(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
1677 -{
1678 - ;
1679 -}
1680 -
1681 -static void mssql_fill_dictionary(int update_every)
1682 -{
1683 - HKEY hKey;
1684 - LSTATUS ret = RegOpenKeyExA(
1685 - HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Microsoft SQL Server\\Instance Names\\SQL", 0, KEY_READ, &hKey);
1686 - if (ret != ERROR_SUCCESS)
1687 - return;
1688 -
1689 - DWORD values = 0;
1690 -
1691 - ret = RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL, &values, NULL, NULL, NULL, NULL);
1692 - if (ret != ERROR_SUCCESS) {
1693 - goto endMSSQLFillDict;
1694 - }
1695 -
1696 - if (!values) {
1697 - ret = ERROR_PATH_NOT_FOUND;
1698 - goto endMSSQLFillDict;
1699 - }
1700 -
1701 -// https://learn.microsoft.com/en-us/windows/win32/sysinfo/enumerating-registry-subkeys
1702 -#define REGISTRY_MAX_VALUE 16383
1703 -
1704 - DWORD i;
1705 - char avalue[REGISTRY_MAX_VALUE] = {'\0'};
1706 - for (i = 0; i < values; i++) {
1707 - avalue[0] = '\0';
1708 - DWORD length = REGISTRY_MAX_VALUE;
1709 -
1710 - ret = RegEnumValue(hKey, i, avalue, &length, NULL, NULL, NULL, NULL);
1711 - if (ret != ERROR_SUCCESS)
1712 - continue;
1713 -
1714 - struct mssql_instance *p = dictionary_set(mssql_instances, avalue, NULL, sizeof(*p));
1715 - p->update_every = update_every;
1716 - }
1717 -
1718 -endMSSQLFillDict:
1719 - RegCloseKey(hKey);
1720 -}
1721 -
1722 -int netdata_mssql_reset_value(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
1723 -{
1724 - struct mssql_db_instance *mdi = value;
1725 -
1726 - mdi->collecting_data = false;
1727 -
1728 - return 1;
1729 -}
1730 -
1731 -int dict_mssql_query_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
1732 -{
1733 - struct mssql_instance *mi = value;
1734 - static long collecting = 1;
1735 -
1736 - if (mi->conn && mi->conn->is_connected && collecting) {
1737 - collecting = metdata_mssql_check_permission(mi);
1738 - if (!collecting) {
1739 - nd_log(
1740 - NDLS_COLLECTORS,
1741 - NDLP_ERR,
1742 - "User %s does not have permission to run queries on %s",
1743 - mi->conn->username,
1744 - mi->instanceID);
1745 - } else {
1746 - metdata_mssql_fill_dictionary_from_db(mi);
1747 - metdata_mssql_fill_mssql_status(mi);
1748 - metdata_mssql_fill_job_status(mi);
1749 - dictionary_sorted_walkthrough_read(mi->databases, dict_mssql_databases_run_queries, NULL);
1750 - }
1751 -
1752 - collecting = dict_mssql_fill_waits(mi);
1753 - } else {
1754 - dictionary_sorted_walkthrough_read(mi->databases, netdata_mssql_reset_value, NULL);
1755 - }
1756 -
1757 - return 1;
1758 -}
1759 -
1760 -static void netdata_mssql_queries(void *ptr __maybe_unused)
1761 -{
1762 - heartbeat_t hb;
1763 - heartbeat_init(&hb, USEC_PER_SEC);
1764 - int update_every = UPDATE_EVERY_MIN;
1765 -
1766 - while (service_running(SERVICE_COLLECTORS)) {
1767 - (void)heartbeat_next(&hb);
1768 -
1769 - if (unlikely(!service_running(SERVICE_COLLECTORS)))
1770 - break;
1771 -
1772 - dictionary_sorted_walkthrough_read(mssql_instances, dict_mssql_query_cb, &update_every);
1773 - }
1774 -}
1775 -
1776 -static ND_THREAD *mssql_queries_thread = NULL;
1777 -
1778 -static int initialize(int update_every)
1779 -{
1780 - static bool create_thread = false;
1781 - mssql_instances = dictionary_create_advanced(
1782 - DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE, NULL, sizeof(struct mssql_instance));
1783 -
1784 - dictionary_register_insert_callback(mssql_instances, dict_mssql_insert_cb, &create_thread);
1785 -
1786 - conn_options = dictionary_create_advanced(
1787 - DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE, NULL, sizeof(struct netdata_mssql_conn));
1788 - dictionary_register_insert_callback(conn_options, dict_mssql_insert_conn_option, NULL);
1789 -
1790 - netdata_read_config_options();
1791 - mssql_fill_dictionary(update_every);
1792 -
1793 - if (create_thread)
1794 - mssql_queries_thread =
1795 - nd_thread_create("mssql_queries", NETDATA_THREAD_OPTION_DEFAULT, netdata_mssql_queries, &update_every);
1796 -
1797 - return 0;
1798 -}
1799 -
1800 -static void do_mssql_general_stats(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *mi, int update_every)
1801 -{
1802 - char id[RRD_ID_LENGTH_MAX + 1];
1803 -
1804 - PERF_OBJECT_TYPE *pObjectType =
1805 - perflibFindObjectTypeByName(pDataBlock, mi->objectName[NETDATA_MSSQL_GENERAL_STATS]);
1806 - if (!pObjectType)
1807 - return;
1808 -
1809 - if (perflibGetObjectCounter(pDataBlock, pObjectType, &mi->MSSQLUserConnections)) {
1810 - if (!mi->st_user_connections) {
1811 - snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_user_connections", mi->instanceID);
1812 - netdata_fix_chart_name(id);
1813 - mi->st_user_connections = rrdset_create_localhost(
1814 - "mssql",
1815 - id,
1816 - NULL,
1817 - "connections",
1818 - "mssql.instance_user_connections",
1819 - "User connections",
1820 - "connections",
1821 - PLUGIN_WINDOWS_NAME,
1822 - "PerflibMSSQL",
1823 - PRIO_MSSQL_USER_CONNECTIONS,
1824 - update_every,
1825 - RRDSET_TYPE_LINE);
1826 -
1827 - mi->rd_user_connections = rrddim_add(mi->st_user_connections, "user", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
1828 -
1829 - rrdlabels_add(mi->st_user_connections->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
1830 - }
1831 -
1832 - rrddim_set_by_pointer(
1833 - mi->st_user_connections, mi->rd_user_connections, (collected_number)mi->MSSQLUserConnections.current.Data);
1834 - rrdset_done(mi->st_user_connections);
1835 - }
1836 -
1837 - if (perflibGetObjectCounter(pDataBlock, pObjectType, &mi->MSSQLBlockedProcesses)) {
1838 - if (!mi->st_process_blocked) {
1839 - snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_blocked_process", mi->instanceID);
1840 - netdata_fix_chart_name(id);
1841 - mi->st_process_blocked = rrdset_create_localhost(
1842 - "mssql",
1843 - id,
1844 - NULL,
1845 - "processes",
1846 - "mssql.instance_blocked_processes",
1847 - "Blocked processes",
1848 - "process",
1849 - PLUGIN_WINDOWS_NAME,
1850 - "PerflibMSSQL",
1851 - PRIO_MSSQL_BLOCKED_PROCESSES,
1852 - update_every,
1853 - RRDSET_TYPE_LINE);
1854 -
1855 - mi->rd_process_blocked = rrddim_add(mi->st_process_blocked, "blocked", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
1856 -
1857 - rrdlabels_add(mi->st_process_blocked->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
1858 - }
1859 -
1860 - rrddim_set_by_pointer(
1861 - mi->st_process_blocked, mi->rd_process_blocked, (collected_number)mi->MSSQLBlockedProcesses.current.Data);
1862 - rrdset_done(mi->st_process_blocked);
1863 - }
1864 -}
1865 -
1866 -static void do_mssql_statistics_perflib(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *mi, int update_every)
1867 -{
1868 - char id[RRD_ID_LENGTH_MAX + 1];
1869 -
1870 - PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, mi->objectName[NETDATA_MSSQL_SQL_STATS]);
1871 - if (!pObjectType)
1872 - return;
1873 -
1874 - if (perflibGetObjectCounter(pDataBlock, pObjectType, &mi->MSSQLStatsAutoParameterization)) {
1875 - if (!mi->st_stats_auto_param) {
1876 - snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_sqlstats_auto_parameterization_attempts", mi->instanceID);
1877 - netdata_fix_chart_name(id);
1878 - mi->st_stats_auto_param = rrdset_create_localhost(
1879 - "mssql",
1880 - id,
1881 - NULL,
1882 - "sql activity",
1883 - "mssql.instance_sqlstats_auto_parameterization_attempts",
1884 - "Failed auto-parameterization attempts",
1885 - "attempts/s",
1886 - PLUGIN_WINDOWS_NAME,
1887 - "PerflibMSSQL",
1888 - PRIO_MSSQL_STATS_AUTO_PARAMETRIZATION,
1889 - update_every,
1890 - RRDSET_TYPE_LINE);
1891 -
1892 - mi->rd_stats_auto_param =
1893 - rrddim_add(mi->st_stats_auto_param, "failed", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1894 -
1895 - rrdlabels_add(mi->st_stats_auto_param->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
1896 - }
1897 -
1898 - rrddim_set_by_pointer(
1899 - mi->st_stats_auto_param,
1900 - mi->rd_stats_auto_param,
1901 - (collected_number)mi->MSSQLStatsAutoParameterization.current.Data);
1902 - rrdset_done(mi->st_stats_auto_param);
1903 - }
1904 -
1905 - if (perflibGetObjectCounter(pDataBlock, pObjectType, &mi->MSSQLStatsBatchRequests)) {
1906 - if (!mi->st_stats_batch_request) {
1907 - snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_sqlstats_batch_requests", mi->instanceID);
1908 - netdata_fix_chart_name(id);
1909 - mi->st_stats_batch_request = rrdset_create_localhost(
1910 - "mssql",
1911 - id,
1912 - NULL,
1913 - "sql activity",
1914 - "mssql.instance_sqlstats_batch_requests",
1915 - "Total of batches requests",
1916 - "requests/s",
1917 - PLUGIN_WINDOWS_NAME,
1918 - "PerflibMSSQL",
1919 - PRIO_MSSQL_STATS_BATCH_REQUEST,
1920 - update_every,
1921 - RRDSET_TYPE_LINE);
1922 -
1923 - mi->rd_stats_batch_request =
1924 - rrddim_add(mi->st_stats_batch_request, "batch", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1925 -
1926 - rrdlabels_add(mi->st_stats_batch_request->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
1927 - }
1928 -
1929 - rrddim_set_by_pointer(
1930 - mi->st_stats_batch_request,
1931 - mi->rd_stats_batch_request,
1932 - (collected_number)mi->MSSQLStatsBatchRequests.current.Data);
1933 - rrdset_done(mi->st_stats_batch_request);
1934 - }
1935 -
1936 - if (perflibGetObjectCounter(pDataBlock, pObjectType, &mi->MSSQLStatSafeAutoParameterization)) {
1937 - if (!mi->st_stats_safe_auto) {
1938 - snprintfz(
1939 - id, RRD_ID_LENGTH_MAX, "instance_%s_sqlstats_safe_auto_parameterization_attempts", mi->instanceID);
1940 - netdata_fix_chart_name(id);
1941 - mi->st_stats_safe_auto = rrdset_create_localhost(
1942 - "mssql",
1943 - id,
1944 - NULL,
1945 - "sql activity",
1946 - "mssql.instance_sqlstats_safe_auto_parameterization_attempts",
1947 - "Safe auto-parameterization attempts",
1948 - "attempts/s",
1949 - PLUGIN_WINDOWS_NAME,
1950 - "PerflibMSSQL",
1951 - PRIO_MSSQL_STATS_SAFE_AUTO_PARAMETRIZATION,
1952 - update_every,
1953 - RRDSET_TYPE_LINE);
1954 -
1955 - mi->rd_stats_safe_auto = rrddim_add(mi->st_stats_safe_auto, "safe", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1956 -
1957 - rrdlabels_add(mi->st_stats_safe_auto->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
1958 - }
1959 -
1960 - rrddim_set_by_pointer(
1961 - mi->st_stats_safe_auto,
1962 - mi->rd_stats_safe_auto,
1963 - (collected_number)mi->MSSQLStatSafeAutoParameterization.current.Data);
1964 - rrdset_done(mi->st_stats_safe_auto);
1965 - }
1966 -}
1967 -
1968 -static void do_mssql_access_methods(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *mi, int update_every)
1969 -{
1970 - char id[RRD_ID_LENGTH_MAX + 1];
1971 -
1972 - PERF_OBJECT_TYPE *pObjectType =
1973 - perflibFindObjectTypeByName(pDataBlock, mi->objectName[NETDATA_MSSQL_ACCESS_METHODS]);
1974 - if (!pObjectType)
1975 - return;
1976 -
1977 - if (perflibGetObjectCounter(pDataBlock, pObjectType, &mi->MSSQLAccessMethodPageSplits)) {
1978 - if (!mi->st_access_method_page_splits) {
1979 - snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_accessmethods_page_splits", mi->instanceID);
1980 - netdata_fix_chart_name(id);
1981 - mi->st_access_method_page_splits = rrdset_create_localhost(
1982 - "mssql",
1983 - id,
1984 - NULL,
1985 - "buffer cache",
1986 - "mssql.instance_accessmethods_page_splits",
1987 - "Page splits",
1988 - "splits/s",
1989 - PLUGIN_WINDOWS_NAME,
1990 - "PerflibMSSQL",
1991 - PRIO_MSSQL_BUFF_METHODS_PAGE_SPLIT,
1992 - update_every,
1993 - RRDSET_TYPE_LINE);
1994 -
1995 - mi->rd_access_method_page_splits =
1996 - rrddim_add(mi->st_access_method_page_splits, "page", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1997 -
1998 - rrdlabels_add(
1999 - mi->st_access_method_page_splits->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
2000 - }
2001 -
2002 - rrddim_set_by_pointer(
2003 - mi->st_access_method_page_splits,
2004 - mi->rd_access_method_page_splits,
2005 - (collected_number)mi->MSSQLAccessMethodPageSplits.current.Data);
2006 - rrdset_done(mi->st_access_method_page_splits);
2007 - }
2008 -}
2009 -
2010 -static void do_mssql_errors(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *mi, int update_every)
2011 -{
2012 - char id[RRD_ID_LENGTH_MAX + 1];
2013 -
2014 - PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, mi->objectName[NETDATA_MSSQL_SQL_ERRORS]);
2015 - if (!pObjectType)
2016 - return;
2017 -
2018 - if (perflibGetObjectCounter(pDataBlock, pObjectType, &mi->MSSQLSQLErrorsTotal)) {
2019 - if (!mi->st_sql_errors) {
2020 - snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_sql_errors_total", mi->instanceID);
2021 - netdata_fix_chart_name(id);
2022 - mi->st_sql_errors = rrdset_create_localhost(
2023 - "mssql",
2024 - id,
2025 - NULL,
2026 - "errors",
2027 - "mssql.instance_sql_errors",
2028 - "Errors",
2029 - "errors/s",
2030 - PLUGIN_WINDOWS_NAME,
2031 - "PerflibMSSQL",
2032 - PRIO_MSSQL_SQL_ERRORS,
2033 - update_every,
2034 - RRDSET_TYPE_LINE);
2035 -
2036 - mi->rd_sql_errors = rrddim_add(mi->st_sql_errors, "errors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
2037 -
2038 - rrdlabels_add(mi->st_sql_errors->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
2039 - }
2040 -
2041 - rrddim_set_by_pointer(
2042 - mi->st_sql_errors, mi->rd_sql_errors, (collected_number)mi->MSSQLAccessMethodPageSplits.current.Data);
2043 - rrdset_done(mi->st_sql_errors);
2044 - }
2045 -}
2046 -
2047 -void dict_mssql_locks_wait_charts(struct mssql_instance *mi, struct mssql_lock_instance *mli, const char *resource)
2048 -{
2049 - if (!mli->st_lockWait) {
2050 - char id[RRD_ID_LENGTH_MAX + 1];
2051 -
2052 - snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_resource_%s_lock_wait", mi->instanceID, resource);
2053 - netdata_fix_chart_name(id);
2054 - mli->st_lockWait = rrdset_create_localhost(
2055 - "mssql",
2056 - id,
2057 - NULL,
2058 - "locks",
2059 - "mssql.instance_resource_lock_waits",
2060 - "Lock requests that required the caller to wait per resource",
2061 - "locks/s",
2062 - PLUGIN_WINDOWS_NAME,
2063 - "PerflibMSSQL",
2064 - PRIO_MSSQL_LOCKS_WAIT,
2065 - mi->update_every,
2066 - RRDSET_TYPE_LINE);
2067 -
2068 - rrdlabels_add(mli->st_lockWait->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
2069 - rrdlabels_add(mli->st_lockWait->rrdlabels, "resource", resource, RRDLABEL_SRC_AUTO);
2070 - mli->rd_lockWait = rrddim_add(mli->st_lockWait, "locks", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
2071 - }
2072 -
2073 - rrddim_set_by_pointer(mli->st_lockWait, mli->rd_lockWait, (collected_number)mli->lockWait.current.Data);
2074 - rrdset_done(mli->st_lockWait);
2075 -}
2076 -
2077 -void dict_mssql_dead_locks_charts(struct mssql_instance *mi, struct mssql_lock_instance *mli, const char *resource)
2078 -{
2079 - if (!mli->st_deadLocks) {
2080 - char id[RRD_ID_LENGTH_MAX + 1];
2081 -
2082 - snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_resource_%s_deadlocks", mi->instanceID, resource);
2083 - netdata_fix_chart_name(id);
2084 - mli->st_deadLocks = rrdset_create_localhost(
2085 - "mssql",
2086 - id,
2087 - NULL,
2088 - "locks",
2089 - "mssql.instance_resource_deadlocks",
2090 - "Active lock requests that resulted in deadlock per resource",
2091 - "deadlocks/s",
2092 - PLUGIN_WINDOWS_NAME,
2093 - "PerflibMSSQL",
2094 - PRIO_MSSQL_LOCKS_DEADLOCK_PER_RESOURCE,
2095 - mi->update_every,
2096 - RRDSET_TYPE_LINE);
2097 -
2098 - rrdlabels_add(mli->st_deadLocks->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
2099 - rrdlabels_add(mli->st_deadLocks->rrdlabels, "resource", resource, RRDLABEL_SRC_AUTO);
2100 - mli->rd_deadLocks = rrddim_add(mli->st_deadLocks, "deadlocks", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
2101 - }
2102 -
2103 - rrddim_set_by_pointer(mli->st_deadLocks, mli->rd_deadLocks, (collected_number)mli->deadLocks.current.Data);
2104 - rrdset_done(mli->st_deadLocks);
2105 -}
2106 -
2107 -int dict_mssql_locks_charts_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
2108 -{
2109 - const char *dimension = dictionary_acquired_item_name((DICTIONARY_ITEM *)item);
2110 - struct mssql_lock_instance *mli = value;
2111 - struct mssql_instance *mi = data;
2112 -
2113 - dict_mssql_locks_wait_charts(mi, mli, dimension);
2114 - dict_mssql_dead_locks_charts(mi, mli, dimension);
2115 -
2116 - return 1;
2117 -}
2118 -
2119 -static void do_mssql_locks(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *mi, int update_every __maybe_unused)
2120 -{
2121 - if (!pDataBlock)
2122 - goto end_mssql_locks;
2123 -
2124 - PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, mi->objectName[NETDATA_MSSQL_LOCKS]);
2125 - if (pObjectType) {
2126 - if (pObjectType->NumInstances) {
2127 - PERF_INSTANCE_DEFINITION *pi = NULL;
2128 - for (LONG i = 0; i < pObjectType->NumInstances; i++) {
2129 - pi = perflibForEachInstance(pDataBlock, pObjectType, pi);
2130 - if (!pi)
2131 - break;
2132 -
2133 - if (!getInstanceName(pDataBlock, pObjectType, pi, windows_shared_buffer, sizeof(windows_shared_buffer)))
2134 - strncpyz(windows_shared_buffer, "[unknown]", sizeof(windows_shared_buffer) - 1);
2135 -
2136 - if (!strcasecmp(windows_shared_buffer, "_Total"))
2137 - continue;
2138 -
2139 - struct mssql_lock_instance *mli =
2140 - dictionary_set(mi->locks_instances, windows_shared_buffer, NULL, sizeof(*mli));
2141 - if (!mli)
2142 - continue;
2143 -
2144 - perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &mli->deadLocks);
2145 - perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &mli->lockWait);
2146 - }
2147 - }
2148 - }
2149 -
2150 -end_mssql_locks:
2151 - dictionary_sorted_walkthrough_read(mi->locks_instances, dict_mssql_locks_charts_cb, mi);
2152 -}
2153 -
2154 -void mssql_total_wait_charts(struct mssql_instance *mi, struct mssql_db_waits *mdw, const char *type)
2155 -{
2156 - if (!mdw->st_total_wait) {
2157 - char id[RRD_ID_LENGTH_MAX + 1];
2158 -
2159 - snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_%s_total_wait", mi->instanceID, type);
2160 - netdata_fix_chart_name(id);
2161 - mdw->st_total_wait = rrdset_create_localhost(
2162 - "mssql",
2163 - id,
2164 - NULL,
2165 - "locks",
2166 - "mssql.instance_total_wait_time",
2167 - "Wait time for each wait type and category",
2168 - "ms",
2169 - PLUGIN_WINDOWS_NAME,
2170 - "PerflibMSSQL",
2171 - PRIO_MSSQL_WAITS_TOTAL,
2172 - mi->update_every,
2173 - RRDSET_TYPE_LINE);
2174 -
2175 - rrdlabels_add(mdw->st_total_wait->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
2176 - rrdlabels_add(mdw->st_total_wait->rrdlabels, "wait_type", mdw->wait_type, RRDLABEL_SRC_AUTO);
2177 - rrdlabels_add(mdw->st_total_wait->rrdlabels, "wait_category", mdw->wait_category, RRDLABEL_SRC_AUTO);
2178 - mdw->rd_total_wait = rrddim_add(mdw->st_total_wait, "duration", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
2179 - }
2180 -
2181 - rrddim_set_by_pointer(
2182 - mdw->st_total_wait, mdw->rd_total_wait, (collected_number)mdw->MSSQLDatabaseTotalWait.current.Data);
2183 -
2184 - rrdset_done(mdw->st_total_wait);
2185 -}
2186 -
2187 -void mssql_resource_wait_charts(struct mssql_instance *mi, struct mssql_db_waits *mdw, const char *type)
2188 -{
2189 - if (!mdw->st_resource_wait_msec) {
2190 - char id[RRD_ID_LENGTH_MAX + 1];
2191 -
2192 - snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_%s_resource_wait", mi->instanceID, type);
2193 - netdata_fix_chart_name(id);
2194 - mdw->st_resource_wait_msec = rrdset_create_localhost(
2195 - "mssql",
2196 - id,
2197 - NULL,
2198 - "locks",
2199 - "mssql.instance_resource_wait_time",
2200 - "Wait time for threads waiting on specific resource types for each wait type and category",
2201 - "ms",
2202 - PLUGIN_WINDOWS_NAME,
2203 - "PerflibMSSQL",
2204 - PRIO_MSSQL_RESOURCE_WAIT,
2205 - mi->update_every,
2206 - RRDSET_TYPE_LINE);
2207 -
2208 - rrdlabels_add(mdw->st_resource_wait_msec->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
2209 - rrdlabels_add(mdw->st_resource_wait_msec->rrdlabels, "wait_type", mdw->wait_type, RRDLABEL_SRC_AUTO);
2210 - rrdlabels_add(mdw->st_resource_wait_msec->rrdlabels, "wait_category", mdw->wait_category, RRDLABEL_SRC_AUTO);
2211 - mdw->rd_resource_wait_msec =
2212 - rrddim_add(mdw->st_resource_wait_msec, "duration", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
2213 - }
2214 -
2215 - rrddim_set_by_pointer(
2216 - mdw->st_resource_wait_msec,
2217 - mdw->rd_resource_wait_msec,
2218 - (collected_number)mdw->MSSQLDatabaseResourceWaitMSec.current.Data);
2219 -
2220 - rrdset_done(mdw->st_resource_wait_msec);
2221 -}
2222 -
2223 -void mssql_signal_wait_charts(struct mssql_instance *mi, struct mssql_db_waits *mdw, const char *type)
2224 -{
2225 - if (!mdw->st_signal_wait_msec) {
2226 - char id[RRD_ID_LENGTH_MAX + 1];
2227 -
2228 - snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_%s_signal_wait", mi->instanceID, type);
2229 - netdata_fix_chart_name(id);
2230 - mdw->st_signal_wait_msec = rrdset_create_localhost(
2231 - "mssql",
2232 - id,
2233 - NULL,
2234 - "locks",
2235 - "mssql.instance_signal_wait_time",
2236 - "Delay between thread wakeup signal and actual execution start for each wait type and category",
2237 - "ms",
2238 - PLUGIN_WINDOWS_NAME,
2239 - "PerflibMSSQL",
2240 - PRIO_MSSQL_SIGNAL_WAIT,
2241 - mi->update_every,
2242 - RRDSET_TYPE_LINE);
2243 -
2244 - rrdlabels_add(mdw->st_signal_wait_msec->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
2245 - rrdlabels_add(mdw->st_signal_wait_msec->rrdlabels, "wait_type", mdw->wait_type, RRDLABEL_SRC_AUTO);
2246 - rrdlabels_add(mdw->st_signal_wait_msec->rrdlabels, "wait_category", mdw->wait_category, RRDLABEL_SRC_AUTO);
2247 - mdw->rd_signal_wait_msec =
2248 - rrddim_add(mdw->st_signal_wait_msec, "duration", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
2249 - }
2250 -
2251 - rrddim_set_by_pointer(
2252 - mdw->st_signal_wait_msec,
2253 - mdw->rd_signal_wait_msec,
2254 - (collected_number)mdw->MSSQLDatabaseSignalWaitMSec.current.Data);
2255 -
2256 - rrdset_done(mdw->st_signal_wait_msec);
2257 -}
2258 -
2259 -void mssql_max_wait_charts(struct mssql_instance *mi, struct mssql_db_waits *mdw, const char *type)
2260 -{
2261 - if (!mdw->st_max_wait_time_msec) {
2262 - char id[RRD_ID_LENGTH_MAX + 1];
2263 -
2264 - snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_%s_max_wait", mi->instanceID, type);
2265 - netdata_fix_chart_name(id);
2266 - mdw->st_max_wait_time_msec = rrdset_create_localhost(
2267 - "mssql",
2268 - id,
2269 - NULL,
2270 - "locks",
2271 - "mssql.instance_max_wait_time",
2272 - "Maximum wait time for each wait type and category",
2273 - "ms",
2274 - PLUGIN_WINDOWS_NAME,
2275 - "PerflibMSSQL",
2276 - PRIO_MSSQL_MAX_WAIT_TIME,
2277 - mi->update_every,
2278 - RRDSET_TYPE_LINE);
2279 -
2280 - rrdlabels_add(mdw->st_max_wait_time_msec->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
2281 - rrdlabels_add(mdw->st_max_wait_time_msec->rrdlabels, "wait_type", mdw->wait_type, RRDLABEL_SRC_AUTO);
2282 - rrdlabels_add(mdw->st_max_wait_time_msec->rrdlabels, "wait_category", mdw->wait_category, RRDLABEL_SRC_AUTO);
2283 - mdw->rd_max_wait_time_msec =
2284 - rrddim_add(mdw->st_max_wait_time_msec, "duration", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
2285 - }
2286 -
2287 - rrddim_set_by_pointer(
2288 - mdw->st_max_wait_time_msec,
2289 - mdw->rd_max_wait_time_msec,
2290 - (collected_number)mdw->MSSQLDatabaseMaxWaitTimeMSec.current.Data);
2291 -
2292 - rrdset_done(mdw->st_max_wait_time_msec);
2293 -}
2294 -
2295 -void mssql_waiting_count_charts(struct mssql_instance *mi, struct mssql_db_waits *mdw, const char *type)
2296 -{
2297 - if (!mdw->st_waiting_tasks) {
2298 - char id[RRD_ID_LENGTH_MAX + 1];
2299 -
2300 - snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_%s_waiting_count", mi->instanceID, type);
2301 - netdata_fix_chart_name(id);
2302 - mdw->st_waiting_tasks = rrdset_create_localhost(
2303 - "mssql",
2304 - id,
2305 - NULL,
2306 - "locks",
2307 - "mssql.instance_waits",
2308 - "Number of waits for each wait type and category",
2309 - "waits/s",
2310 - PLUGIN_WINDOWS_NAME,
2311 - "PerflibMSSQL",
2312 - PRIO_MSSQL_WAITING_COUNT,
2313 - mi->update_every,
2314 - RRDSET_TYPE_LINE);
2315 -
2316 - rrdlabels_add(mdw->st_waiting_tasks->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
2317 - rrdlabels_add(mdw->st_waiting_tasks->rrdlabels, "wait_type", mdw->wait_type, RRDLABEL_SRC_AUTO);
2318 - rrdlabels_add(mdw->st_waiting_tasks->rrdlabels, "wait_category", mdw->wait_category, RRDLABEL_SRC_AUTO);
2319 - mdw->rd_waiting_tasks = rrddim_add(mdw->st_waiting_tasks, "waits", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
2320 - }
2321 -
2322 - rrddim_set_by_pointer(
2323 - mdw->st_waiting_tasks, mdw->rd_waiting_tasks, (collected_number)mdw->MSSQLDatabaseWaitingTasks.current.Data);
2324 -
2325 - rrdset_done(mdw->st_waiting_tasks);
2326 -}
2327 -
2328 -int dict_mssql_waits_charts_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
2329 -{
2330 - const char *dimension = dictionary_acquired_item_name((DICTIONARY_ITEM *)item);
2331 - struct mssql_db_waits *mdw = value;
2332 - struct mssql_instance *mi = data;
2333 -
2334 - mssql_total_wait_charts(mi, mdw, dimension);
2335 - mssql_resource_wait_charts(mi, mdw, dimension);
2336 - mssql_signal_wait_charts(mi, mdw, dimension);
2337 - mssql_max_wait_charts(mi, mdw, dimension);
2338 - mssql_waiting_count_charts(mi, mdw, dimension);
2339 -
2340 - return 1;
2341 -}
2342 -
2343 -static void do_mssql_waits(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *mi, int update_every)
2344 -{
2345 - dictionary_sorted_walkthrough_read(mi->waits, dict_mssql_waits_charts_cb, mi);
2346 -}
2347 -
2348 -void mssql_buffman_iops_chart(struct mssql_db_instance *mdi, struct mssql_instance *mi)
2349 -{
2350 - if (!mdi->st_buff_page_iops) {
2351 - char id[RRD_ID_LENGTH_MAX + 1];
2352 - snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_bufman_iops", mi->instanceID);
2353 - netdata_fix_chart_name(id);
2354 - mdi->st_buff_page_iops = rrdset_create_localhost(
2355 - "mssql",
2356 - id,
2357 - NULL,
2358 - "buffer cache",
2359 - "mssql.instance_bufman_iops",
2360 - "Number of pages input and output",
2361 - "pages/s",
2362 - PLUGIN_WINDOWS_NAME,
2363 - "PerflibMSSQL",
2364 - PRIO_MSSQL_BUFF_MAN_IOPS,
2365 - mi->update_every,
2366 - RRDSET_TYPE_LINE);
2367 -
2368 - mdi->rd_buff_page_reads = rrddim_add(mdi->st_buff_page_iops, "read", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
2369 - mdi->rd_buff_page_writes =
2370 - rrddim_add(mdi->st_buff_page_iops, "written", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
2371 -
2372 - rrdlabels_add(mdi->st_buff_page_iops->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
2373 - }
2374 -
2375 - rrddim_set_by_pointer(
2376 - mdi->st_buff_page_iops, mdi->rd_buff_page_reads, (collected_number)mdi->MSSQLBufferPageReads.current.Data);
2377 - rrddim_set_by_pointer(
2378 - mdi->st_buff_page_iops, mdi->rd_buff_page_writes, (collected_number)mdi->MSSQLBufferPageWrites.current.Data);
2379 -
2380 - rrdset_done(mdi->st_buff_page_iops);
2381 -}
2382 -
2383 -void mssql_buffman_cache_hit_ratio_chart(struct mssql_db_instance *mdi, struct mssql_instance *mi)
2384 -{
2385 - if (!mdi->st_buff_cache_hits) {
2386 - char id[RRD_ID_LENGTH_MAX + 1];
2387 - snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_cache_hit_ratio", mi->instanceID);
2388 - netdata_fix_chart_name(id);
2389 - mdi->st_buff_cache_hits = rrdset_create_localhost(
2390 - "mssql",
2391 - id,
2392 - NULL,
2393 - "buffer cache",
2394 - "mssql.instance_cache_hit_ratio",
2395 - "Buffer Cache hit ratio",
2396 - "percentage",
2397 - PLUGIN_WINDOWS_NAME,
2398 - "PerflibMSSQL",
2399 - PRIO_MSSQL_BUFF_CACHE_HIT_RATIO,
2400 - mi->update_every,
2401 - RRDSET_TYPE_LINE);
2402 -
2403 - mdi->rd_buff_cache_hits = rrddim_add(mdi->st_buff_cache_hits, "hit_ratio", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2404 -
2405 - rrdlabels_add(mdi->st_buff_cache_hits->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
2406 - }
2407 -
2408 - rrddim_set_by_pointer(
2409 - mdi->st_buff_cache_hits, mdi->rd_buff_cache_hits, (collected_number)mdi->MSSQLBufferCacheHits.current.Data);
2410 - rrdset_done(mdi->st_buff_cache_hits);
2411 -}
2412 -
2413 -void mssql_buffman_checkpoints_pages_chart(struct mssql_db_instance *mdi, struct mssql_instance *mi)
2414 -{
2415 - if (!mdi->st_buff_checkpoint_pages) {
2416 - char id[RRD_ID_LENGTH_MAX + 1];
2417 - snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_bufman_checkpoint_pages", mi->instanceID);
2418 - netdata_fix_chart_name(id);
2419 - mdi->st_buff_checkpoint_pages = rrdset_create_localhost(
2420 - "mssql",
2421 - id,
2422 - NULL,
2423 - "buffer cache",
2424 - "mssql.instance_bufman_checkpoint_pages",
2425 - "Flushed pages",
2426 - "pages/s",
2427 - PLUGIN_WINDOWS_NAME,
2428 - "PerflibMSSQL",
2429 - PRIO_MSSQL_BUFF_CHECKPOINT_PAGES,
2430 - mi->update_every,
2431 - RRDSET_TYPE_LINE);
2432 -
2433 - mdi->rd_buff_checkpoint_pages =
2434 - rrddim_add(mdi->st_buff_checkpoint_pages, "log", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
2435 -
2436 - rrdlabels_add(mdi->st_buff_checkpoint_pages->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
2437 - }
2438 -
2439 - rrddim_set_by_pointer(
2440 - mdi->st_buff_checkpoint_pages,
2441 - mdi->rd_buff_checkpoint_pages,
2442 - (collected_number)mdi->MSSQLBufferCheckpointPages.current.Data);
2443 - rrdset_done(mdi->st_buff_checkpoint_pages);
2444 -}
2445 -
2446 -void mssql_buffman_page_life_expectancy_chart(struct mssql_db_instance *mdi, struct mssql_instance *mi)
2447 -{
2448 - if (!mdi->st_buff_cache_page_life_expectancy) {
2449 - char id[RRD_ID_LENGTH_MAX + 1];
2450 - snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_bufman_page_life_expectancy", mi->instanceID);
2451 - netdata_fix_chart_name(id);
2452 - mdi->st_buff_cache_page_life_expectancy = rrdset_create_localhost(
2453 - "mssql",
2454 - id,
2455 - NULL,
2456 - "buffer cache",
2457 - "mssql.instance_bufman_page_life_expectancy",
2458 - "Page life expectancy",
2459 - "seconds",
2460 - PLUGIN_WINDOWS_NAME,
2461 - "PerflibMSSQL",
2462 - PRIO_MSSQL_BUFF_PAGE_LIFE_EXPECTANCY,
2463 - mi->update_every,
2464 - RRDSET_TYPE_LINE);
2465 -
2466 - mdi->rd_buff_cache_page_life_expectancy =
2467 - rrddim_add(mdi->st_buff_cache_page_life_expectancy, "life_expectancy", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2468 -
2469 - rrdlabels_add(
2470 - mdi->st_buff_cache_page_life_expectancy->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
2471 - }
2472 -
2473 - rrddim_set_by_pointer(
2474 - mdi->st_buff_cache_page_life_expectancy,
2475 - mdi->rd_buff_cache_page_life_expectancy,
2476 - (collected_number)mdi->MSSQLBufferPageLifeExpectancy.current.Data);
2477 - rrdset_done(mdi->st_buff_cache_page_life_expectancy);
2478 -}
2479 -
2480 -void mssql_buffman_lazy_write_chart(struct mssql_db_instance *mdi, struct mssql_instance *mi)
2481 -{
2482 - if (!mdi->st_buff_lazy_write) {
2483 - char id[RRD_ID_LENGTH_MAX + 1];
2484 - snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_bufman_lazy_write", mi->instanceID);
2485 - netdata_fix_chart_name(id);
2486 - mdi->st_buff_lazy_write = rrdset_create_localhost(
2487 - "mssql",
2488 - id,
2489 - NULL,
2490 - "buffer cache",
2491 - "mssql.instance_bufman_lazy_write",
2492 - "Buffers written by buffer manager's lazy writer",
2493 - "writes/s",
2494 - PLUGIN_WINDOWS_NAME,
2495 - "PerflibMSSQL",
2496 - PRIO_MSSQL_BUFF_LAZY_WRITE,
2497 - mi->update_every,
2498 - RRDSET_TYPE_LINE);
2499 -
2500 - mdi->rd_buff_lazy_write = rrddim_add(mdi->st_buff_lazy_write, "writes", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
2501 -
2502 - rrdlabels_add(mdi->st_buff_lazy_write->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
2503 - }
2504 -
2505 - rrddim_set_by_pointer(
2506 - mdi->st_buff_lazy_write, mdi->rd_buff_lazy_write, (collected_number)mdi->MSSQLBufferLazyWrite.current.Data);
2507 - rrdset_done(mdi->st_buff_lazy_write);
2508 -}
2509 -
2510 -void mssql_buffman_page_lookups_chart(struct mssql_db_instance *mdi, struct mssql_instance *mi)
2511 -{
2512 - if (!mdi->st_buff_page_lookups) {
2513 - char id[RRD_ID_LENGTH_MAX + 1];
2514 - snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_bufman_page_lookups", mi->instanceID);
2515 - netdata_fix_chart_name(id);
2516 - mdi->st_buff_page_lookups = rrdset_create_localhost(
2517 - "mssql",
2518 - id,
2519 - NULL,
2520 - "buffer cache",
2521 - "mssql.instance_bufman_page_lookups",
2522 - "Requests to find a page in the buffer pool.",
2523 - "lookups/s",
2524 - PLUGIN_WINDOWS_NAME,
2525 - "PerflibMSSQL",
2526 - PRIO_MSSQL_BUFF_PAGE_LOOKUPS,
2527 - mi->update_every,
2528 - RRDSET_TYPE_LINE);
2529 -
2530 - mdi->rd_buff_page_lookups =
2531 - rrddim_add(mdi->st_buff_page_lookups, "lookups", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
2532 -
2533 - rrdlabels_add(mdi->st_buff_page_lookups->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
2534 - }
2535 -
2536 - rrddim_set_by_pointer(
2537 - mdi->st_buff_page_lookups,
2538 - mdi->rd_buff_page_lookups,
2539 - (collected_number)mdi->MSSQLBufferPageLookups.current.Data);
2540 - rrdset_done(mdi->st_buff_page_lookups);
2541 -}
2542 -
2543 -static void netdata_mssql_compilations(struct mssql_db_instance *mdi, struct mssql_instance *mi)
2544 -{
2545 - if (!mdi->st_stats_compilation) {
2546 - char id[RRD_ID_LENGTH_MAX + 1];
2547 - snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_sqlstats_sql_compilations", mi->instanceID);
2548 - netdata_fix_chart_name(id);
2549 - mdi->st_stats_compilation = rrdset_create_localhost(
2550 - "mssql",
2551 - id,
2552 - NULL,
2553 - "sql activity",
2554 - "mssql.instance_sqlstats_sql_compilations",
2555 - "SQL compilations",
2556 - "compilations/s",
2557 - PLUGIN_WINDOWS_NAME,
2558 - "PerflibMSSQL",
2559 - PRIO_MSSQL_STATS_COMPILATIONS,
2560 - mi->update_every,
2561 - RRDSET_TYPE_LINE);
2562 -
2563 - mdi->rd_stats_compilation =
2564 - rrddim_add(mdi->st_stats_compilation, "compilations", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
2565 -
2566 - rrdlabels_add(mdi->st_stats_compilation->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
2567 - }
2568 -
2569 - rrddim_set_by_pointer(
2570 - mdi->st_stats_compilation, mdi->rd_stats_compilation, (collected_number)mdi->MSSQLCompilations.current.Data);
2571 - rrdset_done(mdi->st_stats_compilation);
2572 -}
2573 -
2574 -static void netdata_mssql_recompilations(struct mssql_db_instance *mdi, struct mssql_instance *mi)
2575 -{
2576 - if (!mdi->st_stats_recompiles) {
2577 - char id[RRD_ID_LENGTH_MAX + 1];
2578 - snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_sqlstats_sql_recompilations", mi->instanceID);
2579 - netdata_fix_chart_name(id);
2580 - mdi->st_stats_recompiles = rrdset_create_localhost(
2581 - "mssql",
2582 - id,
2583 - NULL,
2584 - "sql activity",
2585 - "mssql.instance_sqlstats_sql_recompilations",
2586 - "SQL re-compilations",
2587 - "recompiles/s",
2588 - PLUGIN_WINDOWS_NAME,
2589 - "PerflibMSSQL",
2590 - PRIO_MSSQL_STATS_RECOMPILATIONS,
2591 - mi->update_every,
2592 - RRDSET_TYPE_LINE);
2593 -
2594 - mdi->rd_stats_recompiles =
2595 - rrddim_add(mdi->st_stats_recompiles, "recompiles", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
2596 -
2597 - rrdlabels_add(mdi->st_stats_recompiles->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
2598 - }
2599 -
2600 - rrddim_set_by_pointer(
2601 - mdi->st_stats_recompiles, mdi->rd_stats_recompiles, (collected_number)mdi->MSSQLRecompilations.current.Data);
2602 - rrdset_done(mdi->st_stats_recompiles);
2603 -}
2604 -
2605 -int dict_mssql_buffman_stats_charts_cb(
2606 - const DICTIONARY_ITEM *item __maybe_unused,
2607 - void *value,
2608 - void *data __maybe_unused)
2609 -{
2610 - struct mssql_db_instance *mdi = value;
2611 - struct mssql_instance *mi = data;
2612 -
2613 - if (unlikely(!mdi->collect_instance))
2614 - return 1;
2615 -
2616 - mssql_buffman_iops_chart(mdi, mi);
2617 - mssql_buffman_cache_hit_ratio_chart(mdi, mi);
2618 - mssql_buffman_checkpoints_pages_chart(mdi, mi);
2619 - mssql_buffman_page_life_expectancy_chart(mdi, mi);
2620 - mssql_buffman_lazy_write_chart(mdi, mi);
2621 - mssql_buffman_page_lookups_chart(mdi, mi);
2622 -
2623 - netdata_mssql_compilations(mdi, mi);
2624 - netdata_mssql_recompilations(mdi, mi);
2625 -
2626 - return 1;
2627 -}
2628 -
2629 -static void do_mssql_bufferman_stats_sql(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *mi, int update_every)
2630 -{
2631 - dictionary_sorted_walkthrough_read(mi->databases, dict_mssql_buffman_stats_charts_cb, mi);
2632 -}
2633 -
2634 -static void netdata_mssql_jobs_status(struct mssql_db_jobs *mdj, struct mssql_instance *mi, const char *job)
2635 -{
2636 - if (!mdj->st_status) {
2637 - char id[RRD_ID_LENGTH_MAX + 1];
2638 - snprintfz(id, RRD_ID_LENGTH_MAX, "job_%s_instance_%s_status", job, mi->instanceID);
2639 - netdata_fix_chart_name(id);
2640 - mdj->st_status = rrdset_create_localhost(
2641 - "mssql",
2642 - id,
2643 - NULL,
2644 - "jobs",
2645 - "mssql.instance_jobs_status",
2646 - "Jobs running",
2647 - "status",
2648 - PLUGIN_WINDOWS_NAME,
2649 - "PerflibMSSQL",
2650 - PRIO_MSSQL_DATABASE_JOBS_STATUS,
2651 - mi->update_every,
2652 - RRDSET_TYPE_LINE);
2653 -
2654 - mdj->rd_status_enabled = rrddim_add(mdj->st_status, "enabled", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2655 -
2656 - mdj->rd_status_disabled = rrddim_add(mdj->st_status, "disabled", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2657 -
2658 - rrdlabels_add(mdj->st_status->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
2659 - rrdlabels_add(mdj->st_status->rrdlabels, "job_name", job, RRDLABEL_SRC_AUTO);
2660 - }
2661 -
2662 - rrddim_set_by_pointer(
2663 - mdj->st_status, mdj->rd_status_enabled, (collected_number)(mdj->MSSQLJOBState.current.Data == 1));
2664 - rrddim_set_by_pointer(
2665 - mdj->st_status, mdj->rd_status_disabled, (collected_number)(mdj->MSSQLJOBState.current.Data == 0));
2666 - rrdset_done(mdj->st_status);
2667 -}
2668 -
2669 -int dict_mssql_sysjobs_chart_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
2670 -{
2671 - const char *job = dictionary_acquired_item_name((DICTIONARY_ITEM *)item);
2672 - struct mssql_db_jobs *mdj = value;
2673 - struct mssql_instance *mi = data;
2674 -
2675 - netdata_mssql_jobs_status(mdj, mi, job);
2676 -}
2677 -
2678 -static void do_mssql_job_status_sql(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *mi, int update_every)
2679 -{
2680 - dictionary_sorted_walkthrough_read(mi->sysjobs, dict_mssql_sysjobs_chart_cb, mi);
2681 -}
2682 -
2683 -void dict_mssql_replication_status(struct mssql_publisher_publication *mpp, int update_every)
2684 -{
2685 - if (!mpp->st_publisher_status) {
2686 - char id[RRD_ID_LENGTH_MAX + 1];
2687 -
2688 - snprintfz(
2689 - id,
2690 - RRD_ID_LENGTH_MAX,
2691 - "instance_%s_replication_%s_%s_status",
2692 - mpp->parent->instanceID,
2693 - mpp->publication,
2694 - mpp->db);
2695 - netdata_fix_chart_name(id);
2696 - mpp->st_publisher_status = rrdset_create_localhost(
2697 - "mssql",
2698 - id,
2699 - NULL,
2700 - "replication",
2701 - "mssql.replication_status",
2702 - "Current replication status",
2703 - "status",
2704 - PLUGIN_WINDOWS_NAME,
2705 - "PerflibMSSQL",
2706 - PRIO_MSSQL_REPLICATION_STATUS,
2707 - update_every,
2708 - RRDSET_TYPE_LINE);
2709 -
2710 - rrdlabels_add(
2711 - mpp->st_publisher_status->rrdlabels, "mssql_instance", mpp->parent->instanceID, RRDLABEL_SRC_AUTO);
2712 - rrdlabels_add(mpp->st_publisher_status->rrdlabels, "publisher", mpp->publisher, RRDLABEL_SRC_AUTO);
2713 - rrdlabels_add(mpp->st_publisher_status->rrdlabels, "database", mpp->db, RRDLABEL_SRC_AUTO);
2714 - rrdlabels_add(mpp->st_publisher_status->rrdlabels, "publication", mpp->publication, RRDLABEL_SRC_AUTO);
2715 -
2716 - mpp->rd_publisher_status_started =
2717 - rrddim_add(mpp->st_publisher_status, "started", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2718 - mpp->rd_publisher_status_successed =
2719 - rrddim_add(mpp->st_publisher_status, "succeeded", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2720 - mpp->rd_publisher_status_in_progress =
2721 - rrddim_add(mpp->st_publisher_status, "in_progress", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2722 - mpp->rd_publisher_status_idle =
2723 - rrddim_add(mpp->st_publisher_status, "idle", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2724 - mpp->rd_publisher_status_retrying =
2725 - rrddim_add(mpp->st_publisher_status, "retrying", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2726 - mpp->rd_publisher_status_failed =
2727 - rrddim_add(mpp->st_publisher_status, "failed", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2728 - }
2729 -
2730 - int status = mpp->status;
2731 - rrddim_set_by_pointer(mpp->st_publisher_status, mpp->rd_publisher_status_started, (collected_number)(status == 1));
2732 - rrddim_set_by_pointer(
2733 - mpp->st_publisher_status, mpp->rd_publisher_status_successed, (collected_number)(status == 2));
2734 - rrddim_set_by_pointer(
2735 - mpp->st_publisher_status, mpp->rd_publisher_status_in_progress, (collected_number)(status == 3));
2736 - rrddim_set_by_pointer(mpp->st_publisher_status, mpp->rd_publisher_status_idle, (collected_number)(status == 4));
2737 - rrddim_set_by_pointer(mpp->st_publisher_status, mpp->rd_publisher_status_retrying, (collected_number)(status == 5));
2738 - rrddim_set_by_pointer(mpp->st_publisher_status, mpp->rd_publisher_status_failed, (collected_number)(status == 6));
2739 - rrdset_done(mpp->st_publisher_status);
2740 -}
2741 -
2742 -void dict_mssql_replication_warning(struct mssql_publisher_publication *mpp, int update_every)
2743 -{
2744 - if (!mpp->st_warning) {
2745 - char id[RRD_ID_LENGTH_MAX + 1];
2746 -
2747 - snprintfz(
2748 - id,
2749 - RRD_ID_LENGTH_MAX,
2750 - "instance_%s_replication_%s_%s_warning",
2751 - mpp->parent->instanceID,
2752 - mpp->publication,
2753 - mpp->db);
2754 - netdata_fix_chart_name(id);
2755 - mpp->st_warning = rrdset_create_localhost(
2756 - "mssql",
2757 - id,
2758 - NULL,
2759 - "replication",
2760 - "mssql.replication_warning",
2761 - "Maximum threshold warning.",
2762 - "status",
2763 - PLUGIN_WINDOWS_NAME,
2764 - "PerflibMSSQL",
2765 - PRIO_MSSQL_REPLICATION_WARNING,
2766 - update_every,
2767 - RRDSET_TYPE_LINE);
2768 -
2769 - rrdlabels_add(mpp->st_warning->rrdlabels, "mssql_instance", mpp->parent->instanceID, RRDLABEL_SRC_AUTO);
2770 - rrdlabels_add(mpp->st_warning->rrdlabels, "publisher", mpp->publisher, RRDLABEL_SRC_AUTO);
2771 - rrdlabels_add(mpp->st_warning->rrdlabels, "database", mpp->db, RRDLABEL_SRC_AUTO);
2772 - rrdlabels_add(mpp->st_warning->rrdlabels, "publication", mpp->publication, RRDLABEL_SRC_AUTO);
2773 -
2774 - mpp->rd_warning_expiration = rrddim_add(mpp->st_warning, "expiration", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2775 - mpp->rd_warning_latency = rrddim_add(mpp->st_warning, "latency", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2776 - mpp->rd_warning_mergeeexpiration =
2777 - rrddim_add(mpp->st_warning, "merge expiration", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2778 - mpp->rd_warning_mergefastduration =
2779 - rrddim_add(mpp->st_warning, "fast duration", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2780 - mpp->rd_warning_mergelowduration =
2781 - rrddim_add(mpp->st_warning, "low duration", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2782 - mpp->rd_warning_mergefastrunspeed =
2783 - rrddim_add(mpp->st_warning, "fast run speed", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2784 - mpp->rd_warning_mergelowrunspeed =
2785 - rrddim_add(mpp->st_warning, "low run speed", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2786 - }
2787 -
2788 - int warning = mpp->warning;
2789 - rrddim_set_by_pointer(
2790 - mpp->st_warning, mpp->rd_warning_expiration, (collected_number)(warning & MSSQL_REPLICATON_EXPIRATION));
2791 - rrddim_set_by_pointer(
2792 - mpp->st_warning, mpp->rd_warning_latency, (collected_number)(warning & MSSQL_REPLICATON_LATENCY));
2793 - rrddim_set_by_pointer(
2794 - mpp->st_warning,
2795 - mpp->rd_warning_mergeeexpiration,
2796 - (collected_number)(warning & MSSQL_REPLICATON_MERGEEXPIRATION));
2797 - rrddim_set_by_pointer(
2798 - mpp->st_warning,
2799 - mpp->rd_warning_mergefastduration,
2800 - (collected_number)(warning & MSSQL_REPLICATON_MERGEFASTDURATION));
2801 - rrddim_set_by_pointer(
2802 - mpp->st_warning,
2803 - mpp->rd_warning_mergelowduration,
2804 - (collected_number)(warning & MSSQL_REPLICATON_MERGELOWDURATION));
2805 - rrddim_set_by_pointer(
2806 - mpp->st_warning,
2807 - mpp->rd_warning_mergefastrunspeed,
2808 - (collected_number)(warning & MSSQL_REPLICATON_MERGEFASTRUNSPEED));
2809 - rrddim_set_by_pointer(
2810 - mpp->st_warning,
2811 - mpp->rd_warning_mergelowrunspeed,
2812 - (collected_number)(warning & MSSQL_REPLICATON_MERGELOWRUNSPEED));
2813 - rrdset_done(mpp->st_warning);
2814 -}
2815 -
2816 -void dict_mssql_replication_avg_latency(struct mssql_publisher_publication *mpp, int update_every)
2817 -{
2818 - if (!mpp->st_avg_latency) {
2819 - char id[RRD_ID_LENGTH_MAX + 1];
2820 -
2821 - snprintfz(
2822 - id,
2823 - RRD_ID_LENGTH_MAX,
2824 - "instance_%s_replication_%s_%s_avg_latency",
2825 - mpp->parent->instanceID,
2826 - mpp->publication,
2827 - mpp->db);
2828 - netdata_fix_chart_name(id);
2829 - mpp->st_avg_latency = rrdset_create_localhost(
2830 - "mssql",
2831 - id,
2832 - NULL,
2833 - "replication",
2834 - "mssql.replication_avg_latency",
2835 - "Average latency for a transactional publication.",
2836 - "seconds",
2837 - PLUGIN_WINDOWS_NAME,
2838 - "PerflibMSSQL",
2839 - PRIO_MSSQL_REPLICATION_AVG_LATENCY,
2840 - update_every,
2841 - RRDSET_TYPE_LINE);
2842 -
2843 - rrdlabels_add(mpp->st_avg_latency->rrdlabels, "mssql_instance", mpp->parent->instanceID, RRDLABEL_SRC_AUTO);
2844 - rrdlabels_add(mpp->st_avg_latency->rrdlabels, "publisher", mpp->publisher, RRDLABEL_SRC_AUTO);
2845 - rrdlabels_add(mpp->st_avg_latency->rrdlabels, "database", mpp->db, RRDLABEL_SRC_AUTO);
2846 - rrdlabels_add(mpp->st_avg_latency->rrdlabels, "publication", mpp->publication, RRDLABEL_SRC_AUTO);
2847 -
2848 - mpp->rd_avg_latency = rrddim_add(mpp->st_avg_latency, "latency", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2849 - }
2850 -
2851 - rrddim_set_by_pointer(mpp->st_avg_latency, mpp->rd_avg_latency, (collected_number)mpp->avg_latency);
2852 - rrdset_done(mpp->st_avg_latency);
2853 -}
2854 -
2855 -void dict_mssql_replication_subscription(struct mssql_publisher_publication *mpp, int update_every)
2856 -{
2857 - if (!mpp->st_subscription_count) {
2858 - char id[RRD_ID_LENGTH_MAX + 1];
2859 -
2860 - snprintfz(
2861 - id,
2862 - RRD_ID_LENGTH_MAX,
2863 - "instance_%s_replication_%s_%s_subscription",
2864 - mpp->parent->instanceID,
2865 - mpp->publication,
2866 - mpp->db);
2867 - netdata_fix_chart_name(id);
2868 - mpp->st_subscription_count = rrdset_create_localhost(
2869 - "mssql",
2870 - id,
2871 - NULL,
2872 - "replication",
2873 - "mssql.replication_subscription",
2874 - "Number of subscriptions to a publication.",
2875 - "subscription",
2876 - PLUGIN_WINDOWS_NAME,
2877 - "PerflibMSSQL",
2878 - PRIO_MSSQL_REPLICATION_SUBSCRIPTION_COUNT,
2879 - update_every,
2880 - RRDSET_TYPE_LINE);
2881 -
2882 - rrdlabels_add(
2883 - mpp->st_subscription_count->rrdlabels, "mssql_instance", mpp->parent->instanceID, RRDLABEL_SRC_AUTO);
2884 - rrdlabels_add(mpp->st_subscription_count->rrdlabels, "publisher", mpp->publisher, RRDLABEL_SRC_AUTO);
2885 - rrdlabels_add(mpp->st_subscription_count->rrdlabels, "database", mpp->db, RRDLABEL_SRC_AUTO);
2886 - rrdlabels_add(mpp->st_subscription_count->rrdlabels, "publication", mpp->publication, RRDLABEL_SRC_AUTO);
2887 -
2888 - mpp->rd_subscription_count =
2889 - rrddim_add(mpp->st_subscription_count, "subscription", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2890 - }
2891 -
2892 - rrddim_set_by_pointer(
2893 - mpp->st_subscription_count, mpp->rd_subscription_count, (collected_number)mpp->subscriptioncount);
2894 - rrdset_done(mpp->st_subscription_count);
2895 -}
2896 -
2897 -void dict_mssql_replication_dist_agent_running(struct mssql_publisher_publication *mpp, int update_every)
2898 -{
2899 - if (!mpp->st_running_agent) {
2900 - char id[RRD_ID_LENGTH_MAX + 1];
2901 -
2902 - snprintfz(
2903 - id,
2904 - RRD_ID_LENGTH_MAX,
2905 - "instance_%s_replication_%s_%s_agent_running",
2906 - mpp->parent->instanceID,
2907 - mpp->publication,
2908 - mpp->db);
2909 - netdata_fix_chart_name(id);
2910 - mpp->st_running_agent = rrdset_create_localhost(
2911 - "mssql",
2912 - id,
2913 - NULL,
2914 - "replication",
2915 - "mssql.replication_agent_running",
2916 - "Distribution agents running.",
2917 - "agents",
2918 - PLUGIN_WINDOWS_NAME,
2919 - "PerflibMSSQL",
2920 - PRIO_MSSQL_REPLICATION_AGENT_RUNNING,
2921 - update_every,
2922 - RRDSET_TYPE_LINE);
2923 -
2924 - rrdlabels_add(mpp->st_running_agent->rrdlabels, "mssql_instance", mpp->parent->instanceID, RRDLABEL_SRC_AUTO);
2925 - rrdlabels_add(mpp->st_running_agent->rrdlabels, "publisher", mpp->publisher, RRDLABEL_SRC_AUTO);
2926 - rrdlabels_add(mpp->st_running_agent->rrdlabels, "database", mpp->db, RRDLABEL_SRC_AUTO);
2927 - rrdlabels_add(mpp->st_running_agent->rrdlabels, "publication", mpp->publication, RRDLABEL_SRC_AUTO);
2928 -
2929 - mpp->rd_running_agent = rrddim_add(mpp->st_running_agent, "agents", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2930 - }
2931 -
2932 - rrddim_set_by_pointer(mpp->st_running_agent, mpp->rd_running_agent, (collected_number)mpp->runningdistagentcount);
2933 - rrdset_done(mpp->st_running_agent);
2934 -}
2935 -
2936 -void dict_mssql_replication_sync_time(struct mssql_publisher_publication *mpp, int update_every)
2937 -{
2938 - if (!mpp->st_synchronization_time) {
2939 - char id[RRD_ID_LENGTH_MAX + 1];
2940 -
2941 - snprintfz(
2942 - id,
2943 - RRD_ID_LENGTH_MAX,
2944 - "instance_%s_replication_%s_%s_synchronization",
2945 - mpp->parent->instanceID,
2946 - mpp->publication,
2947 - mpp->db);
2948 - netdata_fix_chart_name(id);
2949 - mpp->st_synchronization_time = rrdset_create_localhost(
2950 - "mssql",
2951 - id,
2952 - NULL,
2953 - "replication",
2954 - "mssql.replication_synchronization",
2955 - "The shortest synchronization.",
2956 - "seconds",
2957 - PLUGIN_WINDOWS_NAME,
2958 - "PerflibMSSQL",
2959 - PRIO_MSSQL_REPLICATION_SYNC_TIME,
2960 - update_every,
2961 - RRDSET_TYPE_LINE);
2962 -
2963 - rrdlabels_add(
2964 - mpp->st_synchronization_time->rrdlabels, "mssql_instance", mpp->parent->instanceID, RRDLABEL_SRC_AUTO);
2965 - rrdlabels_add(mpp->st_synchronization_time->rrdlabels, "publisher", mpp->publisher, RRDLABEL_SRC_AUTO);
2966 - rrdlabels_add(mpp->st_synchronization_time->rrdlabels, "database", mpp->db, RRDLABEL_SRC_AUTO);
2967 - rrdlabels_add(mpp->st_synchronization_time->rrdlabels, "publication", mpp->publication, RRDLABEL_SRC_AUTO);
2968 -
2969 - mpp->rd_synchronization_time =
2970 - rrddim_add(mpp->st_synchronization_time, "seconds", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2971 - }
2972 -
2973 - rrddim_set_by_pointer(
2974 - mpp->st_synchronization_time, mpp->rd_synchronization_time, (collected_number)mpp->runningdistagentcount);
2975 - rrdset_done(mpp->st_synchronization_time);
2976 -}
2977 -
2978 -int dict_mssql_replication_chart_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
2979 -{
2980 - struct mssql_publisher_publication *mpp = value;
2981 - int *update_every = data;
2982 -
2983 - dict_mssql_replication_status(mpp, *update_every);
2984 - dict_mssql_replication_warning(mpp, *update_every);
2985 - dict_mssql_replication_avg_latency(mpp, *update_every);
2986 - dict_mssql_replication_subscription(mpp, *update_every);
2987 - dict_mssql_replication_dist_agent_running(mpp, *update_every);
2988 - dict_mssql_replication_sync_time(mpp, *update_every);
2989 -}
2990 -
2991 -static void do_mssql_replication(struct mssql_instance *mi, int update_every)
2992 -{
2993 - dictionary_sorted_walkthrough_read(mi->publisher_publication, dict_mssql_replication_chart_cb, &update_every);
2994 -}
2995 -
2996 -static void mssql_database_backup_restore_chart(struct mssql_db_instance *mdi, const char *db, int update_every)
2997 -{
2998 - char id[RRD_ID_LENGTH_MAX + 1];
2999 -
3000 - if (!mdi->st_db_backup_restore_operations) {
3001 - snprintfz(id, RRD_ID_LENGTH_MAX, "db_%s_instance_%s_backup_restore_operations", db, mdi->parent->instanceID);
3002 - netdata_fix_chart_name(id);
3003 - mdi->st_db_backup_restore_operations = rrdset_create_localhost(
3004 - "mssql",
3005 - id,
3006 - NULL,
3007 - "transactions",
3008 - "mssql.database_backup_restore_operations",
3009 - "Backup IO per database",
3010 - "operations/s",
3011 - PLUGIN_WINDOWS_NAME,
3012 - "PerflibMSSQL",
3013 - PRIO_MSSQL_DATABASE_BACKUP_RESTORE_OPERATIONS,
3014 - update_every,
3015 - RRDSET_TYPE_LINE);
3016 -
3017 - rrdlabels_add(
3018 - mdi->st_db_backup_restore_operations->rrdlabels,
3019 - "mssql_instance",
3020 - mdi->parent->instanceID,
3021 - RRDLABEL_SRC_AUTO);
3022 - rrdlabels_add(mdi->st_db_backup_restore_operations->rrdlabels, "database", db, RRDLABEL_SRC_AUTO);
3023 -
3024 - mdi->rd_db_backup_restore_operations =
3025 - rrddim_add(mdi->st_db_backup_restore_operations, "backup", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
3026 - }
3027 -
3028 - rrddim_set_by_pointer(
3029 - mdi->st_db_backup_restore_operations,
3030 - mdi->rd_db_backup_restore_operations,
3031 - (collected_number)mdi->MSSQLDatabaseBackupRestoreOperations.current.Data);
3032 -
3033 - rrdset_done(mdi->st_db_backup_restore_operations);
3034 -}
3035 -
3036 -static void mssql_database_log_flushes_chart(struct mssql_db_instance *mdi, const char *db, int update_every)
3037 -{
3038 - char id[RRD_ID_LENGTH_MAX + 1];
3039 -
3040 - if (!mdi->st_db_log_flushes) {
3041 - snprintfz(id, RRD_ID_LENGTH_MAX, "db_%s_instance_%s_log_flushes", db, mdi->parent->instanceID);
3042 - netdata_fix_chart_name(id);
3043 - mdi->st_db_log_flushes = rrdset_create_localhost(
3044 - "mssql",
3045 - id,
3046 - NULL,
3047 - "transactions",
3048 - "mssql.database_log_flushes",
3049 - "Log flushes",
3050 - "flushes/s",
3051 - PLUGIN_WINDOWS_NAME,
3052 - "PerflibMSSQL",
3053 - PRIO_MSSQL_DATABASE_LOG_FLUSHES,
3054 - update_every,
3055 - RRDSET_TYPE_LINE);
3056 -
3057 - rrdlabels_add(mdi->st_db_log_flushes->rrdlabels, "mssql_instance", mdi->parent->instanceID, RRDLABEL_SRC_AUTO);
3058 - rrdlabels_add(mdi->st_db_log_flushes->rrdlabels, "database", db, RRDLABEL_SRC_AUTO);
3059 - }
3060 -
3061 - if (!mdi->rd_db_log_flushes) {
3062 - mdi->rd_db_log_flushes = rrddim_add(mdi->st_db_log_flushes, "flushes", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
3063 - }
3064 -
3065 - rrddim_set_by_pointer(
3066 - mdi->st_db_log_flushes, mdi->rd_db_log_flushes, (collected_number)mdi->MSSQLDatabaseLogFlushes.current.Data);
3067 -
3068 - rrdset_done(mdi->st_db_log_flushes);
3069 -}
3070 -
3071 -static void mssql_database_log_flushed_chart(struct mssql_db_instance *mdi, const char *db, int update_every)
3072 -{
3073 - char id[RRD_ID_LENGTH_MAX + 1];
3074 -
3075 - if (!mdi->st_db_log_flushed) {
3076 - snprintfz(id, RRD_ID_LENGTH_MAX, "db_%s_instance_%s_log_flushed", db, mdi->parent->instanceID);
3077 - netdata_fix_chart_name(id);
3078 - mdi->st_db_log_flushed = rrdset_create_localhost(
3079 - "mssql",
3080 - id,
3081 - NULL,
3082 - "transactions",
3083 - "mssql.database_log_flushed",
3084 - "Log flushed",
3085 - "bytes/s",
3086 - PLUGIN_WINDOWS_NAME,
3087 - "PerflibMSSQL",
3088 - PRIO_MSSQL_DATABASE_LOG_FLUSHED,
3089 - update_every,
3090 - RRDSET_TYPE_LINE);
3091 -
3092 - rrdlabels_add(mdi->st_db_log_flushed->rrdlabels, "mssql_instance", mdi->parent->instanceID, RRDLABEL_SRC_AUTO);
3093 - rrdlabels_add(mdi->st_db_log_flushed->rrdlabels, "database", db, RRDLABEL_SRC_AUTO);
3094 -
3095 - mdi->rd_db_log_flushed = rrddim_add(mdi->st_db_log_flushed, "flushed", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
3096 - }
3097 -
3098 - rrddim_set_by_pointer(
3099 - mdi->st_db_log_flushed, mdi->rd_db_log_flushed, (collected_number)mdi->MSSQLDatabaseLogFlushed.current.Data);
3100 -
3101 - rrdset_done(mdi->st_db_log_flushed);
3102 -}
3103 -
3104 -static void mssql_transactions_chart(struct mssql_db_instance *mdi, const char *db, int update_every)
3105 -{
3106 - char id[RRD_ID_LENGTH_MAX + 1];
3107 -
3108 - if (!mdi->st_db_transactions) {
3109 - snprintfz(id, RRD_ID_LENGTH_MAX, "db_%s_instance_%s_transactions", db, mdi->parent->instanceID);
3110 - netdata_fix_chart_name(id);
3111 - mdi->st_db_transactions = rrdset_create_localhost(
3112 - "mssql",
3113 - id,
3114 - NULL,
3115 - "transactions",
3116 - "mssql.database_transactions",
3117 - "Transactions",
3118 - "transactions/s",
3119 - PLUGIN_WINDOWS_NAME,
3120 - "PerflibMSSQL",
3121 - PRIO_MSSQL_DATABASE_TRANSACTIONS,
3122 - update_every,
3123 - RRDSET_TYPE_LINE);
3124 -
3125 - rrdlabels_add(mdi->st_db_transactions->rrdlabels, "mssql_instance", mdi->parent->instanceID, RRDLABEL_SRC_AUTO);
3126 - rrdlabels_add(mdi->st_db_transactions->rrdlabels, "database", db, RRDLABEL_SRC_AUTO);
3127 -
3128 - mdi->rd_db_transactions =
3129 - rrddim_add(mdi->st_db_transactions, "transactions", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
3130 - }
3131 -
3132 - rrddim_set_by_pointer(
3133 - mdi->st_db_transactions,
3134 - mdi->rd_db_transactions,
3135 - (collected_number)mdi->MSSQLDatabaseTransactions.current.Data);
3136 -
3137 - rrdset_done(mdi->st_db_transactions);
3138 -}
3139 -
3140 -static void mssql_write_transactions_chart(struct mssql_db_instance *mdi, const char *db, int update_every)
3141 -{
3142 - char id[RRD_ID_LENGTH_MAX + 1];
3143 -
3144 - if (!mdi->st_db_write_transactions) {
3145 - snprintfz(id, RRD_ID_LENGTH_MAX, "db_%s_instance_%s_write_transactions", db, mdi->parent->instanceID);
3146 - netdata_fix_chart_name(id);
3147 - mdi->st_db_write_transactions = rrdset_create_localhost(
3148 - "mssql",
3149 - id,
3150 - NULL,
3151 - "transactions",
3152 - "mssql.database_write_transactions",
3153 - "Write transactions",
3154 - "transactions/s",
3155 - PLUGIN_WINDOWS_NAME,
3156 - "PerflibMSSQL",
3157 - PRIO_MSSQL_DATABASE_WRITE_TRANSACTIONS,
3158 - update_every,
3159 - RRDSET_TYPE_LINE);
3160 -
3161 - rrdlabels_add(
3162 - mdi->st_db_write_transactions->rrdlabels, "mssql_instance", mdi->parent->instanceID, RRDLABEL_SRC_AUTO);
3163 - rrdlabels_add(mdi->st_db_write_transactions->rrdlabels, "database", db, RRDLABEL_SRC_AUTO);
3164 -
3165 - mdi->rd_db_write_transactions =
3166 - rrddim_add(mdi->st_db_write_transactions, "write", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
3167 - }
3168 -
3169 - rrddim_set_by_pointer(
3170 - mdi->st_db_write_transactions,
3171 - mdi->rd_db_write_transactions,
3172 - (collected_number)mdi->MSSQLDatabaseWriteTransactions.current.Data);
3173 -
3174 - rrdset_done(mdi->st_db_write_transactions);
3175 -}
3176 -
3177 -static void mssql_lockwait_chart(struct mssql_db_instance *mdi, const char *db, int update_every)
3178 -{
3179 - char id[RRD_ID_LENGTH_MAX + 1];
3180 -
3181 - if (!mdi->st_db_lockwait) {
3182 - snprintfz(id, RRD_ID_LENGTH_MAX, "db_%s_instance_%s_lockwait", db, mdi->parent->instanceID);
3183 - netdata_fix_chart_name(id);
3184 - mdi->st_db_lockwait = rrdset_create_localhost(
3185 - "mssql",
3186 - id,
3187 - NULL,
3188 - "locks",
3189 - "mssql.database_lockwait",
3190 - "Lock requests that required the caller to wait.",
3191 - "locks/s",
3192 - PLUGIN_WINDOWS_NAME,
3193 - "PerflibMSSQL",
3194 - PRIO_MSSQL_DATABASE_LOCKWAIT_PER_SECOND,
3195 - update_every,
3196 - RRDSET_TYPE_LINE);
3197 -
3198 - rrdlabels_add(mdi->st_db_lockwait->rrdlabels, "mssql_instance", mdi->parent->instanceID, RRDLABEL_SRC_AUTO);
3199 - rrdlabels_add(mdi->st_db_lockwait->rrdlabels, "database", db, RRDLABEL_SRC_AUTO);
3200 -
3201 - mdi->rd_db_lockwait = rrddim_add(mdi->st_db_lockwait, "lock", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
3202 - }
3203 -
3204 - rrddim_set_by_pointer(
3205 - mdi->st_db_lockwait, mdi->rd_db_lockwait, (collected_number)mdi->MSSQLDatabaseLockWaitSec.current.Data);
3206 -
3207 - rrdset_done(mdi->st_db_lockwait);
3208 -}
3209 -
3210 -static void mssql_deadlock_chart(struct mssql_db_instance *mdi, const char *db, int update_every)
3211 -{
3212 - char id[RRD_ID_LENGTH_MAX + 1];
3213 -
3214 - if (!mdi->st_db_deadlock) {
3215 - snprintfz(id, RRD_ID_LENGTH_MAX, "db_%s_instance_%s_deadlocks", db, mdi->parent->instanceID);
3216 - netdata_fix_chart_name(id);
3217 - mdi->st_db_deadlock = rrdset_create_localhost(
3218 - "mssql",
3219 - id,
3220 - NULL,
3221 - "locks",
3222 - "mssql.database_deadlocks",
3223 - "Lock requests that resulted in deadlock.",
3224 - "deadlocks/s",
3225 - PLUGIN_WINDOWS_NAME,
3226 - "PerflibMSSQL",
3227 - PRIO_MSSQL_DATABASE_DEADLOCKS_PER_SECOND,
3228 - update_every,
3229 - RRDSET_TYPE_LINE);
3230 -
3231 - rrdlabels_add(mdi->st_db_deadlock->rrdlabels, "mssql_instance", mdi->parent->instanceID, RRDLABEL_SRC_AUTO);
3232 - rrdlabels_add(mdi->st_db_deadlock->rrdlabels, "database", db, RRDLABEL_SRC_AUTO);
3233 -
3234 - mdi->rd_db_deadlock = rrddim_add(mdi->st_db_deadlock, "deadlocks", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
3235 - }
3236 -
3237 - rrddim_set_by_pointer(
3238 - mdi->st_db_deadlock, mdi->rd_db_deadlock, (collected_number)mdi->MSSQLDatabaseDeadLockSec.current.Data);
3239 -
3240 - rrdset_done(mdi->st_db_deadlock);
3241 -}
3242 -
3243 -static void mssql_is_readonly_chart(struct mssql_db_instance *mdi, const char *db, int update_every)
3244 -{
3245 - if (!mdi->st_db_readonly) {
3246 - char id[RRD_ID_LENGTH_MAX + 1];
3247 - snprintfz(id, RRD_ID_LENGTH_MAX, "db_%s_instance_%s_readonly", db, mdi->parent->instanceID);
3248 - netdata_fix_chart_name(id);
3249 - mdi->st_db_readonly = rrdset_create_localhost(
3250 - "mssql",
3251 - id,
3252 - NULL,
3253 - "locks",
3254 - "mssql.database_readonly",
3255 - "Current database write status.",
3256 - "status",
3257 - PLUGIN_WINDOWS_NAME,
3258 - "PerflibMSSQL",
3259 - PRIO_MSSQL_DATABASE_READONLY,
3260 - update_every,
3261 - RRDSET_TYPE_LINE);
3262 -
3263 - rrdlabels_add(mdi->st_db_readonly->rrdlabels, "mssql_instance", mdi->parent->instanceID, RRDLABEL_SRC_AUTO);
3264 - rrdlabels_add(mdi->st_db_readonly->rrdlabels, "database", db, RRDLABEL_SRC_AUTO);
3265 -
3266 - mdi->rd_db_readonly_yes = rrddim_add(mdi->st_db_readonly, "writable", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
3267 - mdi->rd_db_readonly_no = rrddim_add(mdi->st_db_readonly, "readonly", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
3268 - }
3269 -
3270 - rrddim_set_by_pointer(
3271 - mdi->st_db_readonly, mdi->rd_db_readonly_no, (collected_number)mdi->MSSQLDBIsReadonly.current.Data);
3272 -
3273 - collected_number opposite = (mdi->MSSQLDBIsReadonly.current.Data) ? 0 : 1;
3274 - rrddim_set_by_pointer(mdi->st_db_readonly, mdi->rd_db_readonly_yes, (collected_number)opposite);
3275 -
3276 - rrdset_done(mdi->st_db_readonly);
3277 -}
3278 -
3279 -static void mssql_db_states_chart(struct mssql_db_instance *mdi, const char *db, int update_every)
3280 -{
3281 - if (!mdi->st_db_state) {
3282 - char id[RRD_ID_LENGTH_MAX + 1];
3283 - snprintfz(id, RRD_ID_LENGTH_MAX, "db_%s_instance_%s_state", db, mdi->parent->instanceID);
3284 - netdata_fix_chart_name(id);
3285 - mdi->st_db_state = rrdset_create_localhost(
3286 - "mssql",
3287 - id,
3288 - NULL,
3289 - "locks",
3290 - "mssql.database_state",
3291 - "Current database state.",
3292 - "status",
3293 - PLUGIN_WINDOWS_NAME,
3294 - "PerflibMSSQL",
3295 - PRIO_MSSQL_DATABASE_STATE,
3296 - update_every,
3297 - RRDSET_TYPE_LINE);
3298 -
3299 - rrdlabels_add(mdi->st_db_state->rrdlabels, "mssql_instance", mdi->parent->instanceID, RRDLABEL_SRC_AUTO);
3300 - rrdlabels_add(mdi->st_db_state->rrdlabels, "database", db, RRDLABEL_SRC_AUTO);
3301 -
3302 - mdi->rd_db_state[0] = rrddim_add(mdi->st_db_state, "online", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
3303 - mdi->rd_db_state[1] = rrddim_add(mdi->st_db_state, "restoring", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
3304 - mdi->rd_db_state[2] = rrddim_add(mdi->st_db_state, "recovering", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
3305 - mdi->rd_db_state[3] = rrddim_add(mdi->st_db_state, "recovering_pending", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
3306 - mdi->rd_db_state[4] = rrddim_add(mdi->st_db_state, "suspect", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
3307 - mdi->rd_db_state[5] = rrddim_add(mdi->st_db_state, "offline", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
3308 - }
3309 -}
3310 -
3311 -static void mssql_db_state_chart_loop(struct mssql_db_instance *mdi, const char *db, int update_every)
3312 -{
3313 - collected_number set_value =
3314 - (mdi->MSSQLDBState.current.Data < 5) ? (collected_number)mdi->MSSQLDBState.current.Data : 5;
3315 - mssql_db_states_chart(mdi, db, update_every);
3316 - for (collected_number i; i < NETDATA_DB_STATES; i++) {
3317 - rrddim_set_by_pointer(mdi->st_db_state, mdi->rd_db_state[i], i == set_value);
3318 - }
3319 - rrdset_done(mdi->st_db_state);
3320 -}
3321 -
3322 -static void mssql_lock_request_chart(struct mssql_db_instance *mdi, const char *db, int update_every)
3323 -{
3324 - char id[RRD_ID_LENGTH_MAX + 1];
3325 -
3326 - if (!mdi->st_lock_requests) {
3327 - snprintfz(id, RRD_ID_LENGTH_MAX, "db_%s_instance_%s_lock_requests", db, mdi->parent->instanceID);
3328 - netdata_fix_chart_name(id);
3329 - mdi->st_lock_requests = rrdset_create_localhost(
3330 - "mssql",
3331 - id,
3332 - NULL,
3333 - "locks",
3334 - "mssql.database_lock_requests",
3335 - "Number of new locks and lock conversions requested.",
3336 - "requests/s",
3337 - PLUGIN_WINDOWS_NAME,
3338 - "PerflibMSSQL",
3339 - PRIO_MSSQL_DATABASE_LOCK_REQUESTS_SEC,
3340 - update_every,
3341 - RRDSET_TYPE_LINE);
3342 -
3343 - rrdlabels_add(mdi->st_lock_requests->rrdlabels, "mssql_instance", mdi->parent->instanceID, RRDLABEL_SRC_AUTO);
3344 - rrdlabels_add(mdi->st_lock_requests->rrdlabels, "database", db, RRDLABEL_SRC_AUTO);
3345 -
3346 - mdi->rd_lock_requests = rrddim_add(mdi->st_lock_requests, "requests", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
3347 - }
3348 -
3349 - rrddim_set_by_pointer(
3350 - mdi->st_lock_requests, mdi->rd_lock_requests, (collected_number)mdi->MSSQLDatabaseLockRequestsSec.current.Data);
3351 -
3352 - rrdset_done(mdi->st_lock_requests);
3353 -}
3354 -
3355 -static void mssql_lock_timeout_chart(struct mssql_db_instance *mdi, const char *db, int update_every)
8 +void do_mssql_access_methods(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *mi, int update_every)
9 {
10 char id[RRD_ID_LENGTH_MAX + 1];
11
3359 - if (!mdi->st_lock_timeouts) {
3360 - snprintfz(id, RRD_ID_LENGTH_MAX, "db_%s_instance_%s_lock_timeouts", db, mdi->parent->instanceID);
3361 - netdata_fix_chart_name(id);
3362 - mdi->st_lock_timeouts = rrdset_create_localhost(
3363 - "mssql",
3364 - id,
3365 - NULL,
3366 - "locks",
3367 - "mssql.database_lock_timeouts",
3368 - "Lock that timed out.",
3369 - "timeouts/s",
3370 - PLUGIN_WINDOWS_NAME,
3371 - "PerflibMSSQL",
3372 - PRIO_MSSQL_DATABASE_LOCKS_TIMEOUT_PER_SECOND,
3373 - update_every,
3374 - RRDSET_TYPE_LINE);
3375 -
3376 - rrdlabels_add(mdi->st_lock_timeouts->rrdlabels, "mssql_instance", mdi->parent->instanceID, RRDLABEL_SRC_AUTO);
3377 - rrdlabels_add(mdi->st_lock_timeouts->rrdlabels, "database", db, RRDLABEL_SRC_AUTO);
3378 -
3379 - mdi->rd_lock_timeouts = rrddim_add(mdi->st_lock_timeouts, "timeouts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
3380 - }
3381 -
3382 - rrddim_set_by_pointer(
3383 - mdi->st_lock_timeouts, mdi->rd_lock_timeouts, (collected_number)mdi->MSSQLDatabaseLockTimeoutsSec.current.Data);
3384 -
3385 - rrdset_done(mdi->st_lock_timeouts);
3386 -}
12 + PERF_OBJECT_TYPE *pObjectType =
13 + perflibFindObjectTypeByName(pDataBlock, mi->objectName[NETDATA_MSSQL_ACCESS_METHODS]);
14 + if (unlikely(!pObjectType))
15 + return;
16
3388 -static void mssql_active_transactions_chart(struct mssql_db_instance *mdi, const char *db, int update_every)
3389 -{
3390 - char id[RRD_ID_LENGTH_MAX + 1];
17 + if (likely(perflibGetObjectCounter(pDataBlock, pObjectType, &mi->MSSQLAccessMethodPageSplits))) {
18 + if (unlikely(!mi->st_access_method_page_splits)) {
19 + snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_accessmethods_page_splits", mi->instanceID);
20 + netdata_fix_chart_name(id);
21 + mi->st_access_method_page_splits = rrdset_create_localhost(
22 + "mssql",
23 + id,
24 + NULL,
25 + "buffer cache",
26 + "mssql.instance_accessmethods_page_splits",
27 + "Page splits",
28 + "splits/s",
29 + PLUGIN_WINDOWS_NAME,
30 + "PerflibMSSQL",
31 + PRIO_MSSQL_BUFF_METHODS_PAGE_SPLIT,
32 + update_every,
33 + RRDSET_TYPE_LINE);
34
3392 - if (!mdi->st_db_active_transactions) {
3393 - snprintfz(id, RRD_ID_LENGTH_MAX, "db_%s_instance_%s_active_transactions", db, mdi->parent->instanceID);
3394 - netdata_fix_chart_name(id);
3395 - mdi->st_db_active_transactions = rrdset_create_localhost(
3396 - "mssql",
3397 - id,
3398 - NULL,
3399 - "transactions",
3400 - "mssql.database_active_transactions",
3401 - "Active transactions per database",
3402 - "transactions",
3403 - PLUGIN_WINDOWS_NAME,
3404 - "PerflibMSSQL",
3405 - PRIO_MSSQL_DATABASE_ACTIVE_TRANSACTIONS,
3406 - update_every,
3407 - RRDSET_TYPE_LINE);
35 + mi->rd_access_method_page_splits =
36 + rrddim_add(mi->st_access_method_page_splits, "page", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
37
3409 - rrdlabels_add(
3410 - mdi->st_db_active_transactions->rrdlabels, "mssql_instance", mdi->parent->instanceID, RRDLABEL_SRC_AUTO);
3411 - rrdlabels_add(mdi->st_db_active_transactions->rrdlabels, "database", db, RRDLABEL_SRC_AUTO);
38 + rrdlabels_add(
39 + mi->st_access_method_page_splits->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
40 + }
41
3413 - mdi->rd_db_active_transactions =
3414 - rrddim_add(mdi->st_db_active_transactions, "active", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
42 + rrddim_set_by_pointer(
43 + mi->st_access_method_page_splits,
44 + mi->rd_access_method_page_splits,
45 + (collected_number)mi->MSSQLAccessMethodPageSplits.current.Data);
46 + rrdset_done(mi->st_access_method_page_splits);
47 }
3416 -
3417 - rrddim_set_by_pointer(
3418 - mdi->st_db_active_transactions,
3419 - mdi->rd_db_active_transactions,
3420 - (collected_number)mdi->MSSQLDatabaseActiveTransactions.current.Data);
3421 -
3422 - rrdset_done(mdi->st_db_active_transactions);
48 }
49
3425 -static inline void mssql_data_file_size_chart(struct mssql_db_instance *mdi, const char *db, int update_every)
50 +void do_mssql_statistics_perflib(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *mi, int update_every)
51 {
52 char id[RRD_ID_LENGTH_MAX + 1];
53
3429 - if (unlikely(!mdi->st_db_data_file_size)) {
3430 - snprintfz(id, RRD_ID_LENGTH_MAX, "db_%s_instance_%s_data_files_size", db, mdi->parent->instanceID);
3431 - netdata_fix_chart_name(id);
3432 - mdi->st_db_data_file_size = rrdset_create_localhost(
3433 - "mssql",
3434 - id,
3435 - NULL,
3436 - "size",
3437 - "mssql.database_data_files_size",
3438 - "Current database size.",
3439 - "bytes",
3440 - PLUGIN_WINDOWS_NAME,
3441 - "PerflibMSSQL",
3442 - PRIO_MSSQL_DATABASE_DATA_FILE_SIZE,
3443 - update_every,
3444 - RRDSET_TYPE_LINE);
3445 -
3446 - rrdlabels_add(
3447 - mdi->st_db_data_file_size->rrdlabels, "mssql_instance", mdi->parent->instanceID, RRDLABEL_SRC_AUTO);
3448 - rrdlabels_add(mdi->st_db_data_file_size->rrdlabels, "database", db, RRDLABEL_SRC_AUTO);
3449 -
3450 - mdi->rd_db_data_file_size = rrddim_add(mdi->st_db_data_file_size, "size", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
3451 - }
54 + PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, mi->objectName[NETDATA_MSSQL_SQL_STATS]);
55 + if (unlikely(!pObjectType))
56 + return;
57
3453 - collected_number data = mdi->MSSQLDatabaseDataFileSize.current.Data;
3454 - rrddim_set_by_pointer(mdi->st_db_data_file_size, mdi->rd_db_data_file_size, data);
58 + if (likely(perflibGetObjectCounter(pDataBlock, pObjectType, &mi->MSSQLStatsAutoParameterization))) {
59 + if (unlikely(!mi->st_stats_auto_param)) {
60 + snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_sqlstats_auto_parameterization_attempts", mi->instanceID);
61 + netdata_fix_chart_name(id);
62 + mi->st_stats_auto_param = rrdset_create_localhost(
63 + "mssql",
64 + id,
65 + NULL,
66 + "sql activity",
67 + "mssql.instance_sqlstats_auto_parameterization_attempts",
68 + "Failed auto-parameterization attempts",
69 + "attempts/s",
70 + PLUGIN_WINDOWS_NAME,
71 + "PerflibMSSQL",
72 + PRIO_MSSQL_STATS_AUTO_PARAMETRIZATION,
73 + update_every,
74 + RRDSET_TYPE_LINE);
75
3456 - rrdset_done(mdi->st_db_data_file_size);
3457 -}
76 + mi->rd_stats_auto_param =
77 + rrddim_add(mi->st_stats_auto_param, "failed", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
78
3459 -int dict_mssql_databases_charts_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
3460 -{
3461 - struct mssql_db_instance *mdi = value;
3462 - const char *db = dictionary_acquired_item_name((DICTIONARY_ITEM *)item);
79 + rrdlabels_add(mi->st_stats_auto_param->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
80 + }
81
3464 - if (!mdi->collecting_data) {
3465 - goto endchartcb;
82 + rrddim_set_by_pointer(
83 + mi->st_stats_auto_param,
84 + mi->rd_stats_auto_param,
85 + (collected_number)mi->MSSQLStatsAutoParameterization.current.Data);
86 + rrdset_done(mi->st_stats_auto_param);
87 }
88
3468 - int *update_every = data;
89 + if (likely(perflibGetObjectCounter(pDataBlock, pObjectType, &mi->MSSQLStatsBatchRequests))) {
90 + if (unlikely(!mi->st_stats_batch_request)) {
91 + snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_sqlstats_batch_requests", mi->instanceID);
92 + netdata_fix_chart_name(id);
93 + mi->st_stats_batch_request = rrdset_create_localhost(
94 + "mssql",
95 + id,
96 + NULL,
97 + "sql activity",
98 + "mssql.instance_sqlstats_batch_requests",
99 + "Total of batches requests",
100 + "requests/s",
101 + PLUGIN_WINDOWS_NAME,
102 + "PerflibMSSQL",
103 + PRIO_MSSQL_STATS_BATCH_REQUEST,
104 + update_every,
105 + RRDSET_TYPE_LINE);
106
3470 - void (*transaction_chart[])(struct mssql_db_instance *, const char *, int) = {
3471 - mssql_data_file_size_chart,
3472 - mssql_transactions_chart,
3473 - mssql_database_backup_restore_chart,
3474 - mssql_database_log_flushed_chart,
3475 - mssql_database_log_flushes_chart,
3476 - mssql_active_transactions_chart,
3477 - mssql_write_transactions_chart,
3478 - mssql_lockwait_chart,
3479 - mssql_deadlock_chart,
3480 - mssql_is_readonly_chart,
3481 - mssql_db_state_chart_loop,
3482 - mssql_lock_timeout_chart,
3483 - mssql_lock_request_chart,
107 + mi->rd_stats_batch_request =
108 + rrddim_add(mi->st_stats_batch_request, "batch", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
109
3485 - // Last function pointer must be NULL
3486 - NULL};
110 + rrdlabels_add(mi->st_stats_batch_request->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
111 + }
112
3488 - int i;
3489 - for (i = 0; transaction_chart[i]; i++) {
3490 - transaction_chart[i](mdi, db, *update_every);
113 + rrddim_set_by_pointer(
114 + mi->st_stats_batch_request,
115 + mi->rd_stats_batch_request,
116 + (collected_number)mi->MSSQLStatsBatchRequests.current.Data);
117 + rrdset_done(mi->st_stats_batch_request);
118 }
119
3493 -endchartcb:
3494 - return 1;
3495 -}
3496 -
3497 -static void do_mssql_databases(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *mi, int update_every)
3498 -{
3499 - if (!pDataBlock)
3500 - goto end_mssql_databases;
3501 -
3502 - PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, mi->objectName[NETDATA_MSSQL_DATABASE]);
3503 - if (!pObjectType)
3504 - return;
3505 -
3506 - PERF_INSTANCE_DEFINITION *pi = NULL;
3507 - for (LONG i = 0; i < pObjectType->NumInstances; i++) {
3508 - pi = perflibForEachInstance(pDataBlock, pObjectType, pi);
3509 - if (!pi)
3510 - break;
3511 -
3512 - if (!getInstanceName(pDataBlock, pObjectType, pi, windows_shared_buffer, sizeof(windows_shared_buffer)))
3513 - strncpyz(windows_shared_buffer, "[unknown]", sizeof(windows_shared_buffer) - 1);
3514 -
3515 - if (!strcasecmp(windows_shared_buffer, "_Total"))
3516 - continue;
120 + if (likely(perflibGetObjectCounter(pDataBlock, pObjectType, &mi->MSSQLStatSafeAutoParameterization))) {
121 + if (unlikely(!mi->st_stats_safe_auto)) {
122 + snprintfz(
123 + id, RRD_ID_LENGTH_MAX, "instance_%s_sqlstats_safe_auto_parameterization_attempts", mi->instanceID);
124 + netdata_fix_chart_name(id);
125 + mi->st_stats_safe_auto = rrdset_create_localhost(
126 + "mssql",
127 + id,
128 + NULL,
129 + "sql activity",
130 + "mssql.instance_sqlstats_safe_auto_parameterization_attempts",
131 + "Safe auto-parameterization attempts",
132 + "attempts/s",
133 + PLUGIN_WINDOWS_NAME,
134 + "PerflibMSSQL",
135 + PRIO_MSSQL_STATS_SAFE_AUTO_PARAMETRIZATION,
136 + update_every,
137 + RRDSET_TYPE_LINE);
138
3518 - struct mssql_db_instance *mdi = dictionary_set(mi->databases, windows_shared_buffer, NULL, sizeof(*mdi));
3519 - if (!mdi)
3520 - continue;
139 + mi->rd_stats_safe_auto = rrddim_add(mi->st_stats_safe_auto, "safe", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
140
3522 - if (!mdi->parent) {
3523 - mdi->parent = mi;
141 + rrdlabels_add(mi->st_stats_safe_auto->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
142 }
143
3526 - if (!i)
3527 - mdi->collect_instance = true;
144 + rrddim_set_by_pointer(
145 + mi->st_stats_safe_auto,
146 + mi->rd_stats_safe_auto,
147 + (collected_number)mi->MSSQLStatSafeAutoParameterization.current.Data);
148 + rrdset_done(mi->st_stats_safe_auto);
149 }
3529 -
3530 -end_mssql_databases:
3531 - dictionary_sorted_walkthrough_read(mi->databases, dict_mssql_databases_charts_cb, &update_every);
150 }
151
3534 -static void do_mssql_memory_mgr(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *mi, int update_every)
152 +void do_mssql_memory_mgr(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *mi, int update_every)
153 {
154 char id[RRD_ID_LENGTH_MAX + 1];
155
156 PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, mi->objectName[NETDATA_MSSQL_MEMORY]);
3539 - if (!pObjectType)
157 + if (unlikely(!pObjectType))
158 return;
159
3542 - if (perflibGetObjectCounter(pDataBlock, pObjectType, &mi->MSSQLConnectionMemoryBytes)) {
3543 - if (!mi->st_conn_memory) {
160 + if (likely(perflibGetObjectCounter(pDataBlock, pObjectType, &mi->MSSQLConnectionMemoryBytes))) {
161 + if (unlikely(!mi->st_conn_memory)) {
162 snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_memmgr_connection_memory_bytes", mi->instanceID);
163 netdata_fix_chart_name(id);
164 mi->st_conn_memory = rrdset_create_localhost(
3547 - "mssql",
3548 - id,
3549 - NULL,
3550 - "memory",
3551 - "mssql.instance_memmgr_connection_memory_bytes",
3552 - "Amount of dynamic memory to maintain connections",
3553 - "bytes",
3554 - PLUGIN_WINDOWS_NAME,
3555 - "PerflibMSSQL",
3556 - PRIO_MSSQL_MEMMGR_CONNECTION_MEMORY_BYTES,
3557 - update_every,
3558 - RRDSET_TYPE_LINE);
165 + "mssql",
166 + id,
167 + NULL,
168 + "memory",
169 + "mssql.instance_memmgr_connection_memory_bytes",
170 + "Amount of dynamic memory to maintain connections",
171 + "bytes",
172 + PLUGIN_WINDOWS_NAME,
173 + "PerflibMSSQL",
174 + PRIO_MSSQL_MEMMGR_CONNECTION_MEMORY_BYTES,
175 + update_every,
176 + RRDSET_TYPE_LINE);
177
178 mi->rd_conn_memory = rrddim_add(mi->st_conn_memory, "memory", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
179
@@ -3563,29 +181,29 @@ static void do_mssql_memory_mgr(PERF_DATA_BLOCK *pDataBlock, struct mssql_instan
181 }
182
183 rrddim_set_by_pointer(
3566 - mi->st_conn_memory,
3567 - mi->rd_conn_memory,
3568 - (collected_number)(mi->MSSQLConnectionMemoryBytes.current.Data * 1024));
184 + mi->st_conn_memory,
185 + mi->rd_conn_memory,
186 + (collected_number)(mi->MSSQLConnectionMemoryBytes.current.Data * 1024));
187 rrdset_done(mi->st_conn_memory);
188 }
189
3572 - if (perflibGetObjectCounter(pDataBlock, pObjectType, &mi->MSSQLExternalBenefitOfMemory)) {
3573 - if (!mi->st_ext_benefit_mem) {
190 + if (likely(perflibGetObjectCounter(pDataBlock, pObjectType, &mi->MSSQLExternalBenefitOfMemory))) {
191 + if (unlikely(!mi->st_ext_benefit_mem)) {
192 snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_memmgr_external_benefit_of_memory", mi->instanceID);
193 netdata_fix_chart_name(id);
194 mi->st_ext_benefit_mem = rrdset_create_localhost(
3577 - "mssql",
3578 - id,
3579 - NULL,
3580 - "memory",
3581 - "mssql.instance_memmgr_external_benefit_of_memory",
3582 - "Performance benefit from adding memory to a specific cache",
3583 - "bytes",
3584 - PLUGIN_WINDOWS_NAME,
3585 - "PerflibMSSQL",
3586 - PRIO_MSSQL_MEMMGR_EXTERNAL_BENEFIT_OF_MEMORY,
3587 - update_every,
3588 - RRDSET_TYPE_LINE);
195 + "mssql",
196 + id,
197 + NULL,
198 + "memory",
199 + "mssql.instance_memmgr_external_benefit_of_memory",
200 + "Performance benefit from adding memory to a specific cache",
201 + "bytes",
202 + PLUGIN_WINDOWS_NAME,
203 + "PerflibMSSQL",
204 + PRIO_MSSQL_MEMMGR_EXTERNAL_BENEFIT_OF_MEMORY,
205 + update_every,
206 + RRDSET_TYPE_LINE);
207
208 mi->rd_ext_benefit_mem = rrddim_add(mi->st_ext_benefit_mem, "benefit", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
209
@@ -3593,61 +211,61 @@ static void do_mssql_memory_mgr(PERF_DATA_BLOCK *pDataBlock, struct mssql_instan
211 }
212
213 rrddim_set_by_pointer(
3596 - mi->st_ext_benefit_mem,
3597 - mi->rd_ext_benefit_mem,
3598 - (collected_number)mi->MSSQLExternalBenefitOfMemory.current.Data);
214 + mi->st_ext_benefit_mem,
215 + mi->rd_ext_benefit_mem,
216 + (collected_number)mi->MSSQLExternalBenefitOfMemory.current.Data);
217 rrdset_done(mi->st_ext_benefit_mem);
218 }
219
3602 - if (perflibGetObjectCounter(pDataBlock, pObjectType, &mi->MSSQLPendingMemoryGrants)) {
3603 - if (!mi->st_pending_mem_grant) {
220 + if (likely(perflibGetObjectCounter(pDataBlock, pObjectType, &mi->MSSQLPendingMemoryGrants))) {
221 + if (unlikely(!mi->st_pending_mem_grant)) {
222 snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_memmgr_pending_memory_grants", mi->instanceID);
223 netdata_fix_chart_name(id);
224 mi->st_pending_mem_grant = rrdset_create_localhost(
3607 - "mssql",
3608 - id,
3609 - NULL,
3610 - "memory",
3611 - "mssql.instance_memmgr_pending_memory_grants",
3612 - "Process waiting for memory grant",
3613 - "processes",
3614 - PLUGIN_WINDOWS_NAME,
3615 - "PerflibMSSQL",
3616 - PRIO_MSSQL_MEMMGR_PENDING_MEMORY_GRANTS,
3617 - update_every,
3618 - RRDSET_TYPE_LINE);
225 + "mssql",
226 + id,
227 + NULL,
228 + "memory",
229 + "mssql.instance_memmgr_pending_memory_grants",
230 + "Process waiting for memory grant",
231 + "processes",
232 + PLUGIN_WINDOWS_NAME,
233 + "PerflibMSSQL",
234 + PRIO_MSSQL_MEMMGR_PENDING_MEMORY_GRANTS,
235 + update_every,
236 + RRDSET_TYPE_LINE);
237
238 mi->rd_pending_mem_grant =
3621 - rrddim_add(mi->st_pending_mem_grant, "pending", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
239 + rrddim_add(mi->st_pending_mem_grant, "pending", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
240
241 rrdlabels_add(mi->st_pending_mem_grant->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
242 }
243
244 rrddim_set_by_pointer(
3627 - mi->st_pending_mem_grant,
3628 - mi->rd_pending_mem_grant,
3629 - (collected_number)mi->MSSQLPendingMemoryGrants.current.Data);
245 + mi->st_pending_mem_grant,
246 + mi->rd_pending_mem_grant,
247 + (collected_number)mi->MSSQLPendingMemoryGrants.current.Data);
248
249 rrdset_done(mi->st_pending_mem_grant);
250 }
251
3634 - if (perflibGetObjectCounter(pDataBlock, pObjectType, &mi->MSSQLTotalServerMemory)) {
3635 - if (!mi->st_mem_tot_server) {
252 + if (likely(perflibGetObjectCounter(pDataBlock, pObjectType, &mi->MSSQLTotalServerMemory))) {
253 + if (unlikely(!mi->st_mem_tot_server)) {
254 snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_memmgr_server_memory", mi->instanceID);
255 netdata_fix_chart_name(id);
256 mi->st_mem_tot_server = rrdset_create_localhost(
3639 - "mssql",
3640 - id,
3641 - NULL,
3642 - "memory",
3643 - "mssql.instance_memmgr_server_memory",
3644 - "Memory committed",
3645 - "bytes",
3646 - PLUGIN_WINDOWS_NAME,
3647 - "PerflibMSSQL",
3648 - PRIO_MSSQL_MEMMGR_TOTAL_SERVER,
3649 - update_every,
3650 - RRDSET_TYPE_LINE);
257 + "mssql",
258 + id,
259 + NULL,
260 + "memory",
261 + "mssql.instance_memmgr_server_memory",
262 + "Memory committed",
263 + "bytes",
264 + PLUGIN_WINDOWS_NAME,
265 + "PerflibMSSQL",
266 + PRIO_MSSQL_MEMMGR_TOTAL_SERVER,
267 + update_every,
268 + RRDSET_TYPE_LINE);
269
270 mi->rd_mem_tot_server = rrddim_add(mi->st_mem_tot_server, "memory", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
271
@@ -3655,101 +273,114 @@ static void do_mssql_memory_mgr(PERF_DATA_BLOCK *pDataBlock, struct mssql_instan
273 }
274
275 rrddim_set_by_pointer(
3658 - mi->st_mem_tot_server,
3659 - mi->rd_mem_tot_server,
3660 - (collected_number)(mi->MSSQLTotalServerMemory.current.Data * 1024));
276 + mi->st_mem_tot_server,
277 + mi->rd_mem_tot_server,
278 + (collected_number)(mi->MSSQLTotalServerMemory.current.Data * 1024));
279
280 rrdset_done(mi->st_mem_tot_server);
281 }
282 }
283
3666 -static inline PERF_DATA_BLOCK *
3667 -netdata_mssql_get_perf_data_block(bool *collect_perflib, struct mssql_instance *mi, DWORD idx)
284 +void do_mssql_errors(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *mi, int update_every)
285 {
3669 - DWORD id = RegistryFindIDByName(mi->objectName[idx]);
3670 - if (id == PERFLIB_REGISTRY_NAME_NOT_FOUND) {
3671 - collect_perflib[idx] = false;
3672 - return NULL;
3673 - }
286 + char id[RRD_ID_LENGTH_MAX + 1];
287
3675 - PERF_DATA_BLOCK *pDataBlock = perflibGetPerformanceData(id);
3676 - if (!pDataBlock) {
3677 - collect_perflib[idx] = true;
3678 - return NULL;
3679 - }
288 + PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, mi->objectName[NETDATA_MSSQL_SQL_ERRORS]);
289 + if (unlikely(!pObjectType))
290 + return;
291
3681 - return pDataBlock;
3682 -}
292 + if (likely(perflibGetObjectCounter(pDataBlock, pObjectType, &mi->MSSQLSQLErrorsTotal))) {
293 + if (unlikely(!mi->st_sql_errors)) {
294 + snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_sql_errors_total", mi->instanceID);
295 + netdata_fix_chart_name(id);
296 + mi->st_sql_errors = rrdset_create_localhost(
297 + "mssql",
298 + id,
299 + NULL,
300 + "errors",
301 + "mssql.instance_sql_errors",
302 + "Errors",
303 + "errors/s",
304 + PLUGIN_WINDOWS_NAME,
305 + "PerflibMSSQL",
306 + PRIO_MSSQL_SQL_ERRORS,
307 + update_every,
308 + RRDSET_TYPE_LINE);
309
3684 -int dict_mssql_charts_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
3685 -{
3686 - struct mssql_instance *mi = value;
3687 - int *update_every = data;
310 + mi->rd_sql_errors = rrddim_add(mi->st_sql_errors, "errors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
311
3689 - static void (*doMSSQL[])(PERF_DATA_BLOCK *, struct mssql_instance *, int) = {
3690 - do_mssql_general_stats,
3691 - do_mssql_errors,
3692 - do_mssql_memory_mgr,
3693 - do_mssql_statistics_perflib,
3694 - do_mssql_access_methods,
312 + rrdlabels_add(mi->st_sql_errors->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
313 + }
314
3696 - do_mssql_databases,
3697 - do_mssql_locks,
3698 - do_mssql_waits,
3699 - do_mssql_bufferman_stats_sql,
3700 - do_mssql_job_status_sql,
315 + rrddim_set_by_pointer(
316 + mi->st_sql_errors, mi->rd_sql_errors, (collected_number)mi->MSSQLAccessMethodPageSplits.current.Data);
317 + rrdset_done(mi->st_sql_errors);
318 + }
319 +}
320
3702 - NULL};
321
3704 - DWORD i;
3705 - PERF_DATA_BLOCK *pDataBlock;
3706 - static bool collect_perflib[NETDATA_MSSQL_METRICS_END] = {
3707 - true, true, true, true, true, true, true, true, true, true};
3708 - for (i = 0; i < NETDATA_MSSQL_ACCESS_METHODS; i++) {
3709 - if (!collect_perflib[i])
3710 - continue;
322 +void do_mssql_general_stats(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *mi, int update_every)
323 +{
324 + char id[RRD_ID_LENGTH_MAX + 1];
325
3712 - pDataBlock = netdata_mssql_get_perf_data_block(collect_perflib, mi, i);
3713 - if (!pDataBlock)
3714 - continue;
326 + PERF_OBJECT_TYPE *pObjectType =
327 + perflibFindObjectTypeByName(pDataBlock, mi->objectName[NETDATA_MSSQL_GENERAL_STATS]);
328 + if (unlikely(!pObjectType))
329 + return;
330
3716 - doMSSQL[i](pDataBlock, mi, *update_every);
3717 - }
331 + if (likely(perflibGetObjectCounter(pDataBlock, pObjectType, &mi->MSSQLUserConnections))) {
332 + if (unlikely(!mi->st_user_connections)) {
333 + snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_user_connections", mi->instanceID);
334 + netdata_fix_chart_name(id);
335 + mi->st_user_connections = rrdset_create_localhost(
336 + "mssql",
337 + id,
338 + NULL,
339 + "connections",
340 + "mssql.instance_user_connections",
341 + "User connections",
342 + "connections",
343 + PLUGIN_WINDOWS_NAME,
344 + "PerflibMSSQL",
345 + PRIO_MSSQL_USER_CONNECTIONS,
346 + update_every,
347 + RRDSET_TYPE_LINE);
348
3719 - if (unlikely(!mi->conn || !mi->conn->is_connected))
3720 - return 1;
349 + mi->rd_user_connections = rrddim_add(mi->st_user_connections, "user", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
350
3722 - for (i = NETDATA_MSSQL_DATABASE; doMSSQL[i]; i++) {
3723 - pDataBlock = (collect_perflib[i]) ? netdata_mssql_get_perf_data_block(collect_perflib, mi, i) : NULL;
351 + rrdlabels_add(mi->st_user_connections->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
352 + }
353
3725 - doMSSQL[i](pDataBlock, mi, *update_every);
354 + rrddim_set_by_pointer(
355 + mi->st_user_connections, mi->rd_user_connections, (collected_number)mi->MSSQLUserConnections.current.Data);
356 + rrdset_done(mi->st_user_connections);
357 }
358
3728 - do_mssql_replication(mi, *update_every);
3729 -
3730 - return 1;
3731 -}
3732 -
3733 -// Entry point
359 + if (likely(perflibGetObjectCounter(pDataBlock, pObjectType, &mi->MSSQLBlockedProcesses))) {
360 + if (unlikely(!mi->st_process_blocked)) {
361 + snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_blocked_process", mi->instanceID);
362 + netdata_fix_chart_name(id);
363 + mi->st_process_blocked = rrdset_create_localhost(
364 + "mssql",
365 + id,
366 + NULL,
367 + "processes",
368 + "mssql.instance_blocked_processes",
369 + "Blocked processes",
370 + "process",
371 + PLUGIN_WINDOWS_NAME,
372 + "PerflibMSSQL",
373 + PRIO_MSSQL_BLOCKED_PROCESSES,
374 + update_every,
375 + RRDSET_TYPE_LINE);
376
3735 -int do_PerflibMSSQL(int update_every, usec_t dt __maybe_unused)
3736 -{
3737 - static bool initialized = false;
377 + mi->rd_process_blocked = rrddim_add(mi->st_process_blocked, "blocked", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
378
3739 - if (unlikely(!initialized)) {
3740 - if (initialize(update_every))
3741 - return -1;
379 + rrdlabels_add(mi->st_process_blocked->rrdlabels, "mssql_instance", mi->instanceID, RRDLABEL_SRC_AUTO);
380 + }
381
3743 - initialized = true;
382 + rrddim_set_by_pointer(
383 + mi->st_process_blocked, mi->rd_process_blocked, (collected_number)mi->MSSQLBlockedProcesses.current.Data);
384 + rrdset_done(mi->st_process_blocked);
385 }
3745 -
3746 - dictionary_sorted_walkthrough_read(mssql_instances, dict_mssql_charts_cb, &update_every);
3747 -
3748 - return 0;
3749 -}
3750 -
3751 -void do_PerflibMSSQL_cleanup()
3752 -{
3753 - if (nd_thread_join(mssql_queries_thread))
3754 - nd_log_daemon(NDLP_ERR, "Failed to join mssql queries thread");
386 }