diff options
author | Stelios Fragkakis <52996999+stelfrag@users.noreply.github.com> | 2023-09-01 15:37:55 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-09-01 15:37:55 +0300 |
commit | 24006ed5c19cf7c398cf8a76e7bdce1f60c7e5a4 (patch) | |
tree | b7ef3ec6b5d999d3884b9af40c2b7a53eca8f027 /database | |
parent | beba227adf489a30e826c3922e4cb3635fb0b154 (diff) |
Reduce label memory (#15255)
Diffstat (limited to 'database')
-rw-r--r-- | database/contexts/api_v1.c | 2 | ||||
-rw-r--r-- | database/contexts/api_v2.c | 2 | ||||
-rw-r--r-- | database/contexts/instance.c | 6 | ||||
-rw-r--r-- | database/contexts/internal.h | 2 | ||||
-rw-r--r-- | database/contexts/rrdcontext.h | 2 | ||||
-rw-r--r-- | database/rrd.h | 67 | ||||
-rw-r--r-- | database/rrdcalc.c | 2 | ||||
-rw-r--r-- | database/rrdhost.c | 6 | ||||
-rw-r--r-- | database/rrdlabels.c | 714 | ||||
-rw-r--r-- | database/rrdlabels.h | 59 | ||||
-rw-r--r-- | database/sqlite/sqlite_functions.c | 10 | ||||
-rw-r--r-- | database/sqlite/sqlite_functions.h | 2 | ||||
-rw-r--r-- | database/sqlite/sqlite_metadata.c | 2 |
13 files changed, 538 insertions, 338 deletions
diff --git a/database/contexts/api_v1.c b/database/contexts/api_v1.c index bc7fee496d..d8446d8490 100644 --- a/database/contexts/api_v1.c +++ b/database/contexts/api_v1.c @@ -213,7 +213,7 @@ static inline int rrdinstance_to_json_callback(const DICTIONARY_ITEM *item, void buffer_json_array_close(wb); } - if(options & RRDCONTEXT_OPTION_SHOW_LABELS && ri->rrdlabels && dictionary_entries(ri->rrdlabels)) { + if(options & RRDCONTEXT_OPTION_SHOW_LABELS && ri->rrdlabels && rrdlabels_entries(ri->rrdlabels)) { buffer_json_member_add_object(wb, "labels"); rrdlabels_to_buffer_json_members(ri->rrdlabels, wb); buffer_json_object_close(wb); diff --git a/database/contexts/api_v2.c b/database/contexts/api_v2.c index ae03228cbd..ff977f7384 100644 --- a/database/contexts/api_v2.c +++ b/database/contexts/api_v2.c @@ -418,7 +418,7 @@ static FTS_MATCH rrdcontext_to_json_v2_full_text_search(struct rrdcontext_to_jso dfe_done(rm); size_t label_searches = 0; - if(unlikely(ri->rrdlabels && dictionary_entries(ri->rrdlabels) && + if(unlikely(ri->rrdlabels && rrdlabels_entries(ri->rrdlabels) && rrdlabels_match_simple_pattern_parsed(ri->rrdlabels, q, ':', &label_searches))) { ctl->q.fts.searches += label_searches; ctl->q.fts.char_searches += label_searches; diff --git a/database/contexts/instance.c b/database/contexts/instance.c index 7e572fb80a..0c1dbf4c49 100644 --- a/database/contexts/instance.c +++ b/database/contexts/instance.c @@ -35,7 +35,7 @@ inline STRING *rrdinstance_acquired_units_dup(RRDINSTANCE_ACQUIRED *ria) { return string_dup(ri->units); } -inline DICTIONARY *rrdinstance_acquired_labels(RRDINSTANCE_ACQUIRED *ria) { +inline RRDLABELS *rrdinstance_acquired_labels(RRDINSTANCE_ACQUIRED *ria) { RRDINSTANCE *ri = rrdinstance_acquired_value(ria); return ri->rrdlabels; } @@ -68,7 +68,7 @@ inline time_t rrdinstance_acquired_update_every(RRDINSTANCE_ACQUIRED *ria) { static void rrdinstance_free(RRDINSTANCE *ri) { if(rrd_flag_check(ri, RRD_FLAG_OWN_LABELS)) - dictionary_destroy(ri->rrdlabels); + rrdlabels_destroy(ri->rrdlabels); rrdmetrics_destroy_from_rrdinstance(ri); string_freez(ri->id); @@ -211,7 +211,7 @@ static bool rrdinstance_conflict_callback(const DICTIONARY_ITEM *item __maybe_un ri->rrdset = ri_new->rrdset; if(ri->rrdset && rrd_flag_check(ri, RRD_FLAG_OWN_LABELS)) { - DICTIONARY *old = ri->rrdlabels; + RRDLABELS *old = ri->rrdlabels; ri->rrdlabels = ri->rrdset->rrdlabels; rrd_flag_clear(ri, RRD_FLAG_OWN_LABELS); rrdlabels_destroy(old); diff --git a/database/contexts/internal.h b/database/contexts/internal.h index 04ad0883a3..293659fdd0 100644 --- a/database/contexts/internal.h +++ b/database/contexts/internal.h @@ -230,7 +230,7 @@ typedef struct rrdinstance { time_t update_every_s; // data collection frequency RRDSET *rrdset; // pointer to RRDSET when collected, or NULL - DICTIONARY *rrdlabels; // linked to RRDSET->chart_labels or own version + RRDLABELS *rrdlabels; // linked to RRDSET->chart_labels or own version struct rrdcontext *rc; DICTIONARY *rrdmetrics; diff --git a/database/contexts/rrdcontext.h b/database/contexts/rrdcontext.h index 0bcdb68ded..ffc42e79a2 100644 --- a/database/contexts/rrdcontext.h +++ b/database/contexts/rrdcontext.h @@ -40,7 +40,7 @@ const char *rrdinstance_acquired_name(RRDINSTANCE_ACQUIRED *ria); bool rrdinstance_acquired_has_name(RRDINSTANCE_ACQUIRED *ria); const char *rrdinstance_acquired_units(RRDINSTANCE_ACQUIRED *ria); STRING *rrdinstance_acquired_units_dup(RRDINSTANCE_ACQUIRED *ria); -DICTIONARY *rrdinstance_acquired_labels(RRDINSTANCE_ACQUIRED *ria); +RRDLABELS *rrdinstance_acquired_labels(RRDINSTANCE_ACQUIRED *ria); DICTIONARY *rrdinstance_acquired_functions(RRDINSTANCE_ACQUIRED *ria); RRDHOST *rrdinstance_acquired_rrdhost(RRDINSTANCE_ACQUIRED *ria); RRDSET *rrdinstance_acquired_rrdset(RRDINSTANCE_ACQUIRED *ria); diff --git a/database/rrd.h b/database/rrd.h index c5a00aceac..baa3f4ab79 100644 --- a/database/rrd.h +++ b/database/rrd.h @@ -23,6 +23,8 @@ typedef struct rrdcalc RRDCALC; typedef struct rrdcalctemplate RRDCALCTEMPLATE; typedef struct alarm_entry ALARM_ENTRY; +typedef struct rrdlabels RRDLABELS; + typedef struct rrdfamily_acquired RRDFAMILY_ACQUIRED; typedef struct rrdvar_acquired RRDVAR_ACQUIRED; typedef struct rrdsetvar_acquired RRDSETVAR_ACQUIRED; @@ -113,6 +115,7 @@ struct ml_metrics_statistics { #include "rrddimvar.h" #include "rrdcalc.h" #include "rrdcalctemplate.h" +#include "rrdlabels.h" #include "streaming/rrdpush.h" #include "aclk/aclk_rrdhost_state.h" #include "sqlite/sqlite_health.h" @@ -265,60 +268,6 @@ typedef enum __attribute__ ((__packed__)) rrddim_flags { #define rrddim_flag_set(rd, flag) __atomic_or_fetch(&((rd)->flags), (flag), __ATOMIC_SEQ_CST) #define rrddim_flag_clear(rd, flag) __atomic_and_fetch(&((rd)->flags), ~(flag), __ATOMIC_SEQ_CST) -typedef enum __attribute__ ((__packed__)) rrdlabel_source { - RRDLABEL_SRC_AUTO = (1 << 0), // set when Netdata found the label by some automation - RRDLABEL_SRC_CONFIG = (1 << 1), // set when the user configured the label - RRDLABEL_SRC_K8S = (1 << 2), // set when this label is found from k8s (RRDLABEL_SRC_AUTO should also be set) - RRDLABEL_SRC_ACLK = (1 << 3), // set when this label is found from ACLK (RRDLABEL_SRC_AUTO should also be set) - - // more sources can be added here - - RRDLABEL_FLAG_PERMANENT = (1 << 29), // set when this label should never be removed (can be overwritten though) - RRDLABEL_FLAG_OLD = (1 << 30), // marks for rrdlabels internal use - they are not exposed outside rrdlabels - RRDLABEL_FLAG_NEW = (1 << 31) // marks for rrdlabels internal use - they are not exposed outside rrdlabels -} RRDLABEL_SRC; - -#define RRDLABEL_FLAG_INTERNAL (RRDLABEL_FLAG_OLD | RRDLABEL_FLAG_NEW | RRDLABEL_FLAG_PERMANENT) - -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); - -DICTIONARY *rrdlabels_create(void); -void rrdlabels_destroy(DICTIONARY *labels_dict); -void rrdlabels_add(DICTIONARY *dict, const char *name, const char *value, RRDLABEL_SRC ls); -void rrdlabels_add_pair(DICTIONARY *dict, const char *string, RRDLABEL_SRC ls); -void rrdlabels_get_value_to_buffer_or_null(DICTIONARY *labels, BUFFER *wb, const char *key, const char *quote, const char *null); -void rrdlabels_value_to_buffer_array_item_or_null(DICTIONARY *labels, BUFFER *wb, const char *key); -void rrdlabels_get_value_strdup_or_null(DICTIONARY *labels, char **value, const char *key); -void rrdlabels_get_value_strcpyz(DICTIONARY *labels, char *dst, size_t dst_len, const char *key); -STRING *rrdlabels_get_value_string_dup(DICTIONARY *labels, const char *key); -STRING *rrdlabels_get_value_to_buffer_or_unset(DICTIONARY *labels, BUFFER *wb, const char *key, const char *unset); -void rrdlabels_flush(DICTIONARY *labels_dict); - -void rrdlabels_unmark_all(DICTIONARY *labels); -void rrdlabels_remove_all_unmarked(DICTIONARY *labels); - -int rrdlabels_walkthrough_read(DICTIONARY *labels, int (*callback)(const char *name, const char *value, RRDLABEL_SRC ls, void *data), void *data); -int rrdlabels_sorted_walkthrough_read(DICTIONARY *labels, int (*callback)(const char *name, const char *value, RRDLABEL_SRC ls, void *data), void *data); - -void rrdlabels_log_to_buffer(DICTIONARY *labels, BUFFER *wb); -bool rrdlabels_match_simple_pattern(DICTIONARY *labels, const char *simple_pattern_txt); - -bool rrdlabels_match_simple_pattern_parsed(DICTIONARY *labels, SIMPLE_PATTERN *pattern, char equal, size_t *searches); -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)); -void rrdlabels_to_buffer_json_members(DICTIONARY *labels, BUFFER *wb); - -void rrdlabels_migrate_to_these(DICTIONARY *dst, DICTIONARY *src); -void rrdlabels_copy(DICTIONARY *dst, DICTIONARY *src); - -void reload_host_labels(void); -void rrdset_update_rrdlabels(RRDSET *st, DICTIONARY *new_rrdlabels); -void rrdset_save_rrdlabels_to_sql(RRDSET *st); -void rrdhost_set_is_parent_label(void); -int rrdlabels_unittest(void); - -// unfortunately this break when defined in exporting_engine.h -bool exporting_labels_filter_callback(const char *name, const char *value, RRDLABEL_SRC ls, void *data); - // ---------------------------------------------------------------------------- // engine-specific iterator state for dimension data collection typedef struct storage_collect_handle { @@ -795,7 +744,7 @@ struct rrdset { int32_t priority; // the sorting priority of this chart int32_t update_every; // data collection frequency - DICTIONARY *rrdlabels; // chart labels + RRDLABELS *rrdlabels; // chart labels DICTIONARY *rrdsetvar_root_index; // chart variables DICTIONARY *rrddimvar_root_index; // dimension variables // we use this dictionary to manage their allocation @@ -1156,7 +1105,7 @@ struct rrdhost_system_info { int mc_version; }; -struct rrdhost_system_info *rrdhost_labels_to_system_info(DICTIONARY *labels); +struct rrdhost_system_info *rrdhost_labels_to_system_info(RRDLABELS *labels); struct rrdhost { char machine_guid[GUID_LEN + 1]; // the unique ID of this host @@ -1263,7 +1212,7 @@ struct rrdhost { // ------------------------------------------------------------------------ // Support for host-level labels - DICTIONARY *rrdlabels; + RRDLABELS *rrdlabels; // ------------------------------------------------------------------------ // Support for functions @@ -1509,6 +1458,8 @@ time_t rrdset_last_entry_s_of_tier(RRDSET *st, size_t tier); 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); +void rrdset_update_rrdlabels(RRDSET *st, RRDLABELS *new_rrdlabels); + // ---------------------------------------------------------------------------- // RRD DIMENSION functions @@ -1563,6 +1514,8 @@ void rrddim_store_metric(RRDDIM *rd, usec_t point_end_time_ut, NETDATA_DOUBLE n, // Miscellaneous functions char *rrdset_strncpyz_name(char *to, const char *from, size_t length); +void reload_host_labels(void); +void rrdhost_set_is_parent_label(void); // ---------------------------------------------------------------------------- // RRD internal functions diff --git a/database/rrdcalc.c b/database/rrdcalc.c index 8e41df8d65..9278aaf348 100644 --- a/database/rrdcalc.c +++ b/database/rrdcalc.c @@ -155,7 +155,7 @@ static STRING *rrdcalc_replace_variables_with_rrdset_labels(const char *line, RR void rrdcalc_update_info_using_rrdset_labels(RRDCALC *rc) { if(!rc->rrdset || !rc->original_info || !rc->rrdset->rrdlabels) return; - size_t labels_version = dictionary_version(rc->rrdset->rrdlabels); + size_t labels_version = rrdlabels_version(rc->rrdset->rrdlabels); if(rc->labels_version != labels_version) { STRING *old = rc->info; diff --git a/database/rrdhost.c b/database/rrdhost.c index b24047f401..2a5778bf15 100644 --- a/database/rrdhost.c +++ b/database/rrdhost.c @@ -1317,7 +1317,7 @@ void rrdhost_save_charts(RRDHOST *host) { rrdset_foreach_done(st); } -struct rrdhost_system_info *rrdhost_labels_to_system_info(DICTIONARY *labels) { +struct rrdhost_system_info *rrdhost_labels_to_system_info(RRDLABELS *labels) { struct rrdhost_system_info *info = callocz(1, sizeof(struct rrdhost_system_info)); info->hops = 1; @@ -1345,7 +1345,7 @@ struct rrdhost_system_info *rrdhost_labels_to_system_info(DICTIONARY *labels) { } static void rrdhost_load_auto_labels(void) { - DICTIONARY *labels = localhost->rrdlabels; + RRDLABELS *labels = localhost->rrdlabels; if (localhost->system_info->cloud_provider_type) 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) { int count = __atomic_load_n(&localhost->connected_children_count, __ATOMIC_RELAXED); if (count == 0 || count == 1) { - DICTIONARY *labels = localhost->rrdlabels; + RRDLABELS *labels = localhost->rrdlabels; rrdlabels_add(labels, "_is_parent", (count) ? "true" : "false", RRDLABEL_SRC_AUTO); //queue a node info diff --git a/database/rrdlabels.c b/database/rrdlabels.c index 77d9a91f00..3dbcd0cd3c 100644 --- a/database/rrdlabels.c +++ b/database/rrdlabels.c @@ -3,6 +3,91 @@ #define NETDATA_RRD_INTERNALS #include "rrd.h" +// Key OF HS ARRRAY + +struct { + Pvoid_t JudyHS; + SPINLOCK spinlock; +} global_labels = { + .JudyHS = (Pvoid_t) NULL, + .spinlock = NETDATA_SPINLOCK_INITIALIZER +}; + +typedef struct label_registry_idx { + STRING *key; + STRING *value; +} LABEL_REGISTRY_IDX; + +typedef struct labels_registry_entry { + LABEL_REGISTRY_IDX index; +} RRDLABEL; + +// Value of HS array +typedef struct labels_registry_idx_entry { + RRDLABEL label; + size_t refcount; +} RRDLABEL_IDX; + +typedef struct rrdlabels { + SPINLOCK spinlock; + size_t version; + Pvoid_t JudyL; +} RRDLABELS; + +#define lfe_start_nolock(label_list, label, ls) \ + do { \ + bool _first_then_next = true; \ + Pvoid_t *_PValue; \ + Word_t _Index = 0; \ + while ((_PValue = JudyLFirstThenNext((label_list)->JudyL, &_Index, &_first_then_next))) { \ + (ls) = *(RRDLABEL_SRC *)_PValue; \ + (void)(ls); \ + (label) = (void *)_Index; + +#define lfe_done_nolock() \ + } \ + } \ + while (0) + +#define lfe_start_read(label_list, label, ls) \ + do { \ + spinlock_lock(&(label_list)->spinlock); \ + bool _first_then_next = true; \ + Pvoid_t *_PValue; \ + Word_t _Index = 0; \ + while ((_PValue = JudyLFirstThenNext((label_list)->JudyL, &_Index, &_first_then_next))) { \ + (ls) = *(RRDLABEL_SRC *)_PValue; \ + (void)(ls); \ + (label) = (void *)_Index; + +#define lfe_done(label_list) \ + } \ + spinlock_unlock(&(label_list)->spinlock); \ + } \ + while (0) + +static inline void STATS_PLUS_MEMORY(struct dictionary_stats *stats, size_t key_size, size_t item_size, size_t value_size) { + if(key_size) + __atomic_fetch_add(&stats->memory.index, (long)JUDYHS_INDEX_SIZE_ESTIMATE(key_size), __ATOMIC_RELAXED); + + if(item_size) + __atomic_fetch_add(&stats->memory.dict, (long)item_size, __ATOMIC_RELAXED); + + if(value_size) + __atomic_fetch_add(&stats->memory.values, (long)value_size, __ATOMIC_RELAXED); +} + +static inline void STATS_MINUS_MEMORY(struct dictionary_stats *stats, size_t key_size, size_t item_size, size_t value_size) { + if(key_size) + __atomic_fetch_sub(&stats->memory.index, (long)JUDYHS_INDEX_SIZE_ESTIMATE(key_size), __ATOMIC_RELAXED); + + if(item_size) + __atomic_fetch_sub(&stats->memory.dict, (long)item_size, __ATOMIC_RELAXED); + + if(value_size) + __atomic_fetch_sub(&stats->memory.values, (long)value_size, __ATOMIC_RELAXED); +} + // ---------------------------------------------------------------------------- // labels sanitization @@ -369,6 +454,12 @@ __attribute__((constructor)) void initialize_labels_keys_char_map(void) { } +__attribute__((constructor)) void initialize_label_stats(void) { + dictionary_stats_category_rrdlabels.memory.dict = 0; + dictionary_stats_category_rrdlabels.memory.index = 0; + dictionary_stats_category_rrdlabels.memory.values = 0; +} + 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) { if(unlikely(!dst_size)) return 0; @@ -484,93 +575,132 @@ static inline size_t rrdlabels_sanitize_value(char *dst, const char *src, size_t // ---------------------------------------------------------------------------- // rrdlabels_create() -typedef struct rrdlabel { - STRING *label_value; - RRDLABEL_SRC label_source; -} RRDLABEL; - -static void rrdlabel_insert_callback(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *dict_ptr __maybe_unused) { - RRDLABEL *lb = (RRDLABEL *)value; - - // label_value is already allocated by the STRING - lb->label_source |= RRDLABEL_FLAG_NEW; - lb->label_source &= ~RRDLABEL_FLAG_OLD; +RRDLABELS *rrdlabels_create(void) +{ + RRDLABELS *labels = callocz(1, sizeof(*labels)); + STATS_PLUS_MEMORY(&dictionary_stats_category_rrdlabels, 0, sizeof(RRDLABELS), 0); + return labels; } -static void rrdlabel_delete_callback(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *dict_ptr __maybe_unused) { - RRDLABEL *lb = (RRDLABEL *)value; - - string_freez(lb->label_value); - lb->label_value = NULL; -} - -static bool rrdlabel_conflict_callback(const DICTIONARY_ITEM *item __maybe_unused, void *oldvalue, void *newvalue, void *dict_ptr __maybe_unused) { - RRDLABEL *lbold = (RRDLABEL *)oldvalue; - RRDLABEL *lbnew = (RRDLABEL *)newvalue; - - if(lbold->label_value == lbnew->label_value) { - // they are the same - - lbold->label_source |= lbnew->label_source; - lbold->label_source |= RRDLABEL_FLAG_OLD; - lbold->label_source &= ~RRDLABEL_FLAG_NEW; +static void dup_label(RRDLABEL *label_index) +{ + if (!label_index) + return; - // free the new one - string_freez(lbnew->label_value); + spinlock_lock(&global_labels.spinlock); - return false; + Pvoid_t *PValue = JudyHSGet(global_labels.JudyHS, (void *)label_index, sizeof(*label_index)); + if (PValue && *PValue) { + RRDLABEL_IDX *rrdlabel = *PValue; + __atomic_add_fetch(&rrdlabel->refcount, 1, __ATOMIC_RELAXED); } - // they are different - - string_freez(lbold->label_value); - lbold->label_value = lbnew->label_value; - lbold->label_source = lbnew->label_source; - lbold->label_source |= RRDLABEL_FLAG_NEW; - lbold->label_source &= ~RRDLABEL_FLAG_OLD; - - return true; + spinlock_unlock(&global_labels.spinlock); } -DICTIONARY *rrdlabels_create(void) { - DICTIONARY *dict = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE, - &dictionary_stats_category_rrdlabels, sizeof(RRDLABEL)); +static RRDLABEL *add_label_name_value(const char *name, const char *value) +{ + RRDLABEL_IDX *rrdlabel = NULL; + LABEL_REGISTRY_IDX label_index; + label_index.key = string_strdupz(name); + label_index.value = string_strdupz(value); + + spinlock_lock(&global_labels.spinlock); + + Pvoid_t *PValue = JudyHSIns(&global_labels.JudyHS, (void *)&label_index, sizeof(label_index), PJE0); + if(unlikely(!PValue || PValue == PJERR)) + fatal("RRDLABELS: corrupted judyHS array"); + + if (*PValue) { + rrdlabel = *PValue; + string_freez(label_index.key); + string_freez(label_index.value); + } else { + rrdlabel = callocz(1, sizeof(*rrdlabel)); + rrdlabel->label.index = label_index; + *PValue = rrdlabel; + STATS_PLUS_MEMORY(&dictionary_stats_category_rrdlabels, sizeof(LABEL_REGISTRY_IDX), sizeof(RRDLABEL_IDX), 0); + } + __atomic_add_fetch(&rrdlabel->refcount, 1, __ATOMIC_RELAXED); - dictionary_register_insert_callback(dict, rrdlabel_insert_callback, dict); - dictionary_register_delete_callback(dict, rrdlabel_delete_callback, dict); - dictionary_register_conflict_callback(dict, rrdlabel_conflict_callback, dict); - return dict; + spinlock_unlock(&global_labels.spinlock); + return &rrdlabel->label; } +static void delete_label(RRDLABEL *label) +{ + spinlock_lock(&global_labels.spinlock); + + Pvoid_t *PValue = JudyHSGet(global_labels.JudyHS, &label->index, sizeof(label->index)); + if (PValue && *PValue) { + RRDLABEL_IDX *rrdlabel = *PValue; + size_t refcount = __atomic_sub_fetch(&rrdlabel->refcount, 1, __ATOMIC_RELAXED); + if (refcount == 0) { + int ret = JudyHSDel(&global_labels.JudyHS, (void *)label, sizeof(*label), PJE0); + if (unlikely(ret == JERR)) + STATS_MINUS_MEMORY(&dictionary_stats_category_rrdlabels, 0, sizeof(*rrdlabel), 0); + else + STATS_MINUS_MEMORY(&dictionary_stats_category_rrdlabels, sizeof(LABEL_REGISTRY_IDX), sizeof(*rrdlabel), 0); + string_freez(label->index.key); + string_freez(label->index.value); + freez(rrdlabel); + } + } + spinlock_unlock(&global_labels.spinlock); +} // ---------------------------------------------------------------------------- // rrdlabels_destroy() -void rrdlabels_destroy(DICTIONARY *labels_dict) { - dictionary_destroy(labels_dict); -} +void rrdlabels_destroy(RRDLABELS *labels) +{ + if (unlikely(!labels)) + return; -void rrdlabels_flush(DICTIONARY *labels_dict) { - dictionary_flush(labels_dict); + spinlock_lock(&labels->spinlock); + + Pvoid_t *PValue; + Word_t Index = 0; + bool first_then_next = true; + while ((PValue = JudyLFirstThenNext(labels->JudyL, &Index, &first_then_next))) { + delete_label((RRDLABEL *)Index); + } + size_t memory_freed = JudyLFreeArray(&labels->JudyL, PJE0); + STATS_MINUS_MEMORY(&dictionary_stats_category_rrdlabels, 0, memory_freed + sizeof(RRDLABELS), 0); + spinlock_unlock(&labels->spinlock); + freez(labels); } // ---------------------------------------------------------------------------- // rrdlabels_add() -static void labels_add_already_sanitized(DICTIONARY *dict, const char *key, const char *value, RRDLABEL_SRC ls) { - if(ls & RRDLABEL_FLAG_NEW) ls &= ~RRDLABEL_FLAG_NEW; - if(ls & RRDLABEL_FLAG_OLD) ls &= ~RRDLABEL_FLAG_OLD; +static void labels_add_already_sanitized(RRDLABELS *labels, const char *key, const char *value, RRDLABEL_SRC ls) +{ + RRDLABEL *label = add_label_name_value(key, value); - RRDLABEL tmp = { - .label_source = ls, - .label_value = string_strdupz(value) - }; - dictionary_set(dict, key, &tmp, sizeof(RRDLABEL)); -} + spinlock_lock(&labels->spinlock); + + size_t mem_before_judyl = JudyLMemUsed(labels->JudyL); + Pvoid_t *PValue = JudyLIns(&labels->JudyL, (Word_t) label, PJE0); + if(unlikely(!PValue || PValue == PJERR)) + fatal("RRDLABELS: corrupted labels JudyL array"); + + if (!*PValue) { + *((RRDLABEL_SRC *)PValue) = (ls & ~(RRDLABEL_FLAG_NEW | RRDLABEL_FLAG_OLD)); + labels->version++; + size_t mem_after_judyl = JudyLMemUsed(labels->JudyL); + STATS_PLUS_MEMORY(&dictionary_stats_category_rrdlabels, 0, mem_after_judyl - mem_before_judyl, 0); + } + else + delete_label(label); + + spinlock_unlock(&labels->spinlock); +} -void rrdlabels_add(DICTIONARY *dict, const char *name, const char *value, RRDLABEL_SRC ls) { - if(!dict) { +void rrdlabels_add(RRDLABELS *labels, const char *name, const char *value, RRDLABEL_SRC ls) +{ + if(!labels) { netdata_log_error("%s(): called with NULL dictionary.", __FUNCTION__ ); return; } @@ -584,7 +714,30 @@ void rrdlabels_add(DICTIONARY *dict, const char *name, const char *value, RRDLAB return; } - labels_add_already_sanitized(dict, n, v, ls); + labels_add_already_sanitized(labels, n, v, ls); +} + +bool rrdlabels_exist(RRDLABELS *labels, const char *key) +{ + if (!labels) + return false; + + STRING *this_key = string_strdupz(key); + + RRDLABEL *lb; + RRDLABEL_SRC ls; + + bool found = false; + lfe_start_read(labels, lb, ls) + { + if (lb->index.key == this_key) { + found = true; + break; + } + } + lfe_done(labels); + string_freez(this_key); + return found; } 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 return string; } -void rrdlabels_add_pair(DICTIONARY *dict, const char *string, RRDLABEL_SRC ls) { - if(!dict) { +void rrdlabels_add_pair(RRDLABELS *labels, const char *string, RRDLABEL_SRC ls) +{ + if(!labels) { netdata_log_error("%s(): called with NULL dictionary.", __FUNCTION__ ); return; } @@ -631,199 +785,222 @@ void rrdlabels_add_pair(DICTIONARY *dict, const char *string, RRDLABEL_SRC ls) { char value[RRDLABELS_MAX_VALUE_LENGTH + 1]; get_quoted_string_up_to(value, RRDLABELS_MAX_VALUE_LENGTH, string, '\0', '\0'); - rrdlabels_add(dict, name, value, ls); + rrdlabels_add(labels, name, value, ls); } // ---------------------------------------------------------------------------- -// rrdlabels_get_value_to_buffer_or_null() -void rrdlabels_get_value_to_buffer_or_null(DICTIONARY *labels, BUFFER *wb, const char *key, const char *quote, const char *null) { +void rrdlabels_value_to_buffer_array_item_or_null(RRDLABELS *labels, BUFFER *wb, const char *key) { if(!labels) return; - const DICTIONARY_ITEM *acquired_item = dictionary_get_and_acquire_item(labels, key); - RRDLABEL *lb = dictionary_acquired_item_value(acquired_item); + STRING *this_key = string_strdupz(key); - if(lb && lb->label_value) - buffer_sprintf(wb, "%s%s%s", quote, string2str(lb->label_value), quote); - else - buffer_strcat(wb, null); - - dictionary_acquired_item_release(labels, acquired_item); -} - -void rrdlabels_value_to_buffer_array_item_or_null(DICTIONARY *labels, BUFFER *wb, const char *key) { - if(!labels) return; - - const DICTIONARY_ITEM *acquired_item = dictionary_get_and_acquire_item(labels, key); - RRDLABEL *lb = dictionary_acquired_item_value(acquired_item); - - if(lb && lb->label_value) - buffer_json_add_array_item_string(wb, string2str(lb->label_value)); - else - buffer_json_add_array_item_string(wb, NULL); - - dictionary_acquired_item_release(labels, acquired_item); + RRDLABEL *lb; + RRDLABEL_SRC ls; + lfe_start_read(labels, lb, ls) + { + if (lb->index.key == this_key) { + if (lb->index.value) + buffer_json_add_array_item_string(wb, string2str(lb->index.value)); + else + buffer_json_add_array_item_string(wb, NULL); + break; + } + } + lfe_done(labels); + string_freez(this_key); } // ---------------------------------------------------------------------------- -// rrdlabels_get_value_to_char_or_null() - -void rrdlabels_get_value_strdup_or_null(DICTIONARY *labels, char **value, const char *key) { - const DICTIONARY_ITEM *acquired_item = dictionary_get_and_acquire_item(labels, key); - RRDLABEL *lb = dictionary_acquired_item_value(acquired_item); - *value = (lb && lb->label_value) ? strdupz(string2str(lb->label_value)) : NULL; - - dictionary_acquired_item_release(labels, acquired_item); -} +void rrdlabels_get_value_strcpyz(RRDLABELS *labels, char *dst, size_t dst_len, const char *key) { + if(!labels) return; -void rrdlabels_get_value_strcpyz(DICTIONARY *labels, char *dst, size_t dst_len, const char *key) { - const DICTIONARY_ITEM *acquired_item = dictionary_get_and_acquire_item(labels, key); - RRDLABEL *lb = dictionary_acquired_item_value(acquired_item); + STRING *this_key = string_strdupz(key); - if(lb && lb->label_value) - strncpyz(dst, string2str(lb->label_value), dst_len); - else - dst[0] = '\0'; + RRDLABEL *lb; + RRDLABEL_SRC ls; - dictionary_acquired_item_release(labels, acquired_item); + lfe_start_read(labels, lb, ls) + { + if (lb->index.key == this_key) { + if (lb->index.value) + strncpyz(dst, string2str(lb->index.value), dst_len); + else + dst[0] = '\0'; + break; + } + } + lfe_done(labels); + string_freez(this_key); } -STRING *rrdlabels_get_value_string_dup(DICTIONARY *labels, const char *key) { - const DICTIONARY_ITEM *acquired_item = dictionary_get_and_acquire_item(labels, key); - RRDLABEL *lb = dictionary_acquired_item_value(acquired_item); - - STRING *ret = NULL; - if(lb && lb->label_value) - ret = string_dup(lb->label_value); +void rrdlabels_get_value_strdup_or_null(RRDLABELS *labels, char **value, const char *key) +{ + if(!labels) return; - dictionary_acquired_item_release(labels, acquired_item); + STRING *this_key = string_strdupz(key); - return ret; + RRDLABEL *lb; + RRDLABEL_SRC ls; + lfe_start_read(labels, lb, ls) + { + if (lb->index.key == this_key) { + *value = (lb->index.value) ? strdupz(string2str(lb->index.value)) : NULL; + break; + } + } + lfe_done(labels); + string_freez(this_key); } -STRING *rrdlabels_get_value_to_buffer_or_unset(DICTIONARY *labels, BUFFER *wb, const char *key, const char *unset) { - const DICTIONARY_ITEM *acquired_item = dictionary_get_and_acquire_item(labels, key); - RRDLABEL *lb = dictionary_acquired_item_value(acquired_item); - - STRING *ret = NULL; - if(lb && lb->label_value) - buffer_strcat(wb, string2str(lb->label_value)); - else - buffer_strcat(wb, unset); +void rrdlabels_get_value_to_buffer_or_unset(RRDLABELS *labels, BUFFER *wb, const char *key, const char *unset) +{ + if(!labels || !key || !wb) return; - dictionary_acquired_item_release(labels, acquired_item); + STRING *this_key = string_strdupz(key); + RRDLABEL *lb; + RRDLABEL_SRC ls; - return ret; + lfe_start_read(labels, lb, |