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);