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