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