Mercurial > dovecot > core-2.2
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,