| 1 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 2 | |
| 3 | #include "rrdcontext-internal.h" |
| 4 | |
| 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; |
| 9 | rrdlabels_add(ri->rrdlabels, sld->label_key, sld->label_value, sld->label_source); |
| 10 | } |
| 11 | |
| 12 | void load_instance_labels_on_demand(nd_uuid_t *uuid, void *data) { |
| 13 | ctx_get_label_list(uuid, rrdinstance_load_clabel, data); |
| 14 | } |
| 15 | |
| 16 | static void rrdinstance_load_dimension_callback(SQL_DIMENSION_DATA *sd, void *data) { |
| 17 | RRDHOST *host = data; |
| 18 | |
| 19 | UUIDMAP_ID id = uuidmap_create(sd->dim_id); |
| 20 | time_t min_first_time_t = LONG_MAX, max_last_time_t = 0; |
| 21 | get_metric_retention_by_id(host, id, &min_first_time_t, &max_last_time_t, NULL); |
| 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 | th_ignored_metrics++; |
| 31 | uuidmap_free(id); |
| 32 | return; |
| 33 | } |
| 34 | RRDCONTEXT *rc = rrdcontext_acquired_value(rca); |
| 35 | if(!rc) { |
| 36 | th_ignored_metrics++; |
| 37 | dictionary_acquired_item_release(host->rrdctx.contexts, (DICTIONARY_ITEM *)rca); |
| 38 | uuidmap_free(id); |
| 39 | return; |
| 40 | } |
| 41 | |
| 42 | RRDINSTANCE_ACQUIRED *ria = (RRDINSTANCE_ACQUIRED *)dictionary_get_and_acquire_item(rc->rrdinstances, sd->chart_id); |
| 43 | if(!ria) { |
| 44 | th_ignored_metrics++; |
| 45 | rrdcontext_release(rca); |
| 46 | uuidmap_free(id); |
| 47 | return; |
| 48 | } |
| 49 | RRDINSTANCE *ri = rrdinstance_acquired_value(ria); |
| 50 | if(!ri) { |
| 51 | th_ignored_metrics++; |
| 52 | dictionary_acquired_item_release(rc->rrdinstances, (DICTIONARY_ITEM *)ria); |
| 53 | rrdcontext_release(rca); |
| 54 | uuidmap_free(id); |
| 55 | return; |
| 56 | } |
| 57 | |
| 58 | RRDMETRIC trm = { |
| 59 | .uuid = id, |
| 60 | .id = string_strdupz(sd->id), |
| 61 | .name = string_strdupz(sd->name), |
| 62 | .flags = RRD_FLAG_ARCHIVED | RRD_FLAG_UPDATE_REASON_LOAD_SQL, // no need for atomic |
| 63 | .algorithm = (RRD_ALGORITHM)sd->algorithm, |
| 64 | }; |
| 65 | if(sd->hidden) trm.flags |= RRD_FLAG_HIDDEN; |
| 66 | |
| 67 | dictionary_set(ri->rrdmetrics, string2str(trm.id), &trm, sizeof(trm)); |
| 68 | |
| 69 | rrdinstance_release(ria); |
| 70 | rrdcontext_release(rca); |
| 71 | } |
| 72 | |
| 73 | static void rrdinstance_load_instance_callback(SQL_CHART_DATA *sc, void *data) { |
| 74 | RRDHOST *host = data; |
| 75 | |
| 76 | RRDCONTEXT tc = { |
| 77 | .id = string_strdupz(sc->context), |
| 78 | .title = string_strdupz(sc->title), |
| 79 | .units = string_strdupz(sc->units), |
| 80 | .family = string_strdupz(sc->family), |
| 81 | .priority = sc->priority, |
| 82 | .chart_type = sc->chart_type, |
| 83 | .flags = RRD_FLAG_ARCHIVED | RRD_FLAG_UPDATE_REASON_LOAD_SQL, // no need for atomics |
| 84 | .rrdhost = host, |
| 85 | }; |
| 86 | |
| 87 | RRDCONTEXT_ACQUIRED *rca = (RRDCONTEXT_ACQUIRED *)dictionary_set_and_acquire_item(host->rrdctx.contexts, string2str(tc.id), &tc, sizeof(tc)); |
| 88 | if(!rca) { |
| 89 | th_ignored_instances++; |
| 90 | string_freez(tc.id); |
| 91 | string_freez(tc.title); |
| 92 | string_freez(tc.units); |
| 93 | string_freez(tc.family); |
| 94 | return; |
| 95 | } |
| 96 | |
| 97 | RRDCONTEXT *rc = rrdcontext_acquired_value(rca); |
| 98 | if(!rc) { |
| 99 | th_ignored_instances++; |
| 100 | rrdcontext_release(rca); |
| 101 | return; |
| 102 | } |
| 103 | |
| 104 | RRDINSTANCE tri = { |
| 105 | .uuid = uuidmap_create(sc->chart_id), |
| 106 | .id = string_strdupz(sc->id), |
| 107 | .name = string_strdupz(sc->name), |
| 108 | .title = string_strdupz(sc->title), |
| 109 | .units = string_strdupz(sc->units), |
| 110 | .family = string_strdupz(sc->family), |
| 111 | .chart_type = sc->chart_type, |
| 112 | .priority = sc->priority, |
| 113 | .update_every_s = sc->update_every, |
| 114 | .flags = RRD_FLAG_ARCHIVED | RRD_FLAG_UPDATE_REASON_LOAD_SQL, // no need for atomics |
| 115 | }; |
| 116 | |
| 117 | RRDINSTANCE_ACQUIRED *ria = (RRDINSTANCE_ACQUIRED *)dictionary_set_and_acquire_item(rc->rrdinstances, sc->id, &tri, sizeof(tri)); |
| 118 | if(!ria) { |
| 119 | th_ignored_instances++; |
| 120 | uuidmap_free(tri.uuid); |
| 121 | string_freez(tri.id); |
| 122 | string_freez(tri.name); |
| 123 | string_freez(tri.title); |
| 124 | string_freez(tri.units); |
| 125 | string_freez(tri.family); |
| 126 | rrdcontext_release(rca); |
| 127 | return; |
| 128 | } |
| 129 | |
| 130 | rrdinstance_release(ria); |
| 131 | rrdcontext_release(rca); |
| 132 | } |
| 133 | |
| 134 | static void rrdcontext_load_context_callback(VERSIONED_CONTEXT_DATA *ctx_data, void *data) { |
| 135 | RRDHOST *host = data; |
| 136 | (void)host; |
| 137 | |
| 138 | RRDCONTEXT trc = { |
| 139 | .id = string_strdupz(ctx_data->id), |
| 140 | .flags = RRD_FLAG_ARCHIVED | RRD_FLAG_UPDATE_REASON_LOAD_SQL, // no need for atomics |
| 141 | |
| 142 | // no need to set more data here |
| 143 | // we only need the hub data |
| 144 | |
| 145 | .hub = *ctx_data, |
| 146 | }; |
| 147 | dictionary_set(host->rrdctx.contexts, string2str(trc.id), &trc, sizeof(trc)); |
| 148 | } |
| 149 | |
| 150 | void rrdhost_load_rrdcontext_data(RRDHOST *host) { |
| 151 | if(host->rrdctx.contexts) return; |
| 152 | |
| 153 | rrdhost_create_rrdcontexts(host); |
| 154 | if (host->rrd_memory_mode != RRD_DB_MODE_DBENGINE) |
| 155 | return; |
| 156 | |
| 157 | th_ignored_metrics = th_ignored_instances = th_zero_retention_metrics = 0; |
| 158 | |
| 159 | ctx_get_context_list(&host->host_id.uuid, rrdcontext_load_context_callback, host); |
| 160 | if (unlikely(exit_initiated_get())) |
| 161 | return; |
| 162 | |
| 163 | ctx_get_chart_list(&host->host_id.uuid, rrdinstance_load_instance_callback, host); |
| 164 | if (unlikely(exit_initiated_get())) |
| 165 | return; |
| 166 | |
| 167 | ctx_get_dimension_list(&host->host_id.uuid, rrdinstance_load_dimension_callback, host); |
| 168 | if (unlikely(exit_initiated_get())) |
| 169 | return; |
| 170 | |
| 171 | size_t ignored_metrics = th_ignored_metrics, ignored_instances = th_ignored_instances, zero_retention_metrics = th_zero_retention_metrics; |
| 172 | size_t loaded_metrics = 0, loaded_instances = 0, loaded_contexts = 0; |
| 173 | size_t loaded_and_deleted_instances = 0, loaded_and_deleted_contexts = 0; |
| 174 | |
| 175 | RRDCONTEXT *rc; |
| 176 | dfe_start_read(host->rrdctx.contexts, rc) { |
| 177 | if (unlikely(exit_initiated_get())) |
| 178 | break; |
| 179 | |
| 180 | size_t instances = 0; |
| 181 | |
| 182 | RRDINSTANCE *ri; |
| 183 | dfe_start_write(rc->rrdinstances, ri) { |
| 184 | size_t metrics = 0; |
| 185 | |
| 186 | RRDMETRIC *rm; |
| 187 | dfe_start_read(ri->rrdmetrics, rm) { |
| 188 | rrdmetric_trigger_updates(rm, __FUNCTION__ ); |
| 189 | loaded_metrics++; |
| 190 | metrics++; |
| 191 | } |
| 192 | dfe_done(rm); |
| 193 | dictionary_garbage_collect(ri->rrdmetrics); |
| 194 | |
| 195 | if(!metrics) { |
| 196 | dictionary_del(rc->rrdinstances, ri_dfe.name); |
| 197 | loaded_and_deleted_instances++; |
| 198 | } |
| 199 | else { |
| 200 | rrdinstance_trigger_updates(ri, __FUNCTION__); |
| 201 | loaded_instances++; |
| 202 | instances++; |
| 203 | } |
| 204 | } |
| 205 | dfe_done(ri); |
| 206 | dictionary_garbage_collect(rc->rrdinstances); |
| 207 | |
| 208 | if(!instances) { |
| 209 | metadata_queue_ctx_host_cleanup(&host->host_id.uuid, rc_dfe.name); |
| 210 | rrdcontext_delete_after_loading(host, rc); |
| 211 | loaded_and_deleted_contexts++; |
| 212 | } |
| 213 | else { |
| 214 | rrdcontext_trigger_updates(rc, __FUNCTION__); |
| 215 | rrdcontext_initial_processing_after_loading(rc); |
| 216 | loaded_contexts++; |
| 217 | } |
| 218 | } |
| 219 | dfe_done(rc); |
| 220 | dictionary_garbage_collect(host->rrdctx.contexts); |
| 221 | rrdcontext_garbage_collect_single_host(host, false); |
| 222 | |
| 223 | nd_log(NDLS_DAEMON, ignored_metrics || ignored_instances ? NDLP_WARNING : NDLP_NOTICE, |
| 224 | "RRDCONTEXT: metadata for node '%s': " |
| 225 | "contexts %zu (deleted %zu), " |
| 226 | "instances %zu (deleted %zu, ignored %zu), and " |
| 227 | "metrics %zu (ignored %zu, zero retention %zu)", |
| 228 | rrdhost_hostname(host), |
| 229 | loaded_contexts, loaded_and_deleted_contexts, |
| 230 | loaded_instances, loaded_and_deleted_instances, ignored_instances, |
| 231 | loaded_metrics, ignored_metrics, zero_retention_metrics); |
| 232 | } |