@cryptotaxi247 / netdata-1 / commits / bb7323774

allow traversing null-value dictionaries (#13162)

* allow traversing null-value dictionaries * fix lgtm report * void the value too * removed NEVERNULL directive

Costa Tsaousis committed Jun 17, 2022 at 17:32 UTC bb73237748a59290cd92e678978db41f09a11635
2 files changed +45 -11
libnetdata/dictionary/dictionary.c
+39 -7
@@ -77,11 +77,12 @@ typedef struct name_value {
77 struct name_value *next; // a double linked list to allow fast insertions and deletions
78 struct name_value *prev;
79
80 - char *name; // the name of the dictionary item
81 - void *value; // the value of the dictionary item
82 -
80 size_t name_len; // the size of the name, including the terminating zero
81 size_t value_len; // the size of the value (assumed binary)
82 +
83 + void *value; // the value of the dictionary item
84 + char *name; // the name of the dictionary item
85 +
86 } NAME_VALUE;
87
88 /*
@@ -173,7 +174,6 @@ size_t dictionary_stats_deletes(DICTIONARY *dict) {
174 size_t dictionary_stats_resets(DICTIONARY *dict) {
175 return dict->resets;
176 }
176 -
177 size_t dictionary_stats_walkthroughs(DICTIONARY *dict) {
178 return dict->walkthroughs;
179 }
@@ -515,7 +515,7 @@ static NAME_VALUE *namevalue_create_unsafe(DICTIONARY *dict, const char *name, s
515 }
516 }
517 else {
518 - // the caller want an item without any value
518 + // the caller wants an item without any value
519 nv->value = NULL;
520 }
521
@@ -533,6 +533,8 @@ static NAME_VALUE *namevalue_create_unsafe(DICTIONARY *dict, const char *name, s
533 static void namevalue_reset_unsafe(DICTIONARY *dict, NAME_VALUE *nv, void *value, size_t value_len) {
534 debug(D_DICTIONARY, "Dictionary entry with name '%s' found. Changing its value.", nv->name);
535
536 + DICTIONARY_STATS_VALUE_RESETS_PLUS1(dict, nv->value_len, value_len);
537 +
538 if(dict->del_callback)
539 dict->del_callback(nv->name, nv->value, dict->del_callback_data);
540
@@ -543,7 +545,6 @@ static void namevalue_reset_unsafe(DICTIONARY *dict, NAME_VALUE *nv, void *value
545 }
546 else {
547 debug(D_DICTIONARY, "Dictionary: cloning value to '%s'", nv->name);
546 - DICTIONARY_STATS_VALUE_RESETS_PLUS1(dict, nv->value_len, value_len);
548
549 void *oldvalue = nv->value;
550 void *newvalue = NULL;
@@ -982,6 +983,22 @@ static size_t dictionary_unittest_set_clone(DICTIONARY *dict, char **names, char
983 return errors;
984 }
985
986 +static size_t dictionary_unittest_set_null(DICTIONARY *dict, char **names, char **values, size_t entries) {
987 + (void)values;
988 + size_t errors = 0;
989 + size_t i = 0;
990 + for(; i < entries ;i++) {
991 + void *val = dictionary_set(dict, names[i], NULL, 0);
992 + if(val != NULL) { fprintf(stderr, ">>> %s() returns a non NULL value\n", __FUNCTION__); errors++; }
993 + }
994 + if(dictionary_stats_entries(dict) != i) {
995 + fprintf(stderr, ">>> %s() dictionary items do not match\n", __FUNCTION__);
996 + errors++;
997 + }
998 + return errors;
999 +}
1000 +
1001 +
1002 static size_t dictionary_unittest_set_nonclone(DICTIONARY *dict, char **names, char **values, size_t entries) {
1003 size_t errors = 0;
1004 for(size_t i = 0; i < entries ;i++) {
@@ -1264,7 +1281,11 @@ static size_t dictionary_unittest_sorted_walkthrough(DICTIONARY *dict, char **na
1281 static void dictionary_unittest_sorting(DICTIONARY *dict, char **names, char **values, size_t entries, size_t *errors) {
1282 dictionary_unittest_run_and_measure_time(dict, "adding entries", names, values, entries, errors, dictionary_unittest_set_clone);
1283 dictionary_unittest_run_and_measure_time(dict, "sorted walkthrough", names, values, entries, errors, dictionary_unittest_sorted_walkthrough);
1267 - dictionary_unittest_run_and_measure_time(dict, "destroying dictionary", names, values, entries, errors, dictionary_unittest_destroy);
1284 +}
1285 +
1286 +static void dictionary_unittest_null_dfe(DICTIONARY *dict, char **names, char **values, size_t entries, size_t *errors) {
1287 + dictionary_unittest_run_and_measure_time(dict, "adding null value entries", names, values, entries, errors, dictionary_unittest_set_null);
1288 + dictionary_unittest_run_and_measure_time(dict, "traverse foreach read loop", names, values, entries, errors, dictionary_unittest_foreach);
1289 }
1290
1291 int dictionary_unittest(size_t entries) {
@@ -1319,6 +1340,17 @@ int dictionary_unittest(size_t entries) {
1340 fprintf(stderr, "\nCreating dictionary single threaded, clone, %zu items\n", entries);
1341 dict = dictionary_create(DICTIONARY_FLAG_SINGLE_THREADED);
1342 dictionary_unittest_sorting(dict, names, values, entries, &errors);
1343 + dictionary_unittest_run_and_measure_time(dict, "destroying full dictionary", names, values, entries, &errors, dictionary_unittest_destroy);
1344 +
1345 + fprintf(stderr, "\nCreating dictionary single threaded, clone, %zu items\n", entries);
1346 + dict = dictionary_create(DICTIONARY_FLAG_SINGLE_THREADED);
1347 + dictionary_unittest_null_dfe(dict, names, values, entries, &errors);
1348 + dictionary_unittest_run_and_measure_time(dict, "destroying full dictionary", names, values, entries, &errors, dictionary_unittest_destroy);
1349 +
1350 + fprintf(stderr, "\nCreating dictionary single threaded, noclone, %zu items\n", entries);
1351 + dict = dictionary_create(DICTIONARY_FLAG_SINGLE_THREADED|DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE);
1352 + dictionary_unittest_null_dfe(dict, names, values, entries, &errors);
1353 + dictionary_unittest_run_and_measure_time(dict, "destroying full dictionary", names, values, entries, &errors, dictionary_unittest_destroy);
1354
1355 dictionary_unittest_free_char_pp(names, entries);
1356 dictionary_unittest_free_char_pp(values, entries);
libnetdata/dictionary/dictionary.h
+6 -4
@@ -84,7 +84,7 @@ extern size_t dictionary_destroy(DICTIONARY *dict);
84 //
85 // Passing NULL as value, the dictionary will callocz() the newly allocated value, otherwise it will copy it.
86 // Passing 0 as value_len, the dictionary will set the value to NULL (no allocations for value will be made).
87 -extern void *dictionary_set(DICTIONARY *dict, const char *name, void *value, size_t value_len) NEVERNULL;
87 +extern void *dictionary_set(DICTIONARY *dict, const char *name, void *value, size_t value_len);
88
89 // Get an item from the dictionary
90 // If it returns NULL, the item is not found
@@ -166,12 +166,14 @@ typedef DICTFE_CONST struct dictionary_foreach {
166 #define dfe_start_rw(dict, value, mode) \
167 do { \
168 DICTFE value ## _dfe = {}; \
169 - const char *value ## _name; (void)(value ## _name); \
169 + const char *value ## _name; (void)(value ## _name); (void)value; \
170 for((value) = dictionary_foreach_start_rw(&value ## _dfe, (dict), (mode)), ( value ## _name ) = value ## _dfe.name; \
171 - (value) ;\
172 - (value) = dictionary_foreach_next(&value ## _dfe), ( value ## _name ) = value ## _dfe.name)
171 + (value ## _dfe.name) ;\
172 + (value) = dictionary_foreach_next(&value ## _dfe), ( value ## _name ) = value ## _dfe.name) \
173 + {
174
175 #define dfe_done(value) \
176 + } \
177 dictionary_foreach_done(&value ## _dfe); \
178 } while(0)
179