summaryrefslogtreecommitdiffstats
path: root/database
diff options
context:
space:
mode:
authorStelios Fragkakis <52996999+stelfrag@users.noreply.github.com>2023-09-01 15:37:55 +0300
committerGitHub <noreply@github.com>2023-09-01 15:37:55 +0300
commit24006ed5c19cf7c398cf8a76e7bdce1f60c7e5a4 (patch)
treeb7ef3ec6b5d999d3884b9af40c2b7a53eca8f027 /database
parentbeba227adf489a30e826c3922e4cb3635fb0b154 (diff)
Reduce label memory (#15255)
Diffstat (limited to 'database')
-rw-r--r--database/contexts/api_v1.c2
-rw-r--r--database/contexts/api_v2.c2
-rw-r--r--database/contexts/instance.c6
-rw-r--r--database/contexts/internal.h2
-rw-r--r--database/contexts/rrdcontext.h2
-rw-r--r--database/rrd.h67
-rw-r--r--database/rrdcalc.c2
-rw-r--r--database/rrdhost.c6
-rw-r--r--database/rrdlabels.c714
-rw-r--r--database/rrdlabels.h59
-rw-r--r--database/sqlite/sqlite_functions.c10
-rw-r--r--database/sqlite/sqlite_functions.h2
-rw-r--r--database/sqlite/sqlite_metadata.c2
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,