]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
imapc: Keep the last fetched message body cached until mailbox is closed.
authorTimo Sirainen <tss@iki.fi>
Fri, 30 Sep 2011 15:53:09 +0000 (18:53 +0300)
committerTimo Sirainen <tss@iki.fi>
Fri, 30 Sep 2011 15:53:09 +0000 (18:53 +0300)
This primarily helps partial IMAP fetches so each partial fetch doesn't
redownload the message body.

src/lib-storage/index/imapc/imapc-mail-fetch.c
src/lib-storage/index/imapc/imapc-mail.c
src/lib-storage/index/imapc/imapc-mail.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

index 100ea836b598bae2345b229c994e0ea5c1a2cf2a..42a77e2105ce7b415bd43d020284cbbb4de075f2 100644 (file)
@@ -109,12 +109,40 @@ imapc_mail_send_fetch(struct mail *_mail, enum mail_fetch_field fields)
        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 @@ imapc_fetch_stream(struct imapc_mail *mail,
                        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 @@ imapc_fetch_stream(struct imapc_mail *mail,
                        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 @@ imapc_fetch_stream(struct imapc_mail *mail,
                imail->data.stream = i_stream_create_from_data(mail->body->data,
                                                               mail->body->used);
        }
+       mail->body_fetched = body;
 
        imapc_mail_init_stream(mail, body);
 }
index 119534da0483c0705abdd20041fb9916ecdf6ca0..f46811a136d2c7d3103398bb9c0500ab4f7c0df3 100644 (file)
@@ -20,6 +20,7 @@ imapc_mail_alloc(struct mailbox_transaction_context *t,
        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 @@ imapc_mail_alloc(struct mailbox_transaction_context *t,
 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);
 }
 
index 6fae5fb7766539b7dd350dad5df8a99c7489b96a..7493c027b08b859992dcf00e3af00df91b8e6a40 100644 (file)
@@ -12,7 +12,9 @@ struct imapc_mail {
        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;
index 0668ae091175e67ccb20ef46c8e8820b86ca97d7..28d85c27628cee0741d50cb7e811686c6b9e9f16 100644 (file)
@@ -403,7 +403,10 @@ imapc_resp_text_uidvalidity(const struct imapc_untagged_reply *reply,
            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
index 1229df32aec4378f1dfedc4f5f9c31186f029379..66b4dec322f5a77bc441d6f2269585b19af12a00 100644 (file)
@@ -340,6 +340,7 @@ imapc_mailbox_alloc(struct mail_storage *storage, struct mailbox_list *list,
        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 @@ static int imapc_mailbox_open(struct mailbox *box)
        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;
index 3fed89191b038afbf0fe813c31e3e0d70ee2e8f1..d5563eb3e9080299e988602feea8281ba50e560a 100644 (file)
@@ -40,6 +40,14 @@ struct imapc_storage {
        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 @@ struct imapc_mailbox {
        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_commit_post(struct mail_save_context *ctx,
 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,