Mercurial > dovecot > core-2.2
changeset 12786:934c529052eb
imapc: Initial support for local index files.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Thu, 10 Mar 2011 18:32:08 +0200 |
parents | 395af848ec10 |
children | 598bc0b91855 |
files | src/lib-storage/index/imapc/imapc-list.c src/lib-storage/index/imapc/imapc-list.h src/lib-storage/index/imapc/imapc-mailbox.c src/lib-storage/index/imapc/imapc-storage.c src/lib-storage/index/imapc/imapc-storage.h src/lib-storage/index/imapc/imapc-sync.c src/lib-storage/index/imapc/imapc-sync.h |
diffstat | 7 files changed, 206 insertions(+), 53 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib-storage/index/imapc/imapc-list.c Thu Mar 10 18:31:28 2011 +0200 +++ b/src/lib-storage/index/imapc/imapc-list.c Thu Mar 10 18:32:08 2011 +0200 @@ -182,22 +182,84 @@ return list->sep; } -static const char * -imapc_list_get_path(struct mailbox_list *list ATTR_UNUSED, - const char *name ATTR_UNUSED, - enum mailbox_list_path_type type) +static struct mailbox_list *imapc_list_get_fs(struct imapc_mailbox_list *list) { - if (type == MAILBOX_LIST_PATH_TYPE_INDEX) - return ""; - return NULL; + struct mailbox_list_settings list_set; + const char *error, *dir; + + dir = list->list.set.index_dir; + if (dir == NULL) + dir = list->list.set.root_dir; + + if (dir == NULL) { + /* indexes disabled */ + } else if (list->index_list == NULL && !list->index_list_failed) { + memset(&list_set, 0, sizeof(list_set)); + list_set.layout = MAILBOX_LIST_NAME_MAILDIRPLUSPLUS; + /* the root dir shouldn't actually ever be used. we just need + it to be different from index_dir so the index directories + get autocreated */ + list_set.root_dir = t_strconcat(dir, "/", NULL); + list_set.index_dir = dir; + list_set.escape_char = '%'; + + if (mailbox_list_create(list_set.layout, list->list.ns, + &list_set, MAILBOX_LIST_FLAG_SECONDARY, + &list->index_list, &error) < 0) { + i_error("imapc: Couldn't create %s mailbox list: %s", + list_set.layout, error); + list->index_list_failed = TRUE; + } + } + return list->index_list; } static const char * -imapc_list_get_temp_prefix(struct mailbox_list *list, bool global ATTR_UNUSED) +imapc_list_get_fs_name(struct imapc_mailbox_list *list, const char *name) +{ + struct mailbox_list *fs_list = imapc_list_get_fs(list); + const char *vname; + + if (name == NULL) + return name; + + vname = mailbox_list_get_vname(&list->list, name); + return mailbox_list_get_storage_name(fs_list, vname); +} + +static const char * +imapc_list_get_path(struct mailbox_list *_list, const char *name, + enum mailbox_list_path_type type) { - i_panic("imapc: Can't return a temp prefix for '%s'", - list->ns->prefix); - return NULL; + struct imapc_mailbox_list *list = (struct imapc_mailbox_list *)_list; + struct mailbox_list *fs_list = imapc_list_get_fs(list); + const char *fs_name; + + if (fs_list != NULL) { + fs_name = imapc_list_get_fs_name(list, name); + return mailbox_list_get_path(fs_list, fs_name, type); + } else { + if (type == MAILBOX_LIST_PATH_TYPE_INDEX) + return ""; + return NULL; + } +} + +static const char * +imapc_list_get_temp_prefix(struct mailbox_list *_list, bool global) +{ + struct imapc_mailbox_list *list = (struct imapc_mailbox_list *)_list; + struct mailbox_list *fs_list = imapc_list_get_fs(list); + + if (fs_list != NULL) { + return global ? + mailbox_list_get_global_temp_prefix(fs_list) : + mailbox_list_get_temp_prefix(fs_list); + } else { + i_panic("imapc: Can't return a temp prefix for '%s'", + _list->ns->prefix); + return NULL; + } } static const char * @@ -422,9 +484,15 @@ } static int -imapc_list_delete_dir(struct mailbox_list *list ATTR_UNUSED, - const char *name ATTR_UNUSED) +imapc_list_delete_dir(struct mailbox_list *_list, const char *name) { + struct imapc_mailbox_list *list = (struct imapc_mailbox_list *)_list; + struct mailbox_list *fs_list = imapc_list_get_fs(list); + + if (fs_list != NULL) { + name = imapc_list_get_fs_name(list, name); + (void)mailbox_list_delete_dir(fs_list, name); + } return 0; } @@ -434,6 +502,7 @@ bool rename_children) { struct imapc_mailbox_list *list = (struct imapc_mailbox_list *)oldlist; + struct mailbox_list *fs_list = imapc_list_get_fs(list); struct imapc_simple_context ctx; if (!rename_children) { @@ -453,6 +522,13 @@ imapc_list_simple_callback, &ctx, "RENAME %s %s", oldname, newname); imapc_simple_run(&ctx); + if (ctx.ret == 0 && fs_list != NULL && oldlist == newlist) { + oldname = imapc_list_get_fs_name(list, oldname); + newname = imapc_list_get_fs_name(list, newname); + (void)fs_list->v.rename_mailbox(fs_list, oldname, + fs_list, newname, + rename_children); + } return ctx.ret; }
--- a/src/lib-storage/index/imapc/imapc-list.h Thu Mar 10 18:31:28 2011 +0200 +++ b/src/lib-storage/index/imapc/imapc-list.h Thu Mar 10 18:32:08 2011 +0200 @@ -10,6 +10,7 @@ struct imapc_mailbox_list { struct mailbox_list list; struct imapc_storage *storage; + struct mailbox_list *index_list; struct mailbox_tree_context *mailboxes, *tmp_subscriptions; char sep; @@ -21,6 +22,7 @@ unsigned int broken:1; unsigned int refreshed_subscriptions:1; unsigned int refreshed_mailboxes:1; + unsigned int index_list_failed:1; }; void imapc_list_register_callbacks(struct imapc_mailbox_list *list);
--- a/src/lib-storage/index/imapc/imapc-mailbox.c Thu Mar 10 18:31:28 2011 +0200 +++ b/src/lib-storage/index/imapc/imapc-mailbox.c Thu Mar 10 18:32:08 2011 +0200 @@ -6,6 +6,7 @@ #include "imap-util.h" #include "imapc-client.h" #include "imapc-seqmap.h" +#include "imapc-sync.h" #include "imapc-storage.h" #define NOTIFY_DELAY_MSECS 500 @@ -37,6 +38,27 @@ mail_index_transaction_open_updated_view(mbox->delayed_sync_trans); } +int imapc_mailbox_commit_delayed_trans(struct imapc_mailbox *mbox, + bool *changes_r) +{ + int ret = 0; + + *changes_r = FALSE; + + if (mbox->delayed_sync_view != NULL) + mail_index_view_close(&mbox->delayed_sync_view); + if (mbox->delayed_sync_trans != NULL) { + if (mail_index_transaction_commit(&mbox->delayed_sync_trans) < 0) { + mail_storage_set_index_error(&mbox->box); + ret = -1; + } + *changes_r = TRUE; + } + if (mbox->sync_view != NULL) + mail_index_view_close(&mbox->sync_view); + return ret; +} + static void imapc_newmsgs_callback(const struct imapc_command_reply *reply, void *context) @@ -63,7 +85,7 @@ uint32_t rcount = reply->num; const struct mail_index_header *hdr; struct imapc_seqmap *seqmap; - uint32_t next_lseq, next_rseq; + uint32_t first_uid, next_lseq, next_rseq; if (mbox == NULL) return; @@ -74,14 +96,19 @@ seqmap = imapc_client_mailbox_get_seqmap(mbox->client_box); next_lseq = mail_index_view_get_messages_count(view) + 1; next_rseq = imapc_seqmap_lseq_to_rseq(seqmap, next_lseq); - if (next_rseq > rcount) - return; - - hdr = mail_index_get_header(view); + if (next_rseq > rcount) { + if (rcount == 0 || !mbox->opening) + return; + /* initial SELECT. we don't know what the flags are. */ + first_uid = 1; + } else { + hdr = mail_index_get_header(view); + first_uid = hdr->next_uid; + } mbox->new_msgs = TRUE; imapc_client_mailbox_cmdf(mbox->client_box, imapc_newmsgs_callback, - mbox, "UID FETCH %u:* FLAGS", hdr->next_uid); + mbox, "UID FETCH %u:* FLAGS", first_uid); } static void imapc_mailbox_idle_timeout(struct imapc_mailbox *mbox) @@ -101,6 +128,28 @@ } } +static bool keywords_are_equal(struct mail_keywords *kw, + const ARRAY_TYPE(keyword_indexes) *kw_arr) +{ + const unsigned int *kw_idx; + unsigned int i, j, count; + + kw_idx = array_get(kw_arr, &count); + if (count != kw->count) + return FALSE; + + /* there are normally only a few keywords, so O(n^2) is fine */ + for (i = 0; i < count; i++) { + for (j = 0; j < count; j++) { + if (kw->idx[i] == kw_idx[j]) + break; + } + if (j == count) + return FALSE; + } + return TRUE; +} + static void imapc_untagged_fetch(const struct imapc_untagged_reply *reply, struct imapc_mailbox *mbox) { @@ -158,32 +207,49 @@ imapc_mailbox_init_delayed_trans(mbox); old_count = mail_index_view_get_messages_count(mbox->delayed_sync_view); + while (lseq <= old_count) { + rec = mail_index_lookup(mbox->delayed_sync_view, lseq); + if (rec->uid == uid || uid == 0) + break; + + if (!mbox->opening || uid < rec->uid) { + imapc_mailbox_set_corrupted(mbox, + "Message UID changed %u -> %u", rec->uid, uid); + return; + } + /* we're opening the mailbox. this message was expunged + externally, so expunge it ourself too. */ + imapc_seqmap_expunge(seqmap, rseq); + mail_index_expunge(mbox->delayed_sync_trans, lseq); + lseq++; + } if (lseq > old_count) { if (uid == 0 || lseq != old_count + 1) return; i_assert(lseq == old_count + 1); mail_index_append(mbox->delayed_sync_trans, uid, &lseq); } - rec = mail_index_lookup(mbox->delayed_sync_view, lseq); - if (rec->uid != uid && uid != 0) { - imapc_mailbox_set_corrupted(mbox, "Message UID changed %u -> %u", - rec->uid, uid); - return; - } if (seen_flags && rec->flags != flags) { mail_index_update_flags(mbox->delayed_sync_trans, lseq, MODIFY_REPLACE, flags); } - if (seen_flags) { + if (seen_flags) T_BEGIN { + ARRAY_TYPE(keyword_indexes) old_kws; struct mail_keywords *kw; + t_array_init(&old_kws, 8); + mail_index_lookup_keywords(mbox->delayed_sync_view, lseq, + &old_kws); + (void)array_append_space(&keywords); kw = mail_index_keywords_create(mbox->box.index, array_idx(&keywords, 0)); - mail_index_update_keywords(mbox->delayed_sync_trans, lseq, - MODIFY_REPLACE, kw); + if (!keywords_are_equal(kw, &old_kws)) { + mail_index_update_keywords(mbox->delayed_sync_trans, + lseq, MODIFY_REPLACE, kw); + } mail_index_keywords_unref(&kw); - } + } T_END; imapc_mailbox_idle_notify(mbox); } @@ -222,32 +288,47 @@ imapc_resp_text_uidvalidity(const struct imapc_untagged_reply *reply, struct imapc_mailbox *mbox) { + const struct mail_index_header *hdr; uint32_t uid_validity; + bool changes; if (mbox == NULL || reply->resp_text_value == NULL || str_to_uint32(reply->resp_text_value, &uid_validity) < 0) return; - imapc_mailbox_init_delayed_trans(mbox); - mail_index_update_header(mbox->delayed_sync_trans, - offsetof(struct mail_index_header, uid_validity), - &uid_validity, sizeof(uid_validity), TRUE); + hdr = mail_index_get_header(mbox->box.view); + if (hdr->uid_validity != uid_validity) { + imapc_mailbox_init_delayed_trans(mbox); + if (hdr->uid_validity != 0) { + /* uidvalidity changed, reset the entire mailbox */ + mail_index_reset(mbox->delayed_sync_trans); + (void)imapc_mailbox_commit_delayed_trans(mbox, &changes); + imapc_mailbox_init_delayed_trans(mbox); + } + mail_index_update_header(mbox->delayed_sync_trans, + offsetof(struct mail_index_header, uid_validity), + &uid_validity, sizeof(uid_validity), TRUE); + } } static void imapc_resp_text_uidnext(const struct imapc_untagged_reply *reply, struct imapc_mailbox *mbox) { + const struct mail_index_header *hdr; uint32_t uid_next; if (mbox == NULL || reply->resp_text_value == NULL || str_to_uint32(reply->resp_text_value, &uid_next) < 0) return; - imapc_mailbox_init_delayed_trans(mbox); - mail_index_update_header(mbox->delayed_sync_trans, - offsetof(struct mail_index_header, next_uid), - &uid_next, sizeof(uid_next), FALSE); + hdr = mail_index_get_header(mbox->box.view); + if (hdr->next_uid != uid_next) { + imapc_mailbox_init_delayed_trans(mbox); + mail_index_update_header(mbox->delayed_sync_trans, + offsetof(struct mail_index_header, next_uid), + &uid_next, sizeof(uid_next), FALSE); + } } void imapc_mailbox_register_untagged(struct imapc_mailbox *mbox,
--- a/src/lib-storage/index/imapc/imapc-storage.c Thu Mar 10 18:31:28 2011 +0200 +++ b/src/lib-storage/index/imapc/imapc-storage.c Thu Mar 10 18:32:08 2011 +0200 @@ -267,8 +267,6 @@ struct index_mailbox_context *ibox; pool_t pool; - flags |= MAILBOX_FLAG_NO_INDEX_FILES; - pool = pool_alloconly_create("imapc mailbox", 1024*3); mbox = p_new(pool, struct imapc_mailbox, 1); mbox->box = imapc_mailbox; @@ -277,7 +275,8 @@ mbox->box.list = list; mbox->box.mail_vfuncs = &imapc_mail_vfuncs; - index_storage_mailbox_alloc(&mbox->box, vname, flags, NULL); + index_storage_mailbox_alloc(&mbox->box, vname, flags, + IMAPC_INDEX_PREFIX); ibox = INDEX_STORAGE_CONTEXT(&mbox->box); ibox->save_commit_pre = imapc_transaction_save_commit_pre;
--- a/src/lib-storage/index/imapc/imapc-storage.h Thu Mar 10 18:31:28 2011 +0200 +++ b/src/lib-storage/index/imapc/imapc-storage.h Thu Mar 10 18:32:08 2011 +0200 @@ -4,6 +4,7 @@ #include "index-storage.h" #define IMAPC_STORAGE_NAME "imapc" +#define IMAPC_INDEX_PREFIX "dovecot.index" struct imap_arg; struct imapc_untagged_reply; @@ -102,6 +103,8 @@ void *context); int imapc_mailbox_get_client_box(struct imapc_mailbox *mbox, struct imapc_client_mailbox **client_box_r); +int imapc_mailbox_commit_delayed_trans(struct imapc_mailbox *mbox, + bool *changes_r); void imapc_storage_register_untagged(struct imapc_storage *storage, const char *name,
--- a/src/lib-storage/index/imapc/imapc-sync.c Thu Mar 10 18:31:28 2011 +0200 +++ b/src/lib-storage/index/imapc/imapc-sync.c Thu Mar 10 18:32:08 2011 +0200 @@ -309,7 +309,7 @@ { struct imapc_mailbox *mbox = (struct imapc_mailbox *)box; enum imapc_capability capabilities; - bool changes = FALSE; + bool changes; int ret = 0; if (!box->opened) { @@ -327,18 +327,8 @@ imapc_client_run(mbox->storage->client); } - if (mbox->delayed_sync_view != NULL) - mail_index_view_close(&mbox->delayed_sync_view); - if (mbox->delayed_sync_trans != NULL) { - if (mail_index_transaction_commit(&mbox->delayed_sync_trans) < 0) { - mail_storage_set_index_error(&mbox->box); - ret = -1; - } - changes = TRUE; - } - if (mbox->sync_view != NULL) - mail_index_view_close(&mbox->sync_view); - + if (imapc_mailbox_commit_delayed_trans(mbox, &changes) < 0) + ret = -1; if ((changes || index_mailbox_want_full_sync(&mbox->box, flags)) && ret == 0) ret = imapc_sync(mbox);
--- a/src/lib-storage/index/imapc/imapc-sync.h Thu Mar 10 18:31:28 2011 +0200 +++ b/src/lib-storage/index/imapc/imapc-sync.h Thu Mar 10 18:32:08 2011 +0200 @@ -1,7 +1,9 @@ #ifndef CYDIR_SYNC_H #define CYDIR_SYNC_H +enum mailbox_sync_flags; struct mailbox; +struct mailbox_sync_status; struct imapc_sync_context { struct imapc_mailbox *mbox;