]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-index: Don't rewrite dovecot.index if another process has already done it
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Tue, 1 Oct 2019 20:33:47 +0000 (23:33 +0300)
committertimo.sirainen <timo.sirainen@open-xchange.com>
Fri, 27 Mar 2020 14:27:53 +0000 (14:27 +0000)
This mainly happened when there were multiple sessions accessing the index
at the same time.

src/lib-index/mail-index-map-read.c
src/lib-index/mail-index-private.h
src/lib-index/mail-index-write.c

index bf219320f452a139d35c81443c309688dc8e18fe..73f0efc11cef5dc26e667b7ae65c5170e6a2ece6 100644 (file)
@@ -313,6 +313,7 @@ mail_index_map_latest_file(struct mail_index *index, const char **reason_r)
 
        *reason_r = NULL;
 
+       index->reopen_main_index = FALSE;
        ret = mail_index_reopen_if_changed(index, reason_r);
        if (ret <= 0) {
                if (ret < 0)
@@ -418,7 +419,7 @@ int mail_index_map(struct mail_index *index,
                index->map = mail_index_map_alloc(index);
 
        /* first try updating the existing mapping from transaction log. */
-       if (index->initial_mapped) {
+       if (index->initial_mapped && !index->reopen_main_index) {
                /* we're not creating/opening the index.
                   sync this as a view from transaction log. */
                ret = mail_index_sync_map(&index->map, type, FALSE, "initial mapping");
index 67e63d2a7fd63b7a9c2674d1f2de53e5b6fb65b3..5faf525f8d140e2a41ef09a1c00057bbcd510cb2 100644 (file)
@@ -223,6 +223,7 @@ struct mail_index {
        bool modseqs_enabled:1;
        bool initial_create:1;
        bool initial_mapped:1;
+       bool reopen_main_index:1;
        bool fscked:1;
 };
 
index 791cf9f1ce06890b3619f09363bbb721cd435aaa..c0fd2f84cbb4252dd6c7e53357fe4cc993261acd 100644 (file)
@@ -1,6 +1,7 @@
 /* Copyright (c) 2003-2018 Dovecot authors, see the included COPYING file */
 
 #include "lib.h"
+#include "nfs-workarounds.h"
 #include "read-full.h"
 #include "write-full.h"
 #include "ostream.h"
@@ -116,6 +117,40 @@ static int mail_index_recreate(struct mail_index *index)
        return ret;
 }
 
+static bool mail_index_should_recreate(struct mail_index *index)
+{
+       struct stat st1, st2;
+
+       if (nfs_safe_stat(index->filepath, &st1) < 0) {
+               if (errno != ENOENT) {
+                       mail_index_set_syscall_error(index, "stat()");
+                       return FALSE;
+               } else if (index->fd == -1) {
+                       /* main index hasn't been created yet */
+                       return TRUE;
+               } else {
+                       /* mailbox was just deleted? don't log an error */
+                       return FALSE;
+               }
+       }
+       if (index->fd == -1) {
+               /* main index was just created by another process */
+               return FALSE;
+       }
+       if (fstat(index->fd, &st2) < 0) {
+               if (!ESTALE_FSTAT(errno))
+                       mail_index_set_syscall_error(index, "fstat()");
+               return FALSE;
+       }
+       if (st1.st_ino != st2.st_ino ||
+           !CMP_DEV_T(st1.st_dev, st2.st_dev)) {
+               /* Index has already been recreated since we last read it.
+                  We can't trust our decisions about whether to recreate it. */
+               return FALSE;
+       }
+       return TRUE;
+}
+
 void mail_index_write(struct mail_index *index, bool want_rotate,
                      const char *reason)
 {
@@ -152,7 +187,12 @@ void mail_index_write(struct mail_index *index, bool want_rotate,
                }
        }
 
-       if (!MAIL_INDEX_IS_IN_MEMORY(index)) {
+       if (MAIL_INDEX_IS_IN_MEMORY(index))
+               ;
+       else if (!mail_index_should_recreate(index)) {
+               /* make sure we don't keep getting back in here */
+               index->reopen_main_index = TRUE;
+       } else {
                e_debug(index->event, "Recreating %s because: %s",
                        index->filepath, reason);
                if (mail_index_recreate(index) < 0) {