mail-transaction-log.c revision cca351db187fe92ec839b601a32e77eb63207a8d
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Copyright (c) 2003-2010 Dovecot authors, see the included COPYING file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "ioloop.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "buffer.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "file-dotlock.h"
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen#include "nfs-workarounds.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "close-keep-errno.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mmap-util.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mail-index-private.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mail-transaction-log-private.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <stddef.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <stdio.h>
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen#include <sys/stat.h>
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen#define LOG_NEW_DOTLOCK_SUFFIX ".newlock"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenmail_transaction_log_set_head(struct mail_transaction_log *log,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_transaction_log_file *file)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(log->head != file);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen file->refcount++;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen log->head = file;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(log->files != NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(log->files->next != NULL || log->files == file);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct mail_transaction_log *
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenmail_transaction_log_alloc(struct mail_index *index)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_transaction_log *log;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen log = i_new(struct mail_transaction_log, 1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen log->index = index;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen log->dotlock_settings.timeout = MAIL_TRANSCATION_LOG_LOCK_TIMEOUT;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen log->dotlock_settings.stale_timeout =
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen MAIL_TRANSCATION_LOG_LOCK_CHANGE_TIMEOUT;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen log->new_dotlock_settings = log->dotlock_settings;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen log->new_dotlock_settings.lock_suffix = LOG_NEW_DOTLOCK_SUFFIX;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return log;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainenstatic void mail_transaction_log_2_unlink_old(struct mail_transaction_log *log)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen struct stat st;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen if (stat(log->filepath2, &st) < 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (errno != ENOENT && errno != ESTALE) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_set_error(log->index,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "stat(%s) failed: %m", log->filepath2);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (st.st_mtime + MAIL_TRANSACTION_LOG2_STALE_SECS <= ioloop_time &&
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen !log->index->readonly) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (unlink(log->filepath2) < 0 && errno != ENOENT) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_set_error(log->index,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "unlink(%s) failed: %m", log->filepath2);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint mail_transaction_log_open(struct mail_transaction_log *log)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_transaction_log_file *file;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_free(log->filepath);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_free(log->filepath2);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen log->filepath = i_strconcat(log->index->filepath,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen MAIL_TRANSACTION_LOG_SUFFIX, NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen log->filepath2 = i_strconcat(log->filepath, ".2", NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen log->flags = log->index->flags;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen log->dotlock_settings.use_excl_lock =
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (log->flags & MAIL_INDEX_OPEN_FLAG_DOTLOCK_USE_EXCL) != 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen log->dotlock_settings.nfs_flush =
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (log->flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) != 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen log->new_dotlock_settings.use_excl_lock =
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (log->flags & MAIL_INDEX_OPEN_FLAG_DOTLOCK_USE_EXCL) != 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen log->new_dotlock_settings.nfs_flush =
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen (log->flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) != 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (log->open_file != NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_transaction_log_file_free(&log->open_file);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (MAIL_INDEX_IS_IN_MEMORY(log->index))
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
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 Sirainen log->open_file = file;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_transaction_log_set_head(log, file);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_transaction_log_2_unlink_old(log);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint mail_transaction_log_create(struct mail_transaction_log *log, bool reset)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_transaction_log_file *file;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (MAIL_INDEX_IS_IN_MEMORY(log->index)) {
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen file = mail_transaction_log_file_alloc_in_memory(log);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen mail_transaction_log_set_head(log, file);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen file = mail_transaction_log_file_alloc(log, log->filepath);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen if (log->open_file != NULL) {
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->st_ino = log->open_file->st_ino;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen file->st_dev = log->open_file->st_dev;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen file->last_size = log->open_file->last_size;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen file->last_mtime = log->open_file->last_mtime;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen mail_transaction_log_file_free(&log->open_file);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen }
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen if (mail_transaction_log_file_create(file, reset) < 0) {
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen mail_transaction_log_file_free(&file);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen return -1;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen mail_transaction_log_set_head(log, file);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen return 1;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen}
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainenvoid mail_transaction_log_close(struct mail_transaction_log *log)
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen{
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen mail_transaction_log_views_close(log);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen if (log->open_file != NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_transaction_log_file_free(&log->open_file);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (log->head != NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen log->head->refcount--;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen mail_transaction_logs_clean(log);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen i_assert(log->files == NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainenvoid mail_transaction_log_free(struct mail_transaction_log **_log)
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen{
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen struct mail_transaction_log *log = *_log;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen *_log = NULL;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen mail_transaction_log_close(log);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen log->index->log = NULL;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen i_free(log->filepath);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_free(log->filepath2);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_free(log);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen}
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainenvoid mail_transaction_log_move_to_memory(struct mail_transaction_log *log)
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_transaction_log_file *file;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen if (!log->index->initial_mapped && log->files != NULL &&
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen log->files->hdr.prev_file_seq != 0) {
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 mail_transaction_log_close(log);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen }
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen i_free(log->filepath);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen i_free(log->filepath2);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen log->filepath = i_strconcat(log->index->filepath,
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen MAIL_TRANSACTION_LOG_SUFFIX, NULL);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen log->filepath2 = i_strconcat(log->filepath, ".2", NULL);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen if (log->head != NULL)
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen mail_transaction_log_file_move_to_memory(log->head);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen else {
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen file = mail_transaction_log_file_alloc_in_memory(log);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen mail_transaction_log_set_head(log, file);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen }
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen}
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainenvoid mail_transaction_log_indexid_changed(struct mail_transaction_log *log)
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen{
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen struct mail_transaction_log_file *file;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen mail_transaction_logs_clean(log);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen for (file = log->files; file != NULL; file = file->next) {
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen if (file->hdr.indexid != log->index->indexid) {
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen mail_transaction_log_file_set_corrupted(file,
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen "indexid changed: %u -> %u",
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen file->hdr.indexid, log->index->indexid);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen }
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen }
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen if (log->head != NULL &&
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen log->head->hdr.indexid != log->index->indexid) {
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen if (--log->head->refcount == 0)
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen mail_transaction_log_file_free(&log->head);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen (void)mail_transaction_log_create(log, FALSE);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen }
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen}
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainenvoid mail_transaction_logs_clean(struct mail_transaction_log *log)
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen{
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen struct mail_transaction_log_file *file, *next;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
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 next = file->next;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen i_assert(file->refcount >= 0);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen if (file->refcount > 0)
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen break;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen mail_transaction_log_file_free(&file);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen }
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen /* if we still have locked files with refcount=0, unlock them */
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen for (; file != NULL; file = file->next) {
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen if (file->locked && file->refcount == 0)
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen mail_transaction_log_file_unlock(file);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(log->head == NULL || log->files != NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#define LOG_WANT_ROTATE(file) \
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (((file)->sync_offset > MAIL_TRANSACTION_LOG_ROTATE_MIN_SIZE && \
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen (time_t)(file)->hdr.create_stamp < \
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen ioloop_time - MAIL_TRANSACTION_LOG_ROTATE_TIME) || \
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen ((file)->sync_offset > MAIL_TRANSACTION_LOG_ROTATE_MAX_SIZE))
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainenbool mail_transaction_log_want_rotate(struct mail_transaction_log *log)
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen{
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen return LOG_WANT_ROTATE(log->head);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint mail_transaction_log_rotate(struct mail_transaction_log *log, bool reset)
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen{
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen struct mail_transaction_log_file *file;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen const char *path = log->head->filepath;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen struct stat st;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(log->head->locked);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (MAIL_INDEX_IS_IN_MEMORY(log->index)) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen file = mail_transaction_log_file_alloc_in_memory(log);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (reset) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen file->hdr.prev_file_seq = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen file->hdr.prev_file_offset = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen } else {
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen /* we're locked, we shouldn't need to worry about ESTALE
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen problems in here. */
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen if (fstat(log->head->fd, &st) < 0) {
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen mail_index_file_set_syscall_error(log->index,
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen log->head->filepath, "fstat()");
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen return -1;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen }
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen file = mail_transaction_log_file_alloc(log, path);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen file->st_dev = st.st_dev;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen file->st_ino = st.st_ino;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen file->last_mtime = st.st_mtime;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen file->last_size = st.st_size;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen if (mail_transaction_log_file_create(file, reset) < 0) {
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen mail_transaction_log_file_free(&file);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen return -1;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen if (--log->head->refcount == 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_transaction_logs_clean(log);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen mail_transaction_log_file_unlock(log->head);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen mail_transaction_log_set_head(log, file);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainenstatic int
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainenmail_transaction_log_refresh(struct mail_transaction_log *log, bool nfs_flush)
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen{
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen struct mail_transaction_log_file *file;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen struct stat st;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(log->head != NULL);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(log->head))
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen if (nfs_flush && (log->flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) != 0)
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen nfs_flush_file_handle_cache(log->filepath);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen if (nfs_safe_stat(log->filepath, &st) < 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (errno != ENOENT) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_file_set_syscall_error(log->index,
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen log->filepath,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "stat()");
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* see if the whole directory got deleted */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (nfs_safe_stat(log->index->dir, &st) < 0 &&
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen errno == ENOENT) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen log->index->index_deleted = TRUE;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen return -1;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen }
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
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 file = log->head;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (mail_transaction_log_create(log, FALSE) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(file->refcount > 0);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen file->refcount--;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen log->index->need_recreate = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else if (log->head->st_ino == st.st_ino &&
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen CMP_DEV_T(log->head->st_dev, st.st_dev)) {
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 return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen file = mail_transaction_log_file_alloc(log, log->filepath);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (mail_transaction_log_file_open(file, FALSE) <= 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_transaction_log_file_free(&file);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(!file->locked);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (--log->head->refcount == 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_transaction_logs_clean(log);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_transaction_log_set_head(log, file);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid mail_transaction_log_get_mailbox_sync_pos(struct mail_transaction_log *log,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint32_t *file_seq_r,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uoff_t *file_offset_r)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *file_seq_r = log->head->hdr.file_seq;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *file_offset_r = log->head->max_tail_offset;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid mail_transaction_log_set_mailbox_sync_pos(struct mail_transaction_log *log,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint32_t file_seq,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uoff_t file_offset)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(file_seq == log->head->hdr.file_seq);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(file_offset >= log->head->saved_tail_offset);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (file_offset >= log->head->max_tail_offset)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen log->head->max_tail_offset = file_offset;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint mail_transaction_log_find_file(struct mail_transaction_log *log,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint32_t file_seq, bool nfs_flush,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_transaction_log_file **file_r)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_transaction_log_file *file;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen int ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (file_seq > log->head->hdr.file_seq) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* see if the .log file has been recreated */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (log->head->locked) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* transaction log is locked. there's no way a newer
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen file exists. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (mail_transaction_log_refresh(log, FALSE) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (file_seq > log->head->hdr.file_seq) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!nfs_flush ||
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (log->flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) == 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* try again, this time flush attribute cache */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (mail_transaction_log_refresh(log, TRUE) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (file_seq > log->head->hdr.file_seq)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (file = log->files; file != NULL; file = file->next) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (file->hdr.file_seq == file_seq) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *file_r = file;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (MAIL_INDEX_IS_IN_MEMORY(log->index))
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
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 mail_transaction_log_file_free(&file);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* but is it what we expected? */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (file->hdr.file_seq != file_seq)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *file_r = file;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint mail_transaction_log_lock_head(struct mail_transaction_log *log)
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_transaction_log_file *file;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int ret = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
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 created.
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
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
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (;;) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen file = log->head;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (mail_transaction_log_file_lock(file) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen file->refcount++;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = mail_transaction_log_refresh(log, TRUE);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (--file->refcount == 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_transaction_logs_clean(log);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen file = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ret == 0 && log->head == file) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* success */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen break;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (file != NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_transaction_log_file_unlock(file);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ret < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen break;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* try again */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint mail_transaction_log_sync_lock(struct mail_transaction_log *log,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint32_t *file_seq_r, uoff_t *file_offset_r)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen i_assert(!log->index->log_locked);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen if (mail_transaction_log_lock_head(log) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen /* update sync_offset */
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen if (mail_transaction_log_file_map(log->head, log->head->sync_offset,
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen (uoff_t)-1) <= 0) {
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen mail_transaction_log_file_unlock(log->head);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen return -1;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen }
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen log->index->log_locked = TRUE;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen *file_seq_r = log->head->hdr.file_seq;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen *file_offset_r = log->head->sync_offset;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen return 0;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen}
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid mail_transaction_log_sync_unlock(struct mail_transaction_log *log)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(log->index->log_locked);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen log->index->log_locked = FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_transaction_log_file_unlock(log->head);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainenvoid mail_transaction_log_get_head(struct mail_transaction_log *log,
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen uint32_t *file_seq_r, uoff_t *file_offset_r)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen *file_seq_r = log->head->hdr.file_seq;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen *file_offset_r = log->head->sync_offset;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen}
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainenvoid mail_transaction_log_get_tail(struct mail_transaction_log *log,
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen uint32_t *file_seq_r)
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen{
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen struct mail_transaction_log_file *tail, *file = log->files;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
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 Sirainen tail = file->next;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen }
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen *file_seq_r = tail->hdr.file_seq;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen}
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainenbool mail_transaction_log_is_head_prev(struct mail_transaction_log *log,
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen uint32_t file_seq, uoff_t file_offset)
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen{
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen return log->head->hdr.prev_file_seq == file_seq &&
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen log->head->hdr.prev_file_offset == file_offset;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen}
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainenint mail_transaction_log_get_mtime(struct mail_transaction_log *log,
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen time_t *mtime_r)
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen{
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen struct stat st;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *mtime_r = 0;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen if (stat(log->filepath, &st) < 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (errno == ENOENT)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_file_set_syscall_error(log->index, log->filepath,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "stat()");
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen return -1;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *mtime_r = st.st_mtime;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen}
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen