summaryrefslogtreecommitdiffstats
path: root/database/rrddimvar.c
diff options
context:
space:
mode:
Diffstat (limited to 'database/rrddimvar.c')
-rw-r--r--database/rrddimvar.c273
1 files changed, 273 insertions, 0 deletions
diff --git a/database/rrddimvar.c b/database/rrddimvar.c
new file mode 100644
index 00000000..5035d70a
--- /dev/null
+++ b/database/rrddimvar.c
@@ -0,0 +1,273 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "rrd.h"
+
+typedef struct rrddimvar {
+ struct rrddim *rrddim;
+
+ STRING *prefix;
+ STRING *suffix;
+ void *value;
+
+ const RRDVAR_ACQUIRED *rrdvar_local_dim_id;
+ const RRDVAR_ACQUIRED *rrdvar_local_dim_name;
+
+ const RRDVAR_ACQUIRED *rrdvar_family_id;
+ const RRDVAR_ACQUIRED *rrdvar_family_name;
+ const RRDVAR_ACQUIRED *rrdvar_family_context_dim_id;
+ const RRDVAR_ACQUIRED *rrdvar_family_context_dim_name;
+
+ const RRDVAR_ACQUIRED *rrdvar_host_chart_id_dim_id;
+ const RRDVAR_ACQUIRED *rrdvar_host_chart_id_dim_name;
+ const RRDVAR_ACQUIRED *rrdvar_host_chart_name_dim_id;
+ const RRDVAR_ACQUIRED *rrdvar_host_chart_name_dim_name;
+
+ RRDVAR_FLAGS flags:24;
+ RRDVAR_TYPE type:8;
+} RRDDIMVAR;
+
+// ----------------------------------------------------------------------------
+// RRDDIMVAR management
+// DIMENSION VARIABLES
+
+#define RRDDIMVAR_ID_MAX 1024
+
+static inline void rrddimvar_free_variables_unsafe(RRDDIMVAR *rs) {
+ RRDDIM *rd = rs->rrddim;
+ RRDSET *st = rd->rrdset;
+ RRDHOST *host = st->rrdhost;
+
+ // CHART VARIABLES FOR THIS DIMENSION
+
+ if(st->rrdvars) {
+ rrdvar_release_and_del(st->rrdvars, rs->rrdvar_local_dim_id);
+ rs->rrdvar_local_dim_id = NULL;
+
+ rrdvar_release_and_del(st->rrdvars, rs->rrdvar_local_dim_name);
+ rs->rrdvar_local_dim_name = NULL;
+ }
+
+ // FAMILY VARIABLES FOR THIS DIMENSION
+
+ if(st->rrdfamily) {
+ rrdvar_release_and_del(rrdfamily_rrdvars_dict(st->rrdfamily), rs->rrdvar_family_id);
+ rs->rrdvar_family_id = NULL;
+
+ rrdvar_release_and_del(rrdfamily_rrdvars_dict(st->rrdfamily), rs->rrdvar_family_name);
+ rs->rrdvar_family_name = NULL;
+
+ rrdvar_release_and_del(rrdfamily_rrdvars_dict(st->rrdfamily), rs->rrdvar_family_context_dim_id);
+ rs->rrdvar_family_context_dim_id = NULL;
+
+ rrdvar_release_and_del(rrdfamily_rrdvars_dict(st->rrdfamily), rs->rrdvar_family_context_dim_name);
+ rs->rrdvar_family_context_dim_name = NULL;
+ }
+
+ // HOST VARIABLES FOR THIS DIMENSION
+
+ if(host->rrdvars && host->health.health_enabled) {
+ rrdvar_release_and_del(host->rrdvars, rs->rrdvar_host_chart_id_dim_id);
+ rs->rrdvar_host_chart_id_dim_id = NULL;
+
+ rrdvar_release_and_del(host->rrdvars, rs->rrdvar_host_chart_id_dim_name);
+ rs->rrdvar_host_chart_id_dim_name = NULL;
+
+ rrdvar_release_and_del(host->rrdvars, rs->rrdvar_host_chart_name_dim_id);
+ rs->rrdvar_host_chart_name_dim_id = NULL;
+
+ rrdvar_release_and_del(host->rrdvars, rs->rrdvar_host_chart_name_dim_name);
+ rs->rrdvar_host_chart_name_dim_name = NULL;
+ }
+}
+
+static inline void rrddimvar_update_variables_unsafe(RRDDIMVAR *rs) {
+ rrddimvar_free_variables_unsafe(rs);
+
+ RRDDIM *rd = rs->rrddim;
+ RRDSET *st = rd->rrdset;
+ RRDHOST *host = st->rrdhost;
+
+ char buffer[RRDDIMVAR_ID_MAX + 1];
+
+ // KEYS
+
+ snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s%s%s", string2str(rs->prefix), rrddim_id(rd), string2str(rs->suffix));
+ STRING *key_dim_id = string_strdupz(buffer);
+
+ snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s%s%s", string2str(rs->prefix), rrddim_name(rd), string2str(rs->suffix));
+ STRING *key_dim_name = string_strdupz(buffer);
+
+ snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", rrdset_id(st), string2str(key_dim_id));
+ STRING *key_chart_id_dim_id = string_strdupz(buffer);
+
+ snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", rrdset_id(st), string2str(key_dim_name));
+ STRING *key_chart_id_dim_name = string_strdupz(buffer);
+
+ snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", rrdset_context(st), string2str(key_dim_id));
+ STRING *key_context_dim_id = string_strdupz(buffer);
+
+ snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", rrdset_context(st), string2str(key_dim_name));
+ STRING *key_context_dim_name = string_strdupz(buffer);
+
+ snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", rrdset_name(st), string2str(key_dim_id));
+ STRING *key_chart_name_dim_id = string_strdupz(buffer);
+
+ snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", rrdset_name(st), string2str(key_dim_name));
+ STRING *key_chart_name_dim_name = string_strdupz(buffer);
+
+ // CHART VARIABLES FOR THIS DIMENSION
+ // -----------------------------------
+ //
+ // dimensions are available as:
+ // - $id
+ // - $name
+
+ if(st->rrdvars) {
+ rs->rrdvar_local_dim_id = rrdvar_add_and_acquire("local", st->rrdvars, key_dim_id, rs->type, RRDVAR_FLAG_NONE, rs->value);
+ rs->rrdvar_local_dim_name = rrdvar_add_and_acquire("local", st->rrdvars, key_dim_name, rs->type, RRDVAR_FLAG_NONE, rs->value);
+ }
+
+ // FAMILY VARIABLES FOR THIS DIMENSION
+ // -----------------------------------
+ //
+ // dimensions are available as:
+ // - $id (only the first, when multiple overlap)
+ // - $name (only the first, when multiple overlap)
+ // - $chart-context.id
+ // - $chart-context.name
+
+ if(st->rrdfamily) {
+ rs->rrdvar_family_id = rrdvar_add_and_acquire("family", rrdfamily_rrdvars_dict(st->rrdfamily), key_dim_id, rs->type, RRDVAR_FLAG_NONE, rs->value);
+ rs->rrdvar_family_name = rrdvar_add_and_acquire("family", rrdfamily_rrdvars_dict(st->rrdfamily), key_dim_name, rs->type, RRDVAR_FLAG_NONE, rs->value);
+ rs->rrdvar_family_context_dim_id = rrdvar_add_and_acquire("family", rrdfamily_rrdvars_dict(st->rrdfamily), key_context_dim_id, rs->type, RRDVAR_FLAG_NONE, rs->value);
+ rs->rrdvar_family_context_dim_name = rrdvar_add_and_acquire("family", rrdfamily_rrdvars_dict(st->rrdfamily), key_context_dim_name, rs->type, RRDVAR_FLAG_NONE, rs->value);
+ }
+
+ // HOST VARIABLES FOR THIS DIMENSION
+ // -----------------------------------
+ //
+ // dimensions are available as:
+ // - $chart-id.id
+ // - $chart-id.name
+ // - $chart-name.id
+ // - $chart-name.name
+
+ if(host->rrdvars && host->health.health_enabled) {
+ rs->rrdvar_host_chart_id_dim_id = rrdvar_add_and_acquire("host", host->rrdvars, key_chart_id_dim_id, rs->type, RRDVAR_FLAG_NONE, rs->value);
+ rs->rrdvar_host_chart_id_dim_name = rrdvar_add_and_acquire("host", host->rrdvars, key_chart_id_dim_name, rs->type, RRDVAR_FLAG_NONE, rs->value);
+ rs->rrdvar_host_chart_name_dim_id = rrdvar_add_and_acquire("host", host->rrdvars, key_chart_name_dim_id, rs->type, RRDVAR_FLAG_NONE, rs->value);
+ rs->rrdvar_host_chart_name_dim_name = rrdvar_add_and_acquire("host", host->rrdvars, key_chart_name_dim_name, rs->type, RRDVAR_FLAG_NONE, rs->value);
+ }
+
+ // free the keys
+
+ string_freez(key_dim_id);
+ string_freez(key_dim_name);
+ string_freez(key_chart_id_dim_id);
+ string_freez(key_chart_id_dim_name);
+ string_freez(key_context_dim_id);
+ string_freez(key_context_dim_name);
+ string_freez(key_chart_name_dim_id);
+ string_freez(key_chart_name_dim_name);
+}
+
+struct rrddimvar_constructor {
+ RRDDIM *rrddim;
+ const char *prefix;
+ const char *suffix;
+ void *value;
+ RRDVAR_FLAGS flags :16;
+ RRDVAR_TYPE type:8;
+};
+
+static void rrddimvar_insert_callback(const DICTIONARY_ITEM *item __maybe_unused, void *rrddimvar, void *constructor_data) {
+ RRDDIMVAR *rs = rrddimvar;
+ struct rrddimvar_constructor *ctr = constructor_data;
+
+ if(!ctr->prefix) ctr->prefix = "";
+ if(!ctr->suffix) ctr->suffix = "";
+
+ rs->prefix = string_strdupz(ctr->prefix);
+ rs->suffix = string_strdupz(ctr->suffix);
+
+ rs->type = ctr->type;
+ rs->value = ctr->value;
+ rs->flags = ctr->flags;
+ rs->rrddim = ctr->rrddim;
+
+ rrddimvar_update_variables_unsafe(rs);
+}
+
+static bool rrddimvar_conflict_callback(const DICTIONARY_ITEM *item __maybe_unused, void *rrddimvar, void *new_rrddimvar __maybe_unused, void *constructor_data __maybe_unused) {
+ RRDDIMVAR *rs = rrddimvar;
+ rrddimvar_update_variables_unsafe(rs);
+
+ return true;
+}
+
+static void rrddimvar_delete_callback(const DICTIONARY_ITEM *item __maybe_unused, void *rrddimvar, void *rrdset __maybe_unused) {
+ RRDDIMVAR *rs = rrddimvar;
+ rrddimvar_free_variables_unsafe(rs);
+ string_freez(rs->prefix);
+ string_freez(rs->suffix);
+}
+
+void rrddimvar_index_init(RRDSET *st) {
+ if(!st->rrddimvar_root_index) {
+ st->rrddimvar_root_index = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE,
+ &dictionary_stats_category_rrdhealth, sizeof(RRDDIMVAR));
+
+ dictionary_register_insert_callback(st->rrddimvar_root_index, rrddimvar_insert_callback, NULL);
+ dictionary_register_conflict_callback(st->rrddimvar_root_index, rrddimvar_conflict_callback, NULL);
+ dictionary_register_delete_callback(st->rrddimvar_root_index, rrddimvar_delete_callback, st);
+ }
+}
+
+void rrddimvar_index_destroy(RRDSET *st) {
+ dictionary_destroy(st->rrddimvar_root_index);
+ st->rrddimvar_root_index = NULL;
+}
+
+void rrddimvar_add_and_leave_released(RRDDIM *rd, RRDVAR_TYPE type, const char *prefix, const char *suffix, void *value, RRDVAR_FLAGS flags) {
+ if(!prefix) prefix = "";
+ if(!suffix) suffix = "";
+
+ char key[RRDDIMVAR_ID_MAX + 1];
+ size_t key_len = snprintfz(key, RRDDIMVAR_ID_MAX, "%s_%s_%s", prefix, rrddim_id(rd), suffix);
+
+ struct rrddimvar_constructor tmp = {
+ .suffix = suffix,
+ .prefix = prefix,
+ .type = type,
+ .flags = flags,
+ .value = value,
+ .rrddim = rd
+ };
+ dictionary_set_advanced(rd->rrdset->rrddimvar_root_index, key, (ssize_t)(key_len + 1), NULL, sizeof(RRDDIMVAR), &tmp);
+}
+
+void rrddimvar_rename_all(RRDDIM *rd) {
+ RRDSET *st = rd->rrdset;
+
+ netdata_log_debug(D_VARIABLES, "RRDDIMVAR rename for chart id '%s' name '%s', dimension id '%s', name '%s'", rrdset_id(st), rrdset_name(st), rrddim_id(rd), rrddim_name(rd));
+
+ RRDDIMVAR *rs;
+ dfe_start_write(st->rrddimvar_root_index, rs) {
+ if(unlikely(rs->rrddim == rd))
+ rrddimvar_update_variables_unsafe(rs);
+ }
+ dfe_done(rs);
+}
+
+void rrddimvar_delete_all(RRDDIM *rd) {
+ RRDSET *st = rd->rrdset;
+
+ netdata_log_debug(D_VARIABLES, "RRDDIMVAR delete for chart id '%s' name '%s', dimension id '%s', name '%s'", rrdset_id(st), rrdset_name(st), rrddim_id(rd), rrddim_name(rd));
+
+ RRDDIMVAR *rs;
+ dfe_start_write(st->rrddimvar_root_index, rs) {
+ if(unlikely(rs->rrddim == rd))
+ dictionary_del(st->rrddimvar_root_index, rs_dfe.name);
+ }
+ dfe_done(rs);
+}