@cryptotaxi247 / netdata-1 / commits / 807d38622

cleanup contexts during loading (#19416)

* cleanup contexts during loading * Revert book keeping for contexts related to cloud * Move host context cleanup code away from the local cloud context db * Queue context for retention check and cleanup * delete from queue before deleting context * Change msg to debug --------- Co-authored-by: Stelios Fragkakis <52996999+stelfrag@users.noreply.github.com>

Costa Tsaousis committed Jan 16, 2025 at 20:59 UTC 807d38622d723f8710c195c90816596992e62f4e
7 files changed +247 -115
src/database/contexts/contexts-loading.c
+49 -29
@@ -2,8 +2,7 @@
2
3 #include "internal.h"
4
5 -static __thread size_t ignored_metrics = 0, ignored_instances = 0;
6 -static __thread size_t loaded_metrics = 0, loaded_instances = 0, loaded_contexts = 0;
5 +static __thread size_t th_ignored_metrics = 0, th_ignored_instances = 0, th_zero_retention_metrics = 0;
6
7 static void rrdinstance_load_clabel(SQL_CLABEL_DATA *sld, void *data) {
8 RRDINSTANCE *ri = data;
@@ -22,15 +21,13 @@ static void rrdinstance_load_dimension_callback(SQL_DIMENSION_DATA *sd, void *da
21 get_metric_retention_by_id(host, id, &min_first_time_t, &max_last_time_t);
22 if((!min_first_time_t || min_first_time_t == LONG_MAX) && !max_last_time_t) {
23 uuidmap_free(id);
24 + th_zero_retention_metrics++;
25 return;
26 }
27
28 RRDCONTEXT_ACQUIRED *rca = (RRDCONTEXT_ACQUIRED *)dictionary_get_and_acquire_item(host->rrdctx.contexts, sd->context);
29 if(!rca) {
30 - ignored_metrics++;
31 -// nd_log(NDLS_DAEMON, NDLP_ERR,
32 -// "RRDCONTEXT: context '%s' is not found in host '%s' - not loading dimensions",
33 -// sd->context, rrdhost_hostname(host));
30 + th_ignored_metrics++;
31 uuidmap_free(id);
32 return;
33 }
@@ -38,11 +35,8 @@ static void rrdinstance_load_dimension_callback(SQL_DIMENSION_DATA *sd, void *da
35
36 RRDINSTANCE_ACQUIRED *ria = (RRDINSTANCE_ACQUIRED *)dictionary_get_and_acquire_item(rc->rrdinstances, sd->chart_id);
37 if(!ria) {
38 + th_ignored_metrics++;
39 rrdcontext_release(rca);
42 - ignored_metrics++;
43 -// nd_log(NDLS_DAEMON, NDLP_ERR,
44 -// "RRDCONTEXT: instance '%s' of context '%s' is not found in host '%s' - not loading dimensions",
45 -// sd->chart_id, sd->context, rrdhost_hostname(host));
40 uuidmap_free(id);
41 return;
42 }
@@ -60,7 +54,6 @@ static void rrdinstance_load_dimension_callback(SQL_DIMENSION_DATA *sd, void *da
54
55 rrdinstance_release(ria);
56 rrdcontext_release(rca);
63 - loaded_metrics++;
57 }
58
59 static void rrdinstance_load_instance_callback(SQL_CHART_DATA *sc, void *data) {
@@ -97,7 +90,6 @@ static void rrdinstance_load_instance_callback(SQL_CHART_DATA *sc, void *data) {
90
91 rrdinstance_release(ria);
92 rrdcontext_release(rca);
100 - loaded_instances++;
93 }
94
95 static void rrdcontext_load_context_callback(VERSIONED_CONTEXT_DATA *ctx_data, void *data) {
@@ -114,7 +106,6 @@ static void rrdcontext_load_context_callback(VERSIONED_CONTEXT_DATA *ctx_data, v
106 .hub = *ctx_data,
107 };
108 dictionary_set(host->rrdctx.contexts, string2str(trc.id), &trc, sizeof(trc));
117 - loaded_contexts++;
109 }
110
111 void rrdhost_load_rrdcontext_data(RRDHOST *host) {
@@ -124,39 +115,68 @@ void rrdhost_load_rrdcontext_data(RRDHOST *host) {
115 if (host->rrd_memory_mode != RRD_DB_MODE_DBENGINE)
116 return;
117
127 - ignored_metrics = 0;
128 - ignored_instances = 0;
129 - loaded_metrics = 0;
130 - loaded_instances = 0;
131 - loaded_contexts = 0;
118 + th_ignored_metrics = th_ignored_instances = th_zero_retention_metrics = 0;
119
120 ctx_get_context_list(&host->host_id.uuid, rrdcontext_load_context_callback, host);
121 ctx_get_chart_list(&host->host_id.uuid, rrdinstance_load_instance_callback, host);
122 ctx_get_dimension_list(&host->host_id.uuid, rrdinstance_load_dimension_callback, host);
123
137 - nd_log(NDLS_DAEMON, ignored_metrics || ignored_instances ? NDLP_WARNING : NDLP_NOTICE,
138 - "RRDCONTEXT: metadata for node '%s':"
139 - " loaded %zu contexts, %zu instances, and %zu metrics,"
140 - " ignored %zu instances and %zu metrics",
141 - rrdhost_hostname(host),
142 - loaded_contexts, loaded_instances, loaded_metrics,
143 - ignored_instances, ignored_metrics);
124 + size_t ignored_metrics = th_ignored_metrics, ignored_instances = th_ignored_instances, zero_retention_metrics = th_zero_retention_metrics;
125 + size_t loaded_metrics = 0, loaded_instances = 0, loaded_contexts = 0;
126 + size_t loaded_and_deleted_instances = 0, loaded_and_deleted_contexts = 0;
127
128 RRDCONTEXT *rc;
129 dfe_start_read(host->rrdctx.contexts, rc) {
130 + size_t instances = 0;
131 +
132 RRDINSTANCE *ri;
148 - dfe_start_read(rc->rrdinstances, ri) {
133 + dfe_start_write(rc->rrdinstances, ri) {
134 + size_t metrics = 0;
135 +
136 RRDMETRIC *rm;
137 dfe_start_read(ri->rrdmetrics, rm) {
138 rrdmetric_trigger_updates(rm, __FUNCTION__ );
139 + loaded_metrics++;
140 + metrics++;
141 }
142 dfe_done(rm);
154 - rrdinstance_trigger_updates(ri, __FUNCTION__ );
143 + dictionary_garbage_collect(ri->rrdmetrics);
144 +
145 + if(!metrics) {
146 + dictionary_del(rc->rrdinstances, ri_dfe.name);
147 + loaded_and_deleted_instances++;
148 + }
149 + else {
150 + rrdinstance_trigger_updates(ri, __FUNCTION__);
151 + loaded_instances++;
152 + instances++;
153 + }
154 }
155 dfe_done(ri);
157 - rrdcontext_trigger_updates(rc, __FUNCTION__ );
156 + dictionary_garbage_collect(rc->rrdinstances);
157 +
158 + if(!instances) {
159 + metadata_queue_ctx_host_cleanup(&host->host_id.uuid, rc_dfe.name);
160 + rrdcontext_delete_after_loading(host, rc);
161 + loaded_and_deleted_contexts++;
162 + }
163 + else {
164 + rrdcontext_trigger_updates(rc, __FUNCTION__);
165 + rrdcontext_initial_processing_after_loading(rc);
166 + loaded_contexts++;
167 + }
168 }
169 dfe_done(rc);
160 -
170 + dictionary_garbage_collect(host->rrdctx.contexts);
171 rrdcontext_garbage_collect_single_host(host, false);
172 +
173 + nd_log(NDLS_DAEMON, ignored_metrics || ignored_instances ? NDLP_WARNING : NDLP_NOTICE,
174 + "RRDCONTEXT: metadata for node '%s': "
175 + "contexts %zu (deleted %zu), "
176 + "instances %zu (deleted %zu, ignored %zu), and "
177 + "metrics %zu (ignored %zu, zero retention %zu)",
178 + rrdhost_hostname(host),
179 + loaded_contexts, loaded_and_deleted_contexts,
180 + loaded_instances, loaded_and_deleted_instances, ignored_instances,
181 + loaded_metrics, ignored_metrics, zero_retention_metrics);
182 }
src/database/contexts/internal.h
+3
@@ -473,4 +473,7 @@ void rrdcontext_garbage_collect_single_host(RRDHOST *host, bool worker_jobs);
473
474 void get_metric_retention_by_id(RRDHOST *host, UUIDMAP_ID id, time_t *min_first_time_t, time_t *max_last_time_t);
475
476 +void rrdcontext_delete_after_loading(RRDHOST *host, RRDCONTEXT *rc);
477 +void rrdcontext_initial_processing_after_loading(RRDCONTEXT *rc);
478 +
479 #endif //NETDATA_RRDCONTEXT_INTERNAL_H
src/database/contexts/worker.c
+15
@@ -326,8 +326,11 @@ void rrdcontext_garbage_collect_single_host(RRDHOST *host, bool worker_jobs) {
326 string2str(rc->id),
327 rrdhost_hostname(host));
328 }
329 +
330 + dictionary_garbage_collect(ri->rrdmetrics);
331 }
332 dfe_done(ri);
333 + dictionary_garbage_collect(rc->rrdinstances);
334
335 if(unlikely(rrdcontext_should_be_deleted(rc))) {
336 if(worker_jobs) worker_is_busy(WORKER_JOB_CLEANUP_DELETE);
@@ -351,6 +354,8 @@ void rrdcontext_garbage_collect_single_host(RRDHOST *host, bool worker_jobs) {
354 rrdcontext_unlock(rc);
355 }
356 dfe_done(rc);
357 +
358 + dictionary_garbage_collect(host->rrdctx.contexts);
359 }
360
361 static void rrdcontext_garbage_collect_for_all_hosts(void) {
@@ -696,6 +701,16 @@ static void rrdcontext_dequeue_from_post_processing(RRDCONTEXT *rc) {
701 dictionary_del(rc->rrdhost->rrdctx.pp_queue, string2str(rc->id));
702 }
703
704 +void rrdcontext_initial_processing_after_loading(RRDCONTEXT *rc) {
705 + rrdcontext_dequeue_from_post_processing(rc);
706 + rrdcontext_post_process_updates(rc, false, RRD_FLAG_NONE, true);
707 +}
708 +
709 +void rrdcontext_delete_after_loading(RRDHOST *host, RRDCONTEXT *rc) {
710 + rrdcontext_dequeue_from_post_processing(rc);
711 + dictionary_del(host->rrdctx.contexts, string2str(rc->id));
712 +}
713 +
714 static void rrdcontext_post_process_queued_contexts(RRDHOST *host) {
715 if(unlikely(!host->rrdctx.pp_queue)) return;
716
src/database/sqlite/sqlite_context.c
+4 -78
@@ -13,17 +13,12 @@ const char *database_context_config[] = {
13 "last_time_t INT NOT NULL, deleted INT NOT NULL, "
14 "family TEXT, PRIMARY KEY (host_id, id))",
15
16 - "CREATE TABLE IF NOT EXISTS context_metadata_cleanup (id INTEGER PRIMARY KEY, host_id BLOB, context TEXT NOT NULL, date_created INT, "
17 - "UNIQUE (host_id, context))",
18 -
19 - "CREATE TRIGGER IF NOT EXISTS del_context1 AFTER DELETE ON context "
20 - "BEGIN INSERT INTO context_metadata_cleanup (host_id, context, date_created) "
21 - "VALUES (old.host_id, old.id, UNIXEPOCH()) ON CONFLICT DO UPDATE SET date_created = excluded.date_created; END",
22 -
16 NULL
17 };
18
19 const char *database_context_cleanup[] = {
20 + "DROP TRIGGER IF EXISTS del_context1",
21 + "DROP TABLE IF EXISTS context_metadata_cleanup",
22 "VACUUM",
23 NULL
24 };
@@ -189,7 +184,6 @@ done:
184
185 void ctx_get_context_list(nd_uuid_t *host_uuid, void (*dict_cb)(VERSIONED_CONTEXT_DATA *, void *), void *data)
186 {
192 -
187 if (unlikely(!host_uuid))
188 return;
189
@@ -268,76 +262,6 @@ done:
262 return (rc_stored != SQLITE_DONE);
263 }
264
271 -#define CTX_DELETE_CONTEXT_META_CLEANUP_ITEM "DELETE FROM context_metadata_cleanup WHERE host_id = @host_id AND context = @context"
272 -
273 -void ctx_delete_metadata_cleanup_context(sqlite3_stmt **res, nd_uuid_t(*host_uuid), const char *context)
274 -{
275 - if (!*res) {
276 - if (!PREPARE_STATEMENT(db_context_meta, CTX_DELETE_CONTEXT_META_CLEANUP_ITEM, res))
277 - return;
278 - }
279 -
280 - int param = 0;
281 - SQLITE_BIND_FAIL(done, sqlite3_bind_blob(*res, ++param, host_uuid, sizeof(*host_uuid), SQLITE_STATIC));
282 - SQLITE_BIND_FAIL(done, sqlite3_bind_text(*res, ++param, context, -1, SQLITE_STATIC));
283 -
284 - param = 0;
285 - int rc = sqlite3_step_monitored(*res);
286 - if (rc != SQLITE_DONE)
287 - error_report("Failed to delete context check entry, rc = %d", rc);
288 -
289 -done:
290 - REPORT_BIND_FAIL(*res, param);
291 - SQLITE_RESET(*res);
292 -}
293 -
294 -// Schedule context cleanup for host
295 -#define CTX_GET_CONTEXT_META_CLEANUP_LIST "SELECT context FROM context_metadata_cleanup WHERE host_id = @host_id"
296 -
297 -void ctx_get_context_list_to_cleanup(nd_uuid_t *host_uuid, void (*cleanup_cb)(Pvoid_t JudyL, void *data), void *data)
298 -{
299 - if (unlikely(!host_uuid))
300 - return;
301 -
302 - sqlite3_stmt *res = NULL;
303 -
304 - if (!PREPARE_STATEMENT(db_context_meta, CTX_GET_CONTEXT_META_CLEANUP_LIST, &res))
305 - return;
306 -
307 - int param = 0;
308 - SQLITE_BIND_FAIL(done, sqlite3_bind_blob(res, ++param, host_uuid, sizeof(*host_uuid), SQLITE_STATIC));
309 - param = 0;
310 -
311 - const char *context;
312 - Pvoid_t CTX_JudyL = NULL;
313 - Pvoid_t *Pvalue;
314 - while (sqlite3_step_monitored(res) == SQLITE_ROW) {
315 - context = (char *) sqlite3_column_text(res, 0);
316 - STRING *ctx = string_strdupz(context);
317 - Pvalue = JudyLIns(&CTX_JudyL, (Word_t) ctx, PJE0);
318 - if (*Pvalue)
319 - string_freez(ctx);
320 - else
321 - *(int *)Pvalue = 1;
322 - }
323 -
324 - if (CTX_JudyL) {
325 - cleanup_cb(CTX_JudyL, data);
326 -
327 - bool first = true;
328 - Word_t Index = 0;
329 - while ((Pvalue = JudyLFirstThenNext(CTX_JudyL, &Index, &first))) {
330 - STRING *ctx = (STRING *) Index;
331 - string_freez(ctx);
332 - }
333 - }
334 - (void)JudyLFreeArray(&CTX_JudyL, PJE0);
335 -
336 -done:
337 - REPORT_BIND_FAIL(res, param);
338 - SQLITE_FINALIZE(res);
339 -}
340 -
265 // Delete a context
266 #define CTX_DELETE_CONTEXT "DELETE FROM context WHERE host_id = @host_id AND id = @context"
267 int ctx_delete_context(nd_uuid_t *host_uuid, VERSIONED_CONTEXT_DATA *context_data)
@@ -351,6 +275,8 @@ int ctx_delete_context(nd_uuid_t *host_uuid, VERSIONED_CONTEXT_DATA *context_dat
275 if (!PREPARE_STATEMENT(db_context_meta, CTX_DELETE_CONTEXT, &res))
276 return 1;
277
278 + metadata_queue_ctx_host_cleanup(host_uuid, context_data->id);
279 +
280 int param = 0;
281 SQLITE_BIND_FAIL(done, sqlite3_bind_blob(res, ++param, host_uuid, sizeof(*host_uuid), SQLITE_STATIC));
282 SQLITE_BIND_FAIL(done, sqlite3_bind_text(res, ++param, context_data->id, -1, SQLITE_STATIC));
src/database/sqlite/sqlite_context.h
-4
@@ -62,10 +62,6 @@ void ctx_get_label_list(nd_uuid_t *chart_uuid, void (*dict_cb)(SQL_CLABEL_DATA *
62 void ctx_get_dimension_list(nd_uuid_t *host_uuid, void (*dict_cb)(SQL_DIMENSION_DATA *, void *), void *data);
63
64 int ctx_store_context(nd_uuid_t *host_uuid, VERSIONED_CONTEXT_DATA *context_data);
65 -
66 -void ctx_get_context_list_to_cleanup(nd_uuid_t *host_uuid, void (*cleanup_cb)(Pvoid_t context, void *data), void *data);
67 -void ctx_delete_metadata_cleanup_context(sqlite3_stmt **context_res, nd_uuid_t(*host_uuid), const char *context);
68 -
65 #define ctx_update_context(host_uuid, context_data) ctx_store_context(host_uuid, context_data)
66
67 int ctx_delete_context(nd_uuid_t *host_id, VERSIONED_CONTEXT_DATA *context_data);
src/database/sqlite/sqlite_metadata.c
+175 -4
@@ -95,6 +95,9 @@ const char *database_config[] = {
95 "CREATE TABLE IF NOT EXISTS aclk_queue (sequence_id INTEGER PRIMARY KEY, host_id blob, health_log_id INT, "
96 "unique_id INT, date_created INT, UNIQUE(host_id, health_log_id))",
97
98 + "CREATE TABLE IF NOT EXISTS ctx_metadata_cleanup (id INTEGER PRIMARY KEY, host_id BLOB, context TEXT NOT NULL, date_created INT NOT NULL, "
99 + "UNIQUE (host_id, context))",
100 +
101 NULL
102 };
103
@@ -195,6 +198,7 @@ enum metadata_opcode {
198 METADATA_DELETE_HOST_CHART_LABELS,
199 METADATA_ADD_HOST_AE,
200 METADATA_DEL_HOST_AE,
201 + METADATA_ADD_CTX_CLEANUP,
202 METADATA_MAINTENANCE,
203 METADATA_SYNC_SHUTDOWN,
204 METADATA_UNITTEST,
@@ -282,6 +286,110 @@ static inline void set_host_node_id(RRDHOST *host, nd_uuid_t *node_id)
286 stream_path_node_id_updated(host);
287 }
288
289 +struct host_ctx_cleanup_s {
290 + nd_uuid_t host_uuid;
291 + STRING *context;
292 +};
293 +
294 +#define CTX_DELETE_CONTEXT_META_CLEANUP_ITEM "DELETE FROM ctx_metadata_cleanup WHERE host_id = @host_id AND context = @context"
295 +
296 +static void ctx_delete_metadata_cleanup_context(sqlite3_stmt **res, nd_uuid_t *host_uuid, const char *context)
297 +{
298 +// char host_str[UUID_STR_LEN];
299 +// uuid_unparse_lower(*host_uuid, host_str);
300 +// nd_log_daemon(NDLP_INFO, "Will delete context %s for host %s because it was checked", context, host_str);
301 +// return;
302 +
303 + if (!*res) {
304 + if (!PREPARE_STATEMENT(db_meta, CTX_DELETE_CONTEXT_META_CLEANUP_ITEM, res))
305 + return;
306 + }
307 +
308 + int param = 0;
309 + SQLITE_BIND_FAIL(done, sqlite3_bind_blob(*res, ++param, host_uuid, sizeof(*host_uuid), SQLITE_STATIC));
310 + SQLITE_BIND_FAIL(done, sqlite3_bind_text(*res, ++param, context, -1, SQLITE_STATIC));
311 +
312 + param = 0;
313 + int rc = sqlite3_step_monitored(*res);
314 + if (rc != SQLITE_DONE)
315 + error_report("Failed to delete context check entry, rc = %d", rc);
316 +
317 +done:
318 + REPORT_BIND_FAIL(*res, param);
319 + SQLITE_RESET(*res);
320 +}
321 +
322 +#define CTX_GET_CONTEXT_META_CLEANUP_LIST "SELECT context FROM ctx_metadata_cleanup WHERE host_id = @host_id"
323 +
324 +static void ctx_get_context_list_to_cleanup(nd_uuid_t *host_uuid, void (*cleanup_cb)(Pvoid_t JudyL, void *data), void *data)
325 +{
326 + if (unlikely(!host_uuid))
327 + return;
328 +
329 + sqlite3_stmt *res = NULL;
330 +
331 + if (!PREPARE_STATEMENT(db_meta, CTX_GET_CONTEXT_META_CLEANUP_LIST, &res))
332 + return;
333 +
334 + int param = 0;
335 + SQLITE_BIND_FAIL(done, sqlite3_bind_blob(res, ++param, host_uuid, sizeof(*host_uuid), SQLITE_STATIC));
336 + param = 0;
337 +
338 + const char *context;
339 + Pvoid_t CTX_JudyL = NULL;
340 + Pvoid_t *Pvalue;
341 + while (sqlite3_step_monitored(res) == SQLITE_ROW) {
342 + context = (char *) sqlite3_column_text(res, 0);
343 + STRING *ctx = string_strdupz(context);
344 + Pvalue = JudyLIns(&CTX_JudyL, (Word_t) ctx, PJE0);
345 + if (*Pvalue)
346 + string_freez(ctx);
347 + else
348 + *(int *)Pvalue = 1;
349 + }
350 +
351 + if (CTX_JudyL) {
352 + cleanup_cb(CTX_JudyL, data);
353 +
354 + bool first = true;
355 + Word_t Index = 0;
356 + while ((Pvalue = JudyLFirstThenNext(CTX_JudyL, &Index, &first))) {
357 + STRING *ctx = (STRING *) Index;
358 + string_freez(ctx);
359 + }
360 + }
361 + (void)JudyLFreeArray(&CTX_JudyL, PJE0);
362 +
363 +done:
364 + REPORT_BIND_FAIL(res, param);
365 + SQLITE_FINALIZE(res);
366 +}
367 +
368 +#define SQL_SCHEDULE_HOST_CTX_CLEANUP \
369 + "INSERT INTO ctx_metadata_cleanup (host_id, context, date_created) " \
370 + "VALUES (@host_id, @context, UNIXEPOCH()) ON CONFLICT DO UPDATE SET date_created = excluded.date_created; END"
371 +
372 +// Schedule context cleanup for host
373 +static void sql_schedule_host_ctx_cleanup(sqlite3_stmt **res, nd_uuid_t *host_id, const char *context)
374 +{
375 + if (!*res) {
376 + if (!PREPARE_STATEMENT(db_meta, SQL_SCHEDULE_HOST_CTX_CLEANUP, res))
377 + return;
378 + }
379 +
380 + int param = 0;
381 + SQLITE_BIND_FAIL(done, sqlite3_bind_blob(*res, ++param, host_id, sizeof(*host_id), SQLITE_STATIC));
382 + SQLITE_BIND_FAIL(done, sqlite3_bind_text(*res, ++param, context, -1, SQLITE_STATIC));
383 +
384 + param = 0;
385 + int rc = execute_insert(*res);
386 + if (rc != SQLITE_DONE)
387 + error_report("Failed to host context check data, rc = %d", rc);
388 +done:
389 + REPORT_BIND_FAIL(*res, param);
390 + SQLITE_RESET(*res);
391 +}
392 +
393 #define SQL_SET_HOST_LABEL \
394 "INSERT INTO host_label (host_id, source_type, label_key, label_value, date_created) " \
395 "VALUES (@host_id, @source_type, @label_key, @label_value, UNIXEPOCH()) ON CONFLICT (host_id, label_key) " \
@@ -315,7 +423,6 @@ done:
423 return status;
424 }
425
318 -
426 #define SQL_UPDATE_NODE_ID "UPDATE node_instance SET node_id = @node_id WHERE host_id = @host_id"
427
428 int sql_update_node_id(nd_uuid_t *host_id, nd_uuid_t *node_id)
@@ -1600,6 +1707,8 @@ static bool clean_host_chart_dimensions(sqlite3_stmt **res, int64_t chart_row_id
1707 {
1708 struct metadata_wc *wc = &metasync_worker;
1709
1710 + bool can_continue = false;
1711 +
1712 if (!*res) {
1713 if (!PREPARE_STATEMENT(db_meta, SQL_SELECT_HOST_CTX_CHART_DIM_LIST, res))
1714 return false;
@@ -1610,8 +1719,7 @@ static bool clean_host_chart_dimensions(sqlite3_stmt **res, int64_t chart_row_id
1719
1720 sqlite3_stmt *dim_del_stmt = NULL;
1721
1613 - bool can_continue = true;
1614 -
1722 + can_continue = true;
1723 while (can_continue && sqlite3_step_monitored(*res) == SQLITE_ROW) {
1724 if (sqlite3_column_bytes(*res, 0) != sizeof(nd_uuid_t))
1725 continue;
@@ -1702,7 +1810,7 @@ void run_metadata_cleanup(struct metadata_wc *wc)
1810 time_t now = now_realtime_sec();
1811
1812 if (!next_context_list_cleanup)
1705 - next_context_list_cleanup = now + METADATA_MAINTENANCE_FIRST_CHECK;
1813 + next_context_list_cleanup = now + 5;
1814
1815 if (unlikely(metadata_flag_check(wc, METADATA_FLAG_SHUTDOWN)))
1816 return;
@@ -1739,6 +1847,7 @@ struct scan_metadata_payload {
1847 struct metadata_wc *wc;
1848 void *chart_label_cleanup;
1849 void *pending_alert_list;
1850 + void *pending_ctx_cleanup_list;
1851 BUFFER *work_buffer;
1852 uint32_t max_count;
1853 };
@@ -2071,6 +2180,40 @@ struct judy_list_t {
2180 Word_t count;
2181 };
2182
2183 +
2184 +static void store_ctx_cleanup_list(struct judy_list_t *pending_ctx_cleanup_list)
2185 +{
2186 + if (!pending_ctx_cleanup_list)
2187 + return;
2188 +
2189 + usec_t started_ut = now_monotonic_usec(); (void)started_ut;
2190 +
2191 + size_t entries = pending_ctx_cleanup_list->count;
2192 + Word_t Index = 0;
2193 + bool first = true;
2194 + Pvoid_t *PValue;
2195 + sqlite3_stmt *res = NULL;
2196 + while ((PValue = JudyLFirstThenNext(pending_ctx_cleanup_list->JudyL, &Index, &first))) {
2197 + if (!*PValue)
2198 + continue;
2199 +
2200 + struct host_ctx_cleanup_s *ctx_cleanup = *PValue;
2201 + sql_schedule_host_ctx_cleanup(&res, &ctx_cleanup->host_uuid, string2str(ctx_cleanup->context));
2202 + string_freez(ctx_cleanup->context);
2203 + freez(ctx_cleanup);
2204 + }
2205 + (void) JudyLFreeArray(&pending_ctx_cleanup_list->JudyL, PJE0);
2206 + freez(pending_ctx_cleanup_list);
2207 + SQLITE_FINALIZE(res);
2208 +
2209 + usec_t ended_ut = now_monotonic_usec(); (void)ended_ut;
2210 + nd_log_daemon(
2211 + NDLP_DEBUG,
2212 + "Stored %zu host context cleanup items in %0.2f ms",
2213 + entries,
2214 + (double)(ended_ut - started_ut) / USEC_PER_MS);
2215 +}
2216 +
2217 static void store_alert_transitions(struct judy_list_t *pending_alert_list)
2218 {
2219 if (!pending_alert_list)
@@ -2145,6 +2288,7 @@ static void start_metadata_hosts(uv_work_t *req)
2288 nd_log(NDLS_DAEMON, NDLP_DEBUG, "Checking all hosts started");
2289 usec_t started_ut = now_monotonic_usec(); (void)started_ut;
2290
2291 + store_ctx_cleanup_list((struct judy_list_t *)data->pending_ctx_cleanup_list);
2292 store_alert_transitions((struct judy_list_t *)data->pending_alert_list);
2293 do_chart_label_cleanup((struct judy_list_t *)data->chart_label_cleanup);
2294
@@ -2249,6 +2393,7 @@ static void metadata_event_loop(void *arg)
2393 worker_register_job_name(METADATA_DEL_DIMENSION, "delete dimension");
2394 worker_register_job_name(METADATA_STORE_CLAIM_ID, "add claim id");
2395 worker_register_job_name(METADATA_ADD_HOST_INFO, "add host info");
2396 + worker_register_job_name(METADATA_ADD_CTX_CLEANUP, "host ctx cleanup");
2397 worker_register_job_name(METADATA_MAINTENANCE, "maintenance");
2398
2399 int ret;
@@ -2298,6 +2443,7 @@ static void metadata_event_loop(void *arg)
2443 struct judy_list_t *cl_cleanup_data = NULL;
2444 Pvoid_t *PValue;
2445 struct judy_list_t *pending_ae_list = NULL;
2446 + struct judy_list_t *pending_ctx_cleanup_list = NULL;
2447
2448 while (shutdown == 0 || (wc->flags & METADATA_FLAG_PROCESSING)) {
2449 nd_uuid_t *uuid;
@@ -2344,6 +2490,15 @@ static void metadata_event_loop(void *arg)
2490 host = (RRDHOST *) cmd.param[0];
2491 store_host_and_system_info(host, NULL);
2492 break;
2493 +
2494 + case METADATA_ADD_CTX_CLEANUP:
2495 + if (!pending_ctx_cleanup_list)
2496 + pending_ctx_cleanup_list = callocz(1, sizeof(*pending_ctx_cleanup_list));
2497 +
2498 + PValue = JudyLIns(&pending_ctx_cleanup_list->JudyL, ++pending_ctx_cleanup_list->count, PJE0);
2499 + if (PValue)
2500 + *PValue = (void *)cmd.param[0];
2501 + break;
2502 case METADATA_SCAN_HOSTS:
2503 if (unlikely(metadata_flag_check(wc, METADATA_FLAG_PROCESSING)))
2504 break;
@@ -2356,9 +2511,11 @@ static void metadata_event_loop(void *arg)
2511 data->wc = wc;
2512 data->chart_label_cleanup = cl_cleanup_data;
2513 data->pending_alert_list = pending_ae_list;
2514 + data->pending_ctx_cleanup_list = pending_ctx_cleanup_list;
2515 data->work_buffer = work_buffer;
2516 cl_cleanup_data = NULL;
2517 pending_ae_list = NULL;
2518 + pending_ctx_cleanup_list = NULL;
2519
2520 if (unlikely(cmd.completion)) {
2521 data->max_count = 0; // 0 will process all pending updates
@@ -2373,6 +2530,7 @@ static void metadata_event_loop(void *arg)
2530 cmd.completion = wc->scan_complete;
2531 cl_cleanup_data = data->chart_label_cleanup;
2532 pending_ae_list = data->pending_alert_list;
2533 + pending_ctx_cleanup_list = data->pending_ctx_cleanup_list;
2534 freez(data);
2535 metadata_flag_clear(wc, METADATA_FLAG_PROCESSING);
2536 }
@@ -2616,6 +2774,19 @@ void metadata_delete_host_chart_labels(char *machine_guid)
2774 nd_log(NDLS_DAEMON, NDLP_DEBUG, "Queued command delete chart labels for host %s", machine_guid);
2775 }
2776
2777 +void metadata_queue_ctx_host_cleanup(nd_uuid_t *host_uuid, const char *context)
2778 +{
2779 + if (unlikely(!metasync_worker.loop))
2780 + return;
2781 +
2782 + struct host_ctx_cleanup_s *ctx_cleanup = mallocz(sizeof(*ctx_cleanup));
2783 +
2784 + uuid_copy(ctx_cleanup->host_uuid, *host_uuid);
2785 + ctx_cleanup->context = string_strdupz(context);
2786 +
2787 + queue_metadata_cmd(METADATA_ADD_CTX_CLEANUP, ctx_cleanup, NULL);
2788 +}
2789 +
2790 void metadata_queue_ae_save(RRDHOST *host, ALARM_ENTRY *ae)
2791 {
2792 if (unlikely(!metasync_worker.loop))
src/database/sqlite/sqlite_metadata.h
+1
@@ -72,6 +72,7 @@ void commit_alert_transitions(RRDHOST *host);
72
73 void metadata_sync_shutdown_background(void);
74 void metadata_sync_shutdown_background_wait(void);
75 +void metadata_queue_ctx_host_cleanup(nd_uuid_t *host_uuid, const char *context);
76
77 // UNIT TEST
78 int metadata_unittest(void);