diff options
author | Stelios Fragkakis <52996999+stelfrag@users.noreply.github.com> | 2023-11-29 15:57:35 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-11-29 15:57:35 +0200 |
commit | b1465aa5895326c4100e3b535364ca78f91b6f71 (patch) | |
tree | aca7bf7de036671e8392916c56c8b099e8a79b59 | |
parent | 4f6fe91a6d3265fecae01c9d3ee136d2d48208db (diff) |
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
-rw-r--r-- | collectors/plugins.d/pluginsd_parser.c | 3 | ||||
-rw-r--r-- | database/sqlite/sqlite_aclk.c | 27 | ||||
-rw-r--r-- | database/sqlite/sqlite_metadata.c | 87 | ||||
-rw-r--r-- | database/sqlite/sqlite_metadata.h | 1 |
4 files changed, 106 insertions, 12 deletions
diff --git a/collectors/plugins.d/pluginsd_parser.c b/collectors/plugins.d/pluginsd_parser.c index f26c5fb08c..246043a375 100644 --- a/collectors/plugins.d/pluginsd_parser.c +++ b/collectors/plugins.d/pluginsd_parser.c @@ -1422,7 +1422,8 @@ static inline PARSER_RC pluginsd_label(char **words, size_t num_words, PARSER *p int is_ephemeral = appconfig_test_boolean_value((char *) value); if (is_ephemeral) { RRDHOST *host = pluginsd_require_scope_host(parser, PLUGINSD_KEYWORD_LABEL); - rrdhost_option_set(host, RRDHOST_OPTION_EPHEMERAL_HOST); + if (likely(host)) + rrdhost_option_set(host, RRDHOST_OPTION_EPHEMERAL_HOST); } } diff --git a/database/sqlite/sqlite_aclk.c b/database/sqlite/sqlite_aclk.c index 83203b22e3..480148137d 100644 --- a/database/sqlite/sqlite_aclk.c +++ b/database/sqlite/sqlite_aclk.c @@ -257,30 +257,38 @@ static void sql_unregister_node(char *machine_guid) return; rc = uuid_parse(machine_guid, host_uuid); - freez(machine_guid); - if (rc) + if (rc) { + freez(machine_guid); return; + } sqlite3_stmt *res = NULL; rc = sqlite3_prepare_v2(db_meta, "UPDATE node_instance SET node_id = NULL WHERE host_id = @host_id", -1, &res, 0); if (unlikely(rc != SQLITE_OK)) { - error_report("Failed to prepare statement remote node id for a host"); + error_report("Failed to prepare statement to remove the host node id"); + freez(machine_guid); return; } rc = sqlite3_bind_blob(res, 1, &host_uuid, sizeof(host_uuid), SQLITE_STATIC); if (unlikely(rc != SQLITE_OK)) { - error_report("Failed to bind host_id parameter to remove node id"); - goto failed; + error_report("Failed to bind host_id parameter to remove host node id"); + goto skip; } rc = sqlite3_step_monitored(res); - if (unlikely(rc != SQLITE_DONE)) - error_report("Failed to execute command to remove node id"); + if (unlikely(rc != SQLITE_DONE)) { + error_report("Failed to execute command to remove host node id"); + } else { + // node: machine guid will be freed after processing + metadata_delete_host_chart_labels(machine_guid); + machine_guid = NULL; + } -failed: +skip: if (unlikely(sqlite3_finalize(res) != SQLITE_OK)) - error_report("Failed to finalize statement to remove node id"); + error_report("Failed to finalize statement to remove host node id"); + freez(machine_guid); } @@ -448,6 +456,7 @@ static void aclk_synchronization(void *arg __maybe_unused) break; case ACLK_DATABASE_NODE_UNREGISTER: sql_unregister_node(cmd.param[0]); + break; // ALERTS case ACLK_DATABASE_PUSH_ALERT_CONFIG: diff --git a/database/sqlite/sqlite_metadata.c b/database/sqlite/sqlite_metadata.c index 70af4809c8..f2ce7ea913 100644 --- a/database/sqlite/sqlite_metadata.c +++ b/database/sqlite/sqlite_metadata.c @@ -80,6 +80,7 @@ enum metadata_opcode { METADATA_ADD_HOST_INFO, METADATA_SCAN_HOSTS, METADATA_LOAD_HOST_CONTEXT, + METADATA_DELETE_HOST_CHART_LABELS, METADATA_MAINTENANCE, METADATA_SYNC_SHUTDOWN, METADATA_UNITTEST, @@ -119,6 +120,8 @@ struct metadata_wc { #define metadata_flag_set(target_flags, flag) __atomic_or_fetch(&((target_flags)->flags), (flag), __ATOMIC_SEQ_CST) #define metadata_flag_clear(target_flags, flag) __atomic_and_fetch(&((target_flags)->flags), ~(flag), __ATOMIC_SEQ_CST) +struct metadata_wc metasync_worker = {.loop = NULL}; + // // For unittest // @@ -138,6 +141,33 @@ struct query_build { char uuid_str[UUID_STR_LEN]; }; +#define SQL_DELETE_CHART_LABELS_BY_HOST \ + "DELETE FROM chart_label WHERE chart_id in (SELECT chart_id FROM chart WHERE host_id = @host_id)" + +static void delete_host_chart_labels(uuid_t *host_uuid) +{ + sqlite3_stmt *res = NULL; + + int rc = sqlite3_prepare_v2(db_meta, SQL_DELETE_CHART_LABELS_BY_HOST, -1, &res, 0); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to prepare statement to delete chart labels by host"); + return; + } + + rc = sqlite3_bind_blob(res, 1, host_uuid, sizeof(*host_uuid), SQLITE_STATIC); + if (unlikely(rc != SQLITE_OK)) { + error_report("Failed to bind host_id parameter to host chart labels"); + goto failed; + } + rc = sqlite3_step_monitored(res); + if (unlikely(rc != SQLITE_DONE)) + error_report("Failed to execute command to remove host chart labels"); + +failed: + if (unlikely(sqlite3_finalize(res) != SQLITE_OK)) + error_report("Failed to finalize statement to remove host chart labels"); +} + static int host_label_store_to_sql_callback(const char *name, const char *value, RRDLABEL_SRC ls, void *data) { struct query_build *lb = data; if (unlikely(!lb->count)) @@ -1173,6 +1203,7 @@ void run_metadata_cleanup(struct metadata_wc *wc) struct scan_metadata_payload { uv_work_t request; struct metadata_wc *wc; + void *data; BUFFER *work_buffer; uint32_t max_count; }; @@ -1411,6 +1442,11 @@ static void store_host_and_system_info(RRDHOST *host, size_t *query_counter) } } +struct host_chart_label_cleanup { + Pvoid_t JudyL; + Word_t count; +}; + // Worker thread to scan hosts for pending metadata to store static void start_metadata_hosts(uv_work_t *req __maybe_unused) { @@ -1427,6 +1463,29 @@ static void start_metadata_hosts(uv_work_t *req __maybe_unused) internal_error(true, "METADATA: checking all hosts..."); usec_t started_ut = now_monotonic_usec(); (void)started_ut; + struct host_chart_label_cleanup *cl_cleanup_data = data->data; + + if (cl_cleanup_data) { + Word_t Index = 0; + bool first = true; + Pvoid_t *PValue; + while ((PValue = JudyLFirstThenNext(cl_cleanup_data->JudyL, &Index, &first))) { + char *machine_guid = *PValue; + + host = rrdhost_find_by_guid(machine_guid); + if (unlikely(host)) + continue; + + uuid_t host_uuid; + uuid_parse(machine_guid, host_uuid); + delete_host_chart_labels(&host_uuid); + + freez(machine_guid); + } + JudyLFreeArray(&cl_cleanup_data->JudyL, PJE0); + freez(cl_cleanup_data); + } + bool run_again = false; worker_is_busy(UV_EVENT_METADATA_STORE); @@ -1568,6 +1627,7 @@ static void metadata_event_loop(void *arg) completion_mark_complete(&wc->start_stop_complete); BUFFER *work_buffer = buffer_create(1024, &netdata_buffers_statistics.buffers_sqlite); struct scan_metadata_payload *data; + struct host_chart_label_cleanup *cl_cleanup_data = NULL; while (shutdown == 0 || (wc->flags & METADATA_FLAG_PROCESSING)) { uuid_t *uuid; @@ -1624,7 +1684,9 @@ static void metadata_event_loop(void *arg) data = mallocz(sizeof(*data)); data->request.data = data; data->wc = wc; + data->data = cl_cleanup_data; data->work_buffer = work_buffer; + cl_cleanup_data = NULL; if (unlikely(cmd.completion)) { data->max_count = 0; // 0 will process all pending updates @@ -1640,6 +1702,7 @@ static void metadata_event_loop(void *arg) after_metadata_hosts))) { // Failed to launch worker -- let the event loop handle completion cmd.completion = wc->scan_complete; + cl_cleanup_data = data->data; freez(data); metadata_flag_clear(wc, METADATA_FLAG_PROCESSING); } @@ -1657,6 +1720,15 @@ static void metadata_event_loop(void *arg) freez(data); } break; + case METADATA_DELETE_HOST_CHART_LABELS:; + if (!cl_cleanup_data) + cl_cleanup_data = callocz(1,sizeof(*cl_cleanup_data)); + + Pvoid_t *PValue = JudyLIns(&cl_cleanup_data->JudyL, (Word_t) ++cl_cleanup_data->count, PJE0); + if (PValue) + *PValue = (void *) cmd.param[0]; + + break; case METADATA_UNITTEST:; struct thread_unittest *tu = (struct thread_unittest *) cmd.param[0]; sleep_usec(1000); // processing takes 1ms @@ -1702,8 +1774,6 @@ error_after_loop_init: worker_unregister(); } -struct metadata_wc metasync_worker = {.loop = NULL}; - void metadata_sync_shutdown(void) { completion_init(&metasync_worker.start_stop_complete); @@ -1828,6 +1898,19 @@ void metadata_queue_load_host_context(RRDHOST *host) nd_log(NDLS_DAEMON, NDLP_DEBUG, "Queued command to load host contexts"); } +void metadata_delete_host_chart_labels(char *machine_guid) +{ + if (unlikely(!metasync_worker.loop)) { + freez(machine_guid); + return; + } + + // Node machine guid is already strdup-ed + queue_metadata_cmd(METADATA_DELETE_HOST_CHART_LABELS, machine_guid, NULL); + nd_log(NDLS_DAEMON, NDLP_DEBUG, "Queued command delete chart labels for host %s", machine_guid); +} + + // // unitests // diff --git a/database/sqlite/sqlite_metadata.h b/database/sqlite/sqlite_metadata.h index f75a9ab00f..6860cfedf8 100644 --- a/database/sqlite/sqlite_metadata.h +++ b/database/sqlite/sqlite_metadata.h @@ -17,6 +17,7 @@ void metaqueue_host_update_info(RRDHOST *host); void metaqueue_ml_load_models(RRDDIM *rd); void migrate_localhost(uuid_t *host_uuid); void metadata_queue_load_host_context(RRDHOST *host); +void metadata_delete_host_chart_labels(char *machine_guid); void vacuum_database(sqlite3 *database, const char *db_alias, int threshold, int vacuum_pc); // UNIT TEST |