| 1 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 2 | |
| 3 | #define PULSE_INTERNALS 1 |
| 4 | #include "pulse-sqlite3.h" |
| 5 | |
| 6 | static struct sqlite3_statistics { |
| 7 | bool enabled; |
| 8 | |
| 9 | PAD64(uint64_t) sqlite3_queries_made; |
| 10 | PAD64(uint64_t) sqlite3_queries_ok; |
| 11 | PAD64(uint64_t) sqlite3_queries_failed; |
| 12 | PAD64(uint64_t) sqlite3_queries_failed_busy; |
| 13 | PAD64(uint64_t) sqlite3_queries_failed_locked; |
| 14 | PAD64(uint64_t) sqlite3_rows; |
| 15 | PAD64(uint64_t) sqlite3_metadata_cache_hit; |
| 16 | PAD64(uint64_t) sqlite3_context_cache_hit; |
| 17 | PAD64(uint64_t) sqlite3_metadata_cache_miss; |
| 18 | PAD64(uint64_t) sqlite3_context_cache_miss; |
| 19 | PAD64(uint64_t) sqlite3_metadata_cache_spill; |
| 20 | PAD64(uint64_t) sqlite3_context_cache_spill; |
| 21 | PAD64(uint64_t) sqlite3_metadata_cache_write; |
| 22 | PAD64(uint64_t) sqlite3_context_cache_write; |
| 23 | } sqlite3_statistics = { 0 }; |
| 24 | |
| 25 | void pulse_sqlite3_query_completed(bool success, bool busy, bool locked) { |
| 26 | if(!sqlite3_statistics.enabled) return; |
| 27 | |
| 28 | __atomic_fetch_add(&sqlite3_statistics.sqlite3_queries_made, 1, __ATOMIC_RELAXED); |
| 29 | |
| 30 | if(success) { |
| 31 | __atomic_fetch_add(&sqlite3_statistics.sqlite3_queries_ok, 1, __ATOMIC_RELAXED); |
| 32 | } |
| 33 | else { |
| 34 | __atomic_fetch_add(&sqlite3_statistics.sqlite3_queries_failed, 1, __ATOMIC_RELAXED); |
| 35 | |
| 36 | if(busy) |
| 37 | __atomic_fetch_add(&sqlite3_statistics.sqlite3_queries_failed_busy, 1, __ATOMIC_RELAXED); |
| 38 | |
| 39 | if(locked) |
| 40 | __atomic_fetch_add(&sqlite3_statistics.sqlite3_queries_failed_locked, 1, __ATOMIC_RELAXED); |
| 41 | } |
| 42 | } |
| 43 | |
| 44 | void pulse_sqlite3_row_completed(void) { |
| 45 | if(!sqlite3_statistics.enabled) return; |
| 46 | |
| 47 | __atomic_fetch_add(&sqlite3_statistics.sqlite3_rows, 1, __ATOMIC_RELAXED); |
| 48 | } |
| 49 | |
| 50 | static inline void sqlite3_statistics_copy(struct sqlite3_statistics *gs) { |
| 51 | static usec_t last_run = 0; |
| 52 | |
| 53 | gs->sqlite3_queries_made = __atomic_load_n(&sqlite3_statistics.sqlite3_queries_made, __ATOMIC_RELAXED); |
| 54 | gs->sqlite3_queries_ok = __atomic_load_n(&sqlite3_statistics.sqlite3_queries_ok, __ATOMIC_RELAXED); |
| 55 | gs->sqlite3_queries_failed = __atomic_load_n(&sqlite3_statistics.sqlite3_queries_failed, __ATOMIC_RELAXED); |
| 56 | gs->sqlite3_queries_failed_busy = __atomic_load_n(&sqlite3_statistics.sqlite3_queries_failed_busy, __ATOMIC_RELAXED); |
| 57 | gs->sqlite3_queries_failed_locked = __atomic_load_n(&sqlite3_statistics.sqlite3_queries_failed_locked, __ATOMIC_RELAXED); |
| 58 | gs->sqlite3_rows = __atomic_load_n(&sqlite3_statistics.sqlite3_rows, __ATOMIC_RELAXED); |
| 59 | |
| 60 | usec_t timeout = nd_profile.update_every * USEC_PER_SEC + nd_profile.update_every * USEC_PER_SEC / 3; |
| 61 | usec_t now = now_monotonic_usec(); |
| 62 | if(!last_run) |
| 63 | last_run = now; |
| 64 | usec_t delta = now - last_run; |
| 65 | bool query_sqlite3 = delta < timeout; |
| 66 | |
| 67 | if(query_sqlite3 && now_monotonic_usec() - last_run < timeout) |
| 68 | gs->sqlite3_metadata_cache_hit = (uint64_t) sql_metadata_cache_stats(SQLITE_DBSTATUS_CACHE_HIT); |
| 69 | else { |
| 70 | gs->sqlite3_metadata_cache_hit = UINT64_MAX; |
| 71 | query_sqlite3 = false; |
| 72 | } |
| 73 | |
| 74 | if(query_sqlite3 && now_monotonic_usec() - last_run < timeout) |
| 75 | gs->sqlite3_context_cache_hit = (uint64_t) sql_context_cache_stats(SQLITE_DBSTATUS_CACHE_HIT); |
| 76 | else { |
| 77 | gs->sqlite3_context_cache_hit = UINT64_MAX; |
| 78 | query_sqlite3 = false; |
| 79 | } |
| 80 | |
| 81 | if(query_sqlite3 && now_monotonic_usec() - last_run < timeout) |
| 82 | gs->sqlite3_metadata_cache_miss = (uint64_t) sql_metadata_cache_stats(SQLITE_DBSTATUS_CACHE_MISS); |
| 83 | else { |
| 84 | gs->sqlite3_metadata_cache_miss = UINT64_MAX; |
| 85 | query_sqlite3 = false; |
| 86 | } |
| 87 | |
| 88 | if(query_sqlite3 && now_monotonic_usec() - last_run < timeout) |
| 89 | gs->sqlite3_context_cache_miss = (uint64_t) sql_context_cache_stats(SQLITE_DBSTATUS_CACHE_MISS); |
| 90 | else { |
| 91 | gs->sqlite3_context_cache_miss = UINT64_MAX; |
| 92 | query_sqlite3 = false; |
| 93 | } |
| 94 | |
| 95 | if(query_sqlite3 && now_monotonic_usec() - last_run < timeout) |
| 96 | gs->sqlite3_metadata_cache_spill = (uint64_t) sql_metadata_cache_stats(SQLITE_DBSTATUS_CACHE_SPILL); |
| 97 | else { |
| 98 | gs->sqlite3_metadata_cache_spill = UINT64_MAX; |
| 99 | query_sqlite3 = false; |
| 100 | } |
| 101 | |
| 102 | if(query_sqlite3 && now_monotonic_usec() - last_run < timeout) |
| 103 | gs->sqlite3_context_cache_spill = (uint64_t) sql_context_cache_stats(SQLITE_DBSTATUS_CACHE_SPILL); |
| 104 | else { |
| 105 | gs->sqlite3_context_cache_spill = UINT64_MAX; |
| 106 | query_sqlite3 = false; |
| 107 | } |
| 108 | |
| 109 | if(query_sqlite3 && now_monotonic_usec() - last_run < timeout) |
| 110 | gs->sqlite3_metadata_cache_write = (uint64_t) sql_metadata_cache_stats(SQLITE_DBSTATUS_CACHE_WRITE); |
| 111 | else { |
| 112 | gs->sqlite3_metadata_cache_write = UINT64_MAX; |
| 113 | query_sqlite3 = false; |
| 114 | } |
| 115 | |
| 116 | if(query_sqlite3 && now_monotonic_usec() - last_run < timeout) |
| 117 | gs->sqlite3_context_cache_write = (uint64_t) sql_context_cache_stats(SQLITE_DBSTATUS_CACHE_WRITE); |
| 118 | else { |
| 119 | gs->sqlite3_context_cache_write = UINT64_MAX; |
| 120 | query_sqlite3 = false; |
| 121 | } |
| 122 | |
| 123 | last_run = now_monotonic_usec(); |
| 124 | } |
| 125 | |
| 126 | void pulse_sqlite3_do(bool extended) { |
| 127 | if(!extended) return; |
| 128 | sqlite3_statistics.enabled = true; |
| 129 | |
| 130 | struct sqlite3_statistics gs; |
| 131 | sqlite3_statistics_copy(&gs); |
| 132 | |
| 133 | if(gs.sqlite3_queries_made) { |
| 134 | static RRDSET *st_sqlite3_queries = NULL; |
| 135 | static RRDDIM *rd_queries = NULL; |
| 136 | |
| 137 | if (unlikely(!st_sqlite3_queries)) { |
| 138 | st_sqlite3_queries = rrdset_create_localhost( |
| 139 | "netdata" |
| 140 | , "sqlite3_queries" |
| 141 | , NULL |
| 142 | , "sqlite3" |
| 143 | , NULL |
| 144 | , "Netdata SQLite3 Queries" |
| 145 | , "queries/s" |
| 146 | , "netdata" |
| 147 | , "pulse" |
| 148 | , 131100 |
| 149 | , localhost->rrd_update_every |
| 150 | , RRDSET_TYPE_LINE |
| 151 | ); |
| 152 | |
| 153 | rd_queries = rrddim_add(st_sqlite3_queries, "queries", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); |
| 154 | } |
| 155 | |
| 156 | rrddim_set_by_pointer(st_sqlite3_queries, rd_queries, (collected_number)gs.sqlite3_queries_made); |
| 157 | |
| 158 | rrdset_done(st_sqlite3_queries); |
| 159 | } |
| 160 | |
| 161 | // ---------------------------------------------------------------- |
| 162 | |
| 163 | if(gs.sqlite3_queries_ok || gs.sqlite3_queries_failed) { |
| 164 | static RRDSET *st_sqlite3_queries_by_status = NULL; |
| 165 | static RRDDIM *rd_ok = NULL, *rd_failed = NULL, *rd_busy = NULL, *rd_locked = NULL; |
| 166 | |
| 167 | if (unlikely(!st_sqlite3_queries_by_status)) { |
| 168 | st_sqlite3_queries_by_status = rrdset_create_localhost( |
| 169 | "netdata" |
| 170 | , "sqlite3_queries_by_status" |
| 171 | , NULL |
| 172 | , "sqlite3" |
| 173 | , NULL |
| 174 | , "Netdata SQLite3 Queries by status" |
| 175 | , "queries/s" |
| 176 | , "netdata" |
| 177 | , "pulse" |
| 178 | , 131101 |
| 179 | , localhost->rrd_update_every |
| 180 | , RRDSET_TYPE_LINE |
| 181 | ); |
| 182 | |
| 183 | rd_ok = rrddim_add(st_sqlite3_queries_by_status, "ok", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); |
| 184 | rd_failed = rrddim_add(st_sqlite3_queries_by_status, "failed", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); |
| 185 | rd_busy = rrddim_add(st_sqlite3_queries_by_status, "busy", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); |
| 186 | rd_locked = rrddim_add(st_sqlite3_queries_by_status, "locked", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); |
| 187 | } |
| 188 | |
| 189 | rrddim_set_by_pointer(st_sqlite3_queries_by_status, rd_ok, (collected_number)gs.sqlite3_queries_made); |
| 190 | rrddim_set_by_pointer(st_sqlite3_queries_by_status, rd_failed, (collected_number)gs.sqlite3_queries_failed); |
| 191 | rrddim_set_by_pointer(st_sqlite3_queries_by_status, rd_busy, (collected_number)gs.sqlite3_queries_failed_busy); |
| 192 | rrddim_set_by_pointer(st_sqlite3_queries_by_status, rd_locked, (collected_number)gs.sqlite3_queries_failed_locked); |
| 193 | |
| 194 | rrdset_done(st_sqlite3_queries_by_status); |
| 195 | } |
| 196 | |
| 197 | // ---------------------------------------------------------------- |
| 198 | |
| 199 | if(gs.sqlite3_rows) { |
| 200 | static RRDSET *st_sqlite3_rows = NULL; |
| 201 | static RRDDIM *rd_rows = NULL; |
| 202 | |
| 203 | if (unlikely(!st_sqlite3_rows)) { |
| 204 | st_sqlite3_rows = rrdset_create_localhost( |
| 205 | "netdata" |
| 206 | , "sqlite3_rows" |
| 207 | , NULL |
| 208 | , "sqlite3" |
| 209 | , NULL |
| 210 | , "Netdata SQLite3 Rows" |
| 211 | , "rows/s" |
| 212 | , "netdata" |
| 213 | , "pulse" |
| 214 | , 131102 |
| 215 | , localhost->rrd_update_every |
| 216 | , RRDSET_TYPE_LINE |
| 217 | ); |
| 218 | |
| 219 | rd_rows = rrddim_add(st_sqlite3_rows, "ok", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); |
| 220 | } |
| 221 | |
| 222 | rrddim_set_by_pointer(st_sqlite3_rows, rd_rows, (collected_number)gs.sqlite3_rows); |
| 223 | |
| 224 | rrdset_done(st_sqlite3_rows); |
| 225 | } |
| 226 | |
| 227 | if(gs.sqlite3_metadata_cache_hit) { |
| 228 | static RRDSET *st_sqlite3_cache = NULL; |
| 229 | static RRDDIM *rd_cache_hit = NULL; |
| 230 | static RRDDIM *rd_cache_miss= NULL; |
| 231 | static RRDDIM *rd_cache_spill= NULL; |
| 232 | static RRDDIM *rd_cache_write= NULL; |
| 233 | |
| 234 | if (unlikely(!st_sqlite3_cache)) { |
| 235 | st_sqlite3_cache = rrdset_create_localhost( |
| 236 | "netdata" |
| 237 | , "sqlite3_metatada_cache" |
| 238 | , NULL |
| 239 | , "sqlite3" |
| 240 | , NULL |
| 241 | , "Netdata SQLite3 metadata cache" |
| 242 | , "ops/s" |
| 243 | , "netdata" |
| 244 | , "pulse" |
| 245 | , 131103 |
| 246 | , localhost->rrd_update_every |
| 247 | , RRDSET_TYPE_LINE |
| 248 | ); |
| 249 | |
| 250 | rd_cache_hit = rrddim_add(st_sqlite3_cache, "cache_hit", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); |
| 251 | rd_cache_miss = rrddim_add(st_sqlite3_cache, "cache_miss", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); |
| 252 | rd_cache_spill = rrddim_add(st_sqlite3_cache, "cache_spill", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); |
| 253 | rd_cache_write = rrddim_add(st_sqlite3_cache, "cache_write", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); |
| 254 | } |
| 255 | |
| 256 | if(gs.sqlite3_metadata_cache_hit != UINT64_MAX) |
| 257 | rrddim_set_by_pointer(st_sqlite3_cache, rd_cache_hit, (collected_number)gs.sqlite3_metadata_cache_hit); |
| 258 | |
| 259 | if(gs.sqlite3_metadata_cache_miss != UINT64_MAX) |
| 260 | rrddim_set_by_pointer(st_sqlite3_cache, rd_cache_miss, (collected_number)gs.sqlite3_metadata_cache_miss); |
| 261 | |
| 262 | if(gs.sqlite3_metadata_cache_spill != UINT64_MAX) |
| 263 | rrddim_set_by_pointer(st_sqlite3_cache, rd_cache_spill, (collected_number)gs.sqlite3_metadata_cache_spill); |
| 264 | |
| 265 | if(gs.sqlite3_metadata_cache_write != UINT64_MAX) |
| 266 | rrddim_set_by_pointer(st_sqlite3_cache, rd_cache_write, (collected_number)gs.sqlite3_metadata_cache_write); |
| 267 | |
| 268 | rrdset_done(st_sqlite3_cache); |
| 269 | } |
| 270 | |
| 271 | if(gs.sqlite3_context_cache_hit) { |
| 272 | static RRDSET *st_sqlite3_cache = NULL; |
| 273 | static RRDDIM *rd_cache_hit = NULL; |
| 274 | static RRDDIM *rd_cache_miss= NULL; |
| 275 | static RRDDIM *rd_cache_spill= NULL; |
| 276 | static RRDDIM *rd_cache_write= NULL; |
| 277 | |
| 278 | if (unlikely(!st_sqlite3_cache)) { |
| 279 | st_sqlite3_cache = rrdset_create_localhost( |
| 280 | "netdata" |
| 281 | , "sqlite3_context_cache" |
| 282 | , NULL |
| 283 | , "sqlite3" |
| 284 | , NULL |
| 285 | , "Netdata SQLite3 context cache" |
| 286 | , "ops/s" |
| 287 | , "netdata" |
| 288 | , "pulse" |
| 289 | , 131104 |
| 290 | , localhost->rrd_update_every |
| 291 | , RRDSET_TYPE_LINE |
| 292 | ); |
| 293 | |
| 294 | rd_cache_hit = rrddim_add(st_sqlite3_cache, "cache_hit", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); |
| 295 | rd_cache_miss = rrddim_add(st_sqlite3_cache, "cache_miss", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); |
| 296 | rd_cache_spill = rrddim_add(st_sqlite3_cache, "cache_spill", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); |
| 297 | rd_cache_write = rrddim_add(st_sqlite3_cache, "cache_write", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); |
| 298 | } |
| 299 | |
| 300 | if(gs.sqlite3_context_cache_hit != UINT64_MAX) |
| 301 | rrddim_set_by_pointer(st_sqlite3_cache, rd_cache_hit, (collected_number)gs.sqlite3_context_cache_hit); |
| 302 | |
| 303 | if(gs.sqlite3_context_cache_miss != UINT64_MAX) |
| 304 | rrddim_set_by_pointer(st_sqlite3_cache, rd_cache_miss, (collected_number)gs.sqlite3_context_cache_miss); |
| 305 | |
| 306 | if(gs.sqlite3_context_cache_spill != UINT64_MAX) |
| 307 | rrddim_set_by_pointer(st_sqlite3_cache, rd_cache_spill, (collected_number)gs.sqlite3_context_cache_spill); |
| 308 | |
| 309 | if(gs.sqlite3_context_cache_write != UINT64_MAX) |
| 310 | rrddim_set_by_pointer(st_sqlite3_cache, rd_cache_write, (collected_number)gs.sqlite3_context_cache_write); |
| 311 | |
| 312 | rrdset_done(st_sqlite3_cache); |
| 313 | } |
| 314 | } |