]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-storage: mailbox list index - Use hash table to storage name lookups
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Sat, 6 Dec 2025 11:23:05 +0000 (13:23 +0200)
committertimo.sirainen <timo.sirainen@open-xchange.com>
Wed, 24 Jun 2026 15:59:24 +0000 (15:59 +0000)
src/lib-storage/list/mailbox-list-index-backend.c
src/lib-storage/list/mailbox-list-index-sync.c
src/lib-storage/list/mailbox-list-index.c
src/lib-storage/list/mailbox-list-index.h

index 8aba465aa976d8b53d10f12c2bcb91dd96a680fd..9591494d5ab436b1cf4f3927a6595a354bfed638 100644 (file)
@@ -857,10 +857,20 @@ index_list_rename_mailbox(struct mailbox_list *_oldlist, const char *oldname,
        /* copy all the data from old node to new node */
        newnode->uid = oldnode->uid;
        newnode->flags = oldnode->flags;
+
+       /* the children move from oldnode to newnode, so their full storage
+          paths change. drop their stale hash entries before reparenting and
+          re-insert with the new paths afterwards. */
+       for (child = oldnode->children; child != NULL; child = child->next)
+               mailbox_list_index_subtree_hash_remove(sync_ctx->ilist, child);
+
        newnode->children = oldnode->children; oldnode->children = NULL;
        for (child = newnode->children; child != NULL; child = child->next)
                child->parent = newnode;
 
+       for (child = newnode->children; child != NULL; child = child->next)
+               mailbox_list_index_subtree_hash_insert(sync_ctx->ilist, child);
+
        /* remove the old node from existence */
        mailbox_list_index_node_unlink(sync_ctx->ilist, oldnode);
 
index 756e576c35805e5b7ceb09f5501760d39fc5f4fd..3b8a9a6c6f57d834068f411a1c8b400b5c488f74 100644 (file)
@@ -97,6 +97,8 @@ mailbox_list_index_node_add(struct mailbox_list_index_sync_context *ctx,
        hash_table_insert(ctx->ilist->mailbox_names,
                          POINTER_CAST(node->name_id), dup_name);
 
+       mailbox_list_index_node_hash_insert(ctx->ilist, node);
+
        node_add_to_index(ctx, node, seq_r);
        return node;
 }
@@ -109,6 +111,9 @@ mailbox_list_index_node_add_inbox_inbox(struct mailbox_list_index_sync_context *
                mailbox_list_index_node_add_common(ctx, NULL);
        node->raw_name = ctx->ilist->raw_inbox_inbox_name_ptr;
        ctx->ilist->inbox_inbox_name_id = node->name_id;
+
+       mailbox_list_index_node_hash_insert(ctx->ilist, node);
+
        node_add_to_index(ctx, node, seq_r);
        return node;
 }
index e58916c4b8c8ea9b802e8602cc80ae741d5c351e..cb669a13f03fed71427d7e1b59426f9ec1ee4de5 100644 (file)
@@ -43,6 +43,7 @@ void mailbox_list_index_reset(struct mailbox_list_index *ilist)
 {
        hash_table_destroy(&ilist->mailbox_names);
        hash_table_destroy(&ilist->mailbox_hash);
+       hash_table_destroy(&ilist->mailbox_storage_name_hash);
        pool_unref(&ilist->mailbox_pool);
 
        ilist->mailbox_tree = NULL;
@@ -117,6 +118,29 @@ int mailbox_list_index_index_open(struct mailbox_list *list)
        return 0;
 }
 
+static void
+mailbox_list_index_vname_hash_create(struct mailbox_list_index *ilist,
+                                    struct mail_index_view *view)
+{
+       uint32_t count = mail_index_view_get_messages_count(view);
+       hash_table_create(&ilist->mailbox_storage_name_hash,
+                         ilist->mailbox_pool, count,
+                         str_hash, strcmp);
+       string_t *name = t_str_new(128);
+       for (uint32_t seq = 1; seq <= count; seq++) {
+               uint32_t uid;
+               mail_index_lookup_uid(view, seq, &uid);
+               struct mailbox_list_index_node *node =
+                       mailbox_list_index_lookup_uid(ilist, uid);
+               i_assert(node != NULL);
+
+               str_truncate(name, 0);
+               mailbox_list_index_node_get_path(ilist->list, node, name);
+               const char *key = p_strdup(ilist->mailbox_pool, str_c(name));
+               hash_table_insert(ilist->mailbox_storage_name_hash, key, node);
+       }
+}
+
 struct mailbox_list_index_node *
 mailbox_list_index_node_find_sibling(struct mailbox_list *list,
                                     struct mailbox_list_index_node *node,
@@ -149,11 +173,14 @@ static struct mailbox_list_index_node *
 mailbox_list_index_lookup_real(struct mailbox_list *list, const char *name)
 {
        struct mailbox_list_index *ilist = INDEX_LIST_CONTEXT_REQUIRE(list);
-       struct mailbox_list_index_node *node = ilist->mailbox_tree;
        const char *const *path;
        unsigned int i;
        char sep[2];
 
+       if (hash_table_is_created(ilist->mailbox_storage_name_hash))
+               return hash_table_lookup(ilist->mailbox_storage_name_hash, name);
+
+       struct mailbox_list_index_node *node = ilist->mailbox_tree;
        if (*name == '\0')
                return mailbox_list_index_node_find_sibling(list, node, "");
 
@@ -222,11 +249,67 @@ void mailbox_list_index_node_get_path(struct mailbox_list *list,
        mailbox_list_get_escaped_mailbox_name(list, node, storage_name);
 }
 
+void mailbox_list_index_node_hash_insert(struct mailbox_list_index *ilist,
+                                        struct mailbox_list_index_node *node)
+{
+       if (!hash_table_is_created(ilist->mailbox_storage_name_hash))
+               return;
+       T_BEGIN {
+               string_t *storage_name = t_str_new(128);
+               mailbox_list_index_node_get_path(ilist->list, node,
+                                                storage_name);
+               const char *key = p_strdup(ilist->mailbox_pool,
+                                          str_c(storage_name));
+               hash_table_insert(ilist->mailbox_storage_name_hash, key, node);
+       } T_END;
+}
+
+static void
+mailbox_list_index_node_hash_remove(struct mailbox_list_index *ilist,
+                                   struct mailbox_list_index_node *node)
+{
+       if (!hash_table_is_created(ilist->mailbox_storage_name_hash))
+               return;
+       T_BEGIN {
+               string_t *storage_name = t_str_new(128);
+               mailbox_list_index_node_get_path(ilist->list, node,
+                                                storage_name);
+               hash_table_remove(ilist->mailbox_storage_name_hash,
+                                 str_c(storage_name));
+       } T_END;
+}
+
+void mailbox_list_index_subtree_hash_remove(struct mailbox_list_index *ilist,
+                                           struct mailbox_list_index_node *node)
+{
+       struct mailbox_list_index_node *child;
+
+       for (child = node->children; child != NULL; child = child->next)
+               mailbox_list_index_subtree_hash_remove(ilist, child);
+       mailbox_list_index_node_hash_remove(ilist, node);
+}
+
+void mailbox_list_index_subtree_hash_insert(struct mailbox_list_index *ilist,
+                                           struct mailbox_list_index_node *node)
+{
+       struct mailbox_list_index_node *child;
+
+       mailbox_list_index_node_hash_insert(ilist, node);
+       for (child = node->children; child != NULL; child = child->next)
+               mailbox_list_index_subtree_hash_insert(ilist, child);
+}
+
 void mailbox_list_index_node_unlink(struct mailbox_list_index *ilist,
                                    struct mailbox_list_index_node *node)
 {
        struct mailbox_list_index_node **prev;
 
+       if (hash_table_is_created(ilist->mailbox_storage_name_hash)) T_BEGIN {
+               string_t *name = t_str_new(128);
+               mailbox_list_index_node_get_path(ilist->list, node, name);
+               hash_table_remove(ilist->mailbox_storage_name_hash, str_c(name));
+       } T_END;
+
        prev = node->parent == NULL ?
                &ilist->mailbox_tree : &node->parent->children;
 
@@ -531,6 +614,11 @@ static int mailbox_list_index_parse_records(struct mailbox_list_index *ilist,
                        ilist->mailbox_tree = node;
                }
        }
+
+       if (*error_r == NULL) T_BEGIN {
+               mailbox_list_index_vname_hash_create(ilist, view);
+       } T_END;
+
        hash_table_destroy(&duplicate_hash);
        if (!ilist->has_backing_store)
                hash_table_destroy(&duplicate_guid);
@@ -1230,6 +1318,7 @@ static void mailbox_list_index_created(struct mailbox_list *list)
 
        ilist = p_new(list->pool, struct mailbox_list_index, 1);
        ilist->module_ctx.super = *v;
+       ilist->list = list;
        list->vlast = &ilist->module_ctx.super;
        ilist->has_backing_store = has_backing_store;
        ilist->pending_init = TRUE;
index 62445478bdb86f19d8ac44d5afb71b623a4f95dd..09ae6fad825bbb7dc404bf90e92ac9a457a9fb38 100644 (file)
@@ -112,6 +112,7 @@ struct mailbox_list_index_node {
 
 struct mailbox_list_index {
        union mailbox_list_module_context module_ctx;
+       struct mailbox_list *list;
 
        const char *path;
        struct mail_index *index;
@@ -143,6 +144,8 @@ struct mailbox_list_index {
 
        /* uint32_t uid => node */
        HASH_TABLE(void *, struct mailbox_list_index_node *) mailbox_hash;
+       /* full storage name => node */
+       HASH_TABLE(const char *, struct mailbox_list_index_node *) mailbox_storage_name_hash;
        struct mailbox_list_index_node *mailbox_tree;
 
        enum mail_index_error_code index_error_code;
@@ -188,6 +191,12 @@ mailbox_list_index_lookup_uid(struct mailbox_list_index *ilist, uint32_t uid);
 void mailbox_list_index_node_get_path(struct mailbox_list *list,
                                      const struct mailbox_list_index_node *node,
                                      string_t *storage_name);
+void mailbox_list_index_node_hash_insert(struct mailbox_list_index *ilist,
+                                        struct mailbox_list_index_node *node);
+void mailbox_list_index_subtree_hash_remove(struct mailbox_list_index *ilist,
+                                           struct mailbox_list_index_node *node);
+void mailbox_list_index_subtree_hash_insert(struct mailbox_list_index *ilist,
+                                           struct mailbox_list_index_node *node);
 void mailbox_list_index_node_unlink(struct mailbox_list_index *ilist,
                                    struct mailbox_list_index_node *node);