mail-transaction-log.c revision 437b1d7e0a91ed93ff66a9056d0aac16ae23603c
5e0ce63bb65db34d7f48b34bbb5545fa791781c4Timo Sirainen/* Copyright (C) 2003-2007 Timo Sirainen */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "lib.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "ioloop.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "buffer.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "file-dotlock.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "nfs-workarounds.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "close-keep-errno.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "mmap-util.h"
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen#include "mail-index-private.h"
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen#include "mail-transaction-log-private.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include <stddef.h>
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include <stdio.h>
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include <sys/stat.h>
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen/* this lock should never exist for a long time.. */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#define LOG_DOTLOCK_TIMEOUT 60
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#define LOG_DOTLOCK_STALE_TIMEOUT 60
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#define MAIL_TRANSACTION_LOG_SUFFIX ".log"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#define LOG_NEW_DOTLOCK_SUFFIX ".newlock"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic void
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenmail_transaction_log_set_head(struct mail_transaction_log *log,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct mail_transaction_log_file *file)
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_assert(log->head != file);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen file->refcount++;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen log->head = file;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstruct mail_transaction_log *
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenmail_transaction_log_alloc(struct mail_index *index)
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct mail_transaction_log *log;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen log = i_new(struct mail_transaction_log, 1);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen log->index = index;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen log->dotlock_settings.use_excl_lock = index->use_excl_dotlocks;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen log->dotlock_settings.timeout = LOG_DOTLOCK_TIMEOUT;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen log->dotlock_settings.stale_timeout = LOG_DOTLOCK_STALE_TIMEOUT;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen log->new_dotlock_settings = log->dotlock_settings;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen log->new_dotlock_settings.lock_suffix = LOG_NEW_DOTLOCK_SUFFIX;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return log;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenint mail_transaction_log_open(struct mail_transaction_log *log)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct mail_transaction_log_file *file;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen const char *path;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen int ret;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (log->open_file != NULL)
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen mail_transaction_log_file_free(&log->open_file);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
03f5c621d06d6b6d77a145196c9633a7aa64dc78Timo Sirainen if (MAIL_INDEX_IS_IN_MEMORY(log->index))
03f5c621d06d6b6d77a145196c9633a7aa64dc78Timo Sirainen return 0;
03f5c621d06d6b6d77a145196c9633a7aa64dc78Timo Sirainen
03f5c621d06d6b6d77a145196c9633a7aa64dc78Timo Sirainen path = t_strconcat(log->index->filepath,
03f5c621d06d6b6d77a145196c9633a7aa64dc78Timo Sirainen MAIL_TRANSACTION_LOG_SUFFIX, NULL);
03f5c621d06d6b6d77a145196c9633a7aa64dc78Timo Sirainen
03f5c621d06d6b6d77a145196c9633a7aa64dc78Timo Sirainen file = mail_transaction_log_file_alloc(log, path);
03f5c621d06d6b6d77a145196c9633a7aa64dc78Timo Sirainen if ((ret = mail_transaction_log_file_open(file, FALSE)) <= 0) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* leave the file for _create() */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen log->open_file = file;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen return ret;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
f923659c0e5298263d80622c99f4dc4132b4675bTimo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mail_transaction_log_set_head(log, file);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return 1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenint mail_transaction_log_create(struct mail_transaction_log *log)
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct mail_transaction_log_file *file;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen const char *path;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
af81f402ddc897c74c1e85abd02879612ce44882Timo Sirainen if (MAIL_INDEX_IS_IN_MEMORY(log->index)) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen file = mail_transaction_log_file_alloc_in_memory(log);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen mail_transaction_log_set_head(log, file);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen path = t_strconcat(log->index->filepath,
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen MAIL_TRANSACTION_LOG_SUFFIX, NULL);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen file = mail_transaction_log_file_alloc(log, path);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (log->open_file != NULL) {
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* remember what file we tried to open. if someone else created
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen a new file, use it instead of recreating it */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen file->st_ino = log->open_file->st_ino;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen file->st_dev = log->open_file->st_dev;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen file->last_size = log->open_file->last_size;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen file->last_mtime = log->open_file->last_mtime;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mail_transaction_log_file_free(&log->open_file);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (mail_transaction_log_file_create(file) < 0)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mail_transaction_log_file_free(&file);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mail_transaction_log_set_head(log, file);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return 1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenvoid mail_transaction_log_close(struct mail_transaction_log *log)
b3142c8e513bc78da821fa70f479016148fa95e5Timo Sirainen{
af81f402ddc897c74c1e85abd02879612ce44882Timo Sirainen mail_transaction_log_views_close(log);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (log->open_file != NULL)
b3142c8e513bc78da821fa70f479016148fa95e5Timo Sirainen mail_transaction_log_file_free(&log->open_file);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (log->head != NULL)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen log->head->refcount--;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mail_transaction_logs_clean(log);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_assert(log->files == NULL);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenvoid mail_transaction_log_free(struct mail_transaction_log **_log)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct mail_transaction_log *log = *_log;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen *_log = NULL;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mail_transaction_log_close(log);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen log->index->log = NULL;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_free(log);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen}
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenvoid mail_transaction_log_move_to_memory(struct mail_transaction_log *log)
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (log->head != NULL)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mail_transaction_log_file_move_to_memory(log->head);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen}
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenvoid mail_transaction_logs_clean(struct mail_transaction_log *log)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct mail_transaction_log_file *file, *next;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen for (file = log->files; file != NULL; file = next) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen next = file->next;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
b3142c8e513bc78da821fa70f479016148fa95e5Timo Sirainen i_assert(file->refcount >= 0);
b3142c8e513bc78da821fa70f479016148fa95e5Timo Sirainen if (file->refcount == 0)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mail_transaction_log_file_free(&file);
b3142c8e513bc78da821fa70f479016148fa95e5Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#define LOG_WANT_ROTATE(file) \
b3142c8e513bc78da821fa70f479016148fa95e5Timo Sirainen (((file)->sync_offset > MAIL_TRANSACTION_LOG_ROTATE_MIN_SIZE && \
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen (time_t)(file)->hdr.create_stamp < \
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ioloop_time - MAIL_TRANSACTION_LOG_ROTATE_TIME) || \
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ((file)->sync_offset > MAIL_TRANSACTION_LOG_ROTATE_MAX_SIZE))
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenbool mail_transaction_log_want_rotate(struct mail_transaction_log *log)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return LOG_WANT_ROTATE(log->head);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen}
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenint mail_transaction_log_rotate(struct mail_transaction_log *log)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct mail_transaction_log_file *file;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen const char *path = log->head->filepath;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct stat st;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_assert(log->head->locked);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
03f5c621d06d6b6d77a145196c9633a7aa64dc78Timo Sirainen if (MAIL_INDEX_IS_IN_MEMORY(log->index))
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen file = mail_transaction_log_file_alloc_in_memory(log);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen else {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* we're locked, we shouldn't need to worry about ESTALE
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen problems in here. */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (fstat(log->head->fd, &st) < 0) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mail_index_file_set_syscall_error(log->index,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen file->filepath, "fstat()");
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return -1;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen file = mail_transaction_log_file_alloc(log, path);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen file->st_dev = st.st_dev;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen file->st_ino = st.st_ino;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen file->last_mtime = st.st_mtime;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen file->last_size = st.st_size;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (mail_transaction_log_file_create(file) < 0) {
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen mail_transaction_log_file_free(&file);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return -1;
03f5c621d06d6b6d77a145196c9633a7aa64dc78Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (--log->head->refcount == 0)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mail_transaction_logs_clean(log);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen else
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mail_transaction_log_file_unlock(log->head);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mail_transaction_log_set_head(log, file);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenstatic int mail_transaction_log_refresh(struct mail_transaction_log *log)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen struct mail_transaction_log_file *file;
03f5c621d06d6b6d77a145196c9633a7aa64dc78Timo Sirainen struct stat st;
03f5c621d06d6b6d77a145196c9633a7aa64dc78Timo Sirainen const char *path;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
i_assert(log->head != NULL);
if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(log->head))
return 0;
path = t_strconcat(log->index->filepath,
MAIL_TRANSACTION_LOG_SUFFIX, NULL);
if (nfs_safe_stat(path, &st) < 0) {
if (errno != ENOENT) {
mail_index_file_set_syscall_error(log->index, path,
"stat()");
return -1;
}
return -1;
} else {
if (log->head->st_ino == st.st_ino &&
CMP_DEV_T(log->head->st_dev, st.st_dev)) {
/* same file */
return 0;
}
}
file = mail_transaction_log_file_alloc(log, path);
if (mail_transaction_log_file_open(file, FALSE) <= 0) {
mail_transaction_log_file_free(&file);
return -1;
}
i_assert(!file->locked);
if (--log->head->refcount == 0)
mail_transaction_logs_clean(log);
mail_transaction_log_set_head(log, file);
return 0;
}
void mail_transaction_log_get_mailbox_sync_pos(struct mail_transaction_log *log,
uint32_t *file_seq_r,
uoff_t *file_offset_r)
{
*file_seq_r = log->head->hdr.file_seq;
*file_offset_r = log->head->mailbox_sync_max_offset;
}
void mail_transaction_log_set_mailbox_sync_pos(struct mail_transaction_log *log,
uint32_t file_seq,
uoff_t file_offset)
{
i_assert(file_seq == log->head->hdr.file_seq);
i_assert(file_offset >= log->head->mailbox_sync_saved_offset);
if (file_offset >= log->head->mailbox_sync_max_offset)
log->head->mailbox_sync_max_offset = file_offset;
}
int mail_transaction_log_find_file(struct mail_transaction_log *log,
uint32_t file_seq,
struct mail_transaction_log_file **file_r)
{
struct mail_transaction_log_file *file;
const char *path;
int ret;
if (file_seq > log->head->hdr.file_seq) {
/* see if the .log file has been recreated */
if (log->head->locked) {
/* transaction log is locked. there's no way a newer
file exists. */
return 0;
}
if (mail_transaction_log_refresh(log) < 0)
return -1;
if (file_seq > log->head->hdr.file_seq)
return 0;
}
for (file = log->files; file != NULL; file = file->next) {
if (file->hdr.file_seq == file_seq) {
*file_r = file;
return 1;
}
}
if (MAIL_INDEX_IS_IN_MEMORY(log->index))
return 0;
/* see if we have it in log.2 file */
path = t_strconcat(log->index->filepath,
MAIL_TRANSACTION_LOG_SUFFIX".2", NULL);
file = mail_transaction_log_file_alloc(log, path);
if ((ret = mail_transaction_log_file_open(file, TRUE)) <= 0)
return ret;
/* but is it what we expected? */
if (file->hdr.file_seq != file_seq)
return 0;
*file_r = file;
return 1;
}
int mail_transaction_log_lock_head(struct mail_transaction_log *log)
{
struct mail_transaction_log_file *file;
int ret = 0;
/* we want to get the head file locked. this is a bit racy,
since by the time we have it locked a new log file may have been
created.
creating new log file requires locking the head file, so if we
can lock it and don't see another file, we can be sure no-one is
creating a new log at the moment */
for (;;) {
file = log->head;
if (mail_transaction_log_file_lock(file) < 0)
return -1;
file->refcount++;
ret = mail_transaction_log_refresh(log);
if (--file->refcount == 0) {
mail_transaction_logs_clean(log);
file = NULL;
}
if (ret == 0 && log->head == file) {
/* success */
break;
}
if (file != NULL)
mail_transaction_log_file_unlock(file);
if (ret < 0)
break;
/* try again */
}
return ret;
}
int mail_transaction_log_sync_lock(struct mail_transaction_log *log,
uint32_t *file_seq_r, uoff_t *file_offset_r)
{
i_assert(!log->index->log_locked);
if (mail_transaction_log_lock_head(log) < 0)
return -1;
/* update sync_offset */
if (mail_transaction_log_file_map(log->head, log->head->sync_offset,
(uoff_t)-1) <= 0) {
mail_transaction_log_file_unlock(log->head);
return -1;
}
log->index->log_locked = TRUE;
*file_seq_r = log->head->hdr.file_seq;
*file_offset_r = log->head->sync_offset;
return 0;
}
void mail_transaction_log_sync_unlock(struct mail_transaction_log *log)
{
i_assert(log->index->log_locked);
log->index->log_locked = FALSE;
mail_transaction_log_file_unlock(log->head);
}
void mail_transaction_log_get_head(struct mail_transaction_log *log,
uint32_t *file_seq_r, uoff_t *file_offset_r)
{
i_assert(log->index->log_locked);
*file_seq_r = log->head->hdr.file_seq;
*file_offset_r = log->head->sync_offset;
}
bool mail_transaction_log_is_head_prev(struct mail_transaction_log *log,
uint32_t file_seq, uoff_t file_offset)
{
return log->head->hdr.prev_file_seq == file_seq &&
log->head->hdr.prev_file_offset == file_offset;
}