When unregistering an ephemeral host, delete its chart labels (#16486)
* When unregistering an ephemeral host, delete its chart labels * Fix memory leak in case of query preparation or bind failure * Add check to handle CID 410125 Dereference null return value
Stelios Fragkakis committed
Nov 29, 2023 at 15:57 UTC
b1465aa5895326c4100e3b535364ca78f91b6f71
4 files changed
+106
-12
collectors/plugins.d/pluginsd_parser.c
+2
-1
@@ -1422,7 +1422,8 @@ static inline PARSER_RC pluginsd_label(char **words, size_t num_words, PARSER *p
1422
int is_ephemeral = appconfig_test_boolean_value((char *) value);
1423
if (is_ephemeral) {
1424
RRDHOST *host = pluginsd_require_scope_host(parser, PLUGINSD_KEYWORD_LABEL);
1425
- rrdhost_option_set(host, RRDHOST_OPTION_EPHEMERAL_HOST);
1425
+ if (likely(host))
1426
+ rrdhost_option_set(host, RRDHOST_OPTION_EPHEMERAL_HOST);
1427
}
1428
}
1429
database/sqlite/sqlite_aclk.c
+18
-9
@@ -257,30 +257,38 @@ static void sql_unregister_node(char *machine_guid)
257
return;
258
259
rc = uuid_parse(machine_guid, host_uuid);
260
- freez(machine_guid);
261
- if (rc)
260
+ if (rc) {
261
+ freez(machine_guid);
262
return;
263
+ }
264
265
sqlite3_stmt *res = NULL;
266
267
rc = sqlite3_prepare_v2(db_meta, "UPDATE node_instance SET node_id = NULL WHERE host_id = @host_id", -1, &res, 0);
268
if (unlikely(rc != SQLITE_OK)) {
268
- error_report("Failed to prepare statement remote node id for a host");
269
+ error_report("Failed to prepare statement to remove the host node id");
270
+ freez(machine_guid);
271
return;
272
}
273
274
rc = sqlite3_bind_blob(res, 1, &host_uuid, sizeof(host_uuid), SQLITE_STATIC);
275
if (unlikely(rc != SQLITE_OK)) {
274
- error_report("Failed to bind host_id parameter to remove node id");
275
- goto failed;
276
+ error_report("Failed to bind host_id parameter to remove host node id");
277
+ goto skip;
278
}
279
rc = sqlite3_step_monitored(res);
278
- if (unlikely(rc != SQLITE_DONE))
279
- error_report("Failed to execute command to remove node id");
280
+ if (unlikely(rc != SQLITE_DONE)) {
281
+ error_report("Failed to execute command to remove host node id");
282
+ } else {
283
+ // node: machine guid will be freed after processing
284
+ metadata_delete_host_chart_labels(machine_guid);
285
+ machine_guid = NULL;
286
+ }
287
281
-failed:
288
+skip:
289
if (unlikely(sqlite3_finalize(res) != SQLITE_OK))
283
- error_report("Failed to finalize statement to remove node id");
290
+ error_report("Failed to finalize statement to remove host node id");
291
+ freez(machine_guid);
292
}
293
294
@@ -448,6 +456,7 @@ static void aclk_synchronization(void *arg __maybe_unused)
456
break;
457
case ACLK_DATABASE_NODE_UNREGISTER:
458
sql_unregister_node(cmd.param[0]);
459
+
460
break;
461
// ALERTS
462
case ACLK_DATABASE_PUSH_ALERT_CONFIG:
database/sqlite/sqlite_metadata.c
+85
-2
@@ -80,6 +80,7 @@ enum metadata_opcode {
80
METADATA_ADD_HOST_INFO,
81
METADATA_SCAN_HOSTS,
82
METADATA_LOAD_HOST_CONTEXT,
83
+ METADATA_DELETE_HOST_CHART_LABELS,
84
METADATA_MAINTENANCE,
85
METADATA_SYNC_SHUTDOWN,
86
METADATA_UNITTEST,
@@ -119,6 +120,8 @@ struct metadata_wc {
120
#define metadata_flag_set(target_flags, flag) __atomic_or_fetch(&((target_flags)->flags), (flag), __ATOMIC_SEQ_CST)
121
#define metadata_flag_clear(target_flags, flag) __atomic_and_fetch(&((target_flags)->flags), ~(flag), __ATOMIC_SEQ_CST)
122
123
+struct metadata_wc metasync_worker = {.loop = NULL};
124
+
125
//
126
// For unittest
127
//
@@ -138,6 +141,33 @@ struct query_build {
141
char uuid_str[UUID_STR_LEN];
142
};
143
144
+#define SQL_DELETE_CHART_LABELS_BY_HOST \
145
+ "DELETE FROM chart_label WHERE chart_id in (SELECT chart_id FROM chart WHERE host_id = @host_id)"
146
+
147
+static void delete_host_chart_labels(uuid_t *host_uuid)
148
+{
149
+ sqlite3_stmt *res = NULL;
150
+
151
+ int rc = sqlite3_prepare_v2(db_meta, SQL_DELETE_CHART_LABELS_BY_HOST, -1, &res, 0);
152
+ if (unlikely(rc != SQLITE_OK)) {
153
+ error_report("Failed to prepare statement to delete chart labels by host");
154
+ return;
155
+ }
156
+
157
+ rc = sqlite3_bind_blob(res, 1, host_uuid, sizeof(*host_uuid), SQLITE_STATIC);
158
+ if (unlikely(rc != SQLITE_OK)) {
159
+ error_report("Failed to bind host_id parameter to host chart labels");
160
+ goto failed;
161
+ }
162
+ rc = sqlite3_step_monitored(res);
163
+ if (unlikely(rc != SQLITE_DONE))
164
+ error_report("Failed to execute command to remove host chart labels");
165
+
166
+failed:
167
+ if (unlikely(sqlite3_finalize(res) != SQLITE_OK))
168
+ error_report("Failed to finalize statement to remove host chart labels");
169
+}
170
+
171
static int host_label_store_to_sql_callback(const char *name, const char *value, RRDLABEL_SRC ls, void *data) {
172
struct query_build *lb = data;
173
if (unlikely(!lb->count))
@@ -1173,6 +1203,7 @@ void run_metadata_cleanup(struct metadata_wc *wc)
1203
struct scan_metadata_payload {
1204
uv_work_t request;
1205
struct metadata_wc *wc;
1206
+ void *data;
1207
BUFFER *work_buffer;
1208
uint32_t max_count;
1209
};
@@ -1411,6 +1442,11 @@ static void store_host_and_system_info(RRDHOST *host, size_t *query_counter)
1442
}
1443
}
1444
1445
+struct host_chart_label_cleanup {
1446
+ Pvoid_t JudyL;
1447
+ Word_t count;
1448
+};
1449
+
1450
// Worker thread to scan hosts for pending metadata to store
1451
static void start_metadata_hosts(uv_work_t *req __maybe_unused)
1452
{
@@ -1427,6 +1463,29 @@ static void start_metadata_hosts(uv_work_t *req __maybe_unused)
1463
internal_error(true, "METADATA: checking all hosts...");
1464
usec_t started_ut = now_monotonic_usec(); (void)started_ut;
1465
1466
+ struct host_chart_label_cleanup *cl_cleanup_data = data->data;
1467
+
1468
+ if (cl_cleanup_data) {
1469
+ Word_t Index = 0;
1470
+ bool first = true;
1471
+ Pvoid_t *PValue;
1472
+ while ((PValue = JudyLFirstThenNext(cl_cleanup_data->JudyL, &Index, &first))) {
1473
+ char *machine_guid = *PValue;
1474
+
1475
+ host = rrdhost_find_by_guid(machine_guid);
1476
+ if (unlikely(host))
1477
+ continue;
1478
+
1479
+ uuid_t host_uuid;
1480
+ uuid_parse(machine_guid, host_uuid);
1481
+ delete_host_chart_labels(&host_uuid);
1482
+
1483
+ freez(machine_guid);
1484
+ }
1485
+ JudyLFreeArray(&cl_cleanup_data->JudyL, PJE0);
1486
+ freez(cl_cleanup_data);
1487
+ }
1488
+
1489
bool run_again = false;
1490
worker_is_busy(UV_EVENT_METADATA_STORE);
1491
@@ -1568,6 +1627,7 @@ static void metadata_event_loop(void *arg)
1627
completion_mark_complete(&wc->start_stop_complete);
1628
BUFFER *work_buffer = buffer_create(1024, &netdata_buffers_statistics.buffers_sqlite);
1629
struct scan_metadata_payload *data;
1630
+ struct host_chart_label_cleanup *cl_cleanup_data = NULL;
1631
1632
while (shutdown == 0 || (wc->flags & METADATA_FLAG_PROCESSING)) {
1633
uuid_t *uuid;
@@ -1624,7 +1684,9 @@ static void metadata_event_loop(void *arg)
1684
data = mallocz(sizeof(*data));
1685
data->request.data = data;
1686
data->wc = wc;
1687
+ data->data = cl_cleanup_data;
1688
data->work_buffer = work_buffer;
1689
+ cl_cleanup_data = NULL;
1690
1691
if (unlikely(cmd.completion)) {
1692
data->max_count = 0; // 0 will process all pending updates
@@ -1640,6 +1702,7 @@ static void metadata_event_loop(void *arg)
1702
after_metadata_hosts))) {
1703
// Failed to launch worker -- let the event loop handle completion
1704
cmd.completion = wc->scan_complete;
1705
+ cl_cleanup_data = data->data;
1706
freez(data);
1707
metadata_flag_clear(wc, METADATA_FLAG_PROCESSING);
1708
}
@@ -1656,6 +1719,15 @@ static void metadata_event_loop(void *arg)
1719
after_start_host_load_context))) {
1720
freez(data);
1721
}
1722
+ break;
1723
+ case METADATA_DELETE_HOST_CHART_LABELS:;
1724
+ if (!cl_cleanup_data)
1725
+ cl_cleanup_data = callocz(1,sizeof(*cl_cleanup_data));
1726
+
1727
+ Pvoid_t *PValue = JudyLIns(&cl_cleanup_data->JudyL, (Word_t) ++cl_cleanup_data->count, PJE0);
1728
+ if (PValue)
1729
+ *PValue = (void *) cmd.param[0];
1730
+
1731
break;
1732
case METADATA_UNITTEST:;
1733
struct thread_unittest *tu = (struct thread_unittest *) cmd.param[0];
@@ -1702,8 +1774,6 @@ error_after_loop_init:
1774
worker_unregister();
1775
}
1776
1705
-struct metadata_wc metasync_worker = {.loop = NULL};
1706
-
1777
void metadata_sync_shutdown(void)
1778
{
1779
completion_init(&metasync_worker.start_stop_complete);
@@ -1828,6 +1898,19 @@ void metadata_queue_load_host_context(RRDHOST *host)
1898
nd_log(NDLS_DAEMON, NDLP_DEBUG, "Queued command to load host contexts");
1899
}
1900
1901
+void metadata_delete_host_chart_labels(char *machine_guid)
1902
+{
1903
+ if (unlikely(!metasync_worker.loop)) {
1904
+ freez(machine_guid);
1905
+ return;
1906
+ }
1907
+
1908
+ // Node machine guid is already strdup-ed
1909
+ queue_metadata_cmd(METADATA_DELETE_HOST_CHART_LABELS, machine_guid, NULL);
1910
+ nd_log(NDLS_DAEMON, NDLP_DEBUG, "Queued command delete chart labels for host %s", machine_guid);
1911
+}
1912
+
1913
+
1914
//
1915
// unitests
1916
//
database/sqlite/sqlite_metadata.h
+1
@@ -17,6 +17,7 @@ void metaqueue_host_update_info(RRDHOST *host);
17
void metaqueue_ml_load_models(RRDDIM *rd);
18
void migrate_localhost(uuid_t *host_uuid);
19
void metadata_queue_load_host_context(RRDHOST *host);
20
+void metadata_delete_host_chart_labels(char *machine_guid);
21
void vacuum_database(sqlite3 *database, const char *db_alias, int threshold, int vacuum_pc);
22
23
// UNIT TEST