# HG changeset patch # User Timo Sirainen # Date 1297198454 -7200 # Node ID d3d5f104ca40af7c316c9fe6e35ffb2d896223d4 # Parent 13fdb8fed8bc93e639f76e27d47784c54916b2e9 lib-storage: Mailbox list indexes now refresh the index on create/delete/rename. diff -r 13fdb8fed8bc -r d3d5f104ca40 src/lib-storage/list/index-mailbox-list-status.c --- a/src/lib-storage/list/index-mailbox-list-status.c Tue Feb 08 22:18:14 2011 +0200 +++ b/src/lib-storage/list/index-mailbox-list-status.c Tue Feb 08 22:54:14 2011 +0200 @@ -40,7 +40,7 @@ view = mail_index_view_open(ilist->index); if (!mail_index_lookup_seq(view, node->uid, &seq)) { /* our in-memory tree is out of sync */ - ilist->force_refresh = TRUE; + index_mailbox_list_refresh_later(box->list); mail_index_view_close(&view); return 0; } @@ -242,7 +242,7 @@ /* update mailbox list index */ node = index_mailbox_list_lookup(box->list, box->vname); if (node == NULL) - ilist->force_refresh = TRUE; + index_mailbox_list_refresh_later(box->list); else { view = mail_index_view_open(ilist->index); if (mail_index_lookup_seq(view, node->uid, &seq)) { diff -r 13fdb8fed8bc -r d3d5f104ca40 src/lib-storage/list/index-mailbox-list.c --- a/src/lib-storage/list/index-mailbox-list.c Tue Feb 08 22:18:14 2011 +0200 +++ b/src/lib-storage/list/index-mailbox-list.c Tue Feb 08 22:54:14 2011 +0200 @@ -24,7 +24,7 @@ MODULE_CONTEXT_INIT(&mailbox_list_module_register); static int index_mailbox_list_read(struct index_mailbox_list *ilist, - bool force); + struct mail_index_view *view, bool force); static void index_mailbox_list_reset(struct index_mailbox_list *ilist) { @@ -81,7 +81,8 @@ char *dup_name; node = p_new(ctx->ilist->mailbox_pool, struct index_mailbox_node, 1); - node->flags = MAILBOX_LIST_INDEX_FLAG_NONEXISTENT; + node->flags = MAILBOX_LIST_INDEX_FLAG_NONEXISTENT | + MAILBOX_LIST_INDEX_FLAG_MARKED; node->name = dup_name = p_strdup(ctx->ilist->mailbox_pool, name); node->name_id = ++ctx->ilist->highest_name_id; node->uid = ctx->next_uid++; @@ -144,6 +145,7 @@ node = index_mailbox_node_find_sibling(node, path[i]); if (node == NULL) break; + node->flags |= MAILBOX_LIST_INDEX_FLAG_MARKED; parent = node; node = node->children; } @@ -157,7 +159,7 @@ node = index_mailbox_node_add(ctx, node, path[i], &seq); } - node->flags = flags; + node->flags = flags | MAILBOX_LIST_INDEX_FLAG_MARKED; return seq; } @@ -165,9 +167,11 @@ const struct index_mailbox_node *node) { for (; node != NULL; node = node->next) { - if (node->children != NULL) - get_existing_name_ids(ids, node->children); - array_append(ids, &node->name_id, 1); + if ((node->flags & MAILBOX_LIST_INDEX_FLAG_MARKED) != 0) { + if (node->children != NULL) + get_existing_name_ids(ids, node->children); + array_append(ids, &node->name_id, 1); + } } } @@ -183,6 +187,7 @@ struct index_mailbox_list *ilist = ctx->ilist; ARRAY_TYPE(uint32_t) existing_name_ids; buffer_t *buf; + struct mailbox_list_index_header *hdr; const void *ext_data; size_t ext_size; const char *name; @@ -194,6 +199,8 @@ array_sort(&existing_name_ids, uint32_cmp); buf = buffer_create_dynamic(pool_datastack_create(), 1024); + hdr = buffer_append_space_unsafe(buf, sizeof(*hdr)); + array_foreach(&existing_name_ids, id_p) { if (*id_p != prev_id) { buffer_append(buf, id_p, sizeof(*id_p)); @@ -217,6 +224,52 @@ 0, buf->data, buf->used); } +static void +index_mailbox_list_node_unmark_recursive(struct index_mailbox_node *node) +{ + while (node != NULL) { + if (node->children != NULL) + index_mailbox_list_node_unmark_recursive(node->children); + + node->flags &= ~MAILBOX_LIST_INDEX_FLAG_MARKED; + node = node->next; + } +} + +static void +index_mailbox_node_unlink(struct index_mailbox_list_sync_context *sync_ctx, + struct index_mailbox_node *node) +{ + struct index_mailbox_node **prev; + + prev = node->parent == NULL ? + &sync_ctx->ilist->mailbox_tree : &node->parent; + + while (*prev != node) + prev = &(*prev)->next; + *prev = node->next; +} + +static void +index_mailbox_nodes_expunge(struct index_mailbox_list_sync_context *sync_ctx, + struct index_mailbox_node *node) +{ + uint32_t seq; + + while (node != NULL) { + if (node->children != NULL) + index_mailbox_nodes_expunge(sync_ctx, node->children); + + if ((node->flags & MAILBOX_LIST_INDEX_FLAG_MARKED) == 0) { + if (mail_index_lookup_seq(sync_ctx->view, node->uid, + &seq)) + mail_index_expunge(sync_ctx->trans, seq); + index_mailbox_node_unlink(sync_ctx, node); + } + node = node->next; + } +} + static int index_mailbox_list_sync(struct mailbox_list *list) { struct index_mailbox_list *ilist = INDEX_LIST_CONTEXT(list); @@ -239,7 +292,7 @@ MAIL_INDEX_SYNC_FLAG_AVOID_FLAG_UPDATES) < 0) return -1; - if (index_mailbox_list_read(ilist, TRUE) < 0) { + if (index_mailbox_list_read(ilist, sync_ctx.view, TRUE) < 0) { mail_index_sync_rollback(&sync_ctx.sync_ctx); return -1; } @@ -256,6 +309,8 @@ &uid_validity, sizeof(uid_validity), TRUE); } + index_mailbox_list_node_unmark_recursive(ilist->mailbox_tree); + patterns[0] = "*"; patterns[1] = NULL; iter = ilist->module_ctx.super.iter_init(list, patterns, 0); while ((info = ilist->module_ctx.super.iter_next(iter)) != NULL) { @@ -283,26 +338,40 @@ return -1; } + index_mailbox_nodes_expunge(&sync_ctx, ilist->mailbox_tree); + if (orig_highest_name_id != ilist->highest_name_id) { /* new names added */ T_BEGIN { index_mailbox_list_sync_names(&sync_ctx); } T_END; + } else { + struct mailbox_list_index_header new_hdr; + + new_hdr.refresh_flag = 0; + mail_index_update_header_ext(sync_ctx.trans, ilist->ext_id, + offsetof(struct mailbox_list_index_header, refresh_flag), + &new_hdr.refresh_flag, sizeof(new_hdr.refresh_flag)); } - ilist->force_refresh = FALSE; + return mail_index_sync_commit(&sync_ctx.sync_ctx); } static int index_mailbox_list_parse_header(struct index_mailbox_list *ilist, struct mail_index_view *view) { + const struct mailbox_list_index_header *hdr; const void *data, *p; size_t i, len, size; uint32_t id, prev_id = 0; char *name; mail_index_get_header_ext(view, ilist->ext_id, &data, &size); - for (i = 0; i < size; ) { + if (size == 0) + return 0; + + hdr = data; + for (i = sizeof(*hdr); i < size; ) { /* get id */ if (i + sizeof(id) > size) return -1; @@ -379,19 +448,17 @@ return 0; } -static int index_mailbox_list_read(struct index_mailbox_list *ilist, bool force) +static int index_mailbox_list_read(struct index_mailbox_list *ilist, + struct mail_index_view *view, bool force) { - struct mail_index_view *view; const struct mail_index_header *hdr; int ret; - view = mail_index_view_open(ilist->index); hdr = mail_index_get_header(view); if (!force && hdr->log_file_seq == ilist->sync_log_file_seq && hdr->log_file_head_offset == ilist->sync_log_file_offset) { /* nothing changed */ - mail_index_view_close(&view); return 0; } @@ -402,7 +469,6 @@ ret = index_mailbox_list_parse_header(ilist, view); if (ret == 0) ret = index_mailbox_list_parse_records(ilist, view); - mail_index_view_close(&view); if (ret < 0) { i_error("Corrupted mailbox list index %s", ilist->path); mail_index_mark_corrupted(ilist->index); @@ -411,28 +477,66 @@ return 0; } +static bool +index_mailbox_list_need_refresh(struct index_mailbox_list *ilist, + struct mail_index_view *view) +{ + const struct mailbox_list_index_header *hdr; + const void *data; + size_t size; + + mail_index_get_header_ext(view, ilist->ext_id, &data, &size); + hdr = data; + return hdr != NULL && hdr->refresh_flag != 0; +} + int index_mailbox_list_refresh(struct mailbox_list *list) { struct index_mailbox_list *ilist = INDEX_LIST_CONTEXT(list); + struct mail_index_view *view; + int ret; if (ilist->iter_refcount > 0) { /* someone's already iterating. don't break them. */ return 0; } - if (ilist->mailbox_tree == NULL || ilist->force_refresh) { - /* the first mailbox list in this session, - refresh list of mailboxes */ - if (index_mailbox_list_sync(list) < 0) - return -1; + if (mail_index_refresh(ilist->index) < 0) + return -1; + + view = mail_index_view_open(ilist->index); + if (ilist->mailbox_tree == NULL || + index_mailbox_list_need_refresh(ilist, view)) { + /* refresh list of mailboxes */ + ret = index_mailbox_list_sync(list); } else { - if (mail_index_refresh(ilist->index) < 0) - return -1; + ret = index_mailbox_list_read(ilist, view, FALSE); + } + mail_index_view_close(&view); + return ret; +} + +void index_mailbox_list_refresh_later(struct mailbox_list *list) +{ + struct index_mailbox_list *ilist = INDEX_LIST_CONTEXT(list); + struct mailbox_list_index_header new_hdr; + struct mail_index_view *view; + struct mail_index_transaction *trans; - if (index_mailbox_list_read(ilist, FALSE) < 0) - return -1; + view = mail_index_view_open(ilist->index); + if (!index_mailbox_list_need_refresh(ilist, view)) { + new_hdr.refresh_flag = 1; + + trans = mail_index_transaction_begin(view, + MAIL_INDEX_TRANSACTION_FLAG_EXTERNAL); + mail_index_update_header_ext(trans, ilist->ext_id, + offsetof(struct mailbox_list_index_header, refresh_flag), + &new_hdr.refresh_flag, sizeof(new_hdr.refresh_flag)); + if (mail_index_transaction_commit(&trans) < 0) + mail_index_mark_corrupted(ilist->index); + } - return 0; + mail_index_view_close(&view); } static struct mailbox_list_iterate_context * @@ -454,7 +558,7 @@ if (index_mailbox_list_refresh(ctx->ctx.list) < 0) { /* no indexing */ - ilist->force_refresh = TRUE; + mail_index_mark_corrupted(ilist->index); ctx->backend_ctx = ilist->module_ctx.super. iter_init(list, patterns, flags); } else { @@ -634,6 +738,52 @@ return 0; } +static int +index_mailbox_list_create_mailbox_dir(struct mailbox_list *list, + const char *name, + enum mailbox_dir_create_type type) +{ + struct index_mailbox_list *ilist = INDEX_LIST_CONTEXT(list); + + index_mailbox_list_refresh_later(list); + return ilist->module_ctx.super.create_mailbox_dir(list, name, type); +} + +static int +index_mailbox_list_delete_mailbox(struct mailbox_list *list, const char *name) +{ + struct index_mailbox_list *ilist = INDEX_LIST_CONTEXT(list); + + index_mailbox_list_refresh_later(list); + return ilist->module_ctx.super.delete_mailbox(list, name); +} + +static int +index_mailbox_list_delete_dir(struct mailbox_list *list, const char *name) +{ + struct index_mailbox_list *ilist = INDEX_LIST_CONTEXT(list); + + index_mailbox_list_refresh_later(list); + return ilist->module_ctx.super.delete_dir(list, name); +} + +static int +index_mailbox_list_rename_mailbox(struct mailbox_list *oldlist, + const char *oldname, + struct mailbox_list *newlist, + const char *newname, + bool rename_children) +{ + struct index_mailbox_list *oldilist = INDEX_LIST_CONTEXT(oldlist); + + index_mailbox_list_refresh_later(oldlist); + if (oldlist != newlist) + index_mailbox_list_refresh_later(newlist); + return oldilist->module_ctx.super. + rename_mailbox(oldlist, oldname, + newlist, newname, rename_children); +} + static void index_mailbox_list_created(struct mailbox_list *list) { struct index_mailbox_list *ilist; @@ -655,13 +805,20 @@ list->v.iter_init = index_mailbox_list_iter_init; list->v.iter_deinit = index_mailbox_list_iter_deinit; list->v.iter_next = index_mailbox_list_iter_next; + + list->v.create_mailbox_dir = index_mailbox_list_create_mailbox_dir; + list->v.delete_mailbox = index_mailbox_list_delete_mailbox; + list->v.delete_dir = index_mailbox_list_delete_dir; + list->v.rename_mailbox = index_mailbox_list_rename_mailbox; + MODULE_CONTEXT_SET(list, index_mailbox_list_module, ilist); ilist->path = p_strdup_printf(list->pool, "%s/"MAILBOX_LIST_INDEX_PREFIX, dir); ilist->index = mail_index_alloc(dir, MAILBOX_LIST_INDEX_PREFIX); - ilist->ext_id = mail_index_ext_register(ilist->index, "list", 0, + ilist->ext_id = mail_index_ext_register(ilist->index, "list", + sizeof(struct mailbox_list_index_header), sizeof(struct mailbox_list_index_record), sizeof(uint32_t)); diff -r 13fdb8fed8bc -r d3d5f104ca40 src/lib-storage/list/index-mailbox-list.h --- a/src/lib-storage/list/index-mailbox-list.h Tue Feb 08 22:18:14 2011 +0200 +++ b/src/lib-storage/list/index-mailbox-list.h Tue Feb 08 22:54:14 2011 +0200 @@ -19,6 +19,11 @@ MAILBOX_LIST_INDEX_FLAG_MARKED }; +struct mailbox_list_index_header { + uint8_t refresh_flag; + /* array of { uint32_t id; char name[]; } */ +}; + struct mailbox_list_index_record { /* points to given id in header */ uint32_t name_id; @@ -68,11 +73,11 @@ uint32_t sync_log_file_seq; uoff_t sync_log_file_offset; + uint32_t sync_stamp; + /* uint32_t uid => struct index_mailbox_node* */ struct hash_table *mailbox_hash; struct index_mailbox_node *mailbox_tree; - - unsigned int force_refresh:1; }; struct index_mailbox_list_iterate_context { @@ -95,6 +100,7 @@ index_mailbox_list_lookup(struct mailbox_list *list, const char *vname); int index_mailbox_list_refresh(struct mailbox_list *list); +void index_mailbox_list_refresh_later(struct mailbox_list *list); void index_mailbox_list_status_init(void); void index_mailbox_list_status_init_list(struct mailbox_list *list);