# HG changeset patch # User Timo Sirainen # Date 1317397989 -10800 # Node ID 5726f89486a0fbaef9be4a30ed5e15b1de4538d3 # Parent 690f60827f5987e6d1b262d67dd8be1b91aa70c2 imapc: Keep the last fetched message body cached until mailbox is closed. This primarily helps partial IMAP fetches so each partial fetch doesn't redownload the message body. diff -r 690f60827f59 -r 5726f89486a0 src/lib-storage/index/imapc/imapc-mail-fetch.c --- a/src/lib-storage/index/imapc/imapc-mail-fetch.c Fri Sep 30 18:19:17 2011 +0300 +++ b/src/lib-storage/index/imapc/imapc-mail-fetch.c Fri Sep 30 18:53:09 2011 +0300 @@ -109,12 +109,40 @@ return 0; } +static void imapc_mail_cache_get(struct imapc_mail *mail, + struct imapc_mail_cache *cache) +{ + if (mail->body_fetched) + return; + + if (cache->fd != -1) { + mail->fd = cache->fd; + mail->imail.data.stream = + i_stream_create_fd(mail->fd, 0, FALSE); + cache->fd = -1; + } else if (cache->buf != NULL) { + mail->body = cache->buf; + mail->imail.data.stream = + i_stream_create_from_data(mail->body->data, + mail->body->used); + cache->buf = NULL; + } else { + return; + } + mail->body_fetched = TRUE; + imapc_mail_init_stream(mail, TRUE); +} + bool imapc_mail_prefetch(struct mail *_mail) { struct imapc_mail *mail = (struct imapc_mail *)_mail; + struct imapc_mailbox *mbox = (struct imapc_mailbox *)_mail->box; struct index_mail_data *data = &mail->imail.data; enum mail_fetch_field fields = 0; + if (mbox->prev_mail_cache.uid == _mail->uid) + imapc_mail_cache_get(mail, &mbox->prev_mail_cache); + if ((mail->imail.wanted_fields & MAIL_FETCH_RECEIVED_DATE) != 0 && data->received_date == (time_t)-1) fields |= MAIL_FETCH_RECEIVED_DATE; @@ -256,6 +284,11 @@ return; /* maybe the existing stream has no body. replace it. */ i_stream_unref(&imail->data.stream); + if (mail->fd != -1) { + if (close(mail->fd) < 0) + i_error("close(imapc mail) failed: %m"); + mail->fd = -1; + } } if (arg->type == IMAP_ARG_LITERAL_SIZE) { @@ -265,7 +298,8 @@ i_error("dup() failed: %m"); return; } - imail->data.stream = i_stream_create_fd(fd, 0, TRUE); + mail->fd = fd; + imail->data.stream = i_stream_create_fd(fd, 0, FALSE); } else { if (!imap_arg_get_nstring(arg, &value)) return; @@ -282,6 +316,7 @@ imail->data.stream = i_stream_create_from_data(mail->body->data, mail->body->used); } + mail->body_fetched = body; imapc_mail_init_stream(mail, body); } diff -r 690f60827f59 -r 5726f89486a0 src/lib-storage/index/imapc/imapc-mail.c --- a/src/lib-storage/index/imapc/imapc-mail.c Fri Sep 30 18:19:17 2011 +0300 +++ b/src/lib-storage/index/imapc/imapc-mail.c Fri Sep 30 18:53:09 2011 +0300 @@ -20,6 +20,7 @@ pool = pool_alloconly_create("mail", 2048); mail = p_new(pool, struct imapc_mail, 1); mail->imail.mail.pool = pool; + mail->fd = -1; index_mail_init(&mail->imail, t, wanted_fields, wanted_headers); return &mail->imail.mail.mail; @@ -28,9 +29,27 @@ static void imapc_mail_free(struct mail *_mail) { struct imapc_mail *mail = (struct imapc_mail *)_mail; + struct imapc_mailbox *mbox = (struct imapc_mailbox *)_mail->box; + struct imapc_mail_cache *cache = &mbox->prev_mail_cache; + if (mail->body_fetched) { + imapc_mail_cache_free(cache); + cache->uid = _mail->uid; + if (cache->fd != -1) { + cache->fd = mail->fd; + mail->fd = -1; + } else { + cache->buf = mail->body; + mail->body = NULL; + } + } + if (mail->fd != -1) { + if (close(mail->fd) < 0) + i_error("close(imapc mail) failed: %m"); + } if (mail->body != NULL) buffer_free(&mail->body); + index_mail_free(_mail); } diff -r 690f60827f59 -r 5726f89486a0 src/lib-storage/index/imapc/imapc-mail.h --- a/src/lib-storage/index/imapc/imapc-mail.h Fri Sep 30 18:19:17 2011 +0300 +++ b/src/lib-storage/index/imapc/imapc-mail.h Fri Sep 30 18:53:09 2011 +0300 @@ -12,7 +12,9 @@ enum mail_fetch_field fetching_fields; unsigned int fetch_count; + int fd; buffer_t *body; + bool body_fetched; }; extern struct mail_vfuncs imapc_mail_vfuncs; diff -r 690f60827f59 -r 5726f89486a0 src/lib-storage/index/imapc/imapc-mailbox.c --- a/src/lib-storage/index/imapc/imapc-mailbox.c Fri Sep 30 18:19:17 2011 +0300 +++ b/src/lib-storage/index/imapc/imapc-mailbox.c Fri Sep 30 18:53:09 2011 +0300 @@ -403,7 +403,10 @@ str_to_uint32(reply->resp_text_value, &uid_validity) < 0) return; - mbox->sync_uid_validity = uid_validity; + if (mbox->sync_uid_validity != uid_validity) { + mbox->sync_uid_validity = uid_validity; + imapc_mail_cache_free(&mbox->prev_mail_cache); + } } static void diff -r 690f60827f59 -r 5726f89486a0 src/lib-storage/index/imapc/imapc-storage.c --- a/src/lib-storage/index/imapc/imapc-storage.c Fri Sep 30 18:19:17 2011 +0300 +++ b/src/lib-storage/index/imapc/imapc-storage.c Fri Sep 30 18:53:09 2011 +0300 @@ -340,6 +340,7 @@ p_array_init(&mbox->fetch_mails, pool, 16); p_array_init(&mbox->permanent_keywords, pool, 32); p_array_init(&mbox->delayed_expunged_uids, pool, 16); + mbox->prev_mail_cache.fd = -1; imapc_mailbox_register_callbacks(mbox); return &mbox->box; } @@ -432,6 +433,18 @@ return 0; } +void imapc_mail_cache_free(struct imapc_mail_cache *cache) +{ + if (cache->fd != -1) { + if (close(cache->fd) < 0) + i_error("close(imapc cached mail) failed: %m"); + cache->fd = -1; + } + if (cache->buf != NULL) + buffer_free(&cache->buf); + cache->uid = 0; +} + static void imapc_mailbox_close(struct mailbox *box) { struct imapc_mailbox *mbox = (struct imapc_mailbox *)box; diff -r 690f60827f59 -r 5726f89486a0 src/lib-storage/index/imapc/imapc-storage.h --- a/src/lib-storage/index/imapc/imapc-storage.h Fri Sep 30 18:19:17 2011 +0300 +++ b/src/lib-storage/index/imapc/imapc-storage.h Fri Sep 30 18:53:09 2011 +0300 @@ -40,6 +40,14 @@ ARRAY_DEFINE(untagged_callbacks, struct imapc_storage_event_callback); }; +struct imapc_mail_cache { + uint32_t uid; + + /* either fd != -1 or buf != NULL */ + int fd; + buffer_t *buf; +}; + struct imapc_mailbox { struct mailbox box; struct imapc_storage *storage; @@ -66,6 +74,10 @@ uint32_t exists_count; uint32_t min_append_uid; + /* keep the previous fetched message body cached, + mainly for partial IMAP fetches */ + struct imapc_mail_cache prev_mail_cache; + uint32_t prev_skipped_rseq, prev_skipped_uid; unsigned int selecting:1; @@ -92,6 +104,7 @@ void imapc_transaction_save_rollback(struct mail_save_context *ctx); void imapc_storage_run(struct imapc_storage *storage); +void imapc_mail_cache_free(struct imapc_mail_cache *cache); void imapc_copy_error_from_reply(struct imapc_storage *storage, enum mail_error default_error,