changeset 5368:7d45edb81fe4 HEAD

When copying/syncing a lot of mails, send "* OK Hang in there" replies to client every 15 seconds so it doesn't just timeout the connection.
author Timo Sirainen <tss@iki.fi>
date Wed, 21 Mar 2007 21:19:52 +0200
parents fab770c51321
children e897aaa24cdd
files src/imap/cmd-copy.c src/lib-storage/index/maildir/maildir-sync.c src/lib-storage/mail-storage.h
diffstat 3 files changed, 82 insertions(+), 24 deletions(-) [+]
line wrap: on
line diff
--- a/src/imap/cmd-copy.c	Wed Mar 21 21:16:44 2007 +0200
+++ b/src/imap/cmd-copy.c	Wed Mar 21 21:19:52 2007 +0200
@@ -1,12 +1,32 @@
-/* Copyright (C) 2002 Timo Sirainen */
+/* Copyright (C) 2002-2007 Timo Sirainen */
 
 #include "common.h"
 #include "str.h"
+#include "ostream.h"
 #include "commands.h"
 #include "imap-search.h"
 
-static int fetch_and_copy(struct mailbox_transaction_context *t,
-			  struct mailbox *srcbox,
+#include <time.h>
+
+#define COPY_CHECK_INTERVAL 100
+
+static void client_send_sendalive_if_needed(struct client *client)
+{
+	time_t now;
+
+	if (o_stream_get_buffer_used_size(client->output) != 0)
+		return;
+
+	now = time(NULL);
+	if (now - client->last_output > MAIL_STORAGE_STAYALIVE_SECS) {
+		o_stream_send_str(client->output, "* OK Hang in there..\r\n");
+		o_stream_flush(client->output);
+		client->last_output = now;
+	}
+}
+
+static int fetch_and_copy(struct client *client,
+			  struct mailbox_transaction_context *t,
 			  struct mail_search_arg *search_args)
 {
 	struct mail_search_context *search_ctx;
@@ -14,9 +34,10 @@
 	struct mail_keywords *keywords;
 	const char *const *keywords_list;
 	struct mail *mail;
+	unsigned int copy_count = 0;
 	int ret;
 
-	src_trans = mailbox_transaction_begin(srcbox, 0);
+	src_trans = mailbox_transaction_begin(client->mailbox, 0);
 	search_ctx = mailbox_search_init(src_trans, NULL, search_args, NULL);
 
 	mail = mail_alloc(src_trans, MAIL_FETCH_STREAM_HEADER |
@@ -28,6 +49,9 @@
 			break;
 		}
 
+		if ((++copy_count % COPY_CHECK_INTERVAL) != 0)
+			client_send_sendalive_if_needed(client);
+
 		keywords_list = mail_get_keywords(mail);
 		keywords = strarray_length(keywords_list) == 0 ? NULL :
 			mailbox_keywords_create(t, keywords_list);
@@ -92,7 +116,7 @@
 
 	t = mailbox_transaction_begin(destbox,
 				      MAILBOX_TRANSACTION_FLAG_EXTERNAL);
-	ret = fetch_and_copy(t, client->mailbox, search_arg);
+	ret = fetch_and_copy(client, t, search_arg);
 
 	if (ret <= 0)
 		mailbox_transaction_rollback(&t);
--- a/src/lib-storage/index/maildir/maildir-sync.c	Wed Mar 21 21:16:44 2007 +0200
+++ b/src/lib-storage/index/maildir/maildir-sync.c	Wed Mar 21 21:19:52 2007 +0200
@@ -209,12 +209,17 @@
 	const char *new_dir, *cur_dir;
 	bool partial;
 
+	unsigned int move_count, check_count;
+	time_t last_touch, last_notify;
+
 	struct maildir_uidlist_sync_ctx *uidlist_sync_ctx;
         struct maildir_index_sync_context *index_sync_ctx;
 };
 
 struct maildir_index_sync_context {
         struct maildir_mailbox *mbox;
+	struct maildir_sync_context *maildir_sync_ctx;
+
 	struct mail_index_view *view;
 	struct mail_index_sync_ctx *sync_ctx;
         struct maildir_keywords_sync_ctx *keywords_sync_ctx;
@@ -468,6 +473,38 @@
 	return -1;
 }
 
+static void
+maildir_sync_check_timeouts(struct maildir_sync_context *ctx, bool move)
+{
+	time_t now;
+
+	if (move) {
+		ctx->move_count++;
+		if ((ctx->move_count % MAILDIR_SLOW_MOVE_COUNT) != 0)
+			return;
+	} else {
+		ctx->check_count++;
+		if ((ctx->check_count % MAILDIR_SLOW_CHECK_COUNT) != 0)
+			return;
+	}
+
+	now = time(NULL);
+	if (now - ctx->last_touch > MAILDIR_LOCK_TOUCH_SECS) {
+		(void)maildir_uidlist_lock_touch(ctx->mbox->uidlist);
+		ctx->last_touch = now;
+	}
+	if (now - ctx->last_notify > MAIL_STORAGE_STAYALIVE_SECS) {
+		struct mailbox *box = &ctx->mbox->ibox.box;
+
+		if (box->storage->callbacks->notify_ok != NULL) {
+			box->storage->callbacks->
+				notify_ok(box, "Hang in there..",
+					  box->storage->callback_context);
+		}
+		ctx->last_notify = now;
+	}
+}
+
 static int
 maildir_sync_record_commit_until(struct maildir_index_sync_context *ctx,
 				 uint32_t last_seq)
@@ -508,10 +545,14 @@
 
 		ctx->seq = seq;
 		if (expunged) {
+			maildir_sync_check_timeouts(ctx->maildir_sync_ctx,
+						    TRUE);
 			if (maildir_file_do(ctx->mbox, uid,
 					    maildir_expunge, ctx) < 0)
 				return -1;
 		} else if (flag_changed) {
+			maildir_sync_check_timeouts(ctx->maildir_sync_ctx,
+						    TRUE);
 			if (maildir_file_do(ctx->mbox, uid,
 					    maildir_sync_flags, ctx) < 0)
 				return -1;
@@ -620,6 +661,8 @@
 	ctx->mbox = mbox;
 	ctx->new_dir = t_strconcat(mbox->path, "/new", NULL);
 	ctx->cur_dir = t_strconcat(mbox->path, "/cur", NULL);
+	ctx->last_touch = ioloop_time;
+	ctx->last_notify = ioloop_time;
 	return ctx;
 }
 
@@ -692,13 +735,9 @@
 	string_t *src, *dest;
 	struct dirent *dp;
 	enum maildir_uidlist_rec_flag flags;
-	time_t last_touch;
-	unsigned int moves = 0, count = 0;
 	int ret = 1;
 	bool move_new, check_touch;
 
-	last_touch = ioloop_time;
-
 	dir = new_dir ? ctx->new_dir : ctx->cur_dir;
 	dirp = opendir(dir);
 	if (dirp == NULL) {
@@ -711,6 +750,7 @@
 	src = t_str_new(1024);
 	dest = t_str_new(1024);
 
+	ctx->move_count = 0;
 	move_new = new_dir && !mailbox_is_readonly(&ctx->mbox->ibox.box) &&
 		!ctx->mbox->ibox.keep_recent;
 	while ((dp = readdir(dirp)) != NULL) {
@@ -743,13 +783,13 @@
 			}
 			if (rename(str_c(src), str_c(dest)) == 0) {
 				/* we moved it - it's \Recent for us */
-				moves++;
+				maildir_sync_check_timeouts(ctx, TRUE);
 				ctx->mbox->dirty_cur_time = ioloop_time;
 				flags |= MAILDIR_UIDLIST_REC_FLAG_MOVED |
 					MAILDIR_UIDLIST_REC_FLAG_RECENT;
 			} else if (ENOTFOUND(errno)) {
 				/* someone else moved it already */
-				moves++;
+				maildir_sync_check_timeouts(ctx, TRUE);
 				flags |= MAILDIR_UIDLIST_REC_FLAG_MOVED;
 			} else if (ENOSPACE(errno) || errno == EACCES) {
 				/* not enough disk space / read-only maildir,
@@ -764,23 +804,12 @@
 					"rename(%s, %s) failed: %m",
 					str_c(src), str_c(dest));
 			}
-			if ((moves % MAILDIR_SLOW_MOVE_COUNT) == 0)
-				check_touch = TRUE;
 		} else if (new_dir) {
 			flags |= MAILDIR_UIDLIST_REC_FLAG_NEW_DIR |
 				MAILDIR_UIDLIST_REC_FLAG_RECENT;
 		}
 
-		count++;
-		if (check_touch || (count % MAILDIR_SLOW_CHECK_COUNT) == 0) {
-			time_t now = time(NULL);
-
-			if (now - last_touch > MAILDIR_LOCK_TOUCH_SECS) {
-				(void)maildir_uidlist_lock_touch(
-							ctx->mbox->uidlist);
-				last_touch = now;
-			}
-		}
+		maildir_sync_check_timeouts(ctx, FALSE);
 
 		ret = maildir_uidlist_sync_next(ctx->uidlist_sync_ctx,
 						dp->d_name, flags);
@@ -802,7 +831,8 @@
 	}
 
 	t_pop();
-	return ret < 0 ? -1 : (moves <= MAILDIR_RENAME_RESCAN_COUNT ? 0 : 1);
+	return ret < 0 ? -1 :
+		(ctx->move_count <= MAILDIR_RENAME_RESCAN_COUNT ? 0 : 1);
 }
 
 static void
@@ -1358,6 +1388,7 @@
 		if (maildir_sync_index_begin(ctx->mbox,
 					     &ctx->index_sync_ctx) < 0)
 			return -1;
+		ctx->index_sync_ctx->maildir_sync_ctx = ctx;
 	}
 
 	if (new_changed || cur_changed) {
--- a/src/lib-storage/mail-storage.h	Wed Mar 21 21:16:44 2007 +0200
+++ b/src/lib-storage/mail-storage.h	Wed Mar 21 21:19:52 2007 +0200
@@ -6,6 +6,9 @@
 #include "mail-types.h"
 #include "mailbox-list.h"
 
+/* If some operation is taking long, call notify_ok every n seconds. */
+#define MAIL_STORAGE_STAYALIVE_SECS 15
+
 enum mail_storage_flags {
 	/* Print debugging information while initializing the storage */
 	MAIL_STORAGE_FLAG_DEBUG			= 0x01,