summaryrefslogtreecommitdiffstats
path: root/database/rrdlabels.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2023-10-17 09:30:23 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2023-10-17 09:30:23 +0000
commit517a443636daa1e8085cb4e5325524a54e8a8fd7 (patch)
tree5352109cc7cd5122274ab0cfc1f887b685f04edf /database/rrdlabels.c
parentReleasing debian version 1.42.4-1. (diff)
downloadnetdata-517a443636daa1e8085cb4e5325524a54e8a8fd7.tar.xz
netdata-517a443636daa1e8085cb4e5325524a54e8a8fd7.zip
Merging upstream version 1.43.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--database/rrdlabels.c755
1 files changed, 500 insertions, 255 deletions
diff --git a/database/rrdlabels.c b/database/rrdlabels.c
index 77d9a91f..243b16c6 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,164 @@ 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;
+
+ 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);
}
-void rrdlabels_flush(DICTIONARY *labels_dict) {
- dictionary_flush(labels_dict);
+static RRDLABEL *rrdlabels_find_label_with_key_unsafe(RRDLABELS *labels, RRDLABEL *label)
+{
+ if (unlikely(!labels))
+ return NULL;
+
+ Pvoid_t *PValue;
+ Word_t Index = 0;
+ bool first_then_next = true;
+ RRDLABEL *found = NULL;
+ while ((PValue = JudyLFirstThenNext(labels->JudyL, &Index, &first_then_next))) {
+ RRDLABEL *lb = (RRDLABEL *)Index;
+ if (lb->index.key == label->index.key && lb->index.value != label->index.value) {
+ found = (RRDLABEL *)Index;
+ break;
+ }
+ }
+ return found;
}
// ----------------------------------------------------------------------------
// 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);
+
+ RRDLABEL *old_key = rrdlabels_find_label_with_key_unsafe(labels, label);
+
+ 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 new_ls;
+ if (old_key)
+ new_ls = ((ls & ~(RRDLABEL_FLAG_NEW | RRDLABEL_FLAG_OLD)) | RRDLABEL_FLAG_OLD);
+ else
+ new_ls = ((ls & ~(RRDLABEL_FLAG_NEW | RRDLABEL_FLAG_OLD)) | RRDLABEL_FLAG_NEW);
+ *((RRDLABEL_SRC *)PValue) = new_ls;
+ labels->version++;
-void rrdlabels_add(DICTIONARY *dict, const char *name, const char *value, RRDLABEL_SRC ls) {
- if(!dict) {
+ if (old_key) {
+ (void)JudyLDel(&labels->JudyL, (Word_t) old_key, PJE0);
+ delete_label((RRDLABEL *)old_key);
+ }
+ 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(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 +746,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 +804,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 +817,243 @@ 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);
-
- if(lb && lb->label_value)
- buffer_sprintf(wb, "%s%s%s", quote, string2str(lb->label_value), quote);
- else
- buffer_strcat(wb, null);
+ STRING *this_key = string_strdupz(key);
- 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);
}
-void rrdlabels_value_to_buffer_array_item_or_null(DICTIONARY *labels, BUFFER *wb, const char *key) {
+// ----------------------------------------------------------------------------
+
+void rrdlabels_get_value_strcpyz(RRDLABELS *labels, char *dst, size_t dst_len, 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_json_add_array_item_string(wb, string2str(lb->label_value));
- else
- buffer_json_add_array_item_string(wb, NULL);
+ 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);
}
-// ----------------------------------------------------------------------------
-// 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);
+void rrdlabels_get_value_strdup_or_null(RRDLABELS *labels, char **value, const char *key)
+{
+ if(!labels) return;
- *value = (lb && lb->label_value) ? strdupz(string2str(lb->label_value)) : NULL;
+ STRING *this_key = string_strdupz(key);
- dictionary_acquired_item_release(labels, acquired_item);
+ 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);
}
-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);
+void rrdlabels_get_value_to_buffer_or_unset(RRDLABELS *labels, BUFFER *wb, const char *key, const char *unset)
+{
+ if(!labels || !key || !wb) return;
- if(lb && lb->label_value)
- strncpyz(dst, string2str(lb->label_value), dst_len);
- else
- dst[0] = '\0';
+ STRING *this_key = string_strdupz(key);
+ 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)
+ buffer_strcat(wb, string2str(lb->index.value));
+ else
+ buffer_strcat(wb, unset);
+ 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);
-
- dictionary_acquired_item_release(labels, acquired_item);
-
- return ret;
+static void rrdlabels_unmark_all_unsafe(RRDLABELS *labels)
+{
+ Pvoid_t *PValue;
+ Word_t Index = 0;
+ bool first_then_next = true;
+ while ((PValue = JudyLFirstThenNext(labels->JudyL, &Index, &first_then_next)))
+ *((RRDLABEL_SRC *)PValue) &= ~(RRDLABEL_FLAG_OLD | RRDLABEL_FLAG_NEW);
}
-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_unmark_all(RRDLABELS *labels)
+{
+ spinlock_lock(&labels->spinlock);
- dictionary_acquired_item_release(labels, acquired_item);
+ rrdlabels_unmark_all_unsafe(labels);
- return ret;
+ spinlock_unlock(&labels->spinlock);
}
-// ----------------------------------------------------------------------------
-// rrdlabels_unmark_all()
-// remove labels RRDLABEL_FLAG_OLD and RRDLABEL_FLAG_NEW from all dictionary items
+static void rrdlabels_remove_all_unmarked_unsafe(RRDLABELS *labels)
+{
+ Pvoid_t *PValue;
+ Word_t Index = 0;
+ bool first_then_next = true;
-static int remove_flags_old_new(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused) {
- RRDLABEL *lb = (RRDLABEL *)value;
+ while ((PValue = JudyLFirstThenNext(labels->JudyL, &Index, &first_then_next))) {
+ if (!((*((RRDLABEL_SRC *)PValue)) & (RRDLABEL_FLAG_OLD | RRDLABEL_FLAG_NEW | RRDLABEL_FLAG_PERMANENT))) {
- if(lb->label_source & RRDLABEL_FLAG_OLD) lb->label_source &= ~RRDLABEL_FLAG_OLD;
- if(lb->label_source & RRDLABEL_FLAG_NEW) lb->label_source &= ~RRDLABEL_FLAG_NEW;
+ size_t mem_before_judyl = JudyLMemUsed(labels->JudyL);
+ (void)JudyLDel(&labels->JudyL, Index, PJE0);
+ size_t mem_after_judyl = JudyLMemUsed(labels->JudyL);
- return 1;
-}
+ STATS_MINUS_MEMORY(&dictionary_stats_category_rrdlabels, 0, mem_before_judyl - mem_after_judyl, 0);
-void rrdlabels_unmark_all(DICTIONARY *labels) {
- dictionary_walkthrough_read(labels, remove_flags_old_new, NULL);
+ delete_label((RRDLABEL *)Index);
+ if (labels->JudyL != (Pvoid_t) NULL) {
+ Index = 0;
+ first_then_next = true;
+ }
+ }
+ }
}
+void rrdlabels_remove_all_unmarked(RRDLABELS *labels)
+{
+ spinlock_lock(&labels->spinlock);
+ rrdlabels_remove_all_unmarked_unsafe(labels);
+ spinlock_unlock(&labels->spinlock);
+}
// ----------------------------------------------------------------------------
-// rrdlabels_remove_all_unmarked()
-// remove dictionary items that are neither old, nor new
+// rrdlabels_walkthrough_read()
-static int remove_not_old_not_new_callback(const DICTIONARY_ITEM *item, void *value, void *data) {
- const char *name = dictionary_acquired_item_name(item);
- DICTIONARY *dict = (DICTIONARY *)data;
- RRDLABEL *lb = (RRDLABEL *)value;
+int rrdlabels_walkthrough_read(RRDLABELS *labels, int (*callback)(const char *name, const char *value, RRDLABEL_SRC ls, void *data), void *data)
+{
+ int ret = 0;
- if(!(lb->label_source & (RRDLABEL_FLAG_OLD | RRDLABEL_FLAG_NEW | RRDLABEL_FLAG_PERMANENT))) {
- dictionary_del(dict, name);
- return 1;
- }
+ if(unlikely(!labels || !callback)) return 0;
- return 0;
-}
+ RRDLABEL *lb;
+ RRDLABEL_SRC ls;
+ lfe_start_read(labels, lb, ls)
+ {
+ ret = callback(string2str(lb->index.key), string2str(lb->index.value), ls, data);
+ if (ret < 0)
+ break;
+ }
+ lfe_done(labels);
-void rrdlabels_remove_all_unmarked(DICTIONARY *labels) {
- dictionary_walkthrough_write(labels, remove_not_old_not_new_callback, labels);
+ return ret;
}
-
// ----------------------------------------------------------------------------
-// rrdlabels_walkthrough_read()
-
-struct labels_walkthrough {
- int (*callback)(const char *name, const char *value, RRDLABEL_SRC ls, void *data);
- void *data;
-};
+// rrdlabels_migrate_to_these()
+// migrate an existing label list to a new list
-static int labels_walkthrough_callback(const DICTIONARY_ITEM *item, void *value, void *data) {
- const char *name = dictionary_acquired_item_name(item);
- struct labels_walkthrough *d = (struct labels_walkthrough *)data;
- RRDLABEL *lb = (RRDLABEL *)value;
+void rrdlabels_migrate_to_these(RRDLABELS *dst, RRDLABELS *src) {
+ if (!dst || !src)
+ return;
- RRDLABEL_SRC ls = lb->label_source;
- if(ls & RRDLABEL_FLAG_NEW) ls &= ~RRDLABEL_FLAG_NEW;
- if(ls & RRDLABEL_FLAG_OLD) ls &= ~RRDLABEL_FLAG_OLD;
+ spinlock_lock(&dst->spinlock);
+ spinlock_lock(&src->spinlock);
- return d->callback(name, string2str(lb->label_value), ls, d->data);
-}
+ rrdlabels_unmark_all_unsafe(dst);
-int rrdlabels_walkthrough_read(DICTIONARY *labels, int (*callback)(const char *name, const char *value, RRDLABEL_SRC ls, void *data), void *data) {
- struct labels_walkthrough d = {
- .callback = callback,
- .data = data
- };
- return dictionary_walkthrough_read(labels, labels_walkthrough_callback, &d);
-}
+ RRDLABEL *label;
+ Pvoid_t *PValue;
-int rrdlabels_sorted_walkthrough_read(DICTIONARY *labels, int (*callback)(const char *name, const char *value, RRDLABEL_SRC ls, void *data), void *data) {
- struct labels_walkthrough d = {
- .callback = callback,
- .data = data
- };
- return dictionary_sorted_walkthrough_read(labels, labels_walkthrough_callback, &d);
-}
+ RRDLABEL_SRC ls;
+ lfe_start_nolock(src, label, ls)
+ {
+ size_t mem_before_judyl = JudyLMemUsed(dst->JudyL);
+ PValue = JudyLIns(&dst->JudyL, (Word_t)label, PJE0);
+ if(unlikely(!PValue || PValue == PJERR))
+ fatal("RRDLABELS migrate: corrupted labels array");
+
+ RRDLABEL_SRC flag = RRDLABEL_FLAG_NEW;
+ if (!*PValue) {
+ dup_label(label);
+ size_t mem_after_judyl = JudyLMemUsed(dst->JudyL);
+ STATS_PLUS_MEMORY(&dictionary_stats_category_rrdlabels, 0, mem_after_judyl - mem_before_judyl, 0);
+ }
+ else
+ flag = RRDLABEL_FLAG_OLD;
+ *((RRDLABEL_SRC *)PValue) |= flag;
+ }
+ lfe_done_nolock();
-// ----------------------------------------------------------------------------
-// rrdlabels_migrate_to_these()
-// migrate an existing label list to a new list, INPLACE
+ rrdlabels_remove_all_unmarked_unsafe(dst);
+ dst->version = src->version;
-static int copy_label_to_dictionary_callback(const DICTIONARY_ITEM *item, void *value, void *data) {
- const char *name = dictionary_acquired_item_name(item);
- DICTIONARY *dst = (DICTIONARY *)data;
- RRDLABEL *lb = (RRDLABEL *)value;
- labels_add_already_sanitized(dst, name, string2str(lb->label_value), lb->label_source);
- return 1;
+ spinlock_unlock(&src->spinlock);
+ spinlock_unlock(&dst->spinlock);
}
-void rrdlabels_migrate_to_these(DICTIONARY *dst, DICTIONARY *src) {
- if(!dst || !src) return;
-
- // remove the RRDLABEL_FLAG_OLD and RRDLABEL_FLAG_NEW from all items
- rrdlabels_unmark_all(dst);
+void rrdlabels_copy(RRDLABELS *dst, RRDLABELS *src)
+{
+ if (!dst || !src)
+ return;
- // Mark the existing ones as RRDLABEL_FLAG_OLD,
- // or the newly added ones as RRDLABEL_FLAG_NEW
- dictionary_walkthrough_read(src, copy_label_to_dictionary_callback, dst);
+ RRDLABEL *label;
+ RRDLABEL_SRC ls;
- // remove the unmarked dst
- rrdlabels_remove_all_unmarked(dst);
-}
+ spinlock_lock(&dst->spinlock);
+ spinlock_lock(&src->spinlock);
+
+ lfe_start_nolock(src, label, ls)
+ {
+ size_t mem_before_judyl = JudyLMemUsed(dst->JudyL);
+ Pvoid_t *PValue = JudyLIns(&dst->JudyL, (Word_t)label, PJE0);
+ if(unlikely(!PValue || PValue == PJERR))
+ fatal("RRDLABELS: corrupted labels array");
+
+ if (!*PValue) {
+ dup_label(label);
+ size_t mem_after_judyl = JudyLMemUsed(dst->JudyL);
+ STATS_PLUS_MEMORY(&dictionary_stats_category_rrdlabels, 0, mem_after_judyl - mem_before_judyl, 0);
+ *((RRDLABEL_SRC *)PValue) = ls;
+ }
+ }
+ lfe_done_nolock();
-void rrdlabels_copy(DICTIONARY *dst, DICTIONARY *src) {
- if(!dst || !src) return;
+ dst->version = src->version;
- dictionary_walkthrough_read(src, copy_label_to_dictionary_callback, dst);
+ spinlock_unlock(&src->spinlock);
+ spinlock_unlock(&dst->spinlock);
}
@@ -837,8 +1067,7 @@ struct simple_pattern_match_name_value {
char equal;
};
-static int simple_pattern_match_name_only_callback(const DICTIONARY_ITEM *item, void *value, void *data) {
- const char *name = dictionary_acquired_item_name(item);
+static int simple_pattern_match_name_only_callback(const char *name, const char *value, RRDLABEL_SRC ls __maybe_unused, void *data) {
struct simple_pattern_match_name_value *t = (struct simple_pattern_match_name_value *)data;
(void)value;
@@ -849,10 +1078,8 @@ static int simple_pattern_match_name_only_callback(const DICTIONARY_ITEM *item,
return 0;
}
-static int simple_pattern_match_name_and_value_callback(const DICTIONARY_ITEM *item, void *value, void *data) {
- const char *name = dictionary_acquired_item_name(item);
+static int simple_pattern_match_name_and_value_callback(const char *name, const char *value, RRDLABEL_SRC ls __maybe_unused, void *data) {
struct simple_pattern_match_name_value *t = (struct simple_pattern_match_name_value *)data;
- RRDLABEL *lb = (RRDLABEL *)value;
// we return -1 to stop the walkthrough on first match
t->searches++;
@@ -860,7 +1087,7 @@ static int simple_pattern_match_name_and_value_callback(const DICTIONARY_ITEM *i
size_t len = RRDLABELS_MAX_NAME_LENGTH + RRDLABELS_MAX_VALUE_LENGTH + 2; // +1 for =, +1 for \0
char tmp[len], *dst = &tmp[0];
- const char *v = string2str(lb->label_value);
+ const char *v = value;
// copy the name
while(*name) *dst++ = *name++;
@@ -881,7 +1108,7 @@ static int simple_pattern_match_name_and_value_callback(const DICTIONARY_ITEM *i
return 0;
}
-bool rrdlabels_match_simple_pattern_parsed(DICTIONARY *labels, SIMPLE_PATTERN *pattern, char equal, size_t *searches) {
+bool rrdlabels_match_simple_pattern_parsed(RRDLABELS *labels, SIMPLE_PATTERN *pattern, char equal, size_t *searches) {
if (!labels) return false;
struct simple_pattern_match_name_value t = {
@@ -890,7 +1117,7 @@ bool rrdlabels_match_simple_pattern_parsed(DICTIONARY *labels, SIMPLE_PATTERN *p
.equal = equal
};
- int ret = dictionary_walkthrough_read(labels, equal?simple_pattern_match_name_and_value_callback:simple_pattern_match_name_only_callback, &t);
+ int ret = rrdlabels_walkthrough_read(labels, equal?simple_pattern_match_name_and_value_callback:simple_pattern_match_name_only_callback, &t);
if(searches)
*searches = t.searches;
@@ -898,7 +1125,7 @@ bool rrdlabels_match_simple_pattern_parsed(DICTIONARY *labels, SIMPLE_PATTERN *p
return (ret == -1)?true:false;
}
-bool rrdlabels_match_simple_pattern(DICTIONARY *labels, const char *simple_pattern_txt) {
+bool rrdlabels_match_simple_pattern(RRDLABELS *labels, const char *simple_pattern_txt) {
if (!labels) return false;
SIMPLE_PATTERN *pattern = simple_pattern_create(simple_pattern_txt, " ,|\t\r\n\f\v", SIMPLE_PATTERN_EXACT, true);
@@ -923,39 +1150,23 @@ bool rrdlabels_match_simple_pattern(DICTIONARY *labels, const char *simple_patte
// ----------------------------------------------------------------------------
// Log all labels
-static int rrdlabels_log_label_to_buffer_callback(const DICTIONARY_ITEM *item, void *value, void *data) {
- const char *name = dictionary_acquired_item_name(item);
-
+static int rrdlabels_log_label_to_buffer_callback(const char *name, const char *value, void *data) {
BUFFER *wb = (BUFFER *)data;
- RRDLABEL *lb = (RRDLABEL *)value;
-
- buffer_sprintf(wb, "Label: %s: \"%s\" (", name, string2str(lb->label_value));
-
- size_t sources = 0;
- if(lb->label_source & RRDLABEL_SRC_AUTO) {
- buffer_sprintf(wb, "auto");
- sources++;
- }
-
- if(lb->label_source & RRDLABEL_SRC_CONFIG)
- buffer_sprintf(wb, "%snetdata.conf", sources++?",":"");
-
- if(lb->label_source & RRDLABEL_SRC_K8S)
- buffer_sprintf(wb, "%sk8s", sources++?",":"");
-
- if(lb->label_source & RRDLABEL_SRC_ACLK)
- buffer_sprintf(wb, "%saclk", sources++?",":"");
-
- if(!sources)
- buffer_strcat(wb, "unknown");
+ buffer_sprintf(wb, "Label: %s: \"%s\" (", name, value);
+ buffer_strcat(wb, "unknown");
buffer_strcat(wb, ")\n");
return 1;
}
-void rrdlabels_log_to_buffer(DICTIONARY *labels, BUFFER *wb) {
- dictionary_sorted_walkthrough_read(labels, rrdlabels_log_label_to_buffer_callback, wb);
+void rrdlabels_log_to_buffer(RRDLABELS *labels, BUFFER *wb)
+{
+ RRDLABEL *lb;
+ RRDLABEL_SRC ls;
+ lfe_start_read(labels, lb, ls)
+ rrdlabels_log_label_to_buffer_callback((void *) string2str(lb->index.key), (void *) string2str(lb->index.value), wb);
+ lfe_done(labels);
}
@@ -975,10 +1186,10 @@ struct labels_to_buffer {
size_t count;
};
-static int label_to_buffer_callback(const DICTIONARY_ITEM *item, void *value, void *data) {
- const char *name = dictionary_acquired_item_name(item);
+static int label_to_buffer_callback(const RRDLABEL *lb, void *value __maybe_unused, RRDLABEL_SRC ls, void *data)
+{
+
struct labels_to_buffer *t = (struct labels_to_buffer *)data;
- RRDLABEL *lb = (RRDLABEL *)value;
size_t n_size = (t->name_sanitizer ) ? ( RRDLABELS_MAX_NAME_LENGTH * 2 ) : 1;
size_t v_size = (t->value_sanitizer) ? ( RRDLABELS_MAX_VALUE_LENGTH * 2 ) : 1;
@@ -986,7 +1197,9 @@ static int label_to_buffer_callback(const DICTIONARY_ITEM *item, void *value, vo
char n[n_size];
char v[v_size];
- const char *nn = name, *vv = string2str(lb->label_value);
+ const char *name = string2str(lb->index.key);
+
+ const char *nn = name, *vv = string2str(lb->index.value);
if(t->name_sanitizer) {
t->name_sanitizer(n, name, n_size);
@@ -994,11 +1207,11 @@ static int label_to_buffer_callback(const DICTIONARY_ITEM *item, void *value, vo
}
if(t->value_sanitizer) {
- t->value_sanitizer(v, string2str(lb->label_value), v_size);
+ t->value_sanitizer(v, string2str(lb->index.value), v_size);
vv = v;
}
- if(!t->filter_callback || t->filter_callback(name, string2str(lb->label_value), lb->label_source, t->filter_data)) {
+ if(!t->filter_callback || t->filter_callback(name, string2str(lb->index.value), ls, t->filter_data)) {
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);
return 1;
}
@@ -1006,7 +1219,26 @@ static int label_to_buffer_callback(const DICTIONARY_ITEM *item, void *value, vo
return 0;
}
-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)) {
+
+int label_walkthrough_read(RRDLABELS *labels, int (*callback)(const RRDLABEL *item, void *entry, RRDLABEL_SRC ls, void *data), void *data)
+{
+ int ret = 0;
+
+ if(unlikely(!labels || !callback)) return 0;
+
+ RRDLABEL *lb;
+ RRDLABEL_SRC ls;
+ lfe_start_read(labels, lb, ls)
+ {
+ ret = callback((const RRDLABEL *)lb, (void *)string2str(lb->index.value), ls, data);
+ if (ret < 0)
+ break;
+ }
+ lfe_done(labels);
+ return ret;
+}
+
+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)) {
struct labels_to_buffer tmp = {
.wb = wb,
.filter_callback = filter_callback,
@@ -1019,18 +1251,33 @@ int rrdlabels_to_buffer(DICTIONARY *labels, BUFFER *wb, const char *before_each,
.between_them = between_them,
.count = 0
};
- return dictionary_walkthrough_read(labels, label_to_buffer_callback, (void *)&tmp);
+ return label_walkthrough_read(labels, label_to_buffer_callback, (void *)&tmp);
}
-void rrdlabels_to_buffer_json_members(DICTIONARY *labels, BUFFER *wb) {
+void rrdlabels_to_buffer_json_members(RRDLABELS *labels, BUFFER *wb)
+{
RRDLABEL *lb;
- dfe_start_read(labels, lb) {
- buffer_json_member_add_string(wb, lb_dfe.name, string2str(lb->label_value));
- }
- dfe_done(lb);
+ RRDLABEL_SRC ls;
+ lfe_start_read(labels, lb, ls)
+ buffer_json_member_add_string(wb, string2str(lb->index.key), string2str(lb->index.value));
+ lfe_done(labels);
+}
+
+size_t rrdlabels_entries(RRDLABELS *labels __maybe_unused)
+{
+ size_t count;
+ spinlock_lock(&labels->spinlock);
+ count = JudyLCount(labels->JudyL, 0, -1, PJE0);
+ spinlock_unlock(&labels->spinlock);
+ return count;
}
-void rrdset_update_rrdlabels(RRDSET *st, DICTIONARY *new_rrdlabels) {
+size_t rrdlabels_version(RRDLABELS *labels __maybe_unused)
+{
+ return (size_t) labels->version;
+}
+
+void rrdset_update_rrdlabels(RRDSET *st, RRDLABELS *new_rrdlabels) {
if(!st->rrdlabels)
st->rrdlabels = rrdlabels_create();
@@ -1051,16 +1298,14 @@ struct rrdlabels_unittest_add_a_pair {
const char *expected_value;
const char *name;
const char *value;
- RRDLABEL_SRC ls;
int errors;
};
-int rrdlabels_unittest_add_a_pair_callback(const char *name, const char *value, RRDLABEL_SRC ls, void *data) {
+int rrdlabels_unittest_add_a_pair_callback(const char *name, const char *value, RRDLABEL_SRC ls __maybe_unused, void *data) {
struct rrdlabels_unittest_add_a_pair *t = (struct rrdlabels_unittest_add_a_pair *)data;
t->name = name;
t->value = value;
- t->ls = ls;
if(strcmp(name, t->expected_name) != 0) {
fprintf(stderr, "name is wrong, found \"%s\", expected \"%s\"", name, t->expected_name);
@@ -1083,7 +1328,7 @@ int rrdlabels_unittest_add_a_pair_callback(const char *name, const char *value,
}
int rrdlabels_unittest_add_a_pair(const char *pair, const char *name, const char *value) {
- DICTIONARY *labels = rrdlabels_create();
+ RRDLABELS *labels = rrdlabels_create();
int errors;
fprintf(stderr, "rrdlabels_add_pair(labels, %s) ... ", pair);
@@ -1160,7 +1405,7 @@ int rrdlabels_unittest_add_pairs() {
return errors;
}
-int rrdlabels_unittest_check_simple_pattern(DICTIONARY *labels, const char *pattern, bool expected) {
+int rrdlabels_unittest_check_simple_pattern(RRDLABELS *labels, const char *pattern, bool expected) {
fprintf(stderr, "rrdlabels_match_simple_pattern(labels, \"%s\") ... ", pattern);
bool ret = rrdlabels_match_simple_pattern(labels, pattern);
@@ -1174,7 +1419,7 @@ int rrdlabels_unittest_simple_pattern() {
int errors = 0;
- DICTIONARY *labels = rrdlabels_create();
+ RRDLABELS *labels = rrdlabels_create();
rrdlabels_add(labels, "tag1", "value1", RRDLABEL_SRC_CONFIG);
rrdlabels_add(labels, "tag2", "value2", RRDLABEL_SRC_CONFIG);
rrdlabels_add(labels, "tag3", "value3", RRDLABEL_SRC_CONFIG);