summaryrefslogtreecommitdiffstats
path: root/libnetdata/dictionary
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2023-02-06 16:11:34 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2023-02-06 16:11:34 +0000
commitd079b656b4719739b2247dcd9d46e9bec793095a (patch)
treed2c950c70a776bcf697c963151c5bd959f8a9f03 /libnetdata/dictionary
parentReleasing debian version 1.37.1-2. (diff)
downloadnetdata-d079b656b4719739b2247dcd9d46e9bec793095a.tar.xz
netdata-d079b656b4719739b2247dcd9d46e9bec793095a.zip
Merging upstream version 1.38.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'libnetdata/dictionary')
-rw-r--r--libnetdata/dictionary/README.md4
-rw-r--r--libnetdata/dictionary/dictionary.c130
-rw-r--r--libnetdata/dictionary/dictionary.h13
3 files changed, 116 insertions, 31 deletions
diff --git a/libnetdata/dictionary/README.md b/libnetdata/dictionary/README.md
index 6d7e55392..508c4e031 100644
--- a/libnetdata/dictionary/README.md
+++ b/libnetdata/dictionary/README.md
@@ -1,5 +1,9 @@
<!--
custom_edit_url: https://github.com/netdata/netdata/edit/master/libnetdata/dictionary/README.md
+sidebar_label: "Dictionaries"
+learn_status: "Published"
+learn_topic_type: "Tasks"
+learn_rel_path: "Developers/libnetdata libraries"
-->
# Dictionaries
diff --git a/libnetdata/dictionary/dictionary.c b/libnetdata/dictionary/dictionary.c
index 0277e067f..061b671ab 100644
--- a/libnetdata/dictionary/dictionary.c
+++ b/libnetdata/dictionary/dictionary.c
@@ -143,6 +143,8 @@ struct dictionary {
DICT_OPTIONS options; // the configuration flags of the dictionary (they never change - no atomics)
DICT_FLAGS flags; // run time flags for the dictionary (they change all the time - atomics needed)
+ ARAL *value_aral;
+
struct { // support for multiple indexing engines
Pvoid_t JudyHSArray; // the hash table
netdata_rwlock_t rwlock; // protect the index
@@ -179,7 +181,9 @@ struct dictionary {
#endif
};
+// ----------------------------------------------------------------------------
// forward definitions of functions used in reverse order in the code
+
static void garbage_collect_pending_deletes(DICTIONARY *dict);
static inline void item_linked_list_remove(DICTIONARY *dict, DICTIONARY_ITEM *item);
static size_t dict_item_free_with_hooks(DICTIONARY *dict, DICTIONARY_ITEM *item);
@@ -260,7 +264,7 @@ static inline void pointer_del(DICTIONARY *dict __maybe_unused, DICTIONARY_ITEM
static inline void DICTIONARY_STATS_PLUS_MEMORY(DICTIONARY *dict, size_t key_size, size_t item_size, size_t value_size) {
if(key_size)
- __atomic_fetch_add(&dict->stats->memory.indexed, (long)key_size, __ATOMIC_RELAXED);
+ __atomic_fetch_add(&dict->stats->memory.index, (long)JUDYHS_INDEX_SIZE_ESTIMATE(key_size), __ATOMIC_RELAXED);
if(item_size)
__atomic_fetch_add(&dict->stats->memory.dict, (long)item_size, __ATOMIC_RELAXED);
@@ -270,7 +274,7 @@ static inline void DICTIONARY_STATS_PLUS_MEMORY(DICTIONARY *dict, size_t key_siz
}
static inline void DICTIONARY_STATS_MINUS_MEMORY(DICTIONARY *dict, size_t key_size, size_t item_size, size_t value_size) {
if(key_size)
- __atomic_fetch_sub(&dict->stats->memory.indexed, (long)key_size, __ATOMIC_RELAXED);
+ __atomic_fetch_sub(&dict->stats->memory.index, (long)JUDYHS_INDEX_SIZE_ESTIMATE(key_size), __ATOMIC_RELAXED);
if(item_size)
__atomic_fetch_sub(&dict->stats->memory.dict, (long)item_size, __ATOMIC_RELAXED);
@@ -380,7 +384,7 @@ size_t dictionary_referenced_items(DICTIONARY *dict) {
long int dictionary_stats_for_registry(DICTIONARY *dict) {
if(unlikely(!dict)) return 0;
- return (dict->stats->memory.indexed + dict->stats->memory.dict);
+ return (dict->stats->memory.index + dict->stats->memory.dict);
}
void dictionary_version_increment(DICTIONARY *dict) {
__atomic_fetch_add(&dict->version, 1, __ATOMIC_SEQ_CST);
@@ -789,7 +793,7 @@ static void garbage_collect_pending_deletes(DICTIONARY *dict) {
// we didn't get a reference
if(item_is_not_referenced_and_can_be_removed(dict, item)) {
- DOUBLE_LINKED_LIST_REMOVE_UNSAFE(dict->items.list, item, prev, next);
+ DOUBLE_LINKED_LIST_REMOVE_ITEM_UNSAFE(dict->items.list, item, prev, next);
dict_item_free_with_hooks(dict, item);
deleted++;
@@ -1167,9 +1171,9 @@ static inline void item_linked_list_add(DICTIONARY *dict, DICTIONARY_ITEM *item)
ll_recursive_lock(dict, DICTIONARY_LOCK_WRITE);
if(dict->options & DICT_OPTION_ADD_IN_FRONT)
- DOUBLE_LINKED_LIST_PREPEND_UNSAFE(dict->items.list, item, prev, next);
+ DOUBLE_LINKED_LIST_PREPEND_ITEM_UNSAFE(dict->items.list, item, prev, next);
else
- DOUBLE_LINKED_LIST_APPEND_UNSAFE(dict->items.list, item, prev, next);
+ DOUBLE_LINKED_LIST_APPEND_ITEM_UNSAFE(dict->items.list, item, prev, next);
#ifdef NETDATA_INTERNAL_CHECKS
item->ll_adder_pid = gettid();
@@ -1186,7 +1190,7 @@ static inline void item_linked_list_add(DICTIONARY *dict, DICTIONARY_ITEM *item)
static inline void item_linked_list_remove(DICTIONARY *dict, DICTIONARY_ITEM *item) {
ll_recursive_lock(dict, DICTIONARY_LOCK_WRITE);
- DOUBLE_LINKED_LIST_REMOVE_UNSAFE(dict->items.list, item, prev, next);
+ DOUBLE_LINKED_LIST_REMOVE_ITEM_UNSAFE(dict->items.list, item, prev, next);
#ifdef NETDATA_INTERNAL_CHECKS
item->ll_remover_pid = gettid();
@@ -1234,11 +1238,45 @@ static inline size_t item_get_name_len(const DICTIONARY_ITEM *item) {
return strlen(item->caller_name);
}
+static ARAL *dict_items_aral = NULL;
+static ARAL *dict_shared_items_aral = NULL;
+
+void dictionary_static_items_aral_init(void) {
+ static SPINLOCK spinlock;
+
+ if(unlikely(!dict_items_aral || !dict_shared_items_aral)) {
+ netdata_spinlock_lock(&spinlock);
+
+ // we have to check again
+ if(!dict_items_aral)
+ dict_items_aral = aral_create(
+ "dict-items",
+ sizeof(DICTIONARY_ITEM),
+ 0,
+ 65536,
+ aral_by_size_statistics(),
+ NULL, NULL, false, false);
+
+ // we have to check again
+ if(!dict_shared_items_aral)
+ dict_shared_items_aral = aral_create(
+ "dict-shared-items",
+ sizeof(DICTIONARY_ITEM_SHARED),
+ 0,
+ 65536,
+ aral_by_size_statistics(),
+ NULL, NULL, false, false);
+
+ netdata_spinlock_unlock(&spinlock);
+ }
+}
+
static DICTIONARY_ITEM *dict_item_create(DICTIONARY *dict __maybe_unused, size_t *allocated_bytes, DICTIONARY_ITEM *master_item) {
DICTIONARY_ITEM *item;
size_t size = sizeof(DICTIONARY_ITEM);
- item = callocz(1, size);
+ item = aral_mallocz(dict_items_aral);
+ memset(item, 0, sizeof(DICTIONARY_ITEM));
#ifdef NETDATA_INTERNAL_CHECKS
item->creator_pid = gettid();
@@ -1257,7 +1295,9 @@ static DICTIONARY_ITEM *dict_item_create(DICTIONARY *dict __maybe_unused, size_t
}
else {
size = sizeof(DICTIONARY_ITEM_SHARED);
- item->shared = callocz(1, size);
+ item->shared = aral_mallocz(dict_shared_items_aral);
+ memset(item->shared, 0, sizeof(DICTIONARY_ITEM_SHARED));
+
item->shared->links = 1;
*allocated_bytes += size;
}
@@ -1268,20 +1308,39 @@ static DICTIONARY_ITEM *dict_item_create(DICTIONARY *dict __maybe_unused, size_t
return item;
}
-static void *dict_item_value_create(void *value, size_t value_len) {
+static inline void *dict_item_value_mallocz(DICTIONARY *dict, size_t value_len) {
+ if(dict->value_aral) {
+ internal_fatal(aral_element_size(dict->value_aral) != value_len,
+ "DICTIONARY: item value size %zu does not match the configured fixed one %zu",
+ value_len, aral_element_size(dict->value_aral));
+ return aral_mallocz(dict->value_aral);
+ }
+ else
+ return mallocz(value_len);
+}
+
+static inline void dict_item_value_freez(DICTIONARY *dict, void *ptr) {
+ if(dict->value_aral)
+ aral_freez(dict->value_aral, ptr);
+ else
+ freez(ptr);
+}
+
+static void *dict_item_value_create(DICTIONARY *dict, void *value, size_t value_len) {
void *ptr = NULL;
if(likely(value_len)) {
if (likely(value)) {
// a value has been supplied
// copy it
- ptr = mallocz(value_len);
+ ptr = dict_item_value_mallocz(dict, value_len);
memcpy(ptr, value, value_len);
}
else {
// no value has been supplied
// allocate a clear memory block
- ptr = callocz(1, value_len);
+ ptr = dict_item_value_mallocz(dict, value_len);
+ memset(ptr, 0, value_len);
}
}
// else
@@ -1320,7 +1379,7 @@ static DICTIONARY_ITEM *dict_item_create_with_hooks(DICTIONARY *dict, const char
if(unlikely(dict->options & DICT_OPTION_VALUE_LINK_DONT_CLONE))
item->shared->value = value;
else
- item->shared->value = dict_item_value_create(value, value_len);
+ item->shared->value = dict_item_value_create(dict, value, value_len);
item->shared->value_len = value_len;
value_size += value_len;
@@ -1360,7 +1419,7 @@ static void dict_item_reset_value_with_hooks(DICTIONARY *dict, DICTIONARY_ITEM *
void *old_value = item->shared->value;
void *new_value = NULL;
if(value_len) {
- new_value = mallocz(value_len);
+ new_value = dict_item_value_mallocz(dict, value_len);
if(value) memcpy(new_value, value, value_len);
else memset(new_value, 0, value_len);
}
@@ -1368,7 +1427,7 @@ static void dict_item_reset_value_with_hooks(DICTIONARY *dict, DICTIONARY_ITEM *
item->shared->value_len = value_len;
debug(D_DICTIONARY, "Dictionary: freeing old value of '%s'", item_get_name(item));
- freez(old_value);
+ dict_item_value_freez(dict, old_value);
}
dictionary_execute_insert_callback(dict, item, constructor_data);
@@ -1391,17 +1450,18 @@ static size_t dict_item_free_with_hooks(DICTIONARY *dict, DICTIONARY_ITEM *item)
if(unlikely(!(dict->options & DICT_OPTION_VALUE_LINK_DONT_CLONE))) {
debug(D_DICTIONARY, "Dictionary freeing value of '%s'", item_get_name(item));
- freez(item->shared->value);
+ dict_item_value_freez(dict, item->shared->value);
item->shared->value = NULL;
}
value_size += item->shared->value_len;
- freez(item->shared);
+ aral_freez(dict_shared_items_aral, item->shared);
item->shared = NULL;
item_size += sizeof(DICTIONARY_ITEM_SHARED);
}
- freez(item);
+ aral_freez(dict_items_aral, item);
+
item_size += sizeof(DICTIONARY_ITEM);
DICTIONARY_STATS_MINUS_MEMORY(dict, key_size, item_size, value_size);
@@ -1749,6 +1809,9 @@ static bool dictionary_free_all_resources(DICTIONARY *dict, size_t *mem, bool fo
dict_size += sizeof(DICTIONARY);
DICTIONARY_STATS_MINUS_MEMORY(dict, 0, sizeof(DICTIONARY), 0);
+ if(dict->value_aral)
+ aral_by_size_release(dict->value_aral);
+
freez(dict);
internal_error(
@@ -1934,19 +1997,34 @@ static bool api_is_name_good_with_trace(DICTIONARY *dict __maybe_unused, const c
// ----------------------------------------------------------------------------
// API - dictionary management
-static DICTIONARY *dictionary_create_internal(DICT_OPTIONS options, struct dictionary_stats *stats) {
+static DICTIONARY *dictionary_create_internal(DICT_OPTIONS options, struct dictionary_stats *stats, size_t fixed_size) {
cleanup_destroyed_dictionaries();
DICTIONARY *dict = callocz(1, sizeof(DICTIONARY));
dict->options = options;
dict->stats = stats;
+ if((dict->options & DICT_OPTION_FIXED_SIZE) && !fixed_size) {
+ dict->options &= ~DICT_OPTION_FIXED_SIZE;
+ internal_fatal(true, "DICTIONARY: requested fixed size dictionary, without setting the size");
+ }
+ if(!(dict->options & DICT_OPTION_FIXED_SIZE) && fixed_size) {
+ dict->options |= DICT_OPTION_FIXED_SIZE;
+ internal_fatal(true, "DICTIONARY: set a fixed size for the items, without setting DICT_OPTION_FIXED_SIZE flag");
+ }
+
+ if(dict->options & DICT_OPTION_FIXED_SIZE)
+ dict->value_aral = aral_by_size_acquire(fixed_size);
+ else
+ dict->value_aral = NULL;
+
size_t dict_size = 0;
dict_size += sizeof(DICTIONARY);
dict_size += dictionary_locks_init(dict);
dict_size += reference_counter_init(dict);
dict_size += hashtable_init_unsafe(dict);
+ dictionary_static_items_aral_init();
pointer_index_init(dict);
DICTIONARY_STATS_PLUS_MEMORY(dict, 0, dict_size, 0);
@@ -1955,12 +2033,12 @@ static DICTIONARY *dictionary_create_internal(DICT_OPTIONS options, struct dicti
}
#ifdef NETDATA_INTERNAL_CHECKS
-DICTIONARY *dictionary_create_advanced_with_trace(DICT_OPTIONS options, struct dictionary_stats *stats, const char *function, size_t line, const char *file) {
+DICTIONARY *dictionary_create_advanced_with_trace(DICT_OPTIONS options, struct dictionary_stats *stats, size_t fixed_size, const char *function, size_t line, const char *file) {
#else
-DICTIONARY *dictionary_create_advanced(DICT_OPTIONS options, struct dictionary_stats *stats) {
+DICTIONARY *dictionary_create_advanced(DICT_OPTIONS options, struct dictionary_stats *stats, size_t fixed_size) {
#endif
- DICTIONARY *dict = dictionary_create_internal(options, stats?stats:&dictionary_stats_category_other);
+ DICTIONARY *dict = dictionary_create_internal(options, stats?stats:&dictionary_stats_category_other, fixed_size);
#ifdef NETDATA_INTERNAL_CHECKS
dict->creation_function = function;
@@ -1978,7 +2056,9 @@ DICTIONARY *dictionary_create_view_with_trace(DICTIONARY *master, const char *fu
DICTIONARY *dictionary_create_view(DICTIONARY *master) {
#endif
- DICTIONARY *dict = dictionary_create_internal(master->options, master->stats);
+ DICTIONARY *dict = dictionary_create_internal(master->options, master->stats,
+ master->value_aral ? aral_element_size(master->value_aral) : 0);
+
dict->master = master;
dictionary_hooks_allocate(master);
@@ -3295,7 +3375,7 @@ static int dictionary_unittest_view_threads() {
// threads testing of dictionary
struct dictionary_stats stats_master = {};
struct dictionary_stats stats_view = {};
- tv.master = dictionary_create_advanced(DICT_OPTION_NAME_LINK_DONT_CLONE | DICT_OPTION_DONT_OVERWRITE_VALUE, &stats_master);
+ tv.master = dictionary_create_advanced(DICT_OPTION_NAME_LINK_DONT_CLONE | DICT_OPTION_DONT_OVERWRITE_VALUE, &stats_master, 0);
tv.view = dictionary_create_view(tv.master);
tv.view->stats = &stats_view;
@@ -3388,7 +3468,7 @@ static int dictionary_unittest_view_threads() {
size_t dictionary_unittest_views(void) {
size_t errors = 0;
struct dictionary_stats stats = {};
- DICTIONARY *master = dictionary_create_advanced(DICT_OPTION_NONE, &stats);
+ DICTIONARY *master = dictionary_create_advanced(DICT_OPTION_NONE, &stats, 0);
DICTIONARY *view = dictionary_create_view(master);
fprintf(stderr, "\n\nChecking dictionary views...\n");
diff --git a/libnetdata/dictionary/dictionary.h b/libnetdata/dictionary/dictionary.h
index 0e7b3d39f..58220def0 100644
--- a/libnetdata/dictionary/dictionary.h
+++ b/libnetdata/dictionary/dictionary.h
@@ -53,6 +53,7 @@ typedef enum dictionary_options {
DICT_OPTION_NAME_LINK_DONT_CLONE = (1 << 2), // don't copy the name, just point to the one provided (default: copy)
DICT_OPTION_DONT_OVERWRITE_VALUE = (1 << 3), // don't overwrite values of dictionary items (default: overwrite)
DICT_OPTION_ADD_IN_FRONT = (1 << 4), // add dictionary items at the front of the linked list (default: at the end)
+ DICT_OPTION_FIXED_SIZE = (1 << 5), // the items of the dictionary have a fixed size
} DICT_OPTIONS;
struct dictionary_stats {
@@ -91,7 +92,7 @@ struct dictionary_stats {
// memory
struct {
- long indexed; // bytes of keys indexed (indication of the index size)
+ long index; // bytes of keys indexed (indication of the index size)
long values; // bytes of caller structures
long dict; // bytes of the structures dictionary needs
} memory;
@@ -107,12 +108,12 @@ struct dictionary_stats {
// Create a dictionary
#ifdef NETDATA_INTERNAL_CHECKS
-#define dictionary_create(options) dictionary_create_advanced_with_trace(options, NULL, __FUNCTION__, __LINE__, __FILE__)
-#define dictionary_create_advanced(options, stats) dictionary_create_advanced_with_trace(options, stats, __FUNCTION__, __LINE__, __FILE__)
-DICTIONARY *dictionary_create_advanced_with_trace(DICT_OPTIONS options, struct dictionary_stats *stats, const char *function, size_t line, const char *file);
+#define dictionary_create(options) dictionary_create_advanced_with_trace(options, NULL, 0, __FUNCTION__, __LINE__, __FILE__)
+#define dictionary_create_advanced(options, stats, fixed_size) dictionary_create_advanced_with_trace(options, stats, fixed_size, __FUNCTION__, __LINE__, __FILE__)
+DICTIONARY *dictionary_create_advanced_with_trace(DICT_OPTIONS options, struct dictionary_stats *stats, size_t fixed_size, const char *function, size_t line, const char *file);
#else
-#define dictionary_create(options) dictionary_create_advanced(options, NULL);
-DICTIONARY *dictionary_create_advanced(DICT_OPTIONS options, struct dictionary_stats *stats);
+#define dictionary_create(options) dictionary_create_advanced(options, NULL, 0);
+DICTIONARY *dictionary_create_advanced(DICT_OPTIONS options, struct dictionary_stats *stats, size_t fixed_size);
#endif
// Create a view on a dictionary