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