@cryptotaxi247 / netdata-1 / commits / 24006ed5c

Reduce label memory (#15255)

Stelios Fragkakis committed Sep 1, 2023 at 15:37 UTC 24006ed5c19cf7c398cf8a76e7bdce1f60c7e5a4
34 files changed +588 -392
CMakeLists.txt
+1
@@ -741,6 +741,7 @@ set(RRD_PLUGIN_FILES
741 database/rrdfunctions.h
742 database/rrdhost.c
743 database/rrdlabels.c
744 + database/rrdlabels.h
745 database/rrd.c
746 database/rrd.h
747 database/rrdset.c
Makefile.am
+1
@@ -473,6 +473,7 @@ RRD_PLUGIN_FILES = \
473 database/rrdfamily.c \
474 database/rrdhost.c \
475 database/rrdlabels.c \
476 + database/rrdlabels.h \
477 database/rrd.c \
478 database/rrd.h \
479 database/rrdset.c \
aclk/aclk.c
+1 -1
@@ -1292,7 +1292,7 @@ char *aclk_state_json(void)
1292 }
1293
1294 void add_aclk_host_labels(void) {
1295 - DICTIONARY *labels = localhost->rrdlabels;
1295 + RRDLABELS *labels = localhost->rrdlabels;
1296
1297 #ifdef ENABLE_ACLK
1298 rrdlabels_add(labels, "_aclk_available", "true", RRDLABEL_SRC_AUTO|RRDLABEL_SRC_ACLK);
aclk/schema-wrappers/node_info.h
+1 -1
@@ -39,7 +39,7 @@ struct aclk_node_info {
39 const char *custom_info;
40 const char *machine_guid;
41
42 - DICTIONARY *host_labels_ptr;
42 + RRDLABELS *host_labels_ptr;
43 struct machine_learning_info ml_info;
44 };
45
aclk/schema-wrappers/schema_wrapper_utils.cc
+2 -2
@@ -14,8 +14,8 @@ void set_timeval_from_google_timestamp(const google::protobuf::Timestamp &ts, st
14 tv->tv_usec = ts.nanos()/1000;
15 }
16
17 -int label_add_to_map_callback(const char *name, const char *value, RRDLABEL_SRC ls, void *data) {
18 - (void)ls;
17 +int label_add_to_map_callback(const char *name, const char *value, RRDLABEL_SRC ls __maybe_unused, void *data)
18 +{
19 auto map = (google::protobuf::Map<std::string, std::string> *)data;
20 map->insert({name, value});
21 return 1;
collectors/cgroups.plugin/sys_fs_cgroup.c
+4 -5
@@ -806,7 +806,7 @@ struct cgroup {
806
807 char *chart_title;
808
809 - DICTIONARY *chart_labels;
809 + RRDLABELS *chart_labels;
810
811 int container_orchestrator;
812
@@ -1781,14 +1781,14 @@ static inline void substitute_dots_in_id(char *s) {
1781 // ----------------------------------------------------------------------------
1782 // parse k8s labels
1783
1784 -char *cgroup_parse_resolved_name_and_labels(DICTIONARY *labels, char *data) {
1784 +char *cgroup_parse_resolved_name_and_labels(RRDLABELS *labels, char *data) {
1785 // the first word, up to the first space is the name
1786 char *name = strsep_skip_consecutive_separators(&data, " ");
1787
1788 // the rest are key=value pairs separated by comma
1789 while(data) {
1790 char *pair = strsep_skip_consecutive_separators(&data, ",");
1791 - rrdlabels_add_pair(labels, pair, RRDLABEL_SRC_AUTO| RRDLABEL_SRC_K8S);
1791 + rrdlabels_add_pair(labels, pair, RRDLABEL_SRC_AUTO | RRDLABEL_SRC_K8S);
1792 }
1793
1794 return name;
@@ -2745,9 +2745,8 @@ static inline void discovery_process_cgroup(struct cgroup *cg) {
2745
2746 if (!k8s_is_kubepod(cg)) {
2747 rrdlabels_add(cg->chart_labels, "cgroup_name", cg->chart_id, RRDLABEL_SRC_AUTO);
2748 - if (!dictionary_get(cg->chart_labels, "image")) {
2748 + if (!rrdlabels_exist(cg->chart_labels, "image"))
2749 rrdlabels_add(cg->chart_labels, "image", "", RRDLABEL_SRC_AUTO);
2750 - }
2750 }
2751
2752 worker_is_busy(WORKER_DISCOVERY_PROCESS_NETWORK);
collectors/cgroups.plugin/sys_fs_cgroup.h
+1 -1
@@ -39,6 +39,6 @@ typedef struct netdata_ebpf_cgroup_shm {
39
40 #include "../proc.plugin/plugin_proc.h"
41
42 -char *cgroup_parse_resolved_name_and_labels(DICTIONARY *labels, char *data);
42 +char *cgroup_parse_resolved_name_and_labels(RRDLABELS *labels, char *data);
43
44 #endif //NETDATA_SYS_FS_CGROUP_H
collectors/cgroups.plugin/tests/test_cgroups_plugin.c
+2 -3
@@ -20,13 +20,12 @@ struct k8s_test_data {
20 int i;
21 };
22
23 -static int read_label_callback(const char *name, const char *value, RRDLABEL_SRC ls, void *data)
23 +static int read_label_callback(const char *name, const char *value, void *data)
24 {
25 struct k8s_test_data *test_data = (struct k8s_test_data *)data;
26
27 test_data->result_key[test_data->i] = name;
28 test_data->result_value[test_data->i] = value;
29 - test_data->result_ls[test_data->i] = ls;
29
30 test_data->i++;
31
@@ -37,7 +36,7 @@ static void test_cgroup_parse_resolved_name(void **state)
36 {
37 UNUSED(state);
38
40 - DICTIONARY *labels = rrdlabels_create();
39 + RRDLABELS *labels = rrdlabels_create();
40
41 struct k8s_test_data test_data[] = {
42 // One label
collectors/diskspace.plugin/plugin_diskspace.c
+1 -1
@@ -42,7 +42,7 @@ struct mount_point_metadata {
42 int updated;
43 int slow;
44
45 - DICTIONARY *chart_labels;
45 + RRDLABELS *chart_labels;
46
47 size_t collected; // the number of times this has been collected
48
collectors/plugins.d/pluginsd_parser.c
+7 -7
@@ -353,7 +353,7 @@ static inline PARSER_RC pluginsd_end(char **words, size_t num_words, PARSER *par
353
354 static void pluginsd_host_define_cleanup(PARSER *parser) {
355 string_freez(parser->user.host_define.hostname);
356 - dictionary_destroy(parser->user.host_define.rrdlabels);
356 + rrdlabels_destroy(parser->user.host_define.rrdlabels);
357
358 parser->user.host_define.hostname = NULL;
359 parser->user.host_define.rrdlabels = NULL;
@@ -390,17 +390,17 @@ static inline PARSER_RC pluginsd_host_define(char **words, size_t num_words, PAR
390 return PARSER_RC_OK;
391 }
392
393 -static inline PARSER_RC pluginsd_host_dictionary(char **words, size_t num_words, PARSER *parser, DICTIONARY *dict, const char *keyword) {
393 +static inline PARSER_RC pluginsd_host_dictionary(char **words, size_t num_words, PARSER *parser, RRDLABELS *labels, const char *keyword) {
394 char *name = get_word(words, num_words, 1);
395 char *value = get_word(words, num_words, 2);
396
397 if(!name || !*name || !value)
398 return PLUGINSD_DISABLE_PLUGIN(parser, keyword, "missing parameters");
399
400 - if(!parser->user.host_define.parsing_host || !dict)
400 + if(!parser->user.host_define.parsing_host || !labels)
401 return PLUGINSD_DISABLE_PLUGIN(parser, keyword, "host is not defined, send " PLUGINSD_KEYWORD_HOST_DEFINE " before this");
402
403 - rrdlabels_add(dict, name, value, RRDLABEL_SRC_CONFIG);
403 + rrdlabels_add(labels, name, value, RRDLABEL_SRC_CONFIG);
404
405 return PARSER_RC_OK;
406 }
@@ -776,7 +776,7 @@ static void inflight_functions_insert_callback(const DICTIONARY_ITEM *item, void
776
777 if (!pf->payload)
778 return;
779 -
779 +
780 // send the payload to the plugin
781 ret = send_to_plugin(pf->payload, parser);
782
@@ -2097,7 +2097,7 @@ static inline PARSER_RC pluginsd_register_module(char **words __maybe_unused, si
2097 struct configurable_plugin *plug_cfg = parser->user.cd->configuration;
2098 if (unlikely(plug_cfg == NULL))
2099 return PLUGINSD_DISABLE_PLUGIN(parser, PLUGINSD_KEYWORD_DYNCFG_REGISTER_MODULE, "you have to enable dynamic configuration first using " PLUGINSD_KEYWORD_DYNCFG_ENABLE);
2100 -
2100 +
2101 if (unlikely(num_words != 3))
2102 return PLUGINSD_DISABLE_PLUGIN(parser, PLUGINSD_KEYWORD_DYNCFG_REGISTER_MODULE, "expected 2 parameters module_name followed by module_type");
2103
@@ -2452,7 +2452,7 @@ PARSER_RC parser_execute(PARSER *parser, PARSER_KEYWORD *keyword, char **words,
2452
2453 case 101:
2454 return pluginsd_register_plugin(words, num_words, parser);
2455 -
2455 +
2456 case 102:
2457 return pluginsd_register_module(words, num_words, parser);
2458
collectors/plugins.d/pluginsd_parser.h
+3 -3
@@ -43,8 +43,8 @@ typedef struct parser_user_object {
43 void *opaque;
44 struct plugind *cd;
45 int trust_durations;
46 - DICTIONARY *new_host_labels;
47 - DICTIONARY *chart_rrdlabels_linked_temporarily;
46 + RRDLABELS *new_host_labels;
47 + RRDLABELS *chart_rrdlabels_linked_temporarily;
48 size_t data_collections_count;
49 int enabled;
50
@@ -55,7 +55,7 @@ typedef struct parser_user_object {
55 uuid_t machine_guid;
56 char machine_guid_str[UUID_STR_LEN];
57 STRING *hostname;
58 - DICTIONARY *rrdlabels;
58 + RRDLABELS *rrdlabels;
59 } host_define;
60
61 struct parser_user_object_replay {
collectors/proc.plugin/plugin_proc.h
+1 -1
@@ -58,7 +58,7 @@ void netdev_rename_device_add(
58 const char *host_device,
59 const char *container_device,
60 const char *container_name,
61 - DICTIONARY *labels,
61 + RRDLABELS *labels,
62 const char *ctx_prefix);
63
64 void netdev_rename_device_del(const char *host_device);
collectors/proc.plugin/proc_net_dev.c
+3 -3
@@ -123,7 +123,7 @@ static struct netdev {
123
124 const char *chart_family;
125
126 - DICTIONARY *chart_labels;
126 + RRDLABELS *chart_labels;
127
128 int flipped;
129 unsigned long priority;
@@ -348,7 +348,7 @@ static struct netdev_rename {
348 const char *container_name;
349 const char *ctx_prefix;
350
351 - DICTIONARY *chart_labels;
351 + RRDLABELS *chart_labels;
352
353 int processed;
354
@@ -373,7 +373,7 @@ void netdev_rename_device_add(
373 const char *host_device,
374 const char *container_device,
375 const char *container_name,
376 - DICTIONARY *labels,
376 + RRDLABELS *labels,
377 const char *ctx_prefix)
378 {
379 netdata_mutex_lock(&netdev_rename_mutex);
collectors/proc.plugin/sys_devices_system_edac_mc.c
+6 -6
@@ -265,22 +265,22 @@ int do_proc_sys_devices_system_edac_mc(int update_every, usec_t dt __maybe_unuse
265
266 char buffer[1024 + 1];
267
268 - if(read_edac_mc_rank_file(m->name, d->name, "dimm_dev_type", buffer, 1024))
268 + if (read_edac_mc_rank_file(m->name, d->name, "dimm_dev_type", buffer, 1024))
269 rrdlabels_add(d->st->rrdlabels, "dimm_dev_type", buffer, RRDLABEL_SRC_AUTO);
270
271 - if(read_edac_mc_rank_file(m->name, d->name, "dimm_edac_mode", buffer, 1024))
271 + if (read_edac_mc_rank_file(m->name, d->name, "dimm_edac_mode", buffer, 1024))
272 rrdlabels_add(d->st->rrdlabels, "dimm_edac_mode", buffer, RRDLABEL_SRC_AUTO);
273
274 - if(read_edac_mc_rank_file(m->name, d->name, "dimm_label", buffer, 1024))
274 + if (read_edac_mc_rank_file(m->name, d->name, "dimm_label", buffer, 1024))
275 rrdlabels_add(d->st->rrdlabels, "dimm_label", buffer, RRDLABEL_SRC_AUTO);
276
277 - if(read_edac_mc_rank_file(m->name, d->name, "dimm_location", buffer, 1024))
277 + if (read_edac_mc_rank_file(m->name, d->name, "dimm_location", buffer, 1024))
278 rrdlabels_add(d->st->rrdlabels, "dimm_location", buffer, RRDLABEL_SRC_AUTO);
279
280 - if(read_edac_mc_rank_file(m->name, d->name, "dimm_mem_type", buffer, 1024))
280 + if (read_edac_mc_rank_file(m->name, d->name, "dimm_mem_type", buffer, 1024))
281 rrdlabels_add(d->st->rrdlabels, "dimm_mem_type", buffer, RRDLABEL_SRC_AUTO);
282
283 - if(read_edac_mc_rank_file(m->name, d->name, "size", buffer, 1024))
283 + if (read_edac_mc_rank_file(m->name, d->name, "size", buffer, 1024))
284 rrdlabels_add(d->st->rrdlabels, "size", buffer, RRDLABEL_SRC_AUTO);
285
286 d->ce.rd = rrddim_add(d->st, "correctable", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
database/contexts/api_v1.c
+1 -1
@@ -213,7 +213,7 @@ static inline int rrdinstance_to_json_callback(const DICTIONARY_ITEM *item, void
213 buffer_json_array_close(wb);
214 }
215
216 - if(options & RRDCONTEXT_OPTION_SHOW_LABELS && ri->rrdlabels && dictionary_entries(ri->rrdlabels)) {
216 + if(options & RRDCONTEXT_OPTION_SHOW_LABELS && ri->rrdlabels && rrdlabels_entries(ri->rrdlabels)) {
217 buffer_json_member_add_object(wb, "labels");
218 rrdlabels_to_buffer_json_members(ri->rrdlabels, wb);
219 buffer_json_object_close(wb);
database/contexts/api_v2.c
+1 -1
@@ -418,7 +418,7 @@ static FTS_MATCH rrdcontext_to_json_v2_full_text_search(struct rrdcontext_to_jso
418 dfe_done(rm);
419
420 size_t label_searches = 0;
421 - if(unlikely(ri->rrdlabels && dictionary_entries(ri->rrdlabels) &&
421 + if(unlikely(ri->rrdlabels && rrdlabels_entries(ri->rrdlabels) &&
422 rrdlabels_match_simple_pattern_parsed(ri->rrdlabels, q, ':', &label_searches))) {
423 ctl->q.fts.searches += label_searches;
424 ctl->q.fts.char_searches += label_searches;
database/contexts/instance.c
+3 -3
@@ -35,7 +35,7 @@ inline STRING *rrdinstance_acquired_units_dup(RRDINSTANCE_ACQUIRED *ria) {
35 return string_dup(ri->units);
36 }
37
38 -inline DICTIONARY *rrdinstance_acquired_labels(RRDINSTANCE_ACQUIRED *ria) {
38 +inline RRDLABELS *rrdinstance_acquired_labels(RRDINSTANCE_ACQUIRED *ria) {
39 RRDINSTANCE *ri = rrdinstance_acquired_value(ria);
40 return ri->rrdlabels;
41 }
@@ -68,7 +68,7 @@ inline time_t rrdinstance_acquired_update_every(RRDINSTANCE_ACQUIRED *ria) {
68 static void rrdinstance_free(RRDINSTANCE *ri) {
69
70 if(rrd_flag_check(ri, RRD_FLAG_OWN_LABELS))
71 - dictionary_destroy(ri->rrdlabels);
71 + rrdlabels_destroy(ri->rrdlabels);
72
73 rrdmetrics_destroy_from_rrdinstance(ri);
74 string_freez(ri->id);
@@ -211,7 +211,7 @@ static bool rrdinstance_conflict_callback(const DICTIONARY_ITEM *item __maybe_un
211 ri->rrdset = ri_new->rrdset;
212
213 if(ri->rrdset && rrd_flag_check(ri, RRD_FLAG_OWN_LABELS)) {
214 - DICTIONARY *old = ri->rrdlabels;
214 + RRDLABELS *old = ri->rrdlabels;
215 ri->rrdlabels = ri->rrdset->rrdlabels;
216 rrd_flag_clear(ri, RRD_FLAG_OWN_LABELS);
217 rrdlabels_destroy(old);
database/contexts/internal.h
+1 -1
@@ -230,7 +230,7 @@ typedef struct rrdinstance {
230 time_t update_every_s; // data collection frequency
231 RRDSET *rrdset; // pointer to RRDSET when collected, or NULL
232
233 - DICTIONARY *rrdlabels; // linked to RRDSET->chart_labels or own version
233 + RRDLABELS *rrdlabels; // linked to RRDSET->chart_labels or own version
234
235 struct rrdcontext *rc;
236 DICTIONARY *rrdmetrics;
database/contexts/rrdcontext.h
+1 -1
@@ -40,7 +40,7 @@ const char *rrdinstance_acquired_name(RRDINSTANCE_ACQUIRED *ria);
40 bool rrdinstance_acquired_has_name(RRDINSTANCE_ACQUIRED *ria);
41 const char *rrdinstance_acquired_units(RRDINSTANCE_ACQUIRED *ria);
42 STRING *rrdinstance_acquired_units_dup(RRDINSTANCE_ACQUIRED *ria);
43 -DICTIONARY *rrdinstance_acquired_labels(RRDINSTANCE_ACQUIRED *ria);
43 +RRDLABELS *rrdinstance_acquired_labels(RRDINSTANCE_ACQUIRED *ria);
44 DICTIONARY *rrdinstance_acquired_functions(RRDINSTANCE_ACQUIRED *ria);
45 RRDHOST *rrdinstance_acquired_rrdhost(RRDINSTANCE_ACQUIRED *ria);
46 RRDSET *rrdinstance_acquired_rrdset(RRDINSTANCE_ACQUIRED *ria);
database/rrd.h
+10 -57
@@ -23,6 +23,8 @@ typedef struct rrdcalc RRDCALC;
23 typedef struct rrdcalctemplate RRDCALCTEMPLATE;
24 typedef struct alarm_entry ALARM_ENTRY;
25
26 +typedef struct rrdlabels RRDLABELS;
27 +
28 typedef struct rrdfamily_acquired RRDFAMILY_ACQUIRED;
29 typedef struct rrdvar_acquired RRDVAR_ACQUIRED;
30 typedef struct rrdsetvar_acquired RRDSETVAR_ACQUIRED;
@@ -113,6 +115,7 @@ struct ml_metrics_statistics {
115 #include "rrddimvar.h"
116 #include "rrdcalc.h"
117 #include "rrdcalctemplate.h"
118 +#include "rrdlabels.h"
119 #include "streaming/rrdpush.h"
120 #include "aclk/aclk_rrdhost_state.h"
121 #include "sqlite/sqlite_health.h"
@@ -265,60 +268,6 @@ typedef enum __attribute__ ((__packed__)) rrddim_flags {
268 #define rrddim_flag_set(rd, flag) __atomic_or_fetch(&((rd)->flags), (flag), __ATOMIC_SEQ_CST)
269 #define rrddim_flag_clear(rd, flag) __atomic_and_fetch(&((rd)->flags), ~(flag), __ATOMIC_SEQ_CST)
270
268 -typedef enum __attribute__ ((__packed__)) rrdlabel_source {
269 - RRDLABEL_SRC_AUTO = (1 << 0), // set when Netdata found the label by some automation
270 - RRDLABEL_SRC_CONFIG = (1 << 1), // set when the user configured the label
271 - RRDLABEL_SRC_K8S = (1 << 2), // set when this label is found from k8s (RRDLABEL_SRC_AUTO should also be set)
272 - RRDLABEL_SRC_ACLK = (1 << 3), // set when this label is found from ACLK (RRDLABEL_SRC_AUTO should also be set)
273 -
274 - // more sources can be added here
275 -
276 - RRDLABEL_FLAG_PERMANENT = (1 << 29), // set when this label should never be removed (can be overwritten though)
277 - RRDLABEL_FLAG_OLD = (1 << 30), // marks for rrdlabels internal use - they are not exposed outside rrdlabels
278 - RRDLABEL_FLAG_NEW = (1 << 31) // marks for rrdlabels internal use - they are not exposed outside rrdlabels
279 -} RRDLABEL_SRC;
280 -
281 -#define RRDLABEL_FLAG_INTERNAL (RRDLABEL_FLAG_OLD | RRDLABEL_FLAG_NEW | RRDLABEL_FLAG_PERMANENT)
282 -
283 -size_t text_sanitize(unsigned char *dst, const unsigned char *src, size_t dst_size, unsigned char *char_map, bool utf, const char *empty, size_t *multibyte_length);
284 -
285 -DICTIONARY *rrdlabels_create(void);
286 -void rrdlabels_destroy(DICTIONARY *labels_dict);
287 -void rrdlabels_add(DICTIONARY *dict, const char *name, const char *value, RRDLABEL_SRC ls);
288 -void rrdlabels_add_pair(DICTIONARY *dict, const char *string, RRDLABEL_SRC ls);
289 -void rrdlabels_get_value_to_buffer_or_null(DICTIONARY *labels, BUFFER *wb, const char *key, const char *quote, const char *null);
290 -void rrdlabels_value_to_buffer_array_item_or_null(DICTIONARY *labels, BUFFER *wb, const char *key);
291 -void rrdlabels_get_value_strdup_or_null(DICTIONARY *labels, char **value, const char *key);
292 -void rrdlabels_get_value_strcpyz(DICTIONARY *labels, char *dst, size_t dst_len, const char *key);
293 -STRING *rrdlabels_get_value_string_dup(DICTIONARY *labels, const char *key);
294 -STRING *rrdlabels_get_value_to_buffer_or_unset(DICTIONARY *labels, BUFFER *wb, const char *key, const char *unset);
295 -void rrdlabels_flush(DICTIONARY *labels_dict);
296 -
297 -void rrdlabels_unmark_all(DICTIONARY *labels);
298 -void rrdlabels_remove_all_unmarked(DICTIONARY *labels);
299 -
300 -int rrdlabels_walkthrough_read(DICTIONARY *labels, int (*callback)(const char *name, const char *value, RRDLABEL_SRC ls, void *data), void *data);
301 -int rrdlabels_sorted_walkthrough_read(DICTIONARY *labels, int (*callback)(const char *name, const char *value, RRDLABEL_SRC ls, void *data), void *data);
302 -
303 -void rrdlabels_log_to_buffer(DICTIONARY *labels, BUFFER *wb);
304 -bool rrdlabels_match_simple_pattern(DICTIONARY *labels, const char *simple_pattern_txt);
305 -
306 -bool rrdlabels_match_simple_pattern_parsed(DICTIONARY *labels, SIMPLE_PATTERN *pattern, char equal, size_t *searches);
307 -int rrdlabels_to_buffer(DICTIONARY *labels, BUFFER *wb, const char *before_each, const char *equal, const char *quote, const char *between_them, bool (*filter_callback)(const char *name, const char *value, RRDLABEL_SRC ls, void *data), void *filter_data, void (*name_sanitizer)(char *dst, const char *src, size_t dst_size), void (*value_sanitizer)(char *dst, const char *src, size_t dst_size));
308 -void rrdlabels_to_buffer_json_members(DICTIONARY *labels, BUFFER *wb);
309 -
310 -void rrdlabels_migrate_to_these(DICTIONARY *dst, DICTIONARY *src);
311 -void rrdlabels_copy(DICTIONARY *dst, DICTIONARY *src);
312 -
313 -void reload_host_labels(void);
314 -void rrdset_update_rrdlabels(RRDSET *st, DICTIONARY *new_rrdlabels);
315 -void rrdset_save_rrdlabels_to_sql(RRDSET *st);
316 -void rrdhost_set_is_parent_label(void);
317 -int rrdlabels_unittest(void);
318 -
319 -// unfortunately this break when defined in exporting_engine.h
320 -bool exporting_labels_filter_callback(const char *name, const char *value, RRDLABEL_SRC ls, void *data);
321 -
271 // ----------------------------------------------------------------------------
272 // engine-specific iterator state for dimension data collection
273 typedef struct storage_collect_handle {
@@ -795,7 +744,7 @@ struct rrdset {
744 int32_t priority; // the sorting priority of this chart
745 int32_t update_every; // data collection frequency
746
798 - DICTIONARY *rrdlabels; // chart labels
747 + RRDLABELS *rrdlabels; // chart labels
748 DICTIONARY *rrdsetvar_root_index; // chart variables
749 DICTIONARY *rrddimvar_root_index; // dimension variables
750 // we use this dictionary to manage their allocation
@@ -1156,7 +1105,7 @@ struct rrdhost_system_info {
1105 int mc_version;
1106 };
1107
1159 -struct rrdhost_system_info *rrdhost_labels_to_system_info(DICTIONARY *labels);
1108 +struct rrdhost_system_info *rrdhost_labels_to_system_info(RRDLABELS *labels);
1109
1110 struct rrdhost {
1111 char machine_guid[GUID_LEN + 1]; // the unique ID of this host
@@ -1263,7 +1212,7 @@ struct rrdhost {
1212
1213 // ------------------------------------------------------------------------
1214 // Support for host-level labels
1266 - DICTIONARY *rrdlabels;
1215 + RRDLABELS *rrdlabels;
1216
1217 // ------------------------------------------------------------------------
1218 // Support for functions
@@ -1509,6 +1458,8 @@ time_t rrdset_last_entry_s_of_tier(RRDSET *st, size_t tier);
1458
1459 void rrdset_get_retention_of_tier_for_collected_chart(RRDSET *st, time_t *first_time_s, time_t *last_time_s, time_t now_s, size_t tier);
1460
1461 +void rrdset_update_rrdlabels(RRDSET *st, RRDLABELS *new_rrdlabels);
1462 +
1463 // ----------------------------------------------------------------------------
1464 // RRD DIMENSION functions
1465
@@ -1563,6 +1514,8 @@ void rrddim_store_metric(RRDDIM *rd, usec_t point_end_time_ut, NETDATA_DOUBLE n,
1514 // Miscellaneous functions
1515
1516 char *rrdset_strncpyz_name(char *to, const char *from, size_t length);
1517 +void reload_host_labels(void);
1518 +void rrdhost_set_is_parent_label(void);
1519
1520 // ----------------------------------------------------------------------------
1521 // RRD internal functions
database/rrdcalc.c
+1 -1
@@ -155,7 +155,7 @@ static STRING *rrdcalc_replace_variables_with_rrdset_labels(const char *line, RR
155 void rrdcalc_update_info_using_rrdset_labels(RRDCALC *rc) {
156 if(!rc->rrdset || !rc->original_info || !rc->rrdset->rrdlabels) return;
157
158 - size_t labels_version = dictionary_version(rc->rrdset->rrdlabels);
158 + size_t labels_version = rrdlabels_version(rc->rrdset->rrdlabels);
159 if(rc->labels_version != labels_version) {
160
161 STRING *old = rc->info;
database/rrdhost.c
+3 -3
@@ -1317,7 +1317,7 @@ void rrdhost_save_charts(RRDHOST *host) {
1317 rrdset_foreach_done(st);
1318 }
1319
1320 -struct rrdhost_system_info *rrdhost_labels_to_system_info(DICTIONARY *labels) {
1320 +struct rrdhost_system_info *rrdhost_labels_to_system_info(RRDLABELS *labels) {
1321 struct rrdhost_system_info *info = callocz(1, sizeof(struct rrdhost_system_info));
1322 info->hops = 1;
1323
@@ -1345,7 +1345,7 @@ struct rrdhost_system_info *rrdhost_labels_to_system_info(DICTIONARY *labels) {
1345 }
1346
1347 static void rrdhost_load_auto_labels(void) {
1348 - DICTIONARY *labels = localhost->rrdlabels;
1348 + RRDLABELS *labels = localhost->rrdlabels;
1349
1350 if (localhost->system_info->cloud_provider_type)
1351 rrdlabels_add(labels, "_cloud_provider_type", localhost->system_info->cloud_provider_type, RRDLABEL_SRC_AUTO);
@@ -1418,7 +1418,7 @@ void rrdhost_set_is_parent_label(void) {
1418 int count = __atomic_load_n(&localhost->connected_children_count, __ATOMIC_RELAXED);
1419
1420 if (count == 0 || count == 1) {
1421 - DICTIONARY *labels = localhost->rrdlabels;
1421 + RRDLABELS *labels = localhost->rrdlabels;
1422 rrdlabels_add(labels, "_is_parent", (count) ? "true" : "false", RRDLABEL_SRC_AUTO);
1423
1424 //queue a node info
database/rrdlabels.c
+453 -261
@@ -3,6 +3,91 @@
3 #define NETDATA_RRD_INTERNALS
4 #include "rrd.h"
5
6 +// Key OF HS ARRRAY
7 +
8 +struct {
9 + Pvoid_t JudyHS;
10 + SPINLOCK spinlock;
11 +} global_labels = {
12 + .JudyHS = (Pvoid_t) NULL,
13 + .spinlock = NETDATA_SPINLOCK_INITIALIZER
14 +};
15 +
16 +typedef struct label_registry_idx {
17 + STRING *key;
18 + STRING *value;
19 +} LABEL_REGISTRY_IDX;
20 +
21 +typedef struct labels_registry_entry {
22 + LABEL_REGISTRY_IDX index;
23 +} RRDLABEL;
24 +
25 +// Value of HS array
26 +typedef struct labels_registry_idx_entry {
27 + RRDLABEL label;
28 + size_t refcount;
29 +} RRDLABEL_IDX;
30 +
31 +typedef struct rrdlabels {
32 + SPINLOCK spinlock;
33 + size_t version;
34 + Pvoid_t JudyL;
35 +} RRDLABELS;
36 +
37 +#define lfe_start_nolock(label_list, label, ls) \
38 + do { \
39 + bool _first_then_next = true; \
40 + Pvoid_t *_PValue; \
41 + Word_t _Index = 0; \
42 + while ((_PValue = JudyLFirstThenNext((label_list)->JudyL, &_Index, &_first_then_next))) { \
43 + (ls) = *(RRDLABEL_SRC *)_PValue; \
44 + (void)(ls); \
45 + (label) = (void *)_Index;
46 +
47 +#define lfe_done_nolock() \
48 + } \
49 + } \
50 + while (0)
51 +
52 +#define lfe_start_read(label_list, label, ls) \
53 + do { \
54 + spinlock_lock(&(label_list)->spinlock); \
55 + bool _first_then_next = true; \
56 + Pvoid_t *_PValue; \
57 + Word_t _Index = 0; \
58 + while ((_PValue = JudyLFirstThenNext((label_list)->JudyL, &_Index, &_first_then_next))) { \
59 + (ls) = *(RRDLABEL_SRC *)_PValue; \
60 + (void)(ls); \
61 + (label) = (void *)_Index;
62 +
63 +#define lfe_done(label_list) \
64 + } \
65 + spinlock_unlock(&(label_list)->spinlock); \
66 + } \
67 + while (0)
68 +
69 +static inline void STATS_PLUS_MEMORY(struct dictionary_stats *stats, size_t key_size, size_t item_size, size_t value_size) {
70 + if(key_size)
71 + __atomic_fetch_add(&stats->memory.index, (long)JUDYHS_INDEX_SIZE_ESTIMATE(key_size), __ATOMIC_RELAXED);
72 +
73 + if(item_size)
74 + __atomic_fetch_add(&stats->memory.dict, (long)item_size, __ATOMIC_RELAXED);
75 +
76 + if(value_size)
77 + __atomic_fetch_add(&stats->memory.values, (long)value_size, __ATOMIC_RELAXED);
78 +}
79 +
80 +static inline void STATS_MINUS_MEMORY(struct dictionary_stats *stats, size_t key_size, size_t item_size, size_t value_size) {
81 + if(key_size)
82 + __atomic_fetch_sub(&stats->memory.index, (long)JUDYHS_INDEX_SIZE_ESTIMATE(key_size), __ATOMIC_RELAXED);
83 +
84 + if(item_size)
85 + __atomic_fetch_sub(&stats->memory.dict, (long)item_size, __ATOMIC_RELAXED);
86 +
87 + if(value_size)
88 + __atomic_fetch_sub(&stats->memory.values, (long)value_size, __ATOMIC_RELAXED);
89 +}
90 +
91 // ----------------------------------------------------------------------------
92 // labels sanitization
93
@@ -369,6 +454,12 @@ __attribute__((constructor)) void initialize_labels_keys_char_map(void) {
454
455 }
456
457 +__attribute__((constructor)) void initialize_label_stats(void) {
458 + dictionary_stats_category_rrdlabels.memory.dict = 0;
459 + dictionary_stats_category_rrdlabels.memory.index = 0;
460 + dictionary_stats_category_rrdlabels.memory.values = 0;
461 +}
462 +
463 size_t text_sanitize(unsigned char *dst, const unsigned char *src, size_t dst_size, unsigned char *char_map, bool utf, const char *empty, size_t *multibyte_length) {
464 if(unlikely(!dst_size)) return 0;
465
@@ -484,93 +575,132 @@ static inline size_t rrdlabels_sanitize_value(char *dst, const char *src, size_t
575 // ----------------------------------------------------------------------------
576 // rrdlabels_create()
577
487 -typedef struct rrdlabel {
488 - STRING *label_value;
489 - RRDLABEL_SRC label_source;
490 -} RRDLABEL;
491 -
492 -static void rrdlabel_insert_callback(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *dict_ptr __maybe_unused) {
493 - RRDLABEL *lb = (RRDLABEL *)value;
494 -
495 - // label_value is already allocated by the STRING
496 - lb->label_source |= RRDLABEL_FLAG_NEW;
497 - lb->label_source &= ~RRDLABEL_FLAG_OLD;
578 +RRDLABELS *rrdlabels_create(void)
579 +{
580 + RRDLABELS *labels = callocz(1, sizeof(*labels));
581 + STATS_PLUS_MEMORY(&dictionary_stats_category_rrdlabels, 0, sizeof(RRDLABELS), 0);
582 + return labels;
583 }
584
500 -static void rrdlabel_delete_callback(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *dict_ptr __maybe_unused) {
501 - RRDLABEL *lb = (RRDLABEL *)value;
502 -
503 - string_freez(lb->label_value);
504 - lb->label_value = NULL;
505 -}
506 -
507 -static bool rrdlabel_conflict_callback(const DICTIONARY_ITEM *item __maybe_unused, void *oldvalue, void *newvalue, void *dict_ptr __maybe_unused) {
508 - RRDLABEL *lbold = (RRDLABEL *)oldvalue;
509 - RRDLABEL *lbnew = (RRDLABEL *)newvalue;
510 -
511 - if(lbold->label_value == lbnew->label_value) {
512 - // they are the same
513 -
514 - lbold->label_source |= lbnew->label_source;
515 - lbold->label_source |= RRDLABEL_FLAG_OLD;
516 - lbold->label_source &= ~RRDLABEL_FLAG_NEW;
585 +static void dup_label(RRDLABEL *label_index)
586 +{
587 + if (!label_index)
588 + return;
589
518 - // free the new one
519 - string_freez(lbnew->label_value);
590 + spinlock_lock(&global_labels.spinlock);
591
521 - return false;
592 + Pvoid_t *PValue = JudyHSGet(global_labels.JudyHS, (void *)label_index, sizeof(*label_index));
593 + if (PValue && *PValue) {
594 + RRDLABEL_IDX *rrdlabel = *PValue;
595 + __atomic_add_fetch(&rrdlabel->refcount, 1, __ATOMIC_RELAXED);
596 }
597
524 - // they are different
525 -
526 - string_freez(lbold->label_value);
527 - lbold->label_value = lbnew->label_value;
528 - lbold->label_source = lbnew->label_source;
529 - lbold->label_source |= RRDLABEL_FLAG_NEW;
530 - lbold->label_source &= ~RRDLABEL_FLAG_OLD;
531 -
532 - return true;
598 + spinlock_unlock(&global_labels.spinlock);
599 }
600
535 -DICTIONARY *rrdlabels_create(void) {
536 - DICTIONARY *dict = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE,
537 - &dictionary_stats_category_rrdlabels, sizeof(RRDLABEL));
601 +static RRDLABEL *add_label_name_value(const char *name, const char *value)
602 +{
603 + RRDLABEL_IDX *rrdlabel = NULL;
604 + LABEL_REGISTRY_IDX label_index;
605 + label_index.key = string_strdupz(name);
606 + label_index.value = string_strdupz(value);
607 +
608 + spinlock_lock(&global_labels.spinlock);
609 +
610 + Pvoid_t *PValue = JudyHSIns(&global_labels.JudyHS, (void *)&label_index, sizeof(label_index), PJE0);
611 + if(unlikely(!PValue || PValue == PJERR))
612 + fatal("RRDLABELS: corrupted judyHS array");
613 +
614 + if (*PValue) {
615 + rrdlabel = *PValue;
616 + string_freez(label_index.key);
617 + string_freez(label_index.value);
618 + } else {
619 + rrdlabel = callocz(1, sizeof(*rrdlabel));
620 + rrdlabel->label.index = label_index;
621 + *PValue = rrdlabel;
622 + STATS_PLUS_MEMORY(&dictionary_stats_category_rrdlabels, sizeof(LABEL_REGISTRY_IDX), sizeof(RRDLABEL_IDX), 0);
623 + }
624 + __atomic_add_fetch(&rrdlabel->refcount, 1, __ATOMIC_RELAXED);
625
539 - dictionary_register_insert_callback(dict, rrdlabel_insert_callback, dict);
540 - dictionary_register_delete_callback(dict, rrdlabel_delete_callback, dict);
541 - dictionary_register_conflict_callback(dict, rrdlabel_conflict_callback, dict);
542 - return dict;
626 + spinlock_unlock(&global_labels.spinlock);
627 + return &rrdlabel->label;
628 }
629
630 +static void delete_label(RRDLABEL *label)
631 +{
632 + spinlock_lock(&global_labels.spinlock);
633 +
634 + Pvoid_t *PValue = JudyHSGet(global_labels.JudyHS, &label->index, sizeof(label->index));
635 + if (PValue && *PValue) {
636 + RRDLABEL_IDX *rrdlabel = *PValue;
637 + size_t refcount = __atomic_sub_fetch(&rrdlabel->refcount, 1, __ATOMIC_RELAXED);
638 + if (refcount == 0) {
639 + int ret = JudyHSDel(&global_labels.JudyHS, (void *)label, sizeof(*label), PJE0);
640 + if (unlikely(ret == JERR))
641 + STATS_MINUS_MEMORY(&dictionary_stats_category_rrdlabels, 0, sizeof(*rrdlabel), 0);
642 + else
643 + STATS_MINUS_MEMORY(&dictionary_stats_category_rrdlabels, sizeof(LABEL_REGISTRY_IDX), sizeof(*rrdlabel), 0);
644 + string_freez(label->index.key);
645 + string_freez(label->index.value);
646 + freez(rrdlabel);
647 + }
648 + }
649 + spinlock_unlock(&global_labels.spinlock);
650 +}
651
652 // ----------------------------------------------------------------------------
653 // rrdlabels_destroy()
654
549 -void rrdlabels_destroy(DICTIONARY *labels_dict) {
550 - dictionary_destroy(labels_dict);
551 -}
655 +void rrdlabels_destroy(RRDLABELS *labels)
656 +{
657 + if (unlikely(!labels))
658 + return;
659
553 -void rrdlabels_flush(DICTIONARY *labels_dict) {
554 - dictionary_flush(labels_dict);
660 + spinlock_lock(&labels->spinlock);
661 +
662 + Pvoid_t *PValue;
663 + Word_t Index = 0;
664 + bool first_then_next = true;
665 + while ((PValue = JudyLFirstThenNext(labels->JudyL, &Index, &first_then_next))) {
666 + delete_label((RRDLABEL *)Index);
667 + }
668 + size_t memory_freed = JudyLFreeArray(&labels->JudyL, PJE0);
669 + STATS_MINUS_MEMORY(&dictionary_stats_category_rrdlabels, 0, memory_freed + sizeof(RRDLABELS), 0);
670 + spinlock_unlock(&labels->spinlock);
671 + freez(labels);
672 }
673
674 // ----------------------------------------------------------------------------
675 // rrdlabels_add()
676
560 -static void labels_add_already_sanitized(DICTIONARY *dict, const char *key, const char *value, RRDLABEL_SRC ls) {
561 - if(ls & RRDLABEL_FLAG_NEW) ls &= ~RRDLABEL_FLAG_NEW;
562 - if(ls & RRDLABEL_FLAG_OLD) ls &= ~RRDLABEL_FLAG_OLD;
677 +static void labels_add_already_sanitized(RRDLABELS *labels, const char *key, const char *value, RRDLABEL_SRC ls)
678 +{
679 + RRDLABEL *label = add_label_name_value(key, value);
680
564 - RRDLABEL tmp = {
565 - .label_source = ls,
566 - .label_value = string_strdupz(value)
567 - };
568 - dictionary_set(dict, key, &tmp, sizeof(RRDLABEL));
569 -}
681 + spinlock_lock(&labels->spinlock);
682 +
683 + size_t mem_before_judyl = JudyLMemUsed(labels->JudyL);
684
685 + Pvoid_t *PValue = JudyLIns(&labels->JudyL, (Word_t) label, PJE0);
686 + if(unlikely(!PValue || PValue == PJERR))
687 + fatal("RRDLABELS: corrupted labels JudyL array");
688 +
689 + if (!*PValue) {
690 + *((RRDLABEL_SRC *)PValue) = (ls & ~(RRDLABEL_FLAG_NEW | RRDLABEL_FLAG_OLD));
691 + labels->version++;
692 + size_t mem_after_judyl = JudyLMemUsed(labels->JudyL);
693 + STATS_PLUS_MEMORY(&dictionary_stats_category_rrdlabels, 0, mem_after_judyl - mem_before_judyl, 0);
694 + }
695 + else
696 + delete_label(label);
697 +
698 + spinlock_unlock(&labels->spinlock);
699 +}
700
572 -void rrdlabels_add(DICTIONARY *dict, const char *name, const char *value, RRDLABEL_SRC ls) {
573 - if(!dict) {
701 +void rrdlabels_add(RRDLABELS *labels, const char *name, const char *value, RRDLABEL_SRC ls)
702 +{
703 + if(!labels) {
704 netdata_log_error("%s(): called with NULL dictionary.", __FUNCTION__ );
705 return;
706 }
@@ -584,7 +714,30 @@ void rrdlabels_add(DICTIONARY *dict, const char *name, const char *value, RRDLAB
714 return;
715 }
716
587 - labels_add_already_sanitized(dict, n, v, ls);
717 + labels_add_already_sanitized(labels, n, v, ls);
718 +}
719 +
720 +bool rrdlabels_exist(RRDLABELS *labels, const char *key)
721 +{
722 + if (!labels)
723 + return false;
724 +
725 + STRING *this_key = string_strdupz(key);
726 +
727 + RRDLABEL *lb;
728 + RRDLABEL_SRC ls;
729 +
730 + bool found = false;
731 + lfe_start_read(labels, lb, ls)
732 + {
733 + if (lb->index.key == this_key) {
734 + found = true;
735 + break;
736 + }
737 + }
738 + lfe_done(labels);
739 + string_freez(this_key);
740 + return found;
741 }
742
743 static const char *get_quoted_string_up_to(char *dst, size_t dst_size, const char *string, char upto1, char upto2) {
@@ -619,8 +772,9 @@ static const char *get_quoted_string_up_to(char *dst, size_t dst_size, const cha
772 return string;
773 }
774
622 -void rrdlabels_add_pair(DICTIONARY *dict, const char *string, RRDLABEL_SRC ls) {
623 - if(!dict) {
775 +void rrdlabels_add_pair(RRDLABELS *labels, const char *string, RRDLABEL_SRC ls)
776 +{
777 + if(!labels) {
778 netdata_log_error("%s(): called with NULL dictionary.", __FUNCTION__ );
779 return;
780 }
@@ -631,199 +785,222 @@ void rrdlabels_add_pair(DICTIONARY *dict, const char *string, RRDLABEL_SRC ls) {
785 char value[RRDLABELS_MAX_VALUE_LENGTH + 1];
786 get_quoted_string_up_to(value, RRDLABELS_MAX_VALUE_LENGTH, string, '\0', '\0');
787
634 - rrdlabels_add(dict, name, value, ls);
788 + rrdlabels_add(labels, name, value, ls);
789 }
790
791 // ----------------------------------------------------------------------------
638 -// rrdlabels_get_value_to_buffer_or_null()
792
640 -void rrdlabels_get_value_to_buffer_or_null(DICTIONARY *labels, BUFFER *wb, const char *key, const char *quote, const char *null) {
793 +void rrdlabels_value_to_buffer_array_item_or_null(RRDLABELS *labels, BUFFER *wb, const char *key) {
794 if(!labels) return;
795
643 - const DICTIONARY_ITEM *acquired_item = dictionary_get_and_acquire_item(labels, key);
644 - RRDLABEL *lb = dictionary_acquired_item_value(acquired_item);
796 + STRING *this_key = string_strdupz(key);
797
646 - if(lb && lb->label_value)
647 - buffer_sprintf(wb, "%s%s%s", quote, string2str(lb->label_value), quote);
648 - else
649 - buffer_strcat(wb, null);
650 -
651 - dictionary_acquired_item_release(labels, acquired_item);
652 -}
653 -
654 -void rrdlabels_value_to_buffer_array_item_or_null(DICTIONARY *labels, BUFFER *wb, const char *key) {
655 - if(!labels) return;
656 -
657 - const DICTIONARY_ITEM *acquired_item = dictionary_get_and_acquire_item(labels, key);
658 - RRDLABEL *lb = dictionary_acquired_item_value(acquired_item);
659 -
660 - if(lb && lb->label_value)
661 - buffer_json_add_array_item_string(wb, string2str(lb->label_value));
662 - else
663 - buffer_json_add_array_item_string(wb, NULL);
664 -
665 - dictionary_acquired_item_release(labels, acquired_item);
798 + RRDLABEL *lb;
799 + RRDLABEL_SRC ls;
800 + lfe_start_read(labels, lb, ls)
801 + {
802 + if (lb->index.key == this_key) {
803 + if (lb->index.value)
804 + buffer_json_add_array_item_string(wb, string2str(lb->index.value));
805 + else
806 + buffer_json_add_array_item_string(wb, NULL);
807 + break;
808 + }
809 + }
810 + lfe_done(labels);
811 + string_freez(this_key);
812 }
813
814 // ----------------------------------------------------------------------------
669 -// rrdlabels_get_value_to_char_or_null()
670 -
671 -void rrdlabels_get_value_strdup_or_null(DICTIONARY *labels, char **value, const char *key) {
672 - const DICTIONARY_ITEM *acquired_item = dictionary_get_and_acquire_item(labels, key);
673 - RRDLABEL *lb = dictionary_acquired_item_value(acquired_item);
815
675 - *value = (lb && lb->label_value) ? strdupz(string2str(lb->label_value)) : NULL;
676 -
677 - dictionary_acquired_item_release(labels, acquired_item);
678 -}
816 +void rrdlabels_get_value_strcpyz(RRDLABELS *labels, char *dst, size_t dst_len, const char *key) {
817 + if(!labels) return;
818
680 -void rrdlabels_get_value_strcpyz(DICTIONARY *labels, char *dst, size_t dst_len, const char *key) {
681 - const DICTIONARY_ITEM *acquired_item = dictionary_get_and_acquire_item(labels, key);
682 - RRDLABEL *lb = dictionary_acquired_item_value(acquired_item);
819 + STRING *this_key = string_strdupz(key);
820
684 - if(lb && lb->label_value)
685 - strncpyz(dst, string2str(lb->label_value), dst_len);
686 - else
687 - dst[0] = '\0';
821 + RRDLABEL *lb;
822 + RRDLABEL_SRC ls;
823
689 - dictionary_acquired_item_release(labels, acquired_item);
824 + lfe_start_read(labels, lb, ls)
825 + {
826 + if (lb->index.key == this_key) {
827 + if (lb->index.value)
828 + strncpyz(dst, string2str(lb->index.value), dst_len);
829 + else
830 + dst[0] = '\0';
831 + break;
832 + }
833 + }
834 + lfe_done(labels);
835 + string_freez(this_key);
836 }
837
692 -STRING *rrdlabels_get_value_string_dup(DICTIONARY *labels, const char *key) {
693 - const DICTIONARY_ITEM *acquired_item = dictionary_get_and_acquire_item(labels, key);
694 - RRDLABEL *lb = dictionary_acquired_item_value(acquired_item);
695 -
696 - STRING *ret = NULL;
697 - if(lb && lb->label_value)
698 - ret = string_dup(lb->label_value);
838 +void rrdlabels_get_value_strdup_or_null(RRDLABELS *labels, char **value, const char *key)
839 +{
840 + if(!labels) return;
841
700 - dictionary_acquired_item_release(labels, acquired_item);
842 + STRING *this_key = string_strdupz(key);
843
702 - return ret;
844 + RRDLABEL *lb;
845 + RRDLABEL_SRC ls;
846 + lfe_start_read(labels, lb, ls)
847 + {
848 + if (lb->index.key == this_key) {
849 + *value = (lb->index.value) ? strdupz(string2str(lb->index.value)) : NULL;
850 + break;
851 + }
852 + }
853 + lfe_done(labels);
854 + string_freez(this_key);
855 }
856
705 -STRING *rrdlabels_get_value_to_buffer_or_unset(DICTIONARY *labels, BUFFER *wb, const char *key, const char *unset) {
706 - const DICTIONARY_ITEM *acquired_item = dictionary_get_and_acquire_item(labels, key);
707 - RRDLABEL *lb = dictionary_acquired_item_value(acquired_item);
708 -
709 - STRING *ret = NULL;
710 - if(lb && lb->label_value)
711 - buffer_strcat(wb, string2str(lb->label_value));
712 - else
713 - buffer_strcat(wb, unset);
857 +void rrdlabels_get_value_to_buffer_or_unset(RRDLABELS *labels, BUFFER *wb, const char *key, const char *unset)
858 +{
859 + if(!labels || !key || !wb) return;
860
715 - dictionary_acquired_item_release(labels, acquired_item);
861 + STRING *this_key = string_strdupz(key);
862 + RRDLABEL *lb;
863 + RRDLABEL_SRC ls;
864
717 - return ret;
865 + lfe_start_read(labels, lb, ls)
866 + {
867 + if (lb->index.key == this_key) {
868 + if (lb->index.value)
869 + buffer_strcat(wb, string2str(lb->index.value));
870 + else
871 + buffer_strcat(wb, unset);
872 + break;
873 + }
874 + }
875 + lfe_done(labels);
876 + string_freez(this_key);
877 }
878
720 -// ----------------------------------------------------------------------------
721 -// rrdlabels_unmark_all()
722 -// remove labels RRDLABEL_FLAG_OLD and RRDLABEL_FLAG_NEW from all dictionary items
723 -
724 -static int remove_flags_old_new(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused) {
725 - RRDLABEL *lb = (RRDLABEL *)value;
726 -
727 - if(lb->label_source & RRDLABEL_FLAG_OLD) lb->label_source &= ~RRDLABEL_FLAG_OLD;
728 - if(lb->label_source & RRDLABEL_FLAG_NEW) lb->label_source &= ~RRDLABEL_FLAG_NEW;
729 -
730 - return 1;
879 +void rrdlabels_unmark_all(RRDLABELS *labels __maybe_unused) {
880 }
881
733 -void rrdlabels_unmark_all(DICTIONARY *labels) {
734 - dictionary_walkthrough_read(labels, remove_flags_old_new, NULL);
882 +void rrdlabels_remove_all_unmarked(RRDLABELS *labels __maybe_unused) {
883 }
884
885
886 // ----------------------------------------------------------------------------
739 -// rrdlabels_remove_all_unmarked()
740 -// remove dictionary items that are neither old, nor new
887 +// rrdlabels_walkthrough_read()
888
742 -static int remove_not_old_not_new_callback(const DICTIONARY_ITEM *item, void *value, void *data) {
743 - const char *name = dictionary_acquired_item_name(item);
744 - DICTIONARY *dict = (DICTIONARY *)data;
745 - RRDLABEL *lb = (RRDLABEL *)value;
889 +int rrdlabels_walkthrough_read(RRDLABELS *labels, int (*callback)(const char *name, const char *value, RRDLABEL_SRC ls, void *data), void *data)
890 +{
891 + int ret = 0;
892
747 - if(!(lb->label_source & (RRDLABEL_FLAG_OLD | RRDLABEL_FLAG_NEW | RRDLABEL_FLAG_PERMANENT))) {
748 - dictionary_del(dict, name);
749 - return 1;
893 + if(unlikely(!labels || !callback)) return 0;
894 +
895 + RRDLABEL *lb;
896 + RRDLABEL_SRC ls;
897 + lfe_start_read(labels, lb, ls)
898 + {
899 + ret = callback(string2str(lb->index.key), string2str(lb->index.value), ls, data);
900 + if (ret < 0)
901 + break;
902 }
903 + lfe_done(labels);
904
752 - return 0;
905 + return ret;
906 }
907
755 -void rrdlabels_remove_all_unmarked(DICTIONARY *labels) {
756 - dictionary_walkthrough_write(labels, remove_not_old_not_new_callback, labels);
757 -}
908 +// ----------------------------------------------------------------------------
909 +// rrdlabels_migrate_to_these()
910 +// migrate an existing label list to a new list
911
912 +void rrdlabels_migrate_to_these(RRDLABELS *dst, RRDLABELS *src) {
913 + if (!dst || !src)
914 + return;
915
760 -// ----------------------------------------------------------------------------
761 -// rrdlabels_walkthrough_read()
916 + spinlock_lock(&dst->spinlock);
917 + spinlock_lock(&src->spinlock);
918
763 -struct labels_walkthrough {
764 - int (*callback)(const char *name, const char *value, RRDLABEL_SRC ls, void *data);
765 - void *data;
766 -};
919 + RRDLABEL *label;
920 + Pvoid_t *PValue;
921 + Word_t Index = 0;
922 + bool first_then_next = true;
923 + while ((PValue = JudyLFirstThenNext(dst->JudyL, &Index, &first_then_next))) {
924 + *((RRDLABEL_SRC *)PValue) &= ~(RRDLABEL_FLAG_OLD | RRDLABEL_FLAG_NEW);
925 + }
926
768 -static int labels_walkthrough_callback(const DICTIONARY_ITEM *item, void *value, void *data) {
769 - const char *name = dictionary_acquired_item_name(item);
770 - struct labels_walkthrough *d = (struct labels_walkthrough *)data;
771 - RRDLABEL *lb = (RRDLABEL *)value;
927 + RRDLABEL_SRC ls;
928 + lfe_start_nolock(src, label, ls)
929 + {
930 + size_t mem_before_judyl = JudyLMemUsed(dst->JudyL);
931 + PValue = JudyLIns(&dst->JudyL, (Word_t)label, PJE0);
932 + if(unlikely(!PValue || PValue == PJERR))
933 + fatal("RRDLABELS migrate: corrupted labels array");
934 +
935 + RRDLABEL_SRC flag = RRDLABEL_FLAG_NEW;
936 + if (!*PValue) {
937 + dup_label(label);
938 + size_t mem_after_judyl = JudyLMemUsed(dst->JudyL);
939 + STATS_PLUS_MEMORY(&dictionary_stats_category_rrdlabels, 0, mem_after_judyl - mem_before_judyl, 0);
940 + }
941 + else
942 + flag = RRDLABEL_FLAG_OLD;
943
773 - RRDLABEL_SRC ls = lb->label_source;
774 - if(ls & RRDLABEL_FLAG_NEW) ls &= ~RRDLABEL_FLAG_NEW;
775 - if(ls & RRDLABEL_FLAG_OLD) ls &= ~RRDLABEL_FLAG_OLD;
944 + *((RRDLABEL_SRC *)PValue) |= flag;
945 + }
946 + lfe_done_nolock();
947
777 - return d->callback(name, string2str(lb->label_value), ls, d->data);
778 -}
948 + Index = 0;
949 + first_then_next = true;
950 + while ((PValue = JudyLFirstThenNext(dst->JudyL, &Index, &first_then_next))) {
951 + if (!((*((RRDLABEL_SRC *)PValue)) & (RRDLABEL_FLAG_OLD | RRDLABEL_FLAG_NEW | RRDLABEL_FLAG_PERMANENT))) {
952
780 -int rrdlabels_walkthrough_read(DICTIONARY *labels, int (*callback)(const char *name, const char *value, RRDLABEL_SRC ls, void *data), void *data) {
781 - struct labels_walkthrough d = {
782 - .callback = callback,
783 - .data = data
784 - };
785 - return dictionary_walkthrough_read(labels, labels_walkthrough_callback, &d);
786 -}
953 + size_t mem_before_judyl = JudyLMemUsed(dst->JudyL);
954 + (void)JudyLDel(&dst->JudyL, Index, PJE0);
955 + size_t mem_after_judyl = JudyLMemUsed(dst->JudyL);
956
788 -int rrdlabels_sorted_walkthrough_read(DICTIONARY *labels, int (*callback)(const char *name, const char *value, RRDLABEL_SRC ls, void *data), void *data) {
789 - struct labels_walkthrough d = {
790 - .callback = callback,
791 - .data = data
792 - };
793 - return dictionary_sorted_walkthrough_read(labels, labels_walkthrough_callback, &d);
794 -}
957 + STATS_MINUS_MEMORY(&dictionary_stats_category_rrdlabels, 0, mem_before_judyl - mem_after_judyl, 0);
958
959 + delete_label((RRDLABEL *)Index);
960 + if (dst->JudyL != (Pvoid_t) NULL) {
961 + Index = 0;
962 + first_then_next = true;
963 + }
964 + }
965 + }
966
797 -// ----------------------------------------------------------------------------
798 -// rrdlabels_migrate_to_these()
799 -// migrate an existing label list to a new list, INPLACE
967 + dst->version = src->version;
968
801 -static int copy_label_to_dictionary_callback(const DICTIONARY_ITEM *item, void *value, void *data) {
802 - const char *name = dictionary_acquired_item_name(item);
803 - DICTIONARY *dst = (DICTIONARY *)data;
804 - RRDLABEL *lb = (RRDLABEL *)value;
805 - labels_add_already_sanitized(dst, name, string2str(lb->label_value), lb->label_source);
806 - return 1;
969 + spinlock_unlock(&src->spinlock);
970 + spinlock_unlock(&dst->spinlock);
971 }
972
809 -void rrdlabels_migrate_to_these(DICTIONARY *dst, DICTIONARY *src) {
810 - if(!dst || !src) return;
811 -
812 - // remove the RRDLABEL_FLAG_OLD and RRDLABEL_FLAG_NEW from all items
813 - rrdlabels_unmark_all(dst);
973 +void rrdlabels_copy(RRDLABELS *dst, RRDLABELS *src)
974 +{
975 + if (!dst || !src)
976 + return;
977
815 - // Mark the existing ones as RRDLABEL_FLAG_OLD,
816 - // or the newly added ones as RRDLABEL_FLAG_NEW
817 - dictionary_walkthrough_read(src, copy_label_to_dictionary_callback, dst);
978 + RRDLABEL *label;
979 + RRDLABEL_SRC ls;
980
819 - // remove the unmarked dst
820 - rrdlabels_remove_all_unmarked(dst);
821 -}
981 + spinlock_lock(&dst->spinlock);
982 + spinlock_lock(&src->spinlock);
983 +
984 + lfe_start_nolock(src, label, ls)
985 + {
986 + size_t mem_before_judyl = JudyLMemUsed(dst->JudyL);
987 + Pvoid_t *PValue = JudyLIns(&dst->JudyL, (Word_t)label, PJE0);
988 + if(unlikely(!PValue || PValue == PJERR))
989 + fatal("RRDLABELS: corrupted labels array");
990 +
991 + if (!*PValue) {
992 + dup_label(label);
993 + size_t mem_after_judyl = JudyLMemUsed(dst->JudyL);
994 + STATS_PLUS_MEMORY(&dictionary_stats_category_rrdlabels, 0, mem_after_judyl - mem_before_judyl, 0);
995 + *((RRDLABEL_SRC *)PValue) = ls;
996 + }
997 + }
998 + lfe_done_nolock();
999
823 -void rrdlabels_copy(DICTIONARY *dst, DICTIONARY *src) {
824 - if(!dst || !src) return;
1000 + dst->version = src->version;
1001
826 - dictionary_walkthrough_read(src, copy_label_to_dictionary_callback, dst);
1002 + spinlock_unlock(&src->spinlock);
1003 + spinlock_unlock(&dst->spinlock);
1004 }
1005
1006
@@ -837,8 +1014,7 @@ struct simple_pattern_match_name_value {
1014 char equal;
1015 };
1016
840 -static int simple_pattern_match_name_only_callback(const DICTIONARY_ITEM *item, void *value, void *data) {
841 - const char *name = dictionary_acquired_item_name(item);
1017 +static int simple_pattern_match_name_only_callback(const char *name, const char *value, RRDLABEL_SRC ls __maybe_unused, void *data) {
1018 struct simple_pattern_match_name_value *t = (struct simple_pattern_match_name_value *)data;
1019 (void)value;
1020
@@ -849,10 +1025,8 @@ static int simple_pattern_match_name_only_callback(const DICTIONARY_ITEM *item,
1025 return 0;
1026 }
1027
852 -static int simple_pattern_match_name_and_value_callback(const DICTIONARY_ITEM *item, void *value, void *data) {
853 - const char *name = dictionary_acquired_item_name(item);
1028 +static int simple_pattern_match_name_and_value_callback(const char *name, const char *value, RRDLABEL_SRC ls __maybe_unused, void *data) {
1029 struct simple_pattern_match_name_value *t = (struct simple_pattern_match_name_value *)data;
855 - RRDLABEL *lb = (RRDLABEL *)value;
1030
1031 // we return -1 to stop the walkthrough on first match
1032 t->searches++;
@@ -860,7 +1034,7 @@ static int simple_pattern_match_name_and_value_callback(const DICTIONARY_ITEM *i
1034
1035 size_t len = RRDLABELS_MAX_NAME_LENGTH + RRDLABELS_MAX_VALUE_LENGTH + 2; // +1 for =, +1 for \0
1036 char tmp[len], *dst = &tmp[0];
863 - const char *v = string2str(lb->label_value);
1037 + const char *v = value;
1038
1039 // copy the name
1040 while(*name) *dst++ = *name++;
@@ -881,7 +1055,7 @@ static int simple_pattern_match_name_and_value_callback(const DICTIONARY_ITEM *i
1055 return 0;
1056 }
1057
884 -bool rrdlabels_match_simple_pattern_parsed(DICTIONARY *labels, SIMPLE_PATTERN *pattern, char equal, size_t *searches) {
1058 +bool rrdlabels_match_simple_pattern_parsed(RRDLABELS *labels, SIMPLE_PATTERN *pattern, char equal, size_t *searches) {
1059 if (!labels) return false;
1060
1061 struct simple_pattern_match_name_value t = {
@@ -890,7 +1064,7 @@ bool rrdlabels_match_simple_pattern_parsed(DICTIONARY *labels, SIMPLE_PATTERN *p
1064 .equal = equal
1065 };
1066
893 - int ret = dictionary_walkthrough_read(labels, equal?simple_pattern_match_name_and_value_callback:simple_pattern_match_name_only_callback, &t);
1067 + int ret = rrdlabels_walkthrough_read(labels, equal?simple_pattern_match_name_and_value_callback:simple_pattern_match_name_only_callback, &t);
1068
1069 if(searches)
1070 *searches = t.searches;
@@ -898,7 +1072,7 @@ bool rrdlabels_match_simple_pattern_parsed(DICTIONARY *labels, SIMPLE_PATTERN *p
1072 return (ret == -1)?true:false;
1073 }
1074
901 -bool rrdlabels_match_simple_pattern(DICTIONARY *labels, const char *simple_pattern_txt) {
1075 +bool rrdlabels_match_simple_pattern(RRDLABELS *labels, const char *simple_pattern_txt) {
1076 if (!labels) return false;
1077
1078 SIMPLE_PATTERN *pattern = simple_pattern_create(simple_pattern_txt, " ,|\t\r\n\f\v", SIMPLE_PATTERN_EXACT, true);
@@ -923,39 +1097,23 @@ bool rrdlabels_match_simple_pattern(DICTIONARY *labels, const char *simple_patte
1097 // ----------------------------------------------------------------------------
1098 // Log all labels
1099
926 -static int rrdlabels_log_label_to_buffer_callback(const DICTIONARY_ITEM *item, void *value, void *data) {
927 - const char *name = dictionary_acquired_item_name(item);
928 -
1100 +static int rrdlabels_log_label_to_buffer_callback(const char *name, const char *value, void *data) {
1101 BUFFER *wb = (BUFFER *)data;
930 - RRDLABEL *lb = (RRDLABEL *)value;
931 -
932 - buffer_sprintf(wb, "Label: %s: \"%s\" (", name, string2str(lb->label_value));
933 -
934 - size_t sources = 0;
935 - if(lb->label_source & RRDLABEL_SRC_AUTO) {
936 - buffer_sprintf(wb, "auto");
937 - sources++;
938 - }
939 -
940 - if(lb->label_source & RRDLABEL_SRC_CONFIG)
941 - buffer_sprintf(wb, "%snetdata.conf", sources++?",":"");
942 -
943 - if(lb->label_source & RRDLABEL_SRC_K8S)
944 - buffer_sprintf(wb, "%sk8s", sources++?",":"");
945 -
946 - if(lb->label_source & RRDLABEL_SRC_ACLK)
947 - buffer_sprintf(wb, "%saclk", sources++?",":"");
948 -
949 - if(!sources)
950 - buffer_strcat(wb, "unknown");
1102
1103 + buffer_sprintf(wb, "Label: %s: \"%s\" (", name, value);
1104 + buffer_strcat(wb, "unknown");
1105 buffer_strcat(wb, ")\n");
1106
1107 return 1;
1108 }
1109
957 -void rrdlabels_log_to_buffer(DICTIONARY *labels, BUFFER *wb) {
958 - dictionary_sorted_walkthrough_read(labels, rrdlabels_log_label_to_buffer_callback, wb);
1110 +void rrdlabels_log_to_buffer(RRDLABELS *labels, BUFFER *wb)
1111 +{
1112 + RRDLABEL *lb;
1113 + RRDLABEL_SRC ls;
1114 + lfe_start_read(labels, lb, ls)
1115 + rrdlabels_log_label_to_buffer_callback((void *) string2str(lb->index.key), (void *) string2str(lb->index.value), wb);
1116 + lfe_done(labels);
1117 }
1118
1119
@@ -975,10 +1133,10 @@ struct labels_to_buffer {
1133 size_t count;
1134 };
1135
978 -static int label_to_buffer_callback(const DICTIONARY_ITEM *item, void *value, void *data) {
979 - const char *name = dictionary_acquired_item_name(item);
1136 +static int label_to_buffer_callback(const RRDLABEL *lb, void *value __maybe_unused, RRDLABEL_SRC ls, void *data)
1137 +{
1138 +
1139 struct labels_to_buffer *t = (struct labels_to_buffer *)data;
981 - RRDLABEL *lb = (RRDLABEL *)value;
1140
1141 size_t n_size = (t->name_sanitizer ) ? ( RRDLABELS_MAX_NAME_LENGTH * 2 ) : 1;
1142 size_t v_size = (t->value_sanitizer) ? ( RRDLABELS_MAX_VALUE_LENGTH * 2 ) : 1;
@@ -986,7 +1144,9 @@ static int label_to_buffer_callback(const DICTIONARY_ITEM *item, void *value, vo
1144 char n[n_size];
1145 char v[v_size];
1146
989 - const char *nn = name, *vv = string2str(lb->label_value);
1147 + const char *name = string2str(lb->index.key);
1148 +
1149 + const char *nn = name, *vv = string2str(lb->index.value);
1150
1151 if(t->name_sanitizer) {
1152 t->name_sanitizer(n, name, n_size);
@@ -994,11 +1154,11 @@ static int label_to_buffer_callback(const DICTIONARY_ITEM *item, void *value, vo
1154 }
1155
1156 if(t->value_sanitizer) {
997 - t->value_sanitizer(v, string2str(lb->label_value), v_size);
1157 + t->value_sanitizer(v, string2str(lb->index.value), v_size);
1158 vv = v;
1159 }
1160
1001 - if(!t->filter_callback || t->filter_callback(name, string2str(lb->label_value), lb->label_source, t->filter_data)) {
1161 + if(!t->filter_callback || t->filter_callback(name, string2str(lb->index.value), ls, t->filter_data)) {
1162 buffer_sprintf(t->wb, "%s%s%s%s%s%s%s%s%s", t->count++?t->between_them:"", t->before_each, t->quote, nn, t->quote, t->equal, t->quote, vv, t->quote);
1163 return 1;
1164 }
@@ -1006,7 +1166,26 @@ static int label_to_buffer_callback(const DICTIONARY_ITEM *item, void *value, vo
1166 return 0;
1167 }
1168
1009 -int rrdlabels_to_buffer(DICTIONARY *labels, BUFFER *wb, const char *before_each, const char *equal, const char *quote, const char *between_them, bool (*filter_callback)(const char *name, const char *value, RRDLABEL_SRC ls, void *data), void *filter_data, void (*name_sanitizer)(char *dst, const char *src, size_t dst_size), void (*value_sanitizer)(char *dst, const char *src, size_t dst_size)) {
1169 +
1170 +int label_walkthrough_read(RRDLABELS *labels, int (*callback)(const RRDLABEL *item, void *entry, RRDLABEL_SRC ls, void *data), void *data)
1171 +{
1172 + int ret = 0;
1173 +
1174 + if(unlikely(!labels || !callback)) return 0;
1175 +
1176 + RRDLABEL *lb;
1177 + RRDLABEL_SRC ls;
1178 + lfe_start_read(labels, lb, ls)
1179 + {
1180 + ret = callback((const RRDLABEL *)lb, (void *)string2str(lb->index.value), ls, data);
1181 + if (ret < 0)
1182 + break;
1183 + }
1184 + lfe_done(labels);
1185 + return ret;
1186 +}
1187 +
1188 +int rrdlabels_to_buffer(RRDLABELS *labels, BUFFER *wb, const char *before_each, const char *equal, const char *quote, const char *between_them, bool (*filter_callback)(const char *name, const char *value, RRDLABEL_SRC ls, void *data), void *filter_data, void (*name_sanitizer)(char *dst, const char *src, size_t dst_size), void (*value_sanitizer)(char *dst, const char *src, size_t dst_size)) {
1189 struct labels_to_buffer tmp = {
1190 .wb = wb,
1191 .filter_callback = filter_callback,
@@ -1019,18 +1198,33 @@ int rrdlabels_to_buffer(DICTIONARY *labels, BUFFER *wb, const char *before_each,
1198 .between_them = between_them,
1199 .count = 0
1200 };
1022 - return dictionary_walkthrough_read(labels, label_to_buffer_callback, (void *)&tmp);
1201 + return label_walkthrough_read(labels, label_to_buffer_callback, (void *)&tmp);
1202 }
1203
1025 -void rrdlabels_to_buffer_json_members(DICTIONARY *labels, BUFFER *wb) {
1204 +void rrdlabels_to_buffer_json_members(RRDLABELS *labels, BUFFER *wb)
1205 +{
1206 RRDLABEL *lb;
1027 - dfe_start_read(labels, lb) {
1028 - buffer_json_member_add_string(wb, lb_dfe.name, string2str(lb->label_value));
1029 - }
1030 - dfe_done(lb);
1207 + RRDLABEL_SRC ls;
1208 + lfe_start_read(labels, lb, ls)
1209 + buffer_json_member_add_string(wb, string2str(lb->index.key), string2str(lb->index.value));
1210 + lfe_done(labels);
1211 +}
1212 +
1213 +size_t rrdlabels_entries(RRDLABELS *labels __maybe_unused)
1214 +{
1215 + size_t count;
1216 + spinlock_lock(&labels->spinlock);
1217 + count = JudyLCount(labels->JudyL, 0, -1, PJE0);
1218 + spinlock_unlock(&labels->spinlock);
1219 + return count;
1220 }
1221
1033 -void rrdset_update_rrdlabels(RRDSET *st, DICTIONARY *new_rrdlabels) {
1222 +size_t rrdlabels_version(RRDLABELS *labels __maybe_unused)
1223 +{
1224 + return (size_t) labels->version;
1225 +}
1226 +
1227 +void rrdset_update_rrdlabels(RRDSET *st, RRDLABELS *new_rrdlabels) {
1228 if(!st->rrdlabels)
1229 st->rrdlabels = rrdlabels_create();
1230
@@ -1051,16 +1245,14 @@ struct rrdlabels_unittest_add_a_pair {
1245 const char *expected_value;
1246 const char *name;
1247 const char *value;
1054 - RRDLABEL_SRC ls;
1248 int errors;
1249 };
1250
1058 -int rrdlabels_unittest_add_a_pair_callback(const char *name, const char *value, RRDLABEL_SRC ls, void *data) {
1251 +int rrdlabels_unittest_add_a_pair_callback(const char *name, const char *value, RRDLABEL_SRC ls __maybe_unused, void *data) {
1252 struct rrdlabels_unittest_add_a_pair *t = (struct rrdlabels_unittest_add_a_pair *)data;
1253
1254 t->name = name;
1255 t->value = value;
1063 - t->ls = ls;
1256
1257 if(strcmp(name, t->expected_name) != 0) {
1258 fprintf(stderr, "name is wrong, found \"%s\", expected \"%s\"", name, t->expected_name);
@@ -1083,7 +1275,7 @@ int rrdlabels_unittest_add_a_pair_callback(const char *name, const char *value,
1275 }
1276
1277 int rrdlabels_unittest_add_a_pair(const char *pair, const char *name, const char *value) {
1086 - DICTIONARY *labels = rrdlabels_create();
1278 + RRDLABELS *labels = rrdlabels_create();
1279 int errors;
1280
1281 fprintf(stderr, "rrdlabels_add_pair(labels, %s) ... ", pair);
@@ -1160,7 +1352,7 @@ int rrdlabels_unittest_add_pairs() {
1352 return errors;
1353 }
1354
1163 -int rrdlabels_unittest_check_simple_pattern(DICTIONARY *labels, const char *pattern, bool expected) {
1355 +int rrdlabels_unittest_check_simple_pattern(RRDLABELS *labels, const char *pattern, bool expected) {
1356 fprintf(stderr, "rrdlabels_match_simple_pattern(labels, \"%s\") ... ", pattern);
1357
1358 bool ret = rrdlabels_match_simple_pattern(labels, pattern);
@@ -1174,7 +1366,7 @@ int rrdlabels_unittest_simple_pattern() {
1366
1367 int errors = 0;
1368
1177 - DICTIONARY *labels = rrdlabels_create();
1369 + RRDLABELS *labels = rrdlabels_create();
1370 rrdlabels_add(labels, "tag1", "value1", RRDLABEL_SRC_CONFIG);
1371 rrdlabels_add(labels, "tag2", "value2", RRDLABEL_SRC_CONFIG);
1372 rrdlabels_add(labels, "tag3", "value3", RRDLABEL_SRC_CONFIG);
database/rrdlabels.h new
+59
@@ -0,0 +1,59 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#ifndef NETDATA_RRDLABELS_H
4 +#define NETDATA_RRDLABELS_H
5 +
6 +#include "rrd.h"
7 +
8 +typedef enum __attribute__ ((__packed__)) rrdlabel_source {
9 + RRDLABEL_SRC_AUTO = (1 << 0), // set when Netdata found the label by some automation
10 + RRDLABEL_SRC_CONFIG = (1 << 1), // set when the user configured the label
11 + RRDLABEL_SRC_K8S = (1 << 2), // set when this label is found from k8s (RRDLABEL_SRC_AUTO should also be set)
12 + RRDLABEL_SRC_ACLK = (1 << 3), // set when this label is found from ACLK (RRDLABEL_SRC_AUTO should also be set)
13 +
14 + // more sources can be added here
15 +
16 + RRDLABEL_FLAG_PERMANENT = (1 << 29), // set when this label should never be removed (can be overwritten though)
17 + RRDLABEL_FLAG_OLD = (1 << 30), // marks for rrdlabels internal use - they are not exposed outside rrdlabels
18 + RRDLABEL_FLAG_NEW = (1 << 31) // marks for rrdlabels internal use - they are not exposed outside rrdlabels
19 +} RRDLABEL_SRC;
20 +
21 +#define RRDLABEL_FLAG_INTERNAL (RRDLABEL_FLAG_OLD | RRDLABEL_FLAG_NEW | RRDLABEL_FLAG_PERMANENT)
22 +
23 +size_t text_sanitize(unsigned char *dst, const unsigned char *src, size_t dst_size, unsigned char *char_map, bool utf, const char *empty, size_t *multibyte_length);
24 +
25 +RRDLABELS *rrdlabels_create(void);
26 +void rrdlabels_destroy(RRDLABELS *labels_dict);
27 +void rrdlabels_add(RRDLABELS *labels, const char *name, const char *value, RRDLABEL_SRC ls);
28 +void rrdlabels_add_pair(RRDLABELS *labels, const char *string, RRDLABEL_SRC ls);
29 +void rrdlabels_value_to_buffer_array_item_or_null(RRDLABELS *labels, BUFFER *wb, const char *key);
30 +void rrdlabels_get_value_strdup_or_null(RRDLABELS *labels, char **value, const char *key);
31 +void rrdlabels_get_value_to_buffer_or_unset(RRDLABELS *labels, BUFFER *wb, const char *key, const char *unset);
32 +bool rrdlabels_exist(RRDLABELS *labels, const char *key);
33 +size_t rrdlabels_entries(RRDLABELS *labels __maybe_unused);
34 +size_t rrdlabels_version(RRDLABELS *labels __maybe_unused);
35 +void rrdlabels_get_value_strcpyz(RRDLABELS *labels, char *dst, size_t dst_len, const char *key);
36 +
37 +void rrdlabels_unmark_all(RRDLABELS *labels);
38 +void rrdlabels_remove_all_unmarked(RRDLABELS *labels);
39 +
40 +int rrdlabels_walkthrough_read(RRDLABELS *labels, int (*callback)(const char *name, const char *value, RRDLABEL_SRC ls, void *data), void *data);
41 +void rrdlabels_log_to_buffer(RRDLABELS *labels, BUFFER *wb);
42 +bool rrdlabels_match_simple_pattern(RRDLABELS *labels, const char *simple_pattern_txt);
43 +
44 +bool rrdlabels_match_simple_pattern_parsed(RRDLABELS *labels, SIMPLE_PATTERN *pattern, char equal, size_t *searches);
45 +int rrdlabels_to_buffer(RRDLABELS *labels, BUFFER *wb, const char *before_each, const char *equal, const char *quote, const char *between_them,
46 + bool (*filter_callback)(const char *name, const char *value, RRDLABEL_SRC ls, void *data), void *filter_data,
47 + void (*name_sanitizer)(char *dst, const char *src, size_t dst_size),
48 + void (*value_sanitizer)(char *dst, const char *src, size_t dst_size));
49 +void rrdlabels_to_buffer_json_members(RRDLABELS *labels, BUFFER *wb);
50 +
51 +void rrdlabels_migrate_to_these(RRDLABELS *dst, RRDLABELS *src);
52 +void rrdlabels_copy(RRDLABELS *dst, RRDLABELS *src);
53 +
54 +int rrdlabels_unittest(void);
55 +
56 +// unfortunately this break when defined in exporting_engine.h
57 +bool exporting_labels_filter_callback(const char *name, const char *value, RRDLABEL_SRC ls, void *data);
58 +
59 +#endif /* NETDATA_RRDLABELS_H */
database/sqlite/sqlite_functions.c
+3 -7
@@ -930,11 +930,11 @@ skip:
930 #define SELECT_HOST_LABELS "SELECT label_key, label_value, source_type FROM host_label WHERE host_id = @host_id " \
931 "AND label_key IS NOT NULL AND label_value IS NOT NULL;"
932
933 -DICTIONARY *sql_load_host_labels(uuid_t *host_id)
933 +RRDLABELS *sql_load_host_labels(uuid_t *host_id)
934 {
935 int rc;
936
937 - DICTIONARY *labels = NULL;
937 + RRDLABELS *labels = NULL;
938 sqlite3_stmt *res = NULL;
939
940 rc = sqlite3_prepare_v2(db_meta, SELECT_HOST_LABELS, -1, &res, 0);
@@ -952,11 +952,7 @@ DICTIONARY *sql_load_host_labels(uuid_t *host_id)
952 labels = rrdlabels_create();
953
954 while (sqlite3_step_monitored(res) == SQLITE_ROW) {
955 - rrdlabels_add(
956 - labels,
957 - (const char *)sqlite3_column_text(res, 0),
958 - (const char *)sqlite3_column_text(res, 1),
959 - sqlite3_column_int(res, 2));
955 + rrdlabels_add(labels, (const char *)sqlite3_column_text(res, 0), (const char *)sqlite3_column_text(res, 1), sqlite3_column_int(res, 2));
956 }
957
958 skip:
database/sqlite/sqlite_functions.h
+1 -1
@@ -69,7 +69,7 @@ char *get_hostname_by_node_id(char *node_id);
69
70 // Help build archived hosts in memory when agent starts
71 void sql_build_host_system_info(uuid_t *host_id, struct rrdhost_system_info *system_info);
72 -DICTIONARY *sql_load_host_labels(uuid_t *host_id);
72 +RRDLABELS *sql_load_host_labels(uuid_t *host_id);
73
74 // TODO: move to metadata
75 int update_node_id(uuid_t *host_id, uuid_t *node_id);
database/sqlite/sqlite_metadata.c
+1 -1
@@ -179,7 +179,7 @@ static void clean_old_chart_labels(RRDSET *st)
179 static int check_and_update_chart_labels(RRDSET *st, BUFFER *work_buffer, size_t *query_counter)
180 {
181 size_t old_version = st->rrdlabels_last_saved_version;
182 - size_t new_version = dictionary_version(st->rrdlabels);
182 + size_t new_version = rrdlabels_version(st->rrdlabels);
183
184 if (new_version == old_version)
185 return 0;
exporting/check_filters.c
+1 -1
@@ -3,7 +3,7 @@
3 #include "exporting_engine.h"
4
5
6 -bool exporting_labels_filter_callback(const char *name, const char *value, RRDLABEL_SRC ls, void *data) {
6 +bool exporting_labels_filter_callback(const char *name, const char *value, RRDLABEL_SRC ls __maybe_unused, void *data) {
7 (void)name;
8 (void)value;
9 struct instance *instance = (struct instance *)data;
exporting/exporting_engine.h
+5 -7
@@ -32,21 +32,19 @@ typedef enum exporting_options {
32
33 #define EXPORTING_OPTIONS_SOURCE_BITS \
34 (EXPORTING_SOURCE_DATA_AS_COLLECTED | EXPORTING_SOURCE_DATA_AVERAGE | EXPORTING_SOURCE_DATA_SUM)
35 -#define EXPORTING_OPTIONS_DATA_SOURCE(exporting_options) (exporting_options & EXPORTING_OPTIONS_SOURCE_BITS)
35 +#define EXPORTING_OPTIONS_DATA_SOURCE(exporting_options) ((exporting_options) & EXPORTING_OPTIONS_SOURCE_BITS)
36
37 extern EXPORTING_OPTIONS global_exporting_options;
38 extern const char *global_exporting_prefix;
39
40 #define sending_labels_configured(instance) \
41 - (instance->config.options & (EXPORTING_OPTION_SEND_CONFIGURED_LABELS | EXPORTING_OPTION_SEND_AUTOMATIC_LABELS))
41 + ((instance)->config.options & (EXPORTING_OPTION_SEND_CONFIGURED_LABELS | EXPORTING_OPTION_SEND_AUTOMATIC_LABELS))
42
43 #define should_send_label(instance, label_source) \
44 - ((instance->config.options & EXPORTING_OPTION_SEND_CONFIGURED_LABELS && \
45 - label_source & RRDLABEL_SRC_CONFIG) || \
46 - (instance->config.options & EXPORTING_OPTION_SEND_AUTOMATIC_LABELS && \
47 - label_source & RRDLABEL_SRC_AUTO))
44 + (((instance)->config.options & EXPORTING_OPTION_SEND_CONFIGURED_LABELS && (label_source)&RRDLABEL_SRC_CONFIG) || \
45 + ((instance)->config.options & EXPORTING_OPTION_SEND_AUTOMATIC_LABELS && (label_source)&RRDLABEL_SRC_AUTO))
46
49 -#define should_send_variables(instance) (instance->config.options & EXPORTING_OPTION_SEND_VARIABLES)
47 +#define should_send_variables(instance) ((instance)->config.options & EXPORTING_OPTION_SEND_VARIABLES)
48
49 typedef enum exporting_connector_types {
50 EXPORTING_CONNECTOR_TYPE_UNKNOWN, // Invalid type
exporting/prometheus/prometheus.c
+3 -5
@@ -292,7 +292,7 @@ struct format_prometheus_label_callback {
292 size_t count;
293 };
294
295 -static int format_prometheus_label_callback(const char *name, const char *value, RRDLABEL_SRC ls, void *data) {
295 +static int format_prometheus_label_callback(const char *name, const char *value, RRDLABEL_SRC ls __maybe_unused, void *data) {
296 struct format_prometheus_label_callback *d = (struct format_prometheus_label_callback *)data;
297
298 if (!should_send_label(d->instance, ls)) return 0;
@@ -338,11 +338,9 @@ struct format_prometheus_chart_label_callback {
338 const char *labels_prefix;
339 };
340
341 -static int format_prometheus_chart_label_callback(const char *name, const char *value, RRDLABEL_SRC ls, void *data) {
341 +static int format_prometheus_chart_label_callback(const char *name, const char *value, RRDLABEL_SRC ls __maybe_unused, void *data) {
342 struct format_prometheus_chart_label_callback *d = (struct format_prometheus_chart_label_callback *)data;
343
344 - (void)ls;
345 -
344 if (name[0] == '_' )
345 return 1;
346
@@ -517,7 +515,7 @@ static void generate_as_collected_prom_metric(BUFFER *wb,
515 struct gen_parameters *p,
516 int homogeneous,
517 int prometheus_collector,
520 - DICTIONARY *chart_labels)
518 + RRDLABELS *chart_labels)
519 {
520 struct format_prometheus_chart_label_callback local_label;
521 local_label.labels_buffer = wb;
exporting/prometheus/remote_write/remote_write.c
+2 -2
@@ -139,11 +139,11 @@ struct format_remote_write_label_callback {
139 void *write_request;
140 };
141
142 -static int format_remote_write_label_callback(const char *name, const char *value, RRDLABEL_SRC ls, void *data) {
142 +static int format_remote_write_label_callback(const char *name, const char *value, RRDLABEL_SRC ls __maybe_unused, void *data)
143 +{
144 struct format_remote_write_label_callback *d = (struct format_remote_write_label_callback *)data;
145
146 if (!should_send_label(d->instance, ls)) return 0;
146 -
147 char k[PROMETHEUS_ELEMENT_MAX + 1];
148 char v[PROMETHEUS_ELEMENT_MAX + 1];
149
health/health.c
+1 -1
@@ -1608,7 +1608,7 @@ void *health_main(void *ptr) {
1608 }
1609
1610 void health_add_host_labels(void) {
1611 - DICTIONARY *labels = localhost->rrdlabels;
1611 + RRDLABELS *labels = localhost->rrdlabels;
1612
1613 // The source should be CONF, but when it is set, these labels are exported by default ('send configured labels' in exporting.conf).
1614 // Their export seems to break exporting to Graphite, see https://github.com/netdata/netdata/issues/14084.
web/api/formatters/json_wrapper.c
+1 -1
@@ -1209,7 +1209,7 @@ static void query_target_detailed_objects_tree(BUFFER *wb, RRDR *r, RRDR_OPTIONS
1209 buffer_json_member_add_object(wb, rrdinstance_acquired_id(ria));
1210 buffer_json_member_add_string(wb, "nm", rrdinstance_acquired_name(ria));
1211 buffer_json_member_add_time_t(wb, "ue", rrdinstance_acquired_update_every(ria));
1212 - DICTIONARY *labels = rrdinstance_acquired_labels(ria);
1212 + RRDLABELS *labels = rrdinstance_acquired_labels(ria);
1213 if(labels) {
1214 buffer_json_member_add_object(wb, "labels");
1215 rrdlabels_to_buffer_json_members(labels, wb);
web/api/queries/query.c
+3 -3
@@ -2497,7 +2497,7 @@ static void query_group_by_make_dimension_key(BUFFER *key, RRDR_GROUP_BY group_b
2497 }
2498
2499 if (group_by & RRDR_GROUP_BY_LABEL) {
2500 - DICTIONARY *labels = rrdinstance_acquired_labels(qi->ria);
2500 + RRDLABELS *labels = rrdinstance_acquired_labels(qi->ria);
2501 for (size_t l = 0; l < qt->group_by[group_by_id].used; l++) {
2502 buffer_fast_strcat(key, "|", 1);
2503 rrdlabels_get_value_to_buffer_or_unset(labels, key, qt->group_by[group_by_id].label_keys[l], "[unset]");
@@ -2545,7 +2545,7 @@ static void query_group_by_make_dimension_id(BUFFER *key, RRDR_GROUP_BY group_by
2545 }
2546
2547 if (group_by & RRDR_GROUP_BY_LABEL) {
2548 - DICTIONARY *labels = rrdinstance_acquired_labels(qi->ria);
2548 + RRDLABELS *labels = rrdinstance_acquired_labels(qi->ria);
2549 for (size_t l = 0; l < qt->group_by[group_by_id].used; l++) {
2550 if (buffer_strlen(key) != 0)
2551 buffer_fast_strcat(key, ",", 1);
@@ -2600,7 +2600,7 @@ static void query_group_by_make_dimension_name(BUFFER *key, RRDR_GROUP_BY group_
2600 }
2601
2602 if (group_by & RRDR_GROUP_BY_LABEL) {
2603 - DICTIONARY *labels = rrdinstance_acquired_labels(qi->ria);
2603 + RRDLABELS *labels = rrdinstance_acquired_labels(qi->ria);
2604 for (size_t l = 0; l < qt->group_by[group_by_id].used; l++) {
2605 if (buffer_strlen(key) != 0)
2606 buffer_fast_strcat(key, ",", 1);