diff options
author | Costa Tsaousis <costa@netdata.cloud> | 2022-06-02 16:10:28 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-06-02 16:10:28 +0300 |
commit | 446ac867e414da2c920e8ea7dbc9f7c9a7faebd1 (patch) | |
tree | d2319119e6a7aa6a9a70306644bb75dfae4b864b /libnetdata | |
parent | 27e9c50b569dde9c042379cec5c7e85b888403a2 (diff) |
add the ability to merge dictionary items (#13054)
* add the ability to merge old value and new value
* docs
* merge to conflict
Diffstat (limited to 'libnetdata')
-rw-r--r-- | libnetdata/dictionary/README.md | 7 | ||||
-rw-r--r-- | libnetdata/dictionary/dictionary.c | 20 | ||||
-rw-r--r-- | libnetdata/dictionary/dictionary.h | 5 |
3 files changed, 28 insertions, 4 deletions
diff --git a/libnetdata/dictionary/README.md b/libnetdata/dictionary/README.md index 25d654d718..28d0cfbbd9 100644 --- a/libnetdata/dictionary/README.md +++ b/libnetdata/dictionary/README.md @@ -31,10 +31,11 @@ Dictionaries come with 2 memory management options: - **Clone** (copy) the name and/or the value to memory allocated by the dictionary. - **Link** the name and/or the value, without allocating any memory about them. -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: +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: - 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). - 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). + 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). + 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). + 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. 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. diff --git a/libnetdata/dictionary/dictionary.c b/libnetdata/dictionary/dictionary.c index 1293491651..42285037de 100644 --- a/libnetdata/dictionary/dictionary.c +++ b/libnetdata/dictionary/dictionary.c @@ -134,6 +134,9 @@ struct dictionary { void (*del_callback)(const char *name, void *value, void *data); void *del_callback_data; + void (*conflict_callback)(const char *name, void *old_value, void *new_value, void *data); + void *conflict_callback_data; + struct dictionary_stats *stats; // the statistics when DICTIONARY_FLAG_WITH_STATISTICS is set }; @@ -147,6 +150,11 @@ void dictionary_register_delete_callback(DICTIONARY *dict, void (*del_callback)( dict->del_callback_data = data; } +void dictionary_register_conflict_callback(DICTIONARY *dict, void (*conflict_callback)(const char *name, void *old_value, void *new_value, void *data), void *data) { + dict->conflict_callback = conflict_callback; + dict->conflict_callback_data = data; +} + // ---------------------------------------------------------------------------- // dictionary statistics maintenance @@ -724,8 +732,18 @@ void *dictionary_set_unsafe(DICTIONARY *dict, const char *name, void *value, siz // or overwrite the value, depending on dictionary flags nv = *pnv; - if(!(dict->flags & DICTIONARY_FLAG_DONT_OVERWRITE_VALUE)) + if(!(dict->flags & DICTIONARY_FLAG_DONT_OVERWRITE_VALUE)) { + + if(dict->del_callback) + dict->del_callback(nv->name, nv->value, dict->del_callback_data); + namevalue_reset_unsafe(dict, nv, value, value_len); + + if(dict->ins_callback) + dict->ins_callback(nv->name, nv->value, dict->ins_callback_data); + } + else if(dict->conflict_callback) + dict->conflict_callback(nv->name, nv->value, value, dict->conflict_callback_data); } return nv->value; diff --git a/libnetdata/dictionary/dictionary.h b/libnetdata/dictionary/dictionary.h index 7b9da3a380..356bf18953 100644 --- a/libnetdata/dictionary/dictionary.h +++ b/libnetdata/dictionary/dictionary.h @@ -61,6 +61,11 @@ extern void dictionary_register_insert_callback(DICTIONARY *dict, void (*ins_cal // this callback is called while the dictionary is write locked! extern void dictionary_register_delete_callback(DICTIONARY *dict, void (*del_callback)(const char *name, void *value, void *data), void *data); +// a merge callback to be called when DICTIONARY_FLAG_DONT_OVERWRITE_VALUE +// and an item is already found in the dictionary - the dictionary does nothing else in this case +// the old_value will remain in the dictionary - the new_value is ignored +extern void dictionary_register_conflict_callback(DICTIONARY *dict, void (*conflict_callback)(const char *name, void *old_value, void *new_value, void *data), void *data); + // Destroy a dictionary // returns the number of bytes freed // the returned value will not include name and value sizes if DICTIONARY_FLAG_WITH_STATISTICS is not set |