]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
imapc: Redesigned remote sequence <-> index file record mapping is done.
authorTimo Sirainen <tss@iki.fi>
Sun, 4 Sep 2011 14:59:58 +0000 (17:59 +0300)
committerTimo Sirainen <tss@iki.fi>
Sun, 4 Sep 2011 14:59:58 +0000 (17:59 +0300)
The previous code didn't work when multiple connections modified the same
index files.

14 files changed:
src/lib-storage/index/imapc/Makefile.am
src/lib-storage/index/imapc/imapc-client-private.h
src/lib-storage/index/imapc/imapc-client.c
src/lib-storage/index/imapc/imapc-client.h
src/lib-storage/index/imapc/imapc-connection.c
src/lib-storage/index/imapc/imapc-mail.c
src/lib-storage/index/imapc/imapc-mailbox.c
src/lib-storage/index/imapc/imapc-msgmap.c [new file with mode: 0644]
src/lib-storage/index/imapc/imapc-msgmap.h [new file with mode: 0644]
src/lib-storage/index/imapc/imapc-seqmap.c [deleted file]
src/lib-storage/index/imapc/imapc-seqmap.h [deleted file]
src/lib-storage/index/imapc/imapc-storage.h
src/lib-storage/index/imapc/imapc-sync.c
src/lib-storage/index/imapc/test-imapc-seqmap.c [deleted file]

index d1b228ab78b819758064446d3cdde0f0120a3b5f..baed6dfecb193ba3877a74f02320a1068cf7e4e4 100644 (file)
@@ -20,8 +20,8 @@ libstorage_imapc_la_SOURCES = \
        imapc-mail.c \
        imapc-mail-fetch.c \
        imapc-mailbox.c \
+       imapc-msgmap.c \
        imapc-save.c \
-       imapc-seqmap.c \
        imapc-settings.c \
        imapc-sync.c \
        imapc-storage.c
@@ -32,29 +32,10 @@ headers = \
        imapc-connection.h \
        imapc-list.h \
        imapc-mail.h \
-       imapc-seqmap.h \
+       imapc-msgmap.h \
        imapc-settings.h \
        imapc-storage.h \
        imapc-sync.h
 
 pkginc_libdir=$(pkgincludedir)
 pkginc_lib_HEADERS = $(headers)
-
-test_programs = \
-       test-imapc-seqmap
-
-noinst_PROGRAMS = $(test_programs)
-
-test_libs = \
-       ../../../lib-test/libtest.la \
-       ../../../lib/liblib.la
-
-test_imapc_seqmap_SOURCES = test-imapc-seqmap.c
-test_imapc_seqmap_LDADD = imapc-seqmap.lo $(test_libs)
-test_imapc_seqmap_DEPENDENCIES = imapc-seqmap.lo $(test_libs)
-
-check: check-am check-test
-check-test: all-am
-       for bin in $(test_programs); do \
-         if ! $(RUN_TEST) ./$$bin; then exit 1; fi; \
-       done
index d8442ab0580bab39bf78515c2830594a16857338..a8ac691f523b3eb882f820b1f8ff2eb099266c20 100644 (file)
@@ -26,7 +26,7 @@ struct imapc_client {
 struct imapc_client_mailbox {
        struct imapc_client *client;
        struct imapc_connection *conn;
-       struct imapc_seqmap *seqmap;
+       struct imapc_msgmap *msgmap;
 
        void *untagged_box_context;
        unsigned int pending_box_command_count;
index 254abd1d07f42bfceba65efe4ebd563824a2e8a3..faa1dc5e254c01580ca49c5bfc7d62f4c77a9c03 100644 (file)
@@ -6,7 +6,7 @@
 #include "ioloop.h"
 #include "safe-mkstemp.h"
 #include "iostream-ssl.h"
-#include "imapc-seqmap.h"
+#include "imapc-msgmap.h"
 #include "imapc-connection.h"
 #include "imapc-client-private.h"
 
@@ -219,7 +219,7 @@ imapc_client_mailbox_open(struct imapc_client *client,
        conn = imapc_client_get_unboxed_connection(client);
        conn->box = box;
        box->conn = conn->conn;
-       box->seqmap = imapc_seqmap_init();
+       box->msgmap = imapc_msgmap_init();
 
        imapc_connection_select(box, name, examine, callback, context);
        return box;
@@ -247,7 +247,7 @@ void imapc_client_mailbox_close(struct imapc_client_mailbox **_box)
 
        if (box->conn != NULL)
                imapc_connection_unselect(box);
-       imapc_seqmap_deinit(&box->seqmap);
+       imapc_msgmap_deinit(&box->msgmap);
        i_free(box);
 }
 
@@ -340,10 +340,10 @@ void imapc_client_mailbox_cmdf(struct imapc_client_mailbox *box,
        va_end(args);
 }
 
-struct imapc_seqmap *
-imapc_client_mailbox_get_seqmap(struct imapc_client_mailbox *box)
+struct imapc_msgmap *
+imapc_client_mailbox_get_msgmap(struct imapc_client_mailbox *box)
 {
-       return box->seqmap;
+       return box->msgmap;
 }
 
 void imapc_client_mailbox_idle(struct imapc_client_mailbox *box)
index 052527e7bd6c39d5e134a91aa2f7b7f21eeabce8..c11b21e02f0c1b192b1588e0c9db4c2a698fc127 100644 (file)
@@ -135,8 +135,8 @@ void imapc_client_mailbox_cmdf(struct imapc_client_mailbox *box,
                               imapc_command_callback_t *callback,
                               void *context, const char *cmd_fmt, ...)
        ATTR_FORMAT(4, 5);
-struct imapc_seqmap *
-imapc_client_mailbox_get_seqmap(struct imapc_client_mailbox *box);
+struct imapc_msgmap *
+imapc_client_mailbox_get_msgmap(struct imapc_client_mailbox *box);
 
 void imapc_client_mailbox_idle(struct imapc_client_mailbox *box);
 bool imapc_client_mailbox_is_connected(struct imapc_client_mailbox *box);
index 680181517812cf4ee5d189957ca7a065854c7958..f73229950ca70334264a20b4172865560a75e893 100644 (file)
@@ -14,7 +14,6 @@
 #include "imap-util.h"
 #include "imap-parser.h"
 #include "imapc-client-private.h"
-#include "imapc-seqmap.h"
 #include "imapc-connection.h"
 
 #include <unistd.h>
index c26269bd2706a23d443360239b8b19479969566d..cb669ed7019b54875bfd9c6cf010d74d5ac0da51 100644 (file)
@@ -4,7 +4,7 @@
 #include "str.h"
 #include "istream.h"
 #include "imap-envelope.h"
-#include "imapc-seqmap.h"
+#include "imapc-msgmap.h"
 #include "imapc-mail.h"
 #include "imapc-client.h"
 #include "imapc-storage.h"
@@ -101,8 +101,8 @@ static int imapc_mail_get_physical_size(struct mail *_mail, uoff_t *size_r)
 static bool imapc_mail_is_expunged(struct mail *_mail)
 {
        struct imapc_mailbox *mbox = (struct imapc_mailbox *)_mail->box;
-       struct imapc_seqmap *seqmap;
-       uint32_t lseq;
+       struct imapc_msgmap *msgmap;
+       uint32_t lseq, rseq;
 
        /* first we'll need to convert the mail's sequence to sync_view's
           sequence. if there's no sync_view, then no mails have been
@@ -113,8 +113,8 @@ static bool imapc_mail_is_expunged(struct mail *_mail)
        if (!mail_index_lookup_seq(mbox->sync_view, _mail->uid, &lseq))
                return TRUE;
 
-       seqmap = imapc_client_mailbox_get_seqmap(mbox->client_box);
-       return imapc_seqmap_lseq_to_rseq(seqmap, lseq) == 0;
+       msgmap = imapc_client_mailbox_get_msgmap(mbox->client_box);
+       return !imapc_msgmap_uid_to_rseq(msgmap, _mail->uid, &rseq);
 }
 
 static int
index 6ad5f62f4a6b12e4e2c9bf7e323612f69288676e..e0c9d7009babf835178520a5a7856b37b4154c4f 100644 (file)
@@ -5,8 +5,8 @@
 #include "imap-arg.h"
 #include "imap-util.h"
 #include "imapc-client.h"
-#include "imapc-seqmap.h"
 #include "imapc-mail.h"
+#include "imapc-msgmap.h"
 #include "imapc-sync.h"
 #include "imapc-storage.h"
 
@@ -22,6 +22,8 @@ static void imapc_mailbox_set_corrupted(struct imapc_mailbox *mbox,
                mbox->box.name, t_strdup_vprintf(reason, va));
        va_end(va);
 
+       sleep(3600);
+
        mail_index_mark_corrupted(mbox->box.index);
        imapc_client_mailbox_disconnect(mbox->client_box);
 }
@@ -44,8 +46,6 @@ static void imapc_mailbox_init_delayed_trans(struct imapc_mailbox *mbox)
                                        MAIL_INDEX_TRANSACTION_FLAG_EXTERNAL);
        mbox->delayed_sync_view =
                mail_index_transaction_open_updated_view(mbox->delayed_sync_trans);
-       mbox->min_append_uid =
-               mail_index_get_header(mbox->delayed_sync_view)->next_uid;
 }
 
 int imapc_mailbox_commit_delayed_trans(struct imapc_mailbox *mbox,
@@ -73,10 +73,7 @@ static void imapc_untagged_exists(const struct imapc_untagged_reply *reply,
                                  struct imapc_mailbox *mbox)
 {
        struct mail_index_view *view = mbox->delayed_sync_view;
-       uint32_t rcount = reply->num;
        const struct mail_index_header *hdr;
-       struct imapc_seqmap *seqmap;
-       uint32_t next_lseq, next_rseq;
 
        if (mbox == NULL)
                return;
@@ -84,26 +81,10 @@ static void imapc_untagged_exists(const struct imapc_untagged_reply *reply,
        if (view == NULL)
                view = imapc_mailbox_get_sync_view(mbox);
 
-       if (rcount == 0) {
-               /* nothing in this mailbox */
-               return;
-       }
        if (mbox->opening) {
                /* We don't know the latest flags, refresh them. */
                mbox->sync_fetch_first_uid = 1;
-       } else {
-               seqmap = imapc_client_mailbox_get_seqmap(mbox->client_box);
-               next_lseq = mail_index_view_get_messages_count(view) + 1;
-               next_rseq = imapc_seqmap_lseq_to_rseq(seqmap, next_lseq);
-               if (rcount < next_rseq) {
-                       if (rcount == next_rseq-1) {
-                               /* duplicate EXISTS - ignore */
-                               return;
-                       }
-                       imapc_mailbox_set_corrupted(mbox,
-                               "EXISTS reply shrank mailbox size");
-                       return;
-               }
+       } else if (mbox->sync_fetch_first_uid != 1) {
                hdr = mail_index_get_header(view);
                mbox->sync_fetch_first_uid = hdr->next_uid;
        }
@@ -152,13 +133,13 @@ static void imapc_untagged_fetch(const struct imapc_untagged_reply *reply,
                                 struct imapc_mailbox *mbox)
 {
        uint32_t lseq, rseq = reply->num;
-       struct imapc_seqmap *seqmap;
        struct imapc_mail *const *mailp;
        const struct imap_arg *list, *flags_list;
        const char *atom;
        const struct mail_index_record *rec = NULL;
+       struct imapc_msgmap *msgmap;
        enum mail_flags flags;
-       uint32_t uid, cur_count;
+       uint32_t fetch_uid, uid, msg_count;
        unsigned int i, j;
        ARRAY_TYPE(const_string) keywords = ARRAY_INIT;
        bool seen_flags = FALSE;
@@ -166,14 +147,14 @@ static void imapc_untagged_fetch(const struct imapc_untagged_reply *reply,
        if (mbox == NULL || rseq == 0 || !imap_arg_get_list(reply->args, &list))
                return;
 
-       uid = 0; flags = 0;
+       fetch_uid = 0; flags = 0;
        for (i = 0; list[i].type != IMAP_ARG_EOL; i += 2) {
                if (!imap_arg_get_atom(&list[i], &atom))
                        return;
 
                if (strcasecmp(atom, "UID") == 0) {
                        if (!imap_arg_get_atom(&list[i+1], &atom) ||
-                           str_to_uint32(atom, &uid) < 0)
+                           str_to_uint32(atom, &fetch_uid) < 0)
                                return;
                } else if (strcasecmp(atom, "FLAGS") == 0) {
                        if (!imap_arg_get_list(&list[i+1], &flags_list))
@@ -196,12 +177,52 @@ static void imapc_untagged_fetch(const struct imapc_untagged_reply *reply,
        /* FIXME: need to do something about recent flags */
        flags &= ~MAIL_RECENT;
 
-       seqmap = imapc_client_mailbox_get_seqmap(mbox->client_box);
-       lseq = imapc_seqmap_rseq_to_lseq(seqmap, rseq);
+       imapc_mailbox_init_delayed_trans(mbox);
+
+       msgmap = imapc_client_mailbox_get_msgmap(mbox->client_box);
+       msg_count = imapc_msgmap_count(msgmap);
+       if (rseq > msg_count) {
+               /* newly seen message */
+               if (!mbox->syncing || fetch_uid == 0 || rseq != msg_count+1)
+                       return;
+               uid = fetch_uid;
+
+               if (uid < imapc_msgmap_uidnext(msgmap)) {
+                       imapc_mailbox_set_corrupted(mbox,
+                               "Expunged message reappeared "
+                               "(uid=%u < next_uid=%u)",
+                               uid, imapc_msgmap_uidnext(msgmap));
+                       return;
+               }
+
+               imapc_msgmap_append(msgmap, rseq, uid);
+               if (uid < mbox->min_append_uid) {
+                       /* message is already added to index */
+                       lseq = 0;
+               } else {
+                       mail_index_append(mbox->delayed_sync_trans, uid, &lseq);
+                       mbox->min_append_uid = uid + 1;
+               }
+       } else {
+               uid = imapc_msgmap_rseq_to_uid(msgmap, rseq);
+               if (uid != fetch_uid && fetch_uid != 0) {
+                       imapc_mailbox_set_corrupted(mbox,
+                               "FETCH UID mismatch (%u != %u)",
+                               fetch_uid, uid);
+                       return;
+               }
+               lseq = 0;
+       }
+       if (lseq == 0) {
+               if (!mail_index_lookup_seq(mbox->delayed_sync_view,
+                                          uid, &lseq)) {
+                       /* already expunged by another session */
+                       return;
+               }
+               rec = mail_index_lookup(mbox->delayed_sync_view, lseq);
+       }
 
-       /* fetch_mails' view is different from sync_view, so we can't compare
-          their sequences directly. that is why this code supports only
-          UID FETCH commands which are guaranteed to have UID in the reply. */
+       /* 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;
 
@@ -209,42 +230,19 @@ static void imapc_untagged_fetch(const struct imapc_untagged_reply *reply,
                        imapc_mail_fetch_update(mail, reply, list);
        }
 
-       imapc_mailbox_init_delayed_trans(mbox);
-       cur_count = mail_index_view_get_messages_count(mbox->delayed_sync_view);
-       while (lseq <= cur_count) {
-               rec = mail_index_lookup(mbox->delayed_sync_view, lseq);
-               if (rec->uid == uid || uid == 0)
-                       break;
+       if (rseq == mbox->sync_next_rseq) {
+               /* we're doing the initial full sync of mails. expunge any
+                  mails that no longer exist. */
+               i_assert(mbox->syncing);
 
-               if (!mbox->opening || uid < rec->uid) {
-                       imapc_mailbox_set_corrupted(mbox,
-                               "Message UID changed %u -> %u", rec->uid, uid);
-                       return;
+               while (mbox->sync_next_lseq < lseq) {
+                       mail_index_expunge(mbox->delayed_sync_trans,
+                                          mbox->sync_next_lseq);
+                       mbox->sync_next_lseq++;
                }
-               /* we're opening the mailbox. this message was expunged
-                  externally, so expunge it ourself too. this code assumes
-                  that FETCH responses come in ascending order when opening
-                  mailbox. */
-               imapc_seqmap_expunge(seqmap, rseq);
-               mail_index_expunge(mbox->delayed_sync_trans, lseq);
-               lseq++;
-       }
-       if (lseq > cur_count) {
-               if (!mbox->syncing)
-                       return;
-               if (uid == 0 || lseq != cur_count + 1)
-                       return;
-               if (uid < mbox->min_append_uid) {
-                       imapc_mailbox_set_corrupted(mbox,
-                               "Expunged message reappeared "
-                               "(uid=%u < next_uid=%u)",
-                               uid, mbox->min_append_uid);
-                       return;
-               }
-               i_assert(lseq == cur_count + 1);
-               mail_index_append(mbox->delayed_sync_trans, uid, &lseq);
-               mbox->min_append_uid = uid + 1;
-               rec = NULL;
+               i_assert(lseq == mbox->sync_next_lseq);
+               mbox->sync_next_rseq++;
+               mbox->sync_next_lseq++;
        }
        if (seen_flags && (rec == NULL || rec->flags != flags)) {
                mail_index_update_flags(mbox->delayed_sync_trans, lseq,
@@ -267,38 +265,32 @@ static void imapc_untagged_fetch(const struct imapc_untagged_reply *reply,
                }
                mail_index_keywords_unref(&kw);
        } T_END;
-       if (mbox->highest_seen_uid < uid)
-               mbox->highest_seen_uid = uid;
        imapc_mailbox_idle_notify(mbox);
 }
 
 static void imapc_untagged_expunge(const struct imapc_untagged_reply *reply,
                                   struct imapc_mailbox *mbox)
 {
-       struct imapc_seqmap *seqmap;
-       uint32_t lseq, rseq = reply->num;
+       struct imapc_msgmap *msgmap;
+       uint32_t lseq, uid, rseq = reply->num;
        
        if (mbox == NULL || rseq == 0)
                return;
 
-       imapc_mailbox_init_delayed_trans(mbox);
-
-       seqmap = imapc_client_mailbox_get_seqmap(mbox->client_box);
-       lseq = imapc_seqmap_rseq_to_lseq(seqmap, rseq);
+       msgmap = imapc_client_mailbox_get_msgmap(mbox->client_box);
+       if (rseq > imapc_msgmap_count(msgmap)) {
+               /* we haven't even seen this message yet */
+               return;
+       }
+       uid = imapc_msgmap_rseq_to_uid(msgmap, rseq);
+       imapc_msgmap_expunge(msgmap, rseq);
 
-       if (lseq <= mail_index_view_get_messages_count(mbox->sync_view)) {
-               /* expunging a message in index */
-               imapc_seqmap_expunge(seqmap, rseq);
-               mail_index_expunge(mbox->delayed_sync_trans, lseq);
-       } else if (lseq <= mail_index_view_get_messages_count(mbox->delayed_sync_view)) {
-               /* expunging a message that was added to transaction,
-                  but not yet committed. expunging it here takes
-                  effect immediately. */
-               mail_index_expunge(mbox->delayed_sync_trans, lseq);
+       imapc_mailbox_init_delayed_trans(mbox);
+       if (!mail_index_lookup_seq(mbox->delayed_sync_view, uid, &lseq)) {
+               /* already expunged by another session */
        } else {
-               /* expunging a message whose UID wasn't known yet */
+               mail_index_expunge(mbox->delayed_sync_trans, lseq);
        }
-
        imapc_mailbox_idle_notify(mbox);
 }
 
diff --git a/src/lib-storage/index/imapc/imapc-msgmap.c b/src/lib-storage/index/imapc/imapc-msgmap.c
new file mode 100644 (file)
index 0000000..712d477
--- /dev/null
@@ -0,0 +1,85 @@
+/* Copyright (c) 2011 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "array.h"
+#include "imapc-msgmap.h"
+
+struct imapc_msgmap {
+       ARRAY_TYPE(uint32_t) uids;
+};
+
+struct imapc_msgmap *imapc_msgmap_init(void)
+{
+       struct imapc_msgmap *msgmap;
+
+       msgmap = i_new(struct imapc_msgmap, 1);
+       i_array_init(&msgmap->uids, 128);
+       return msgmap;
+}
+
+void imapc_msgmap_deinit(struct imapc_msgmap **_msgmap)
+{
+       struct imapc_msgmap *msgmap = *_msgmap;
+
+       *_msgmap = NULL;
+
+       array_free(&msgmap->uids);
+       i_free(msgmap);
+}
+
+uint32_t imapc_msgmap_count(struct imapc_msgmap *msgmap)
+{
+       return array_count(&msgmap->uids);
+}
+
+uint32_t imapc_msgmap_uidnext(struct imapc_msgmap *msgmap)
+{
+       return imapc_msgmap_count(msgmap) == 0 ? 1 :
+               imapc_msgmap_rseq_to_uid(msgmap, 1) + 1;
+}
+
+uint32_t imapc_msgmap_rseq_to_uid(struct imapc_msgmap *msgmap, uint32_t rseq)
+{
+       const uint32_t *uidp;
+
+       uidp = array_idx(&msgmap->uids, rseq-1);
+       return *uidp;
+}
+
+static int uint32_cmp(const uint32_t *p1, const uint32_t *p2)
+{
+       return *p1 < *p2 ? -1 :
+               (*p1 > *p2 ? 1 : 0);
+}
+
+bool imapc_msgmap_uid_to_rseq(struct imapc_msgmap *msgmap,
+                             uint32_t uid, uint32_t *rseq_r)
+{
+       const uint32_t *p, *first;
+
+       p = array_bsearch(&msgmap->uids, &uid, uint32_cmp);
+       if (p == NULL) {
+               *rseq_r = 0;
+               return FALSE;
+       }
+
+       first = array_idx(&msgmap->uids, 0);
+       *rseq_r = (p - first) + 1;
+       return TRUE;
+}
+
+void imapc_msgmap_append(struct imapc_msgmap *msgmap,
+                        uint32_t rseq, uint32_t uid)
+{
+       i_assert(rseq == imapc_msgmap_count(msgmap) + 1);
+
+       array_append(&msgmap->uids, &uid, 1);
+}
+
+void imapc_msgmap_expunge(struct imapc_msgmap *msgmap, uint32_t rseq)
+{
+       i_assert(rseq > 0);
+       i_assert(rseq <= imapc_msgmap_count(msgmap));
+
+       array_delete(&msgmap->uids, rseq-1, 1);
+}
diff --git a/src/lib-storage/index/imapc/imapc-msgmap.h b/src/lib-storage/index/imapc/imapc-msgmap.h
new file mode 100644 (file)
index 0000000..51424fd
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef IMAPC_MSGMAP_H
+#define IMAPC_MSGMAP_H
+
+struct imapc_msgmap *imapc_msgmap_init(void);
+void imapc_msgmap_deinit(struct imapc_msgmap **msgmap);
+
+uint32_t imapc_msgmap_count(struct imapc_msgmap *msgmap);
+uint32_t imapc_msgmap_uidnext(struct imapc_msgmap *msgmap);
+uint32_t imapc_msgmap_rseq_to_uid(struct imapc_msgmap *msgmap, uint32_t rseq);
+bool imapc_msgmap_uid_to_rseq(struct imapc_msgmap *msgmap,
+                             uint32_t uid, uint32_t *rseq_r);
+
+void imapc_msgmap_append(struct imapc_msgmap *msgmap,
+                        uint32_t rseq, uint32_t uid);
+void imapc_msgmap_expunge(struct imapc_msgmap *msgmap, uint32_t rseq);
+
+#endif
diff --git a/src/lib-storage/index/imapc/imapc-seqmap.c b/src/lib-storage/index/imapc/imapc-seqmap.c
deleted file mode 100644 (file)
index 3713cdc..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-/* Copyright (c) 2011 Dovecot authors, see the included COPYING file */
-
-#include "lib.h"
-#include "array.h"
-#include "bsearch-insert-pos.h"
-#include "imapc-seqmap.h"
-
-struct imapc_seqmap {
-       ARRAY_TYPE(uint32_t) queue;
-       ARRAY_TYPE(uint32_t) expunges;
-};
-
-struct imapc_seqmap *imapc_seqmap_init(void)
-{
-       struct imapc_seqmap *seqmap;
-
-       seqmap = i_new(struct imapc_seqmap, 1);
-       i_array_init(&seqmap->queue, 64);
-       i_array_init(&seqmap->expunges, 64);
-       return seqmap;
-}
-
-void imapc_seqmap_deinit(struct imapc_seqmap **_seqmap)
-{
-       struct imapc_seqmap *seqmap = *_seqmap;
-
-       *_seqmap = NULL;
-       array_free(&seqmap->expunges);
-       array_free(&seqmap->queue);
-       i_free(seqmap);
-}
-
-void imapc_seqmap_reset(struct imapc_seqmap *seqmap)
-{
-       array_clear(&seqmap->queue);
-       array_clear(&seqmap->expunges);
-}
-
-bool imapc_seqmap_is_reset(struct imapc_seqmap *seqmap)
-{
-       return array_count(&seqmap->queue) == 0 &&
-               array_count(&seqmap->expunges) == 0;
-}
-
-void imapc_seqmap_expunge(struct imapc_seqmap *seqmap, uint32_t rseq)
-{
-       i_assert(rseq > 0);
-
-       array_append(&seqmap->queue, &rseq, 1);
-}
-
-static int uint32_cmp_p(const uint32_t *p1, const uint32_t *p2)
-{
-       if (*p1 < *p2)
-               return -1;
-       else if (*p1 > *p2)
-               return 1;
-       else
-               return 0;
-}
-
-static uint32_t
-imapc_seqmap_rseq_idx_lookup(struct imapc_seqmap *seqmap, uint32_t rseq,
-                            unsigned int *idx_r)
-{
-       const uint32_t *seqs;
-       unsigned int idx, count;
-       uint32_t lseq = rseq;
-
-       seqs = array_get(&seqmap->expunges, &count);
-       for (;;) {
-               array_bsearch_insert_pos(&seqmap->expunges, &lseq, uint32_cmp_p, &idx);
-               lseq = rseq + idx;
-               if (idx == count || seqs[idx] > lseq) {
-                       *idx_r = idx;
-                       return lseq;
-               }
-               if (seqs[idx] == lseq)
-                       lseq++;
-       }
-}
-
-static void
-imapc_seqmap_dequeue_rseq(struct imapc_seqmap *seqmap, uint32_t rseq)
-{
-       unsigned int idx;
-       uint32_t lseq;
-
-       lseq = imapc_seqmap_rseq_idx_lookup(seqmap, rseq, &idx);
-       array_insert(&seqmap->expunges, idx, &lseq, 1);
-}
-
-static void imapc_seqmap_dequeue(struct imapc_seqmap *seqmap)
-{
-       const uint32_t *seqp;
-
-       array_foreach(&seqmap->queue, seqp)
-               imapc_seqmap_dequeue_rseq(seqmap, *seqp);
-       array_clear(&seqmap->queue);
-}
-
-uint32_t imapc_seqmap_rseq_to_lseq(struct imapc_seqmap *seqmap, uint32_t rseq)
-{
-       unsigned int idx;
-
-       i_assert(rseq > 0);
-
-       imapc_seqmap_dequeue(seqmap);
-       return imapc_seqmap_rseq_idx_lookup(seqmap, rseq, &idx);
-}
-
-uint32_t imapc_seqmap_lseq_to_rseq(struct imapc_seqmap *seqmap, uint32_t lseq)
-{
-       unsigned int idx;
-
-       i_assert(lseq > 0);
-
-       imapc_seqmap_dequeue(seqmap);
-       if (array_bsearch_insert_pos(&seqmap->expunges, &lseq,
-                                    uint32_cmp_p, &idx))
-               return 0;
-
-       return lseq - idx;
-}
diff --git a/src/lib-storage/index/imapc/imapc-seqmap.h b/src/lib-storage/index/imapc/imapc-seqmap.h
deleted file mode 100644 (file)
index 7e8d4a4..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef IMAPC_SEQMAP_H
-#define IMAPC_SEQMAP_H
-
-/* Defines a mapping between remote and local sequence numbers.
-   Initially they start the same, but remote sequences can be marked as
-   expunged, which alters the mapping until the seqmap is reset (i.e. when the
-   mailbox is synced and local sequences are expunged too).
-
-   So for example calling imapc_seqmap_expunge(seqmap, 1) twice expunges the
-   first and the second local sequence. imapc_seqmap_rseq_to_lseq(seqmap, 1)
-   will afterward return 3. */
-
-struct imapc_seqmap *imapc_seqmap_init(void);
-void imapc_seqmap_deinit(struct imapc_seqmap **seqmap);
-
-/* Reset local and remote sequences to be equal. */
-void imapc_seqmap_reset(struct imapc_seqmap *seqmap);
-bool imapc_seqmap_is_reset(struct imapc_seqmap *seqmap);
-
-/* Mark given remote sequence expunged. */
-void imapc_seqmap_expunge(struct imapc_seqmap *seqmap, uint32_t rseq);
-/* Convert remote sequence to local sequence. */
-uint32_t imapc_seqmap_rseq_to_lseq(struct imapc_seqmap *seqmap, uint32_t rseq);
-/* Convert local sequence to remote sequence. */
-uint32_t imapc_seqmap_lseq_to_rseq(struct imapc_seqmap *seqmap, uint32_t lseq);
-
-#endif
index 7c0d4fa991719ef97c62505d92efd4ea4fab2db5..8c5093574ac2184c23f842eacd4ada99b4d891d2 100644 (file)
@@ -54,15 +54,16 @@ struct imapc_mailbox {
        ARRAY_DEFINE(untagged_callbacks, struct imapc_mailbox_event_callback);
        ARRAY_DEFINE(resp_text_callbacks, struct imapc_mailbox_event_callback);
 
-       uint32_t min_append_uid;
-       uint32_t highest_seen_uid;
-
        uint32_t sync_uid_validity;
        uint32_t sync_uid_next;
        uint32_t sync_fetch_first_uid;
+       uint32_t sync_next_lseq;
+       uint32_t sync_next_rseq;
+       uint32_t min_append_uid;
 
        unsigned int opening:1;
        unsigned int syncing:1;
+       unsigned int initial_sync_done:1;
 };
 
 struct imapc_simple_context {
index 6beb41ba2780e75d84cdee939564e13cdcaa6dc8..346725d0bb7b461437dd9477b15dfe9f3187b73a 100644 (file)
@@ -7,7 +7,6 @@
 #include "index-sync-private.h"
 #include "imapc-storage.h"
 #include "imapc-client.h"
-#include "imapc-seqmap.h"
 #include "imapc-sync.h"
 
 static void imapc_sync_callback(const struct imapc_command_reply *reply,
@@ -168,19 +167,27 @@ static void imapc_sync_expunge_finish(struct imapc_sync_context *ctx)
 
 static void imapc_sync_expunge_eom(struct imapc_sync_context *ctx)
 {
-       const struct mail_index_record *rec;
-       uint32_t lseq, cur_count;
+       struct imapc_mailbox *mbox = ctx->mbox;
+       uint32_t lseq, uid, msg_count;
+
+       if (mbox->sync_next_lseq == 0)
+               return;
 
        /* if we haven't seen FETCH reply for some messages at the end of
           mailbox they've been externally expunged. */
-       cur_count = mail_index_view_get_messages_count(ctx->sync_view);
-       for (lseq = cur_count; lseq > 0; lseq--) {
-               rec = mail_index_lookup(ctx->sync_view, lseq);
-               if (rec->uid <= ctx->mbox->highest_seen_uid)
+       msg_count = mail_index_view_get_messages_count(ctx->sync_view);
+       for (lseq = mbox->sync_next_lseq; lseq <= msg_count; lseq++) {
+               mail_index_lookup_uid(ctx->sync_view, lseq, &uid);
+               if (uid >= mbox->sync_uid_next) {
+                       /* another process already added new messages to index
+                          that our IMAP connection hasn't seen yet */
                        break;
-
+               }
                mail_index_expunge(ctx->trans, lseq);
        }
+
+       mbox->sync_next_lseq = 0;
+       mbox->sync_next_rseq = 0;
 }
 
 static void imapc_sync_index_header(struct imapc_sync_context *ctx)
@@ -211,12 +218,12 @@ static void imapc_sync_index_header(struct imapc_sync_context *ctx)
 
 static void imapc_sync_index(struct imapc_sync_context *ctx)
 {
-       struct mailbox *box = &ctx->mbox->box;
+       struct imapc_mailbox *mbox = ctx->mbox;
        struct mail_index_sync_rec sync_rec;
        uint32_t seq1, seq2;
 
        i_array_init(&ctx->expunged_uids, 64);
-       ctx->keywords = mail_index_get_keywords(box->index);
+       ctx->keywords = mail_index_get_keywords(mbox->box.index);
 
        imapc_sync_index_header(ctx);
        while (mail_index_sync_next(ctx->index_sync_ctx, &sync_rec)) T_BEGIN {
@@ -246,24 +253,32 @@ static void imapc_sync_index(struct imapc_sync_context *ctx)
                }
        } T_END;
 
-       if (ctx->mbox->sync_fetch_first_uid != 0) {
+       if (!mbox->initial_sync_done) {
+               /* with initial syncing we're fetching all messages' flags and
+                  expunge mails from local index that no longer exist on
+                  remote server */
+               i_assert(mbox->sync_fetch_first_uid == 1);
+               mbox->sync_next_lseq = 1;
+               mbox->sync_next_rseq = 1;
+       }
+       if (mbox->sync_fetch_first_uid != 0) {
                /* we'll resync existing messages' flags and add new messages.
                   adding new messages requires sync locking to avoid
                   duplicates. */
                imapc_sync_cmd(ctx, t_strdup_printf(
-                       "UID FETCH %u:* FLAGS",
-                       ctx->mbox->sync_fetch_first_uid));
-               ctx->mbox->sync_fetch_first_uid = 0;
+                       "UID FETCH %u:* FLAGS", mbox->sync_fetch_first_uid));
+               mbox->sync_fetch_first_uid = 0;
        }
 
        imapc_sync_expunge_finish(ctx);
        while (ctx->sync_command_count > 0)
-               imapc_storage_run(ctx->mbox->storage);
+               imapc_storage_run(mbox->storage);
        array_free(&ctx->expunged_uids);
 
        imapc_sync_expunge_eom(ctx);
-       if (box->v.sync_notify != NULL)
-               box->v.sync_notify(box, 0, 0);
+       if (mbox->box.v.sync_notify != NULL)
+               mbox->box.v.sync_notify(&mbox->box, 0, 0);
+       mbox->initial_sync_done = TRUE;
 }
 
 static int
@@ -300,6 +315,7 @@ imapc_sync_begin(struct imapc_mailbox *mbox,
        mbox->delayed_sync_view =
                mail_index_transaction_open_updated_view(ctx->trans);
        mbox->delayed_sync_trans = ctx->trans;
+       mbox->min_append_uid = mail_index_get_header(ctx->sync_view)->next_uid;
 
        mbox->syncing = TRUE;
        imapc_sync_index(ctx);
@@ -334,25 +350,14 @@ static int imapc_sync_finish(struct imapc_sync_context **_ctx)
 static int imapc_sync(struct imapc_mailbox *mbox)
 {
        struct imapc_sync_context *sync_ctx;
-       struct imapc_seqmap *seqmap;
        bool force = mbox->sync_fetch_first_uid != 0;
 
-       /* if there are any pending expunges, they're now committed. syncing
-          will return a view where they no longer exist, so reset the seqmap
-          before syncing. */
-       seqmap = imapc_client_mailbox_get_seqmap(mbox->client_box);
-       imapc_seqmap_reset(seqmap);
-
        if (imapc_sync_begin(mbox, &sync_ctx, force) < 0)
                return -1;
        if (sync_ctx == NULL)
                return 0;
        if (imapc_sync_finish(&sync_ctx) < 0)
                return -1;
-
-       /* syncing itself may have also seen new expunges, which are also now
-          committed and synced. reset the seqmap again. */
-       imapc_seqmap_reset(seqmap);
        return 0;
 }
 
diff --git a/src/lib-storage/index/imapc/test-imapc-seqmap.c b/src/lib-storage/index/imapc/test-imapc-seqmap.c
deleted file mode 100644 (file)
index 78b1e3b..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-/* Copyright (c) 2011 Dovecot authors, see the included COPYING file */
-
-#include "lib.h"
-#include "array.h"
-#include "imapc-seqmap.h"
-#include "test-common.h"
-
-#include <stdlib.h>
-
-static void test_imapc_seqmap(void)
-{
-       struct imapc_seqmap *seqmap;
-
-       test_begin("imapc seqmap");
-       seqmap = imapc_seqmap_init();
-
-       imapc_seqmap_expunge(seqmap, 4);
-       imapc_seqmap_expunge(seqmap, 3);
-       imapc_seqmap_expunge(seqmap, 2);
-
-       test_assert(imapc_seqmap_rseq_to_lseq(seqmap, 1) == 1);
-       test_assert(imapc_seqmap_rseq_to_lseq(seqmap, 2) == 5);
-
-       test_assert(imapc_seqmap_lseq_to_rseq(seqmap, 1) == 1);
-       test_assert(imapc_seqmap_lseq_to_rseq(seqmap, 2) == 0);
-       test_assert(imapc_seqmap_lseq_to_rseq(seqmap, 3) == 0);
-       test_assert(imapc_seqmap_lseq_to_rseq(seqmap, 4) == 0);
-       test_assert(imapc_seqmap_lseq_to_rseq(seqmap, 5) == 2);
-
-       imapc_seqmap_reset(seqmap);
-       imapc_seqmap_expunge(seqmap, 3);
-       imapc_seqmap_expunge(seqmap, 3);
-       imapc_seqmap_expunge(seqmap, 3);
-
-       test_assert(imapc_seqmap_rseq_to_lseq(seqmap, 1) == 1);
-       test_assert(imapc_seqmap_rseq_to_lseq(seqmap, 2) == 2);
-       test_assert(imapc_seqmap_rseq_to_lseq(seqmap, 3) == 6);
-
-       test_assert(imapc_seqmap_lseq_to_rseq(seqmap, 1) == 1);
-       test_assert(imapc_seqmap_lseq_to_rseq(seqmap, 2) == 2);
-       test_assert(imapc_seqmap_lseq_to_rseq(seqmap, 3) == 0);
-       test_assert(imapc_seqmap_lseq_to_rseq(seqmap, 4) == 0);
-       test_assert(imapc_seqmap_lseq_to_rseq(seqmap, 5) == 0);
-       test_assert(imapc_seqmap_lseq_to_rseq(seqmap, 6) == 3);
-
-       imapc_seqmap_reset(seqmap);
-       /* 9,8,5,4,2,1 */
-       imapc_seqmap_expunge(seqmap, 4);
-       imapc_seqmap_expunge(seqmap, 4);
-       imapc_seqmap_expunge(seqmap, 1);
-       imapc_seqmap_expunge(seqmap, 1);
-       imapc_seqmap_expunge(seqmap, 4);
-       imapc_seqmap_expunge(seqmap, 4);
-
-       test_assert(imapc_seqmap_rseq_to_lseq(seqmap, 1) == 3);
-       test_assert(imapc_seqmap_rseq_to_lseq(seqmap, 2) == 6);
-       test_assert(imapc_seqmap_rseq_to_lseq(seqmap, 3) == 7);
-       test_assert(imapc_seqmap_rseq_to_lseq(seqmap, 4) == 10);
-
-       test_assert(imapc_seqmap_lseq_to_rseq(seqmap, 1) == 0);
-       test_assert(imapc_seqmap_lseq_to_rseq(seqmap, 2) == 0);
-       test_assert(imapc_seqmap_lseq_to_rseq(seqmap, 3) == 1);
-       test_assert(imapc_seqmap_lseq_to_rseq(seqmap, 6) == 2);
-       test_assert(imapc_seqmap_lseq_to_rseq(seqmap, 7) == 3);
-       test_assert(imapc_seqmap_lseq_to_rseq(seqmap, 10) == 4);
-
-       imapc_seqmap_deinit(&seqmap);
-       test_end();
-}
-
-static void test_imapc_seqmap_random(void)
-{
-#define UIDMAP_SIZE 1000
-       struct imapc_seqmap *seqmap;
-       ARRAY_TYPE(uint32_t) uidmap;
-       const uint32_t *uids;
-       unsigned int i, count;
-       uint32_t seq, uid;
-
-       test_begin("imapc seqmap random");
-       seqmap = imapc_seqmap_init();
-
-       t_array_init(&uidmap, UIDMAP_SIZE);
-       for (uid = 1; uid <= UIDMAP_SIZE; uid++)
-               array_append(&uidmap, &uid, 1);
-
-       for (i = 0; i < 100; i++) {
-               seq = (rand() % array_count(&uidmap)) + 1;
-               array_delete(&uidmap, seq-1, 1);
-               imapc_seqmap_expunge(seqmap, seq);
-       }
-
-       uids = array_get(&uidmap, &count);
-       for (i = 0; i < 100; i++) {
-               seq = i + 1;
-               test_assert(imapc_seqmap_rseq_to_lseq(seqmap, seq) == uids[i]);
-               test_assert(imapc_seqmap_lseq_to_rseq(seqmap, uids[i]) == seq);
-       }
-       imapc_seqmap_deinit(&seqmap);
-       test_end();
-}
-
-int main(void)
-{
-       static void (*test_functions[])(void) = {
-               test_imapc_seqmap,
-               test_imapc_seqmap_random,
-               NULL
-       };
-       return test_run(test_functions);
-}