Mercurial > dovecot > core-2.2
changeset 22430:2d9175af5c99
lib-index: Fix wrong mail_index_modseq_header automatically
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.
author | Timo Sirainen <timo.sirainen@dovecot.fi> |
---|---|
date | Tue, 08 Aug 2017 16:56:02 +0300 |
parents | 3ba9331e880d |
children | 691b5466edb3 |
files | 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 |
diffstat | 5 files changed, 57 insertions(+), 7 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib-index/mail-index-sync.c Tue Aug 08 16:54:42 2017 +0300 +++ b/src/lib-index/mail-index-sync.c Tue Aug 08 16:56:02 2017 +0300 @@ -361,7 +361,7 @@ } 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;
--- a/src/lib-index/mail-transaction-log-file.c Tue Aug 08 16:54:42 2017 +0300 +++ b/src/lib-index/mail-transaction-log-file.c Tue Aug 08 16:56:02 2017 +0300 @@ -1257,7 +1257,7 @@ 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 @@ } /* 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 @@ 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 */
--- a/src/lib-index/mail-transaction-log-private.h Tue Aug 08 16:54:42 2017 +0300 +++ b/src/lib-index/mail-transaction-log-private.h Tue Aug 08 16:56:02 2017 +0300 @@ -81,6 +81,7 @@ unsigned int locked:1; unsigned int locked_sync_offset_updated:1; unsigned int corrupted:1; + unsigned int need_rotate:1; }; struct mail_transaction_log {
--- a/src/lib-index/mail-transaction-log.c Tue Aug 08 16:54:42 2017 +0300 +++ b/src/lib-index/mail-transaction-log.c Tue Aug 08 16:56:02 2017 +0300 @@ -234,6 +234,9 @@ { 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)) {
--- a/src/lib-index/test-mail-transaction-log-file.c Tue Aug 08 16:54:42 2017 +0300 +++ b/src/lib-index/test-mail-transaction-log-file.c Tue Aug 08 16:56:02 2017 +0300 @@ -369,11 +369,43 @@ 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;