]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-index: Fix wrong mail_index_modseq_header automatically
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Tue, 8 Aug 2017 13:56:02 +0000 (16:56 +0300)
committerVille Savolainen <ville.savolainen@dovecot.fi>
Mon, 14 Aug 2017 08:23:08 +0000 (11:23 +0300)
It happens only on the next sync, although that isn't actually guaranteed to
happen. Still, it happens almost always so this should be good enough.

src/lib-index/mail-index-sync.c
src/lib-index/mail-transaction-log-file.c
src/lib-index/mail-transaction-log-private.h
src/lib-index/mail-transaction-log.c
src/lib-index/test-mail-transaction-log-file.c

index 24de5e1192a412ce73ba388c1b652738ffb7093e..f4d30eb03bc0e4e175e96fe0e1b54b9590a6043c 100644 (file)
@@ -361,7 +361,7 @@ mail_index_sync_begin_init(struct mail_index *index,
        }
 
        if (!mail_index_need_sync(index, flags, log_file_seq, log_file_offset) &&
-           !index->index_deleted) {
+           !index->index_deleted && !index->need_recreate) {
                if (locked)
                        mail_transaction_log_sync_unlock(index->log, "syncing determined unnecessary");
                return 0;
index 8410865a1721d0f714a8a95a7e5659aedbe740b7..82723fe3a2fad91aefd685b49b220132b1786bea 100644 (file)
@@ -1257,7 +1257,7 @@ int mail_transaction_log_file_get_highest_modseq_at(
 
 static int
 get_modseq_next_offset_at(struct mail_transaction_log_file *file,
-                         uint64_t modseq,
+                         uint64_t modseq, bool use_highest,
                          uoff_t *cur_offset, uint64_t *cur_modseq,
                          uoff_t *next_offset_r)
 {
@@ -1279,7 +1279,7 @@ get_modseq_next_offset_at(struct mail_transaction_log_file *file,
        }
 
        /* check sync_highest_modseq again in case sync_offset was updated */
-       if (modseq >= file->sync_highest_modseq) {
+       if (modseq >= file->sync_highest_modseq && use_highest) {
                *next_offset_r = file->sync_offset;
                return 0;
        }
@@ -1332,16 +1332,30 @@ int mail_transaction_log_file_get_modseq_next_offset(
                cur_modseq = cache->highest_modseq;
        }
 
-       if ((ret = get_modseq_next_offset_at(file, modseq, &cur_offset,
+       if ((ret = get_modseq_next_offset_at(file, modseq, TRUE, &cur_offset,
                                             &cur_modseq, next_offset_r)) <= 0)
                return ret;
        if (cur_offset == file->sync_offset) {
                /* if we got to sync_offset, cur_modseq should be
                   sync_highest_modseq */
                mail_index_set_error(file->log->index,
-                       "%s: Transaction log changed unexpectedly, "
-                       "can't get modseq", file->filepath);
-               return -1;
+                       "%s: Transaction log modseq tracking is corrupted - fixing",
+                       file->filepath);
+               /* retry getting the offset by reading from the beginning
+                  of the file */
+               cur_offset = file->hdr.hdr_size;
+               cur_modseq = file->hdr.initial_modseq;
+               ret = get_modseq_next_offset_at(file, modseq, FALSE,
+                                               &cur_offset, &cur_modseq,
+                                               next_offset_r);
+               if (ret < 0)
+                       return -1;
+               i_assert(ret != 0);
+               /* get it fixed on the next sync */
+               file->log->index->need_recreate = TRUE;
+               file->need_rotate = TRUE;
+               /* clear cache, since it's unreliable */
+               memset(file->modseq_cache, 0, sizeof(file->modseq_cache));
        }
 
        /* @UNSAFE: cache the value */
index f56434b40155a005d7f1825a336786c363ea6980..cba0b6b5bc60f2886687b4494ba16b2cf7e97433 100644 (file)
@@ -81,6 +81,7 @@ struct mail_transaction_log_file {
        unsigned int locked:1;
        unsigned int locked_sync_offset_updated:1;
        unsigned int corrupted:1;
+       unsigned int need_rotate:1;
 };
 
 struct mail_transaction_log {
index 1738e367fc96150519471e456c7ffbadc70d32c9..16d301f3487fd6988bfcaf25b0b6540e406f7468 100644 (file)
@@ -234,6 +234,9 @@ bool mail_transaction_log_want_rotate(struct mail_transaction_log *log)
 {
        struct mail_transaction_log_file *file = log->head;
 
+       if (file->need_rotate)
+               return TRUE;
+
        if (file->hdr.major_version < MAIL_TRANSACTION_LOG_MAJOR_VERSION ||
            (file->hdr.major_version == MAIL_TRANSACTION_LOG_MAJOR_VERSION &&
             file->hdr.minor_version < MAIL_TRANSACTION_LOG_MINOR_VERSION)) {
index e69ce20131a82b1639df7eccbed9ac3268d7805b..e7af08219803f59d0e65a4b09064373dfd4fcd8b 100644 (file)
@@ -369,11 +369,43 @@ static void test_mail_transaction_log_file_modseq_offsets(void)
        test_end();
 }
 
+static void
+test_mail_transaction_log_file_get_modseq_next_offset_inconsistency(void)
+{
+       test_begin("mail_transaction_log_file_get_modseq_next_offset() inconsistency");
+
+       struct mail_index *index = test_mail_index_open();
+       struct mail_transaction_log_file *file = index->log->head;
+       uint32_t seq;
+
+       /* add modseq=2 */
+       struct mail_index_view *view = mail_index_view_open(index);
+       struct mail_index_transaction *trans =
+               mail_index_transaction_begin(view, 0);
+       mail_index_append(trans, 1, &seq);
+       test_assert(mail_index_transaction_commit(&trans) == 0);
+       mail_index_view_close(&view);
+
+       /* emulate a broken mail_index_modseq_header header */
+       file->sync_highest_modseq = 3;
+
+       uoff_t next_offset;
+       test_expect_error_string("Transaction log modseq tracking is corrupted");
+       test_assert(mail_transaction_log_file_get_modseq_next_offset(file, 2, &next_offset) == 0);
+       test_expect_no_more_errors();
+       test_assert(next_offset == file->sync_offset);
+
+       mail_index_close(index);
+       mail_index_free(&index);
+       test_end();
+}
+
 int main(void)
 {
        static void (*const test_functions[])(void) = {
                test_mail_transaction_update_modseq,
                test_mail_transaction_log_file_modseq_offsets,
+               test_mail_transaction_log_file_get_modseq_next_offset_inconsistency,
                NULL
        };
        ioloop_time = 1;