]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
maildir: Allow opening mailbox and expunging messages when uidlist couldn't be locked...
authorTimo Sirainen <tss@iki.fi>
Mon, 15 Dec 2008 08:58:02 +0000 (10:58 +0200)
committerTimo Sirainen <tss@iki.fi>
Mon, 15 Dec 2008 08:58:02 +0000 (10:58 +0200)
--HG--
branch : HEAD

src/lib-storage/index/maildir/maildir-keywords.c
src/lib-storage/index/maildir/maildir-sync-index.c
src/lib-storage/index/maildir/maildir-sync.c
src/lib-storage/index/maildir/maildir-uidlist.c
src/lib-storage/index/maildir/maildir-uidlist.h

index 8ff8dbd2a392ee267a8ccdcfa346639af468338f..cdfce785417b6db9c35ea4967cdea05b972571bc 100644 (file)
@@ -194,9 +194,6 @@ maildir_keywords_lookup(struct maildir_keywords *mk, const char *name)
 {
        void *p;
 
-       i_assert(mk->mbox == NULL ||
-                maildir_uidlist_is_locked(mk->mbox->uidlist));
-
        p = hash_lookup(mk->hash, name);
        if (p == NULL) {
                if (mk->synced)
@@ -256,6 +253,9 @@ maildir_keywords_lookup_or_create(struct maildir_keywords *mk, const char *name)
        if (i == count && count >= MAILDIR_MAX_KEYWORDS)
                return -1;
 
+       if (!maildir_uidlist_is_locked(mk->mbox->uidlist))
+               return -1;
+
         maildir_keywords_create(mk, name, i);
        return i;
 }
@@ -266,9 +266,6 @@ maildir_keywords_idx(struct maildir_keywords *mk, unsigned int idx)
        const char *const *keywords;
        unsigned int count;
 
-       i_assert(mk->mbox == NULL ||
-                maildir_uidlist_is_locked(mk->mbox->uidlist));
-
        keywords = array_get(&mk->list, &count);
        if (idx >= count) {
                if (mk->synced)
index 79b87625687e8508572169b2635e493860c30498..1a502f74b71813519bf843fbf60a65ed00b8a6ab 100644 (file)
@@ -105,15 +105,15 @@ static int maildir_sync_flags(struct maildir_mailbox *mbox, const char *path,
        return -1;
 }
 
-static void maildir_handle_uid_insertion(struct maildir_index_sync_context *ctx,
-                                        enum maildir_uidlist_rec_flag uflags,
-                                        const char *filename, uint32_t uid)
+static int maildir_handle_uid_insertion(struct maildir_index_sync_context *ctx,
+                                       enum maildir_uidlist_rec_flag uflags,
+                                       const char *filename, uint32_t uid)
 {
        int ret;
 
        if ((uflags & MAILDIR_UIDLIST_REC_FLAG_NONSYNCED) != 0) {
                /* partial syncing */
-               return;
+               return 0;
        }
 
        /* most likely a race condition: we read the maildir, then someone else
@@ -124,7 +124,7 @@ static void maildir_handle_uid_insertion(struct maildir_index_sync_context *ctx,
                ctx->mbox->maildir_hdr.cur_check_time = 0;
                maildir_uidlist_add_flags(ctx->mbox->uidlist, filename,
                                          MAILDIR_UIDLIST_REC_FLAG_RACING);
-               return;
+               return 0;
        }
 
        if (ctx->uidlist_sync_ctx == NULL) {
@@ -132,7 +132,8 @@ static void maildir_handle_uid_insertion(struct maildir_index_sync_context *ctx,
                                                MAILDIR_UIDLIST_SYNC_PARTIAL |
                                                MAILDIR_UIDLIST_SYNC_KEEP_STATE,
                                                &ctx->uidlist_sync_ctx);
-               i_assert(ret > 0);
+               if (ret <= 0)
+                       return -1;
        }
 
        uflags &= MAILDIR_UIDLIST_REC_FLAG_NEW_DIR;
@@ -146,6 +147,7 @@ static void maildir_handle_uid_insertion(struct maildir_index_sync_context *ctx,
 
        i_warning("Maildir %s: Expunged message reappeared, giving a new UID "
                  "(old uid=%u, file=%s)", ctx->mbox->path, uid, filename);
+       return 0;
 }
 
 int maildir_sync_index_begin(struct maildir_mailbox *mbox,
@@ -283,7 +285,6 @@ int maildir_sync_index(struct maildir_index_sync_context *ctx,
        bool expunged, full_rescan = FALSE;
 
        i_assert(!mbox->syncing_commit);
-       i_assert(maildir_uidlist_is_locked(mbox->uidlist));
 
        first_uid = 1;
        hdr = mail_index_get_header(view);
@@ -328,8 +329,10 @@ int maildir_sync_index(struct maildir_index_sync_context *ctx,
 
                if (seq > hdr->messages_count) {
                        if (uid < hdr_next_uid) {
-                               maildir_handle_uid_insertion(ctx, uflags,
-                                                            filename, uid);
+                               if (maildir_handle_uid_insertion(ctx, uflags,
+                                                                filename,
+                                                                uid) < 0)
+                                       ret = -1;
                                seq--;
                                continue;
                        }
@@ -367,8 +370,9 @@ int maildir_sync_index(struct maildir_index_sync_context *ctx,
                }
 
                if (uid < rec->uid) {
-                       maildir_handle_uid_insertion(ctx, uflags,
-                                                    filename, uid);
+                       if (maildir_handle_uid_insertion(ctx, uflags,
+                                                        filename, uid) < 0)
+                               ret = -1;
                        seq--;
                        continue;
                }
index f454e46c8e3f0c43228a7f363cb0d6ef8c599bdc..d2868223a7fdbc202546b3ecdc91acc548ded57b 100644 (file)
@@ -670,7 +670,7 @@ static int maildir_sync_context(struct maildir_sync_context *ctx, bool forced,
 {
        enum maildir_uidlist_sync_flags sync_flags;
        enum maildir_uidlist_rec_flag flags;
-       bool new_changed, cur_changed;
+       bool new_changed, cur_changed, lock_failure;
        int ret;
 
        *lost_files_r = FALSE;
@@ -741,15 +741,39 @@ static int maildir_sync_context(struct maildir_sync_context *ctx, bool forced,
        }
        ret = maildir_uidlist_sync_init(ctx->mbox->uidlist, sync_flags,
                                        &ctx->uidlist_sync_ctx);
+       lock_failure = ret <= 0;
        if (ret <= 0) {
-               /* failure / timeout */
-               return ret;
+               struct mail_storage *storage = ctx->mbox->ibox.box.storage;
+
+               if (ret == 0) {
+                       /* timeout */
+                       return 0;
+               }
+               /* locking failed. sync anyway without locking so that it's
+                  possible to expunge messages when out of quota. */
+               if (forced) {
+                       /* we're already forcing a sync, we're trying to find
+                          a message that was probably already expunged, don't
+                          loop for a long time trying to find it. */
+                       return -1;
+               }
+               ret = maildir_uidlist_sync_init(ctx->mbox->uidlist, sync_flags |
+                                               MAILDIR_UIDLIST_SYNC_NOLOCK,
+                                               &ctx->uidlist_sync_ctx);
+               i_assert(ret > 0);
+
+               if (storage->callbacks->notify_no != NULL) {
+                       storage->callbacks->notify_no(&ctx->mbox->ibox.box,
+                               "Internal mailbox synchronization failure, "
+                               "showing only old mails.",
+                               storage->callback_context);
+               }
        }
        ctx->locked = maildir_uidlist_is_locked(ctx->mbox->uidlist);
        if (!ctx->locked)
                ctx->partial = TRUE;
 
-       if (!ctx->mbox->syncing_commit && ctx->locked) {
+       if (!ctx->mbox->syncing_commit && (ctx->locked || lock_failure)) {
                if (maildir_sync_index_begin(ctx->mbox, ctx,
                                             &ctx->index_sync_ctx) < 0)
                        return -1;
@@ -787,7 +811,7 @@ static int maildir_sync_context(struct maildir_sync_context *ctx, bool forced,
                ctx->mbox->maildir_hdr.cur_mtime = 0;
        }
 
-       if (!ctx->mbox->syncing_commit && ctx->locked) {
+       if (ctx->index_sync_ctx != NULL) {
                /* NOTE: index syncing here might cause a re-sync due to
                   files getting lost, so this function might be called
                   re-entrantly. */
@@ -801,7 +825,8 @@ static int maildir_sync_context(struct maildir_sync_context *ctx, bool forced,
                if (ret == 0)
                        *lost_files_r = TRUE;
 
-               i_assert(maildir_uidlist_is_locked(ctx->mbox->uidlist));
+               i_assert(maildir_uidlist_is_locked(ctx->mbox->uidlist) ||
+                        lock_failure);
        }
 
        if (find_uid != NULL && *find_uid != 0) {
index b2b1033d1f59b146eb5ac4ab3af14327a7687d3a..d59072a7959fe23b307dd0946120d211bbe46ec8 100644 (file)
@@ -1287,14 +1287,21 @@ static void maildir_uidlist_mark_all(struct maildir_uidlist *uidlist,
        }
 }
 
-int maildir_uidlist_sync_init(struct maildir_uidlist *uidlist,
-                             enum maildir_uidlist_sync_flags sync_flags,
-                             struct maildir_uidlist_sync_ctx **sync_ctx_r)
+static int maildir_uidlist_sync_lock(struct maildir_uidlist *uidlist,
+                                    enum maildir_uidlist_sync_flags sync_flags,
+                                    bool *locked_r)
 {
-       struct maildir_uidlist_sync_ctx *ctx;
-       bool nonblock, refresh, locked;
+       bool nonblock, refresh;
        int ret;
 
+       *locked_r = FALSE;
+
+       if ((sync_flags & MAILDIR_UIDLIST_SYNC_NOLOCK) != 0) {
+               if (maildir_uidlist_refresh(uidlist) < 0)
+                       return -1;
+               return 1;
+       }
+
        nonblock = (sync_flags & MAILDIR_UIDLIST_SYNC_TRYLOCK) != 0;
        refresh = (sync_flags & MAILDIR_UIDLIST_SYNC_NOREFRESH) == 0;
 
@@ -1309,10 +1316,23 @@ int maildir_uidlist_sync_init(struct maildir_uidlist *uidlist,
                /* forcing the sync anyway */
                if (maildir_uidlist_refresh(uidlist) < 0)
                        return -1;
-               locked = FALSE;
        } else {
-               locked = TRUE;
+               *locked_r = TRUE;
        }
+       return 1;
+}
+
+int maildir_uidlist_sync_init(struct maildir_uidlist *uidlist,
+                             enum maildir_uidlist_sync_flags sync_flags,
+                             struct maildir_uidlist_sync_ctx **sync_ctx_r)
+{
+       struct maildir_uidlist_sync_ctx *ctx;
+       bool locked;
+       int ret;
+
+       ret = maildir_uidlist_sync_lock(uidlist, sync_flags, &locked);
+       if (ret <= 0)
+               return ret;
 
        *sync_ctx_r = ctx = i_new(struct maildir_uidlist_sync_ctx, 1);
        ctx->uidlist = uidlist;
index d78e833b2b8ef48cbad9292677505005e62dd9bd..9485c3ed9a92d0ab13d6336f3e85802772436534 100644 (file)
@@ -15,7 +15,8 @@ enum maildir_uidlist_sync_flags {
        MAILDIR_UIDLIST_SYNC_KEEP_STATE = 0x02,
        MAILDIR_UIDLIST_SYNC_FORCE      = 0x04,
        MAILDIR_UIDLIST_SYNC_TRYLOCK    = 0x08,
-       MAILDIR_UIDLIST_SYNC_NOREFRESH  = 0x10
+       MAILDIR_UIDLIST_SYNC_NOREFRESH  = 0x10,
+       MAILDIR_UIDLIST_SYNC_NOLOCK     = 0x20
 };
 
 enum maildir_uidlist_rec_flag {