]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
QRESYNC: If MODSEQs were returned in FETCH replies but there are pending
authorTimo Sirainen <tss@iki.fi>
Wed, 11 Jun 2008 11:39:52 +0000 (14:39 +0300)
committerTimo Sirainen <tss@iki.fi>
Wed, 11 Jun 2008 11:39:52 +0000 (14:39 +0300)
expunges, send a low enough HIGHESTMODSEQ reply to make sure the client will
later see the expunges.

--HG--
branch : HEAD

src/imap/client.h
src/imap/cmd-select.c
src/imap/imap-fetch.c
src/imap/imap-sync.c
src/lib-index/mail-index-view-sync.c
src/lib-index/mail-index.h
src/lib-storage/index/index-sync.c
src/lib-storage/mail-storage.h

index 7270ef9941a83068ea44b1744fe173397c01615d..8dcb4b026c2c37994d623797df4711ca6d35adb0 100644 (file)
@@ -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
index 11156bf65361bb3dc9d6ba33b92bab12f90b7100..67ff06c18e35f7bbc9b57549d3e8f6799c93b028 100644 (file)
@@ -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) {
index e322cd48ac10ecbe3d5d565af7335e7d26ecdd44..7088169983abebbff546770618ca1ddec0e6d50c 100644 (file)
@@ -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;
 }
 
index 2b07b858b82e394059d00e10f2677e7bc2c81628..d05644b8ab5e3fba18a3fbba296ef3a284ca8914 100644 (file)
@@ -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));
 }
 
index 71225522d932b9349921cf300dc7588ea7c50957..6166dfc0c8fbf7bacfe0bbf93f3c46a341ab040b 100644 (file)
@@ -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) {
index 8fd9405f3a0b6d0f56e92990398f2ced7c243a09..a273ee092a9ec9b04ce6afbb821d2d531e1b1d88 100644 (file)
@@ -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 *
index 2a722c8962a836df539a88a33045b688e6fdf5da..71f08ad9bf245373855e852bf1f9120f94152ffa 100644 (file)
@@ -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);
 
index 718f82f12af3e94b5f24da66f1bb91a5cca31595..2745b36beab9f4127c8c6a0de5a4785ca0bff63f 100644 (file)
@@ -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 {