dovecot-2.2: imapc: Merge identical FETCH commands together (onl...

dovecot at dovecot.org dovecot at dovecot.org
Sun Nov 17 17:15:55 EET 2013


details:   http://hg.dovecot.org/dovecot-2.2/rev/10462996fa32
changeset: 16975:10462996fa32
user:      Timo Sirainen <tss at iki.fi>
date:      Sun Nov 17 16:59:33 2013 +0200
description:
imapc: Merge identical FETCH commands together (only updating UID range)

diffstat:

 src/lib-storage/index/imapc/imapc-mail-fetch.c |  137 +++++++++++++++++++-----
 src/lib-storage/index/imapc/imapc-mail.c       |    2 +-
 src/lib-storage/index/imapc/imapc-mail.h       |    3 +
 src/lib-storage/index/imapc/imapc-mailbox.c    |   11 +-
 src/lib-storage/index/imapc/imapc-save.c       |    6 +-
 src/lib-storage/index/imapc/imapc-storage.c    |   13 +-
 src/lib-storage/index/imapc/imapc-storage.h    |   14 ++-
 src/lib-storage/index/imapc/imapc-sync.c       |    2 +-
 8 files changed, 140 insertions(+), 48 deletions(-)

diffs (truncated from 399 to 300 lines):

diff -r aec5d4170e74 -r 10462996fa32 src/lib-storage/index/imapc/imapc-mail-fetch.c
--- a/src/lib-storage/index/imapc/imapc-mail-fetch.c	Sun Nov 17 16:58:42 2013 +0200
+++ b/src/lib-storage/index/imapc/imapc-mail-fetch.c	Sun Nov 17 16:59:33 2013 +0200
@@ -2,6 +2,7 @@
 
 #include "lib.h"
 #include "str.h"
+#include "ioloop.h"
 #include "istream.h"
 #include "istream-header-filter.h"
 #include "message-header-parser.h"
@@ -13,29 +14,37 @@
 #include "imapc-storage.h"
 
 static void
-imapc_mail_prefetch_callback(const struct imapc_command_reply *reply,
-			     void *context)
+imapc_mail_fetch_callback(const struct imapc_command_reply *reply,
+			  void *context)
 {
-	struct imapc_mail *mail = context;
-	struct imapc_mailbox *mbox =
-		(struct imapc_mailbox *)mail->imail.mail.mail.box;
+	struct imapc_fetch_request *request = context;
+	struct imapc_fetch_request *const *requests;
+	struct imapc_mail *const *mailp;
+	struct imapc_mailbox *mbox = NULL;
+	unsigned int i, count;
 
-	i_assert(mail->fetch_count > 0);
+	array_foreach(&request->mails, mailp) {
+		struct imapc_mail *mail = *mailp;
 
-	if (--mail->fetch_count == 0) {
-		struct imapc_mail *const *fetch_mails;
-		unsigned int i, count;
+		i_assert(mail->fetch_count > 0);
+		if (--mail->fetch_count == 0)
+			mail->fetching_fields = 0;
+		pool_unref(&mail->imail.mail.pool);
+		mbox = (struct imapc_mailbox *)mail->imail.mail.mail.box;
+	}
+	i_assert(mbox != NULL);
 
-		fetch_mails = array_get(&mbox->fetch_mails, &count);
-		for (i = 0; i < count; i++) {
-			if (fetch_mails[i] == mail) {
-				array_delete(&mbox->fetch_mails, i, 1);
-				break;
-			}
+	requests = array_get(&mbox->fetch_requests, &count);
+	for (i = 0; i < count; i++) {
+		if (requests[i] == request) {
+			array_delete(&mbox->fetch_requests, i, 1);
+			break;
 		}
-		i_assert(i != count);
-		mail->fetching_fields = 0;
 	}
+	i_assert(i < count);
+
+	array_free(&request->mails);
+	i_free(request);
 
 	if (reply->state == IMAPC_COMMAND_STATE_OK)
 		;
@@ -47,9 +56,8 @@
 		mail_storage_set_internal_error(&mbox->storage->storage);
 	} else {
 		mail_storage_set_critical(&mbox->storage->storage,
-			"imapc: Mail prefetch failed: %s", reply->text_full);
+			"imapc: Mail FETCH failed: %s", reply->text_full);
 	}
-	pool_unref(&mail->imail.mail.pool);
 	imapc_client_stop(mbox->storage->client->client);
 }
 
@@ -95,13 +103,61 @@
 	return array_idx(&headers, 0);
 }
 
+static bool
+imapc_mail_try_merge_fetch(struct imapc_mailbox *mbox, string_t *str)
+{
+	const char *s1 = str_c(str);
+	const char *s2 = str_c(mbox->pending_fetch_cmd);
+	const char *p1, *p2;
+
+	i_assert(strncmp(s1, "UID FETCH ", 10) == 0);
+	i_assert(strncmp(s2, "UID FETCH ", 10) == 0);
+
+	/* skip over UID range */
+	p1 = strchr(s1+10, ' ');
+	p2 = strchr(s2+10, ' ');
+
+	if (null_strcmp(p1, p2) != 0)
+		return FALSE;
+	/* append the new UID to the pending FETCH UID range */
+	str_truncate(str, p1-s1);
+	str_insert(mbox->pending_fetch_cmd, p2-s2, ",");
+	str_insert(mbox->pending_fetch_cmd, p2-s2+1, str_c(str) + 10);
+	return TRUE;
+}
+
+static void
+imapc_mail_delayed_send_or_merge(struct imapc_mail *mail, string_t *str)
+{
+	struct imapc_mailbox *mbox =
+		(struct imapc_mailbox *)mail->imail.mail.mail.box;
+
+	if (mbox->pending_fetch_request != NULL &&
+	    !imapc_mail_try_merge_fetch(mbox, str)) {
+		/* send the previous FETCH and create a new one */
+		imapc_mail_fetch_flush(mbox);
+	}
+	if (mbox->pending_fetch_request == NULL) {
+		mbox->pending_fetch_request =
+			i_new(struct imapc_fetch_request, 1);
+		i_array_init(&mbox->pending_fetch_request->mails, 4);
+		i_assert(mbox->pending_fetch_cmd->used == 0);
+		str_append_str(mbox->pending_fetch_cmd, str);
+	}
+	array_append(&mbox->pending_fetch_request->mails, &mail, 1);
+
+	if (mbox->to_pending_fetch_send == NULL) {
+		mbox->to_pending_fetch_send =
+			timeout_add_short(0, imapc_mail_fetch_flush, mbox);
+	}
+}
+
 static int
 imapc_mail_send_fetch(struct mail *_mail, enum mail_fetch_field fields,
 		      const char *const *headers)
 {
 	struct imapc_mail *mail = (struct imapc_mail *)_mail;
 	struct imapc_mailbox *mbox = (struct imapc_mailbox *)_mail->box;
-	struct imapc_command *cmd;
 	struct mail_index_view *view;
 	string_t *str;
 	uint32_t seq;
@@ -172,15 +228,10 @@
 
 	pool_ref(mail->imail.mail.pool);
 	mail->fetching_fields |= fields;
-	if (mail->fetch_count++ == 0)
-		array_append(&mbox->fetch_mails, &mail, 1);
+	mail->fetch_count++;
 
-	cmd = imapc_client_mailbox_cmd(mbox->client_box,
-				       imapc_mail_prefetch_callback, mail);
-	imapc_command_set_flags(cmd, IMAPC_COMMAND_FLAG_RETRIABLE);
-	imapc_command_send(cmd, str_c(str));
-	mail->imail.data.prefetch_sent = TRUE;
-	return 0;
+	imapc_mail_delayed_send_or_merge(mail, str);
+	return 1;
 }
 
 static void imapc_mail_cache_get(struct imapc_mail *mail,
@@ -252,9 +303,10 @@
 
 	fields = imapc_mail_get_wanted_fetch_fields(mail);
 	if (fields != 0) T_BEGIN {
-		(void)imapc_mail_send_fetch(_mail, fields,
-					    data->wanted_headers == NULL ? NULL :
-					    data->wanted_headers->name);
+		if (imapc_mail_send_fetch(_mail, fields,
+					  data->wanted_headers == NULL ? NULL :
+					  data->wanted_headers->name) > 0)
+			mail->imail.data.prefetch_sent = TRUE;
 	} T_END;
 	return !mail->imail.data.prefetch_sent;
 }
@@ -316,10 +368,31 @@
 	while (imail->fetch_count > 0 &&
 	       (!imapc_mail_have_fields(imail, fields) ||
 		!imail->header_list_fetched))
-		imapc_storage_run(mbox->storage);
+		imapc_mailbox_run(mbox);
 	return 0;
 }
 
+void imapc_mail_fetch_flush(struct imapc_mailbox *mbox)
+{
+	struct imapc_command *cmd;
+
+	if (mbox->pending_fetch_request == NULL) {
+		i_assert(mbox->to_pending_fetch_send == NULL);
+		return;
+	}
+
+	cmd = imapc_client_mailbox_cmd(mbox->client_box,
+				       imapc_mail_fetch_callback,
+				       mbox->pending_fetch_request);
+	imapc_command_set_flags(cmd, IMAPC_COMMAND_FLAG_RETRIABLE);
+	imapc_command_send(cmd, str_c(mbox->pending_fetch_cmd));
+
+	array_append(&mbox->fetch_requests, &mbox->pending_fetch_request, 1);
+	mbox->pending_fetch_request = NULL;
+	timeout_remove(&mbox->to_pending_fetch_send);
+	str_truncate(mbox->pending_fetch_cmd, 0);
+}
+
 static bool imapc_find_lfile_arg(const struct imapc_untagged_reply *reply,
 				 const struct imap_arg *arg, int *fd_r)
 {
diff -r aec5d4170e74 -r 10462996fa32 src/lib-storage/index/imapc/imapc-mail.c
--- a/src/lib-storage/index/imapc/imapc-mail.c	Sun Nov 17 16:58:42 2013 +0200
+++ b/src/lib-storage/index/imapc/imapc-mail.c	Sun Nov 17 16:59:33 2013 +0200
@@ -358,7 +358,7 @@
 	struct imapc_mail_cache *cache = &mbox->prev_mail_cache;
 
 	while (mail->fetch_count > 0)
-		imapc_storage_run(mbox->storage);
+		imapc_mailbox_run(mbox);
 
 	index_mail_close(_mail);
 
diff -r aec5d4170e74 -r 10462996fa32 src/lib-storage/index/imapc/imapc-mail.h
--- a/src/lib-storage/index/imapc/imapc-mail.h	Sun Nov 17 16:58:42 2013 +0200
+++ b/src/lib-storage/index/imapc/imapc-mail.h	Sun Nov 17 16:59:33 2013 +0200
@@ -5,6 +5,7 @@
 
 struct imap_arg;
 struct imapc_untagged_reply;
+struct imapc_mailbox;
 
 struct imapc_mail {
 	struct index_mail imail;
@@ -28,11 +29,13 @@
 int imapc_mail_fetch(struct mail *mail, enum mail_fetch_field fields,
 		     const char *const *headers);
 bool imapc_mail_prefetch(struct mail *mail);
+void imapc_mail_fetch_flush(struct imapc_mailbox *mbox);
 void imapc_mail_init_stream(struct imapc_mail *mail, bool have_body);
 
 void imapc_mail_fetch_update(struct imapc_mail *mail,
 			     const struct imapc_untagged_reply *reply,
 			     const struct imap_arg *args);
 void imapc_mail_update_access_parts(struct index_mail *mail);
+void imapc_mail_command_flush(struct imapc_mailbox *mbox);
 
 #endif
diff -r aec5d4170e74 -r 10462996fa32 src/lib-storage/index/imapc/imapc-mailbox.c
--- a/src/lib-storage/index/imapc/imapc-mailbox.c	Sun Nov 17 16:58:42 2013 +0200
+++ b/src/lib-storage/index/imapc/imapc-mailbox.c	Sun Nov 17 16:59:33 2013 +0200
@@ -254,6 +254,7 @@
 				 struct imapc_mailbox *mbox)
 {
 	uint32_t lseq, rseq = reply->num;
+	struct imapc_fetch_request *const *fetch_requestp;
 	struct imapc_mail *const *mailp;
 	const struct imap_arg *list, *flags_list;
 	const char *atom;
@@ -303,11 +304,13 @@
 		return;
 
 	/* if this is a reply to some FETCH request, update the mail's fields */
-	array_foreach(&mbox->fetch_mails, mailp) {
-		struct imapc_mail *mail = *mailp;
+	array_foreach(&mbox->fetch_requests, fetch_requestp) {
+		array_foreach(&(*fetch_requestp)->mails, mailp) {
+			struct imapc_mail *mail = *mailp;
 
-		if (mail->imail.mail.mail.uid == uid)
-			imapc_mail_fetch_update(mail, reply, list);
+			if (mail->imail.mail.mail.uid == uid)
+				imapc_mail_fetch_update(mail, reply, list);
+		}
 	}
 
 	if (lseq == 0) {
diff -r aec5d4170e74 -r 10462996fa32 src/lib-storage/index/imapc/imapc-save.c
--- a/src/lib-storage/index/imapc/imapc-save.c	Sun Nov 17 16:58:42 2013 +0200
+++ b/src/lib-storage/index/imapc/imapc-save.c	Sun Nov 17 16:59:33 2013 +0200
@@ -246,7 +246,7 @@
 			    ctx->mbox->box.name, flags, internaldate, input);
 	i_stream_unref(&input);
 	while (sctx.ret == -2)
-		imapc_storage_run(ctx->mbox->storage);
+		imapc_mailbox_run(ctx->mbox);
 
 	if (sctx.ret == 0 && ctx->mbox->selected &&
 	    !ctx->mbox->exists_received) {
@@ -259,7 +259,7 @@
 				       imapc_save_noop_callback, &sctx);
 		imapc_command_send(cmd, "NOOP");
 		while (sctx.ret == -2)
-			imapc_storage_run(ctx->mbox->storage);
+			imapc_mailbox_run(ctx->mbox);
 	}
 	return sctx.ret;
 }
@@ -421,7 +421,7 @@
 		imapc_command_sendf(cmd, "UID COPY %u %s",
 				    mail->uid, _t->box->name);
 		while (sctx.ret == -2)
-			imapc_storage_run(src_mbox->storage);
+			imapc_mailbox_run(src_mbox);
 		ctx->finished = TRUE;


More information about the dovecot-cvs mailing list