]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-index: mail_index_write() - Make sure index is rewritten after log rotation
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Mon, 10 Aug 2020 16:59:36 +0000 (19:59 +0300)
committertimo.sirainen <timo.sirainen@open-xchange.com>
Mon, 23 Nov 2020 13:19:54 +0000 (13:19 +0000)
Otherwise the index will point to .log.2 file, which could become deleted
before the index is rewritten again.

src/lib-index/Makefile.am
src/lib-index/mail-index-write.c
src/lib-index/test-mail-index-write.c [new file with mode: 0644]

index e1c5dbdc4529250657b542775f34df00c4414d97..b9d197c28bd5ae343bcd1d1d8d263f1c7bce95fc 100644 (file)
@@ -69,6 +69,7 @@ test_programs = \
        test-mail-index-sync-ext \
        test-mail-index-transaction-finish \
        test-mail-index-transaction-update \
+       test-mail-index-write \
        test-mail-transaction-log-append \
        test-mail-transaction-log-file \
        test-mail-transaction-log-view
@@ -114,6 +115,10 @@ test_mail_index_transaction_update_SOURCES = test-mail-index-transaction-update.
 test_mail_index_transaction_update_LDADD = mail-index-transaction-update.lo $(test_libs)
 test_mail_index_transaction_update_DEPENDENCIES = $(test_deps)
 
+test_mail_index_write_SOURCES = test-mail-index-write.c
+test_mail_index_write_LDADD = mail-index-write.lo $(test_libs)
+test_mail_index_write_DEPENDENCIES = $(test_deps)
+
 test_mail_transaction_log_append_SOURCES = test-mail-transaction-log-append.c
 test_mail_transaction_log_append_LDADD = mail-transaction-log-append.lo $(test_libs)
 test_mail_transaction_log_append_DEPENDENCIES = $(test_deps)
index 12bbb3904c7ca0e3b15a73c100b807d06dd719c0..6d2054b06dbb9ad22f6c338d0f48f4f2a2301648 100644 (file)
@@ -155,6 +155,7 @@ void mail_index_write(struct mail_index *index, bool want_rotate,
                      const char *reason)
 {
        struct mail_index_header *hdr = &index->map->hdr;
+       bool rotated = FALSE;
 
        i_assert(index->log_sync_locked);
 
@@ -184,12 +185,13 @@ void mail_index_write(struct mail_index *index, bool want_rotate,
                           wasn't, it just causes an extra stat() and gets
                           fixed later on. */
                        hdr->log2_rotate_time = ioloop_time;
+                       rotated = TRUE;
                }
        }
 
        if (MAIL_INDEX_IS_IN_MEMORY(index))
                ;
-       else if (!mail_index_should_recreate(index)) {
+       else if (!rotated && !mail_index_should_recreate(index)) {
                /* make sure we don't keep getting back in here */
                index->reopen_main_index = TRUE;
        } else {
diff --git a/src/lib-index/test-mail-index-write.c b/src/lib-index/test-mail-index-write.c
new file mode 100644 (file)
index 0000000..1559ab3
--- /dev/null
@@ -0,0 +1,148 @@
+/* Copyright (c) 2020 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "test-common.h"
+#include "mail-index-private.h"
+#include "mail-transaction-log-private.h"
+
+#define TEST_INDEX_FNAME ".test.index.write"
+#define TEST_INDEXID 123456
+#define LOG_FILE1_HEAD_OFFSET 200
+
+static bool expect_index_rewrite;
+static bool rotate_fail;
+
+static struct mail_transaction_log_file log_file = {
+       .hdr = {
+               .indexid = TEST_INDEXID,
+               .file_seq = 1,
+       },
+};
+static struct mail_transaction_log_file log_file2 = {
+       .hdr = {
+               .indexid = TEST_INDEXID,
+               .file_seq = 2,
+               .prev_file_seq = 1,
+               .prev_file_offset = LOG_FILE1_HEAD_OFFSET,
+       },
+};
+
+void mail_index_set_error(struct mail_index *index ATTR_UNUSED,
+                         const char *fmt ATTR_UNUSED, ...)
+{
+}
+
+void mail_index_set_syscall_error(struct mail_index *index ATTR_UNUSED,
+                                 const char *function)
+{
+       i_error("%s() failed: %m", function);
+}
+
+void mail_index_file_set_syscall_error(struct mail_index *index ATTR_UNUSED,
+                                      const char *filepath,
+                                      const char *function)
+{
+       i_error("%s(%s) failed: %m", function, filepath);
+}
+
+int mail_index_create_tmp_file(struct mail_index *index ATTR_UNUSED,
+                              const char *path_prefix, const char **path_r)
+{
+       const char *path;
+       int fd;
+
+       test_assert(expect_index_rewrite);
+
+       path = *path_r = t_strconcat(path_prefix, ".tmp", NULL);
+       fd = open(path, O_RDWR|O_CREAT, 0600);
+       if (fd == -1) {
+               i_error("creat() failed: %m");
+               return -1;
+       }
+       return fd;
+}
+
+int mail_index_move_to_memory(struct mail_index *index ATTR_UNUSED)
+{
+       return -1;
+}
+
+int mail_transaction_log_rotate(struct mail_transaction_log *log, bool reset)
+{
+       i_assert(!reset);
+
+       if (rotate_fail)
+               return -1;
+
+       log_file.next = &log_file2;
+       log->head = &log_file2;
+       return 0;
+}
+
+static void test_mail_index_write(void)
+{
+       struct mail_transaction_log log = {
+               .head = &log_file,
+               .files = &log_file,
+       };
+       struct mail_index_record_map rec_map = {
+               .records_count = 0,
+       };
+       struct mail_index_map map = {
+               .hdr = {
+                       .indexid = TEST_INDEXID,
+                       .log_file_seq = 1,
+                       .log_file_tail_offset = 100,
+                       .log_file_head_offset = LOG_FILE1_HEAD_OFFSET,
+               },
+               .rec_map = &rec_map,
+       };
+       struct mail_index index = {
+               .event = event_create(NULL),
+               .log = &log,
+               .map = &map,
+               .dir = ".",
+               .fd = -1,
+               .indexid = TEST_INDEXID,
+               .filepath = TEST_INDEX_FNAME,
+               .log_sync_locked = TRUE,
+       };
+
+       test_begin("test_mail_index_write()");
+
+       /* test failed rotation, no index rewrite */
+       rotate_fail = TRUE;
+       expect_index_rewrite = FALSE;
+       test_assert(!index.reopen_main_index);
+       index.fd = 1; /* anything but -1 */
+       mail_index_write(&index, TRUE, "testing");
+       test_assert(log.head == log.files);
+       test_assert(index.reopen_main_index);
+
+       /* test failed rotation, with index rewrite */
+       expect_index_rewrite = TRUE;
+       index.reopen_main_index = FALSE;
+       index.fd = -1;
+       mail_index_write(&index, TRUE, "testing");
+       test_assert(log.head == log.files);
+       test_assert(!index.reopen_main_index);
+
+       /* test successful rotation, with index rewrite */
+       rotate_fail = FALSE;
+       mail_index_write(&index, TRUE, "testing");
+       test_assert(log.head != log.files && log.head == &log_file2);
+       test_assert(!index.reopen_main_index);
+
+       event_unref(&index.event);
+       i_unlink(TEST_INDEX_FNAME);
+       test_end();
+}
+
+int main(void)
+{
+       static void (*const test_functions[])(void) = {
+               test_mail_index_write,
+               NULL
+       };
+       return test_run(test_functions);
+}