Alert prototypes: use r/w spinlock instead of spinlock (#19410)
use r/w spinlock instead of spinlock
Costa Tsaousis committed
Jan 15, 2025 at 18:30 UTC
6f1655ab9dc113b00ad4353ba2085bf9bfe54726
8 files changed
+38
-21
src/database/sqlite/sqlite_functions.c
+5
-2
@@ -14,12 +14,16 @@ SQLITE_API int sqlite3_exec_monitored(
14
void *data, /* 1st argument to callback */
15
char **errmsg /* Error msg written here */
16
) {
17
+ internal_fatal(!nd_thread_runs_sql(), "THIS THREAD CANNOT RUN SQL");
18
+
19
int rc = sqlite3_exec(db, sql, callback, data, errmsg);
20
pulse_sqlite3_query_completed(rc == SQLITE_OK, rc == SQLITE_BUSY, rc == SQLITE_LOCKED);
21
return rc;
22
}
23
24
SQLITE_API int sqlite3_step_monitored(sqlite3_stmt *stmt) {
25
+ internal_fatal(!nd_thread_runs_sql(), "THIS THREAD CANNOT RUN SQL");
26
+
27
int rc;
28
int cnt = 0;
29
@@ -66,8 +70,7 @@ static bool mark_database_to_recover(sqlite3_stmt *res, sqlite3 *database, int r
70
return false;
71
}
72
69
-int execute_insert(sqlite3_stmt *res)
70
-{
73
+int execute_insert(sqlite3_stmt *res) {
74
int rc;
75
rc = sqlite3_step_monitored(res);
76
if (rc == SQLITE_CORRUPT) {
src/health/health_dyncfg.c
+2
-2
@@ -659,11 +659,11 @@ static int dyncfg_health_prototype_job_action(BUFFER *result, DYNCFG_CMDS cmd, B
659
code = dyncfg_default_response(result, HTTP_RESP_OK, "already enabled");
660
else {
661
size_t matches_enabled = 0;
662
- spinlock_lock(&ap->_internal.spinlock);
662
+ rw_spinlock_write_lock(&ap->_internal.rw_spinlock);
663
for(RRD_ALERT_PROTOTYPE *t = ap; t ;t = t->_internal.next)
664
if(t->match.enabled)
665
matches_enabled++;
666
- spinlock_unlock(&ap->_internal.spinlock);
666
+ rw_spinlock_write_unlock(&ap->_internal.rw_spinlock);
667
668
if(!matches_enabled) {
669
code = dyncfg_default_response(result, HTTP_RESP_BAD_REQUEST, "all rules in this alert are disabled, so enabling the alert has no effect");
src/health/health_internals.h
+1
-2
@@ -53,10 +53,9 @@ typedef struct rrd_alert_prototype {
53
struct rrd_alert_config config;
54
55
struct {
56
- uint32_t uses;
56
bool enabled;
57
bool is_on_disk;
59
- SPINLOCK spinlock;
58
+ RW_SPINLOCK rw_spinlock;
59
struct rrd_alert_prototype *prev, *next;
60
} _internal;
61
} RRD_ALERT_PROTOTYPE;
src/health/health_prototypes.c
+13
-15
@@ -206,7 +206,7 @@ static void health_prototype_cleanup_one_unsafe(RRD_ALERT_PROTOTYPE *ap) {
206
}
207
208
void health_prototype_cleanup(RRD_ALERT_PROTOTYPE *ap) {
209
- spinlock_lock(&ap->_internal.spinlock);
209
+ rw_spinlock_write_lock(&ap->_internal.rw_spinlock);
210
211
while(ap->_internal.next) {
212
RRD_ALERT_PROTOTYPE *t = ap->_internal.next;
@@ -215,7 +215,7 @@ void health_prototype_cleanup(RRD_ALERT_PROTOTYPE *ap) {
215
freez(t);
216
}
217
218
- spinlock_unlock(&ap->_internal.spinlock);
218
+ rw_spinlock_write_unlock(&ap->_internal.rw_spinlock);
219
220
health_prototype_cleanup_one_unsafe(ap);
221
}
@@ -228,7 +228,7 @@ void health_prototype_free(RRD_ALERT_PROTOTYPE *ap) {
228
229
void health_prototype_insert_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused) {
230
RRD_ALERT_PROTOTYPE *ap = value;
231
- spinlock_init(&ap->_internal.spinlock);
231
+ rw_spinlock_init(&ap->_internal.rw_spinlock);
232
if(ap->config.source_type != DYNCFG_SOURCE_TYPE_DYNCFG)
233
ap->_internal.is_on_disk = true;
234
}
@@ -253,9 +253,9 @@ bool health_prototype_conflict_cb(const DICTIONARY_ITEM *item __maybe_unused, vo
253
nap = callocz(1, sizeof(*nap));
254
memcpy(nap, new_value, sizeof(*nap));
255
256
- spinlock_lock(&ap->_internal.spinlock);
256
+ rw_spinlock_write_lock(&ap->_internal.rw_spinlock);
257
DOUBLE_LINKED_LIST_APPEND_ITEM_UNSAFE(ap->_internal.next, nap, _internal.prev, _internal.next);
258
- spinlock_unlock(&ap->_internal.spinlock);
258
+ rw_spinlock_write_unlock(&ap->_internal.rw_spinlock);
259
260
if(nap->_internal.enabled)
261
ap->_internal.enabled = true;
@@ -263,14 +263,13 @@ bool health_prototype_conflict_cb(const DICTIONARY_ITEM *item __maybe_unused, vo
263
}
264
else {
265
// alerts with the same name replace the existing one
266
- spinlock_init(&nap->_internal.spinlock);
267
- nap->_internal.uses = ap->_internal.uses;
266
+ rw_spinlock_init(&nap->_internal.rw_spinlock);
267
269
- spinlock_lock(&nap->_internal.spinlock);
270
- spinlock_lock(&ap->_internal.spinlock);
268
+ rw_spinlock_write_lock(&nap->_internal.rw_spinlock);
269
+ rw_spinlock_write_lock(&ap->_internal.rw_spinlock);
270
SWAP(*ap, *nap);
272
- spinlock_unlock(&ap->_internal.spinlock);
273
- spinlock_unlock(&nap->_internal.spinlock);
271
+ rw_spinlock_write_unlock(&ap->_internal.rw_spinlock);
272
+ rw_spinlock_write_unlock(&nap->_internal.rw_spinlock);
273
274
health_prototype_cleanup(nap);
275
memset(nap, 0, sizeof(*nap));
@@ -598,7 +597,7 @@ static void health_prototype_apply_to_rrdset(RRDSET *st, RRD_ALERT_PROTOTYPE *ap
597
if(!ap->_internal.enabled)
598
return;
599
601
- spinlock_lock(&ap->_internal.spinlock);
600
+ rw_spinlock_read_lock(&ap->_internal.rw_spinlock);
601
for(size_t template = 0; template < 2; template++) {
602
bool want_template = template ? true : false;
603
@@ -617,11 +616,10 @@ static void health_prototype_apply_to_rrdset(RRDSET *st, RRD_ALERT_PROTOTYPE *ap
616
if (!prototype_matches_rrdset(st, t))
617
continue;
618
620
- if (rrdcalc_add_from_prototype(st->rrdhost, st, t))
621
- ap->_internal.uses++;
619
+ rrdcalc_add_from_prototype(st->rrdhost, st, t);
620
}
621
}
624
- spinlock_unlock(&ap->_internal.spinlock);
622
+ rw_spinlock_read_unlock(&ap->_internal.rw_spinlock);
623
}
624
625
void health_prototype_alerts_for_rrdset_incrementally(RRDSET *st) {
src/libnetdata/threads/threads.c
+10
@@ -64,6 +64,16 @@ static struct {
64
65
static __thread ND_THREAD *_nd_thread_info = NULL;
66
static __thread char _nd_thread_os_name[ND_THREAD_TAG_MAX + 1] = "";
67
+static __thread bool _nd_thread_can_run_sql = true;
68
+
69
+void nd_thread_can_run_sql(bool run_sql) {
70
+ _nd_thread_can_run_sql = run_sql;
71
+}
72
+
73
+bool nd_thread_runs_sql(void) {
74
+ return _nd_thread_can_run_sql;
75
+}
76
+
77
78
// --------------------------------------------------------------------------------------------------------------------
79
// O/S abstraction
src/libnetdata/threads/threads.h
+3
@@ -114,4 +114,7 @@ void nd_thread_rwspinlock_write_unlocked(void);
114
#define nd_thread_rwspinlock_write_unlocked() debug_dummy()
115
#endif
116
117
+void nd_thread_can_run_sql(bool exclude);
118
+bool nd_thread_runs_sql(void);
119
+
120
#endif //NETDATA_THREADS_H
src/streaming/stream-connector.c
+2
@@ -511,6 +511,8 @@ static void *stream_connector_thread(void *ptr) {
511
struct connector *sc = ptr;
512
sc->tid = gettid_cached();
513
514
+ nd_thread_can_run_sql(false);
515
+
516
worker_register("STREAMCNT");
517
worker_register_job_name(WORKER_SENDER_CONNECTOR_JOB_CONNECTING, "connect");
518
worker_register_job_name(WORKER_SENDER_CONNECTOR_JOB_CONNECTED, "connected");
src/streaming/stream-thread.c
+2
@@ -381,6 +381,8 @@ static bool stream_thread_process_poll_slot(struct stream_thread *sth, nd_poll_r
381
void *stream_thread(void *ptr) {
382
struct stream_thread *sth = ptr;
383
384
+ nd_thread_can_run_sql(false);
385
+
386
worker_register("STREAM");
387
388
// stream thread main event loop