]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib: lib-event - Add support for iterating the full ancestral tree of an event's...
authorStephan Bosch <stephan.bosch@open-xchange.com>
Sat, 19 Aug 2023 17:46:27 +0000 (19:46 +0200)
committeraki.tuomi <aki.tuomi@open-xchange.com>
Sat, 18 Nov 2023 18:58:04 +0000 (18:58 +0000)
src/lib/lib-event.c
src/lib/lib-event.h

index 8c40848ba979f27bcb983490b4b016ebeae4e002..33a3e64caeb2d7590307ee9cda01f3e715d532ed 100644 (file)
@@ -4,6 +4,7 @@
 #include "lib-event-private.h"
 #include "event-filter.h"
 #include "array.h"
+#include "hash.h"
 #include "llist.h"
 #include "time-util.h"
 #include "str.h"
@@ -12,6 +13,8 @@
 
 #include <ctype.h>
 
+HASH_TABLE_DEFINE_TYPE(category_set, void *, const struct event_category *);
+
 enum event_code {
        EVENT_CODE_ALWAYS_LOG_SOURCE    = 'a',
        EVENT_CODE_CATEGORY             = 'c',
@@ -62,6 +65,11 @@ struct event_reason {
        struct event *event;
 };
 
+struct event_category_iterator {
+       HASH_TABLE_TYPE(category_set) hash;
+       struct hash_iterate_context *iter;
+};
+
 extern struct event_passthrough event_passthrough_vfuncs;
 
 static struct event *events = NULL;
@@ -1257,6 +1265,67 @@ event_get_categories(const struct event *event, unsigned int *count_r)
        return array_get(&event->categories, count_r);
 }
 
+static void
+insert_category(HASH_TABLE_TYPE(category_set) hash,
+               const struct event_category *const cat)
+{
+       /* insert this category (key == the unique internal pointer) */
+       hash_table_update(hash, cat->internal, cat);
+
+       /* insert parent's categories */
+       if (cat->parent != NULL)
+               insert_category(hash, cat->parent);
+}
+
+struct event_category_iterator *
+event_categories_iterate_init(const struct event *event)
+{
+       struct event_category_iterator *iter;
+       struct event_category *const *cats;
+       unsigned int count, i;
+
+       cats = event_get_categories(event, &count);
+       if (count == 0)
+               return NULL;
+
+       iter = i_new(struct event_category_iterator, 1);
+
+       hash_table_create_direct(&iter->hash, default_pool,
+                                3 * count /* estimate */);
+
+       /* Insert all the categories into the hash table */
+       for (i = 0; i < count; i++)
+               insert_category(iter->hash, cats[i]);
+
+       iter->iter = hash_table_iterate_init(iter->hash);
+
+       return iter;
+}
+
+bool event_categories_iterate(struct event_category_iterator *iter,
+                             const struct event_category **cat_r)
+{
+       void *key ATTR_UNUSED;
+
+       if (iter == NULL) {
+               *cat_r = NULL;
+               return FALSE;
+       }
+       return hash_table_iterate(iter->iter, iter->hash, &key, cat_r);
+}
+
+void event_categories_iterate_deinit(struct event_category_iterator **_iter)
+{
+       struct event_category_iterator *iter = *_iter;
+
+       if (iter == NULL)
+               return;
+       *_iter = NULL;
+
+       hash_table_iterate_deinit(&iter->iter);
+       hash_table_destroy(&iter->hash);
+}
+
 void event_send(struct event *event, struct failure_context *ctx,
                const char *fmt, ...)
 {
index b3bdf05302474aa8f5ed1993f40bcb7f9b7b0cfd..ebf15341cd44939c714aaa3720e918c33ed45ea4 100644 (file)
@@ -10,6 +10,7 @@
 
 struct event;
 struct event_log_params;
+struct event_category_iterator;
 
 /* Hierarchical category of events. Each event can belong to multiple
    categories. For example [ lib-storage/maildir, syscall/io ]. The categories
@@ -421,6 +422,20 @@ event_get_fields(const struct event *event, unsigned int *count_r);
 struct event_category *const *
 event_get_categories(const struct event *event, unsigned int *count_r);
 
+/* Iterator for scanning through all categories of the event, including the
+   parents and higher ancestry of the categories directly associated with this
+   event. Note that this does not include the categories of any parent event. To
+   avoid useless allocation of an iterator, the event_categories_iterate_init()
+   function returns NULL if no categories are associated with this event. The
+   event_categories_iterate() and event_categories_iterate_deinit() functions
+   safely handle this NULL iterator.
+ */
+struct event_category_iterator *
+event_categories_iterate_init(const struct event *event);
+bool event_categories_iterate(struct event_category_iterator *iter,
+                             const struct event_category **cat_r);
+void event_categories_iterate_deinit(struct event_category_iterator **_iter);
+
 /* Export the event into a tabescaped string, so its fields are separated
    with TABs and there are no NUL, CR or LF characters. */
 void event_export(const struct event *event, string_t *dest);