add the ability to merge dictionary items (#13054)
* add the ability to merge old value and new value * docs * merge to conflict
Costa Tsaousis committed
Jun 2, 2022 at 16:10 UTC
446ac867e414da2c920e8ea7dbc9f7c9a7faebd1
3 files changed
+28
-4
libnetdata/dictionary/README.md
+4
-3
@@ -31,10 +31,11 @@ Dictionaries come with 2 memory management options:
31
- **Clone** (copy) the name and/or the value to memory allocated by the dictionary.
32
- **Link** the name and/or the value, without allocating any memory about them.
33
34
-In **clone** mode, the dictionary guarantees that all operations on the dictionary items will automatically take care of the memory used by the name and/or the value. In case the value is an object needs to have user allocated memory, two callback functions can be registered:
34
+In **clone** mode, the dictionary guarantees that all operations on the dictionary items will automatically take care of the memory used by the name and/or the value. In case the value is an object needs to have user allocated memory, the following callback functions can be registered:
35
36
- 1.`dictionary_register_insert_callback()` that will be called just after the insertion of an item to the dictionary (but while the dictionary is write-locked - if locking is enabled).
37
- 2. `dictionary_register_delete_callback()` that will be called just prior to the deletion of an item from the dictionary (but while the dictionary is write-locked - if locking is enabled).
36
+ 1.`dictionary_register_insert_callback()` that will be called just after the insertion of an item to the dictionary, or after the replacement of the value of a dictionary item (but while the dictionary is write-locked - if locking is enabled).
37
+ 2. `dictionary_register_delete_callback()` that will be called just prior to the deletion of an item from the dictionary, or prior to the replacement of the value of a dictionary item (but while the dictionary is write-locked - if locking is enabled).
38
+ 3. `dictionary_register_conflict_callback()` that will be called when `DICTIONARY_FLAG_DONT_OVERWRITE_VALUE` is set and another value is attempted to be inserted for the same key.
39
40
In **link** mode, the name and/or the value are just linked to the dictionary item, and it is the user's responsibility to free the memory used after an item is deleted from the dictionary.
41
libnetdata/dictionary/dictionary.c
+19
-1
@@ -134,6 +134,9 @@ struct dictionary {
134
void (*del_callback)(const char *name, void *value, void *data);
135
void *del_callback_data;
136
137
+ void (*conflict_callback)(const char *name, void *old_value, void *new_value, void *data);
138
+ void *conflict_callback_data;
139
+
140
struct dictionary_stats *stats; // the statistics when DICTIONARY_FLAG_WITH_STATISTICS is set
141
};
142
@@ -147,6 +150,11 @@ void dictionary_register_delete_callback(DICTIONARY *dict, void (*del_callback)(
150
dict->del_callback_data = data;
151
}
152
153
+void dictionary_register_conflict_callback(DICTIONARY *dict, void (*conflict_callback)(const char *name, void *old_value, void *new_value, void *data), void *data) {
154
+ dict->conflict_callback = conflict_callback;
155
+ dict->conflict_callback_data = data;
156
+}
157
+
158
// ----------------------------------------------------------------------------
159
// dictionary statistics maintenance
160
@@ -724,8 +732,18 @@ void *dictionary_set_unsafe(DICTIONARY *dict, const char *name, void *value, siz
732
// or overwrite the value, depending on dictionary flags
733
734
nv = *pnv;
727
- if(!(dict->flags & DICTIONARY_FLAG_DONT_OVERWRITE_VALUE))
735
+ if(!(dict->flags & DICTIONARY_FLAG_DONT_OVERWRITE_VALUE)) {
736
+
737
+ if(dict->del_callback)
738
+ dict->del_callback(nv->name, nv->value, dict->del_callback_data);
739
+
740
namevalue_reset_unsafe(dict, nv, value, value_len);
741
+
742
+ if(dict->ins_callback)
743
+ dict->ins_callback(nv->name, nv->value, dict->ins_callback_data);
744
+ }
745
+ else if(dict->conflict_callback)
746
+ dict->conflict_callback(nv->name, nv->value, value, dict->conflict_callback_data);
747
}
748
749
return nv->value;
libnetdata/dictionary/dictionary.h
+5
@@ -61,6 +61,11 @@ extern void dictionary_register_insert_callback(DICTIONARY *dict, void (*ins_cal
61
// this callback is called while the dictionary is write locked!
62
extern void dictionary_register_delete_callback(DICTIONARY *dict, void (*del_callback)(const char *name, void *value, void *data), void *data);
63
64
+// a merge callback to be called when DICTIONARY_FLAG_DONT_OVERWRITE_VALUE
65
+// and an item is already found in the dictionary - the dictionary does nothing else in this case
66
+// the old_value will remain in the dictionary - the new_value is ignored
67
+extern void dictionary_register_conflict_callback(DICTIONARY *dict, void (*conflict_callback)(const char *name, void *old_value, void *new_value, void *data), void *data);
68
+
69
// Destroy a dictionary
70
// returns the number of bytes freed
71
// the returned value will not include name and value sizes if DICTIONARY_FLAG_WITH_STATISTICS is not set