From: Timo Sirainen Date: Wed, 11 Jun 2008 11:39:52 +0000 (+0300) Subject: QRESYNC: If MODSEQs were returned in FETCH replies but there are pending X-Git-Tag: 1.2.alpha1~346 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=17da42c31202b1b3e7e308121ea17d922c24da1b;p=thirdparty%2Fdovecot%2Fcore.git QRESYNC: If MODSEQs were returned in FETCH replies but there are pending expunges, send a low enough HIGHESTMODSEQ reply to make sure the client will later see the expunges. --HG-- branch : HEAD --- diff --git a/src/imap/client.h b/src/imap/client.h index 7270ef9941..8dcb4b026c 100644 --- a/src/imap/client.h +++ b/src/imap/client.h @@ -93,6 +93,8 @@ struct client { struct client_command_context *command_queue; unsigned int command_queue_size; + uint64_t sync_last_full_modseq; + /* SEARCHRES extension: Last saved SEARCH result */ ARRAY_TYPE(seq_range) search_saved_uidset; /* SEARCH=CONTEXT extension: Searches that get updated */ @@ -113,6 +115,7 @@ struct client { unsigned int changing_mailbox:1; unsigned int input_skip_line:1; /* skip all the data until we've found a new line */ + unsigned int modseqs_sent_since_sync:1; }; /* Create new client with specified input/output handles. socket specifies diff --git a/src/imap/cmd-select.c b/src/imap/cmd-select.c index 11156bf653..67ff06c18e 100644 --- a/src/imap/cmd-select.c +++ b/src/imap/cmd-select.c @@ -313,6 +313,7 @@ select_open(struct imap_select_context *ctx, const char *mailbox, bool readonly) client_send_line(client, t_strdup_printf("* OK [HIGHESTMODSEQ %llu]", (unsigned long long)status.highest_modseq)); + client->sync_last_full_modseq = status.highest_modseq; } if (ctx->qresync_uid_validity == status.uidvalidity) { diff --git a/src/imap/imap-fetch.c b/src/imap/imap-fetch.c index e322cd48ac..7088169983 100644 --- a/src/imap/imap-fetch.c +++ b/src/imap/imap-fetch.c @@ -752,6 +752,7 @@ fetch_modseq_init(struct imap_fetch_context *ctx, const char *name, client_enable(ctx->client, MAILBOX_FEATURE_CONDSTORE); imap_fetch_add_handler(ctx, TRUE, FALSE, name, NULL, fetch_modseq, NULL); + ctx->client->modseqs_sent_since_sync = TRUE; return TRUE; } diff --git a/src/imap/imap-sync.c b/src/imap/imap-sync.c index 2b07b858b8..d05644b8ab 100644 --- a/src/imap/imap-sync.c +++ b/src/imap/imap-sync.c @@ -160,6 +160,7 @@ imap_sync_init(struct client *client, struct mailbox *box, int imap_sync_deinit(struct imap_sync_context *ctx) { + struct client *client = ctx->client; struct mailbox_status status; int ret; @@ -168,7 +169,8 @@ int imap_sync_deinit(struct imap_sync_context *ctx) array_free(&ctx->expunges); if (mailbox_sync_deinit(&ctx->sync_ctx, STATUS_UIDVALIDITY | - STATUS_MESSAGES | STATUS_RECENT, &status) < 0 || + STATUS_MESSAGES | STATUS_RECENT | + STATUS_HIGHESTMODSEQ, &status) < 0 || ctx->failed) { mailbox_transaction_rollback(&ctx->t); array_free(&ctx->tmp_keywords); @@ -176,25 +178,38 @@ int imap_sync_deinit(struct imap_sync_context *ctx) return -1; } + if (!status.sync_delayed_expunges || status.highest_modseq == 0) + client->sync_last_full_modseq = status.highest_modseq; + else if (client->modseqs_sent_since_sync && + (client->enabled_features & MAILBOX_FEATURE_QRESYNC) != 0) { + /* if client updates highest-modseq using returned MODSEQs + it loses expunges. try to avoid this by sending it a lower + pre-expunge HIGHESTMODSEQ reply. */ + client_send_line(client, t_strdup_printf( + "* OK [HIGHESTMODSEQ %llu]", + (unsigned long long)client->sync_last_full_modseq)); + } + client->modseqs_sent_since_sync = FALSE; + ret = mailbox_transaction_commit(&ctx->t); - if (status.uidvalidity != ctx->client->uidvalidity) { + if (status.uidvalidity != client->uidvalidity) { /* most clients would get confused by this. disconnect them. */ - client_disconnect_with_error(ctx->client, + client_disconnect_with_error(client, "Mailbox UIDVALIDITY changed"); } if (!ctx->no_newmail) { if (status.messages < ctx->messages_count) i_panic("Message count decreased"); - ctx->client->messages_count = status.messages; + client->messages_count = status.messages; if (status.messages != ctx->messages_count) { - client_send_line(ctx->client, + client_send_line(client, t_strdup_printf("* %u EXISTS", status.messages)); } - if (status.recent != ctx->client->recent_count && + if (status.recent != client->recent_count && !ctx->no_newmail) { - ctx->client->recent_count = status.recent; - client_send_line(ctx->client, + client->recent_count = status.recent; + client_send_line(client, t_strdup_printf("* %u RECENT", status.recent)); } } @@ -231,6 +246,7 @@ static int imap_sync_send_flags(struct imap_sync_context *ctx, string_t *str) str_printfa(str, "UID %u ", ctx->mail->uid); if ((mailbox_get_enabled_features(ctx->box) & MAILBOX_FEATURE_CONDSTORE) != 0) { + ctx->client->modseqs_sent_since_sync = TRUE; str_printfa(str, "MODSEQ %llu ", (unsigned long long)mail_get_modseq(ctx->mail)); } @@ -250,6 +266,7 @@ static int imap_sync_send_modseq(struct imap_sync_context *ctx, string_t *str) str_printfa(str, "UID %u ", ctx->mail->uid); str_printfa(str, "MODSEQ %llu)", (unsigned long long)mail_get_modseq(ctx->mail)); + ctx->client->modseqs_sent_since_sync = TRUE; return client_send_line(ctx->client, str_c(str)); } diff --git a/src/lib-index/mail-index-view-sync.c b/src/lib-index/mail-index-view-sync.c index 71225522d9..6166dfc0c8 100644 --- a/src/lib-index/mail-index-view-sync.c +++ b/src/lib-index/mail-index-view-sync.c @@ -633,7 +633,8 @@ mail_index_view_sync_clean_log_syncs(struct mail_index_view *view) array_delete(&view->syncs_hidden, 0, i); } -int mail_index_view_sync_commit(struct mail_index_view_sync_ctx **_ctx) +int mail_index_view_sync_commit(struct mail_index_view_sync_ctx **_ctx, + bool *delayed_expunges_r) { struct mail_index_view_sync_ctx *ctx = *_ctx; struct mail_index_view *view = ctx->view; @@ -642,6 +643,7 @@ int mail_index_view_sync_commit(struct mail_index_view_sync_ctx **_ctx) i_assert(view->syncing); *_ctx = NULL; + *delayed_expunges_r = ctx->skipped_expunges; if ((!ctx->last_read || view->inconsistent) && (ctx->flags & MAIL_INDEX_VIEW_SYNC_FLAG_FIX_INCONSISTENT) == 0) { diff --git a/src/lib-index/mail-index.h b/src/lib-index/mail-index.h index 8fd9405f3a..a273ee092a 100644 --- a/src/lib-index/mail-index.h +++ b/src/lib-index/mail-index.h @@ -314,7 +314,8 @@ bool mail_index_view_sync_next(struct mail_index_view_sync_ctx *ctx, void mail_index_view_sync_get_expunges(struct mail_index_view_sync_ctx *ctx, const ARRAY_TYPE(seq_range) **expunges_r); -int mail_index_view_sync_commit(struct mail_index_view_sync_ctx **ctx); +int mail_index_view_sync_commit(struct mail_index_view_sync_ctx **ctx, + bool *delayed_expunges_r); /* Returns the index header. */ const struct mail_index_header * diff --git a/src/lib-storage/index/index-sync.c b/src/lib-storage/index/index-sync.c index 2a722c8962..71f08ad9bf 100644 --- a/src/lib-storage/index/index-sync.c +++ b/src/lib-storage/index/index-sync.c @@ -325,6 +325,7 @@ int index_mailbox_sync_deinit(struct mailbox_sync_context *_ctx, struct mailbox_sync_rec sync_rec; const struct mail_index_header *hdr; uint32_t seq1, seq2; + bool delayed_expunges = FALSE; int ret = ctx->failed ? -1 : 0; /* finish handling expunges, so we don't break when updating @@ -332,7 +333,8 @@ int index_mailbox_sync_deinit(struct mailbox_sync_context *_ctx, while (index_mailbox_sync_next_expunge(ctx, &sync_rec) > 0) ; if (ctx->sync_ctx != NULL) { - if (mail_index_view_sync_commit(&ctx->sync_ctx) < 0) { + if (mail_index_view_sync_commit(&ctx->sync_ctx, + &delayed_expunges) < 0) { mail_storage_set_index_error(ibox); ret = -1; } @@ -354,8 +356,10 @@ int index_mailbox_sync_deinit(struct mailbox_sync_context *_ctx, } } - if (ret == 0 && status_items != 0) + if (ret == 0 && status_items != 0) { mailbox_get_status(_ctx->box, status_items, status_r); + status_r->sync_delayed_expunges = delayed_expunges; + } index_sync_search_results_update(ctx); diff --git a/src/lib-storage/mail-storage.h b/src/lib-storage/mail-storage.h index 718f82f12a..2745b36bea 100644 --- a/src/lib-storage/mail-storage.h +++ b/src/lib-storage/mail-storage.h @@ -189,6 +189,9 @@ struct mailbox_status { uint64_t highest_modseq; const ARRAY_TYPE(keywords) *keywords; + + /* There are expunges that haven't been synced yet */ + unsigned int sync_delayed_expunges:1; }; struct mailbox_sync_rec {