]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-index: Fix checking if log file can be rotated
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Sat, 5 Oct 2019 12:46:47 +0000 (15:46 +0300)
committerVille Savolainen <ville.savolainen@dovecot.fi>
Mon, 7 Oct 2019 09:54:47 +0000 (12:54 +0300)
This fixes a bug caused by 883a3022992d0f832f0aff21572caeb7c63b7668 where
dovecot.index.log file wasn't rotated as often as it was supposed to be. It
also could have caused dovecot.index to be rewritten much more often than
it was supposed to be.

The buggy commit was correct that the tail_offset wasn't updated previously
to the dovecot.index.log file after changes. However, I didn't realize that
the tail_offset was internally still updated and required by this rotation
check to work correctly.

The fix works by relaxing the tail_offset==head_offset requirement for
rotation. It's enough that all the changes are synced, which can be checked
from mail_index_sync_ctx.fully_synced. Any changes after tail_offset are
then supposed to be external transactions, which aren't synced anyway, so
rotation is allowed.

src/lib-index/mail-index-sync.c
src/lib-index/mail-index-write.c

index 641ab7be6fba82dc753501b544978e9c2a03dda0..55d56ca355219bcb008f83dd25a119d6fb1f86d2 100644 (file)
@@ -949,7 +949,14 @@ int mail_index_sync_commit(struct mail_index_sync_ctx **_ctx)
                }
        }
 
-       want_rotate = mail_transaction_log_want_rotate(index->log);
+       /* Log rotation is allowed only if everything was synced. Note that
+          tail_offset might not equal head_offset here, because
+          mail_index_sync_update_mailbox_offset() doesn't always update
+          tail_offset to skip over other committed external transactions.
+          However, it's still safe to do the rotation because external
+          transactions don't require syncing. */
+       want_rotate = ctx->fully_synced &&
+               mail_transaction_log_want_rotate(index->log);
        if (ret == 0 &&
            (want_rotate || mail_index_sync_want_index_write(index))) {
                index->need_recreate = FALSE;
index 0c3bfcdd54a72cc7664366a9e8a6c30d8463afa0..473c4e1805fb9790ba746d6f6f2142a62c1f3d87 100644 (file)
@@ -126,10 +126,10 @@ void mail_index_write(struct mail_index *index, bool want_rotate)
                return;
 
        /* rotate the .log before writing index, so the index will point to
-          the latest log. */
-       if (want_rotate &&
-           hdr->log_file_seq == index->log->head->hdr.file_seq &&
-           hdr->log_file_tail_offset == hdr->log_file_head_offset) {
+          the latest log. Note that it's the caller's responsibility to make
+          sure that the .log can be safely rotated (i.e. everything has been
+          synced). */
+       if (want_rotate) {
                if (mail_transaction_log_rotate(index->log, FALSE) == 0) {
                        struct mail_transaction_log_file *file =
                                index->log->head;