From: Timo Sirainen Date: Sat, 6 Dec 2025 11:23:05 +0000 (+0200) Subject: lib-storage: mailbox list index - Use hash table to storage name lookups X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=c2aa2d2223cceab5ece02fb472f13a2b7ee4b52a;p=thirdparty%2Fdovecot%2Fcore.git lib-storage: mailbox list index - Use hash table to storage name lookups --- diff --git a/src/lib-storage/list/mailbox-list-index-backend.c b/src/lib-storage/list/mailbox-list-index-backend.c index 8aba465aa9..9591494d5a 100644 --- a/src/lib-storage/list/mailbox-list-index-backend.c +++ b/src/lib-storage/list/mailbox-list-index-backend.c @@ -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); diff --git a/src/lib-storage/list/mailbox-list-index-sync.c b/src/lib-storage/list/mailbox-list-index-sync.c index 756e576c35..3b8a9a6c6f 100644 --- a/src/lib-storage/list/mailbox-list-index-sync.c +++ b/src/lib-storage/list/mailbox-list-index-sync.c @@ -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; } diff --git a/src/lib-storage/list/mailbox-list-index.c b/src/lib-storage/list/mailbox-list-index.c index e58916c4b8..cb669a13f0 100644 --- a/src/lib-storage/list/mailbox-list-index.c +++ b/src/lib-storage/list/mailbox-list-index.c @@ -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; diff --git a/src/lib-storage/list/mailbox-list-index.h b/src/lib-storage/list/mailbox-list-index.h index 62445478bd..09ae6fad82 100644 --- a/src/lib-storage/list/mailbox-list-index.h +++ b/src/lib-storage/list/mailbox-list-index.h @@ -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);