dovecot-2.1: imapc: Keep the last fetched message body cached un...

dovecot at dovecot.org dovecot at dovecot.org
Fri Sep 30 18:44:50 EEST 2011


details:   http://hg.dovecot.org/dovecot-2.1/rev/5726f89486a0
changeset: 13564:5726f89486a0
user:      Timo Sirainen <tss at iki.fi>
date:      Fri Sep 30 18:53:09 2011 +0300
description:
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.

diffstat:

 src/lib-storage/index/imapc/imapc-mail-fetch.c |  37 +++++++++++++++++++++++++-
 src/lib-storage/index/imapc/imapc-mail.c       |  19 +++++++++++++
 src/lib-storage/index/imapc/imapc-mail.h       |   2 +
 src/lib-storage/index/imapc/imapc-mailbox.c    |   5 ++-
 src/lib-storage/index/imapc/imapc-storage.c    |  13 +++++++++
 src/lib-storage/index/imapc/imapc-storage.h    |  13 +++++++++
 6 files changed, 87 insertions(+), 2 deletions(-)

diffs (208 lines):

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,


More information about the dovecot-cvs mailing list