# HG changeset patch # User Timo Sirainen # Date 1436606216 -10800 # Node ID 46cbde67f50bb02fb6c63a824354b07bd4dadf26 # Parent 421f595a0e9383835561a5eab9f9f52b4e65e30c lib-storage: If mailboxes' vsizes are used, keep them updated also in mailbox list index. This allows looking them up quickly without opening the actual mailbox indexes. diff -r 421f595a0e93 -r 46cbde67f50b src/lib-storage/list/mailbox-list-index-backend.c --- a/src/lib-storage/list/mailbox-list-index-backend.c Sat Jul 11 12:14:48 2015 +0300 +++ b/src/lib-storage/list/mailbox-list-index-backend.c Sat Jul 11 12:16:56 2015 +0300 @@ -175,7 +175,7 @@ T_MAIL_ERR_MAILBOX_NOT_FOUND(name)); ret = -1; } else if (!mailbox_list_index_status(_list, view, seq, 0, - &status, mailbox_guid) || + &status, mailbox_guid, NULL) || guid_128_is_empty(mailbox_guid)) { mailbox_list_set_error(_list, MAIL_ERROR_NOTFOUND, T_MAIL_ERR_MAILBOX_NOT_FOUND(name)); diff -r 421f595a0e93 -r 46cbde67f50b src/lib-storage/list/mailbox-list-index-notify.c --- a/src/lib-storage/list/mailbox-list-index-notify.c Sat Jul 11 12:14:48 2015 +0300 +++ b/src/lib-storage/list/mailbox-list-index-notify.c Sat Jul 11 12:16:56 2015 +0300 @@ -160,7 +160,7 @@ memset(status_r, 0, sizeof(*status_r)); memset(guid_r, 0, GUID_128_SIZE); (void)mailbox_list_index_status(inotify->notify.list, view, seq, - items, status_r, guid_r); + items, status_r, guid_r, NULL); return index_node; } diff -r 421f595a0e93 -r 46cbde67f50b src/lib-storage/list/mailbox-list-index-status.c --- a/src/lib-storage/list/mailbox-list-index-status.c Sat Jul 11 12:14:48 2015 +0300 +++ b/src/lib-storage/list/mailbox-list-index-status.c Sat Jul 11 12:16:56 2015 +0300 @@ -14,10 +14,12 @@ struct mailbox_status status; guid_128_t guid; uint32_t seq; + struct mailbox_index_vsize vsize; bool rec_changed; bool msgs_changed; bool hmodseq_changed; + bool vsize_changed; }; struct index_list_storage_module index_list_storage_module = @@ -108,7 +110,8 @@ struct mail_index_view *view, uint32_t seq, enum mailbox_status_items items, struct mailbox_status *status_r, - uint8_t *mailbox_guid) + uint8_t *mailbox_guid, + struct mailbox_index_vsize *vsize_r) { struct mailbox_list_index *ilist = INDEX_LIST_CONTEXT(list); const void *data; @@ -161,6 +164,14 @@ else status_r->highest_modseq = *rec; } + if (vsize_r != NULL) { + mail_index_lookup_ext(view, seq, ilist->vsize_ext_id, + &data, &expunged); + if (data == NULL) + ret = FALSE; + else + memcpy(vsize_r, data, sizeof(*vsize_r)); + } return ret; } @@ -184,7 +195,7 @@ return ret; ret = mailbox_list_index_status(box->list, view, seq, items, - status_r, NULL) ? 1 : 0; + status_r, NULL, NULL) ? 1 : 0; mail_index_view_close(&view); return ret; } @@ -221,13 +232,81 @@ return ret; ret = mailbox_list_index_status(box->list, view, seq, 0, - &status, guid_r) ? 1 : 0; + &status, guid_r, NULL) ? 1 : 0; if (ret > 0 && guid_128_is_empty(guid_r)) ret = 0; mail_index_view_close(&view); return ret; } +static int index_list_get_cached_vsize(struct mailbox *box, uoff_t *vsize_r) +{ + struct mailbox_list_index *ilist = INDEX_LIST_CONTEXT(box->list); + struct mailbox_status status; + struct mailbox_index_vsize vsize; + struct mail_index_view *view; + uint32_t seq; + int ret; + + i_assert(!ilist->syncing); + + if ((ret = index_list_open_view(box, &view, &seq)) <= 0) + return ret; + + ret = mailbox_list_index_status(box->list, view, seq, + STATUS_MESSAGES | STATUS_UIDNEXT, + &status, NULL, &vsize) ? 1 : 0; + if (ret > 0 && (vsize.highest_uid + 1 != status.uidnext || + vsize.message_count != status.messages)) { + /* out of date vsize info */ + ret = 0; + } + if (ret > 0) + *vsize_r = vsize.vsize; + mail_index_view_close(&view); + return ret; +} + +static int +index_list_try_get_metadata(struct mailbox *box, + enum mailbox_metadata_items items, + struct mailbox_metadata *metadata_r) +{ + enum mailbox_metadata_items noncached_items; + int ret; + + if (box->opened) { + /* if mailbox is already opened, don't bother using the values + in mailbox list index. they have a higher chance of being + wrong. */ + return 0; + } + /* see if we have a chance of fulfilling this without opening + the mailbox. */ + noncached_items = items & ~(MAILBOX_METADATA_GUID | + MAILBOX_METADATA_VIRTUAL_SIZE); + if ((noncached_items & MAILBOX_METADATA_PHYSICAL_SIZE) != 0 && + box->mail_vfuncs->get_physical_size == + box->mail_vfuncs->get_virtual_size) + noncached_items = items & ~MAILBOX_METADATA_PHYSICAL_SIZE; + + if (noncached_items != 0) + return 0; + + if ((items & MAILBOX_METADATA_GUID) != 0) { + if ((ret = index_list_get_cached_guid(box, metadata_r->guid)) <= 0) + return ret; + } + if ((items & (MAILBOX_METADATA_VIRTUAL_SIZE | + MAILBOX_METADATA_PHYSICAL_SIZE)) != 0) { + if ((ret = index_list_get_cached_vsize(box, &metadata_r->virtual_size)) <= 0) + return ret; + if ((items & MAILBOX_METADATA_PHYSICAL_SIZE) != 0) + metadata_r->physical_size = metadata_r->virtual_size; + } + return 1; +} + static int index_list_get_metadata(struct mailbox *box, enum mailbox_metadata_items items, @@ -235,14 +314,25 @@ { struct index_list_mailbox *ibox = INDEX_LIST_STORAGE_CONTEXT(box); - if (items == MAILBOX_METADATA_GUID && !box->opened) { - if (index_list_get_cached_guid(box, metadata_r->guid) > 0) - return 0; - /* nonsynced / error, fallback to doing it the slow way */ - } + if (index_list_try_get_metadata(box, items, metadata_r) != 0) + return 0; return ibox->module_ctx.super.get_metadata(box, items, metadata_r); } +static void +index_list_update_fill_vsize(struct mailbox *box, + struct mail_index_view *view, + struct index_list_changes *changes_r) +{ + const void *data; + size_t size; + + mail_index_get_header_ext(view, box->vsize_hdr_ext_id, + &data, &size); + if (size == sizeof(changes_r->vsize)) + memcpy(&changes_r->vsize, data, sizeof(changes_r->vsize)); +} + static bool index_list_update_fill_changes(struct mailbox *box, struct mail_index_view *list_view, @@ -286,6 +376,7 @@ /* modseqs not enabled yet, but we can't return 0 */ changes_r->status.highest_modseq = 1; } + index_list_update_fill_vsize(box, view, changes_r); mail_index_view_close(&view); hdr = NULL; if (mailbox_get_metadata(box, MAILBOX_METADATA_GUID, &metadata) == 0) @@ -299,13 +390,15 @@ { struct mailbox_list_index *ilist = INDEX_LIST_CONTEXT(box->list); struct mailbox_status old_status; + struct mailbox_index_vsize old_vsize; guid_128_t old_guid; memset(&old_status, 0, sizeof(old_status)); + memset(&old_vsize, 0, sizeof(old_vsize)); memset(old_guid, 0, sizeof(old_guid)); (void)mailbox_list_index_status(box->list, list_view, changes->seq, CACHED_STATUS_ITEMS, - &old_status, old_guid); + &old_status, old_guid, &old_vsize); changes->rec_changed = old_status.uidvalidity != changes->status.uidvalidity && @@ -331,13 +424,11 @@ ilist->hmodseq_ext_id, &data, &expunged); changes->hmodseq_changed = data != NULL; } - - if (changes->hmodseq_changed && - old_status.highest_modseq != changes->status.highest_modseq) - changes->hmodseq_changed = TRUE; + if (memcmp(&old_vsize, &changes->vsize, sizeof(old_vsize)) != 0) + changes->vsize_changed = TRUE; return changes->rec_changed || changes->msgs_changed || - changes->hmodseq_changed; + changes->hmodseq_changed || changes->vsize_changed; } static void @@ -382,6 +473,11 @@ ilist->hmodseq_ext_id, &changes->status.highest_modseq, NULL); } + if (changes->vsize_changed) { + mail_index_update_ext(list_trans, changes->seq, + ilist->vsize_ext_id, + &changes->vsize, NULL); + } } static int index_list_update_mailbox(struct mailbox *box) @@ -482,7 +578,7 @@ (void)mailbox_list_index_status(box->list, list_view, changes.seq, CACHED_STATUS_ITEMS, &status, - mailbox_guid); + mailbox_guid, NULL); if (update->uid_validity != 0) { changes.rec_changed = TRUE; changes.status.uidvalidity = update->uid_validity; @@ -575,7 +671,7 @@ status.recent = 0; (void)mailbox_list_index_status(box->list, view, seq, STATUS_RECENT, - &status, NULL); + &status, NULL, NULL); mail_index_view_close(&view); if (status.recent != 0) @@ -604,4 +700,7 @@ ilist->hmodseq_ext_id = mail_index_ext_register(ilist->index, "hmodseq", 0, sizeof(uint64_t), sizeof(uint64_t)); + ilist->vsize_ext_id = + mail_index_ext_register(ilist->index, "vsize", 0, + sizeof(struct mailbox_index_vsize), sizeof(uint64_t)); } diff -r 421f595a0e93 -r 46cbde67f50b src/lib-storage/list/mailbox-list-index.h --- a/src/lib-storage/list/mailbox-list-index.h Sat Jul 11 12:14:48 2015 +0300 +++ b/src/lib-storage/list/mailbox-list-index.h Sat Jul 11 12:16:56 2015 +0300 @@ -36,6 +36,7 @@ MODULE_CONTEXT(obj, mailbox_list_index_module) struct mail_index_view; +struct mailbox_index_vsize; /* stored in mail_index_record.flags: */ enum mailbox_list_index_flags { @@ -88,6 +89,7 @@ const char *path; struct mail_index *index; uint32_t ext_id, msgs_ext_id, hmodseq_ext_id, subs_hdr_ext_id; + uint32_t vsize_ext_id; struct timeval last_refresh_timeval; pool_t mailbox_pool; @@ -170,7 +172,8 @@ struct mail_index_view *view, uint32_t seq, enum mailbox_status_items items, struct mailbox_status *status_r, - uint8_t *mailbox_guid); + uint8_t *mailbox_guid, + struct mailbox_index_vsize *vsize_r); void mailbox_list_index_status_set_info_flags(struct mailbox *box, uint32_t uid, enum mailbox_info_flags *flags); void mailbox_list_index_update_mailbox_index(struct mailbox *box, diff -r 421f595a0e93 -r 46cbde67f50b src/lib-storage/list/mailbox-list-notify-tree.c --- a/src/lib-storage/list/mailbox-list-notify-tree.c Sat Jul 11 12:14:48 2015 +0300 +++ b/src/lib-storage/list/mailbox-list-notify-tree.c Sat Jul 11 12:16:56 2015 +0300 @@ -29,7 +29,7 @@ memset(&status, 0, sizeof(status)); (void)mailbox_list_index_status(tree->list, tree->view, seq, STATUS_UIDVALIDITY | STATUS_UIDNEXT | STATUS_MESSAGES | - STATUS_UNSEEN | STATUS_HIGHESTMODSEQ, &status, nnode->guid); + STATUS_UNSEEN | STATUS_HIGHESTMODSEQ, &status, nnode->guid, NULL); nnode->uidvalidity = status.uidvalidity; nnode->uidnext = status.uidnext; nnode->messages = status.messages;