mail-transaction-log.c revision 036626b19f14bef582f96e556913ae91b1d67881
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2003-2010 Dovecot authors, see the included COPYING file */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenmail_transaction_log_set_head(struct mail_transaction_log *log,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_assert(log->files->next != NULL || log->files == file);
4db61af2cfe2b206113bcc4b6153521679702bb4Timo Sirainenmail_transaction_log_alloc(struct mail_index *index)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen log->new_dotlock_settings = log->dotlock_settings;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen log->new_dotlock_settings.lock_suffix = LOG_NEW_DOTLOCK_SUFFIX;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic void mail_transaction_log_2_unlink_old(struct mail_transaction_log *log)
f0e416aa42058e7ccc0dc6deec0d4f4a19ee6ebeTimo Sirainen if (st.st_mtime + MAIL_TRANSACTION_LOG2_STALE_SECS <= ioloop_time &&
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (unlink(log->filepath2) < 0 && errno != ENOENT) {
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainenint mail_transaction_log_open(struct mail_transaction_log *log)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen log->filepath = i_strconcat(log->index->filepath,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen log->filepath2 = i_strconcat(log->filepath, ".2", NULL);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen (log->flags & MAIL_INDEX_OPEN_FLAG_DOTLOCK_USE_EXCL) != 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen (log->flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) != 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen (log->flags & MAIL_INDEX_OPEN_FLAG_DOTLOCK_USE_EXCL) != 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen (log->flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) != 0;
2ccb478c35972517721ce415d81fcbd11a73fad3Timo Sirainen mail_transaction_log_file_free(&log->open_file);
61f39b0358a72ebc693d84ba5bac74489ee7df41Timo Sirainen file = mail_transaction_log_file_alloc(log, log->filepath);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if ((ret = mail_transaction_log_file_open(file, FALSE)) <= 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* leave the file for _create() */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenint mail_transaction_log_create(struct mail_transaction_log *log, bool reset)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen file = mail_transaction_log_file_alloc_in_memory(log);
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen file = mail_transaction_log_file_alloc(log, log->filepath);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* remember what file we tried to open. if someone else created
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen a new file, use it instead of recreating it */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen file->last_mtime = log->open_file->last_mtime;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen mail_transaction_log_file_free(&log->open_file);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (mail_transaction_log_file_create(file, reset) < 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenvoid mail_transaction_log_close(struct mail_transaction_log *log)
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen mail_transaction_log_file_free(&log->open_file);
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainenvoid mail_transaction_log_free(struct mail_transaction_log **_log)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenvoid mail_transaction_log_move_to_memory(struct mail_transaction_log *log)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (!log->index->initial_mapped && log->files != NULL &&
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* we couldn't read dovecot.index and we don't have the first
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen .log file, so just start from scratch */
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen log->filepath = i_strconcat(log->index->filepath,
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen log->filepath2 = i_strconcat(log->filepath, ".2", NULL);
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen mail_transaction_log_file_move_to_memory(log->head);
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen file = mail_transaction_log_file_alloc_in_memory(log);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenvoid mail_transaction_log_indexid_changed(struct mail_transaction_log *log)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen for (file = log->files; file != NULL; file = file->next) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (file->hdr.indexid != log->index->indexid) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen "indexid changed: %u -> %u",
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen log->head->hdr.indexid != log->index->indexid) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen (void)mail_transaction_log_create(log, FALSE);
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainenvoid mail_transaction_logs_clean(struct mail_transaction_log *log)
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen struct mail_transaction_log_file *file, *next;
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen /* remove only files from the beginning. this way if a view has
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen referenced an old file, it can still find the new files even if
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen there aren't any references to it currently. */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen for (file = log->files; file != NULL; file = next) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* if we still have locked files with refcount=0, unlock them */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_assert(log->head == NULL || log->files != NULL);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen (((file)->sync_offset > MAIL_TRANSACTION_LOG_ROTATE_MIN_SIZE && \
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ioloop_time - MAIL_TRANSACTION_LOG_ROTATE_TIME) || \
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ((file)->sync_offset > MAIL_TRANSACTION_LOG_ROTATE_MAX_SIZE))
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenbool mail_transaction_log_want_rotate(struct mail_transaction_log *log)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenint mail_transaction_log_rotate(struct mail_transaction_log *log, bool reset)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen file = mail_transaction_log_file_alloc_in_memory(log);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* we're locked, we shouldn't need to worry about ESTALE
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen problems in here. */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen file = mail_transaction_log_file_alloc(log, path);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (mail_transaction_log_file_create(file, reset) < 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenmail_transaction_log_refresh(struct mail_transaction_log *log, bool nfs_flush)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(log->head))
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (nfs_flush && (log->flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) != 0)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* see if the whole directory got deleted */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (nfs_safe_stat(log->index->dir, &st) < 0 &&
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* the file should always exist at this point. if it doesn't,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen someone deleted it manually while the index was open. try to
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen handle this nicely by creating a new log file. */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (mail_transaction_log_create(log, FALSE) < 0)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* NFS: log files get rotated to .log.2 files instead
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen of being unlinked, so we don't bother checking if
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen the existing file has already been unlinked here
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen (in which case inodes could match but point to
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen different files) */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen file = mail_transaction_log_file_alloc(log, log->filepath);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (mail_transaction_log_file_open(file, FALSE) <= 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenvoid mail_transaction_log_get_mailbox_sync_pos(struct mail_transaction_log *log,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenvoid mail_transaction_log_set_mailbox_sync_pos(struct mail_transaction_log *log,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_assert(file_seq == log->head->hdr.file_seq);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_assert(file_offset >= log->head->saved_tail_offset);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (file_offset >= log->head->max_tail_offset)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenint mail_transaction_log_find_file(struct mail_transaction_log *log,
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen /* see if the .log file has been recreated */
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen /* transaction log is locked. there's no way a newer
6ea145a99eeee923602f04d3c9183bbdba6cd190Timo Sirainen file exists. */
7cd055a212d44067e2d94452c05691d696c9f699Timo Sirainen if (mail_transaction_log_refresh(log, FALSE) < 0)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen (log->flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) == 0)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* try again, this time flush attribute cache */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (mail_transaction_log_refresh(log, TRUE) < 0)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen for (file = log->files; file != NULL; file = file->next) {
c72cfe4a2bda39fff3b8a8bd64b31a7cc14d7d11Timo Sirainen /* see if we have it in log.2 file */
c72cfe4a2bda39fff3b8a8bd64b31a7cc14d7d11Timo Sirainen file = mail_transaction_log_file_alloc(log, log->filepath2);
c72cfe4a2bda39fff3b8a8bd64b31a7cc14d7d11Timo Sirainen if ((ret = mail_transaction_log_file_open(file, TRUE)) <= 0) {
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen /* but is it what we expected? */
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainenint mail_transaction_log_lock_head(struct mail_transaction_log *log)
4db61af2cfe2b206113bcc4b6153521679702bb4Timo Sirainen /* we want to get the head file locked. this is a bit racy,
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen since by the time we have it locked a new log file may have been
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen creating new log file requires locking the head file, so if we
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen can lock it and don't see another file, we can be sure no-one is
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen creating a new log at the moment */
f7d018e7e0980044e3d537958126e44ef4c45056Timo Sirainen ret = mail_transaction_log_refresh(log, TRUE);
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen /* success */
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen /* try again */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenint mail_transaction_log_sync_lock(struct mail_transaction_log *log,
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen /* update sync_offset */
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen if (mail_transaction_log_file_map(log->head, log->head->sync_offset,
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainenvoid mail_transaction_log_sync_unlock(struct mail_transaction_log *log)
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainenvoid mail_transaction_log_get_head(struct mail_transaction_log *log,
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainenvoid mail_transaction_log_get_tail(struct mail_transaction_log *log,
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen struct mail_transaction_log_file *tail, *file = log->files;
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen for (tail = file; file->next != NULL; file = file->next) {
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen if (file->hdr.file_seq + 1 != file->next->hdr.file_seq)
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainenbool mail_transaction_log_is_head_prev(struct mail_transaction_log *log,
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen return log->head->hdr.prev_file_seq == file_seq &&
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen log->head->hdr.prev_file_offset == file_offset;
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainenint mail_transaction_log_get_mtime(struct mail_transaction_log *log,