summaryrefslogtreecommitdiffstats
path: root/libnetdata
diff options
context:
space:
mode:
authorCosta Tsaousis <costa@netdata.cloud>2022-06-02 16:10:28 +0300
committerGitHub <noreply@github.com>2022-06-02 16:10:28 +0300
commit446ac867e414da2c920e8ea7dbc9f7c9a7faebd1 (patch)
treed2319119e6a7aa6a9a70306644bb75dfae4b864b /libnetdata
parent27e9c50b569dde9c042379cec5c7e85b888403a2 (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.md7
-rw-r--r--libnetdata/dictionary/dictionary.c20
-rw-r--r--libnetdata/dictionary/dictionary.h5
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