mail-transaction-log.c revision 6f90ce01176bd920609d9d12e6419b9ba27c1359
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin/* Copyright (c) 2003-2009 Dovecot authors, see the included COPYING file */
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin#include "lib.h"
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin#include "ioloop.h"
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin#include "buffer.h"
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin#include "file-dotlock.h"
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin#include "nfs-workarounds.h"
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin#include "close-keep-errno.h"
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin#include "mmap-util.h"
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin#include "mail-index-private.h"
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin#include "mail-transaction-log-private.h"
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin#include <stddef.h>
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin#include <stdio.h>
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin#include <sys/stat.h>
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin#define LOG_NEW_DOTLOCK_SUFFIX ".newlock"
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalinstatic void
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalinmail_transaction_log_set_head(struct mail_transaction_log *log,
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin struct mail_transaction_log_file *file)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin{
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin i_assert(log->head != file);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin file->refcount++;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin log->head = file;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin i_assert(log->files != NULL);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin i_assert(log->files->next != NULL || log->files == file);
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin}
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalinstruct mail_transaction_log *
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalinmail_transaction_log_alloc(struct mail_index *index)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin{
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin struct mail_transaction_log *log;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin log = i_new(struct mail_transaction_log, 1);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin log->index = index;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin log->dotlock_settings.use_excl_lock = index->use_excl_dotlocks;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin log->dotlock_settings.nfs_flush = index->nfs_flush;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin log->dotlock_settings.timeout = MAIL_TRANSCATION_LOG_LOCK_TIMEOUT;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin log->dotlock_settings.stale_timeout =
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin MAIL_TRANSCATION_LOG_LOCK_CHANGE_TIMEOUT;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin log->new_dotlock_settings = log->dotlock_settings;
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin log->new_dotlock_settings.lock_suffix = LOG_NEW_DOTLOCK_SUFFIX;
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin return log;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin}
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalinstatic void mail_transaction_log_2_unlink_old(struct mail_transaction_log *log)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin{
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin struct stat st;
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin const char *path;
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin path = t_strconcat(log->index->filepath,
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin MAIL_TRANSACTION_LOG_SUFFIX".2", NULL);
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin if (stat(path, &st) < 0) {
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin if (errno != ENOENT && errno != ESTALE) {
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin mail_index_set_error(log->index,
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin "stat(%s) failed: %m", path);
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin }
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin return;
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin }
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin if (st.st_mtime + MAIL_TRANSACTION_LOG2_STALE_SECS <= ioloop_time) {
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin if (unlink(path) < 0 && errno != ENOENT) {
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin mail_index_set_error(log->index,
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin "unlink(%s) failed: %m", path);
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin }
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin }
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin}
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalinint mail_transaction_log_open(struct mail_transaction_log *log)
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin{
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin struct mail_transaction_log_file *file;
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin const char *path;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin int ret;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (log->open_file != NULL)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin mail_transaction_log_file_free(&log->open_file);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (MAIL_INDEX_IS_IN_MEMORY(log->index))
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin return 0;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin path = t_strconcat(log->index->filepath,
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin MAIL_TRANSACTION_LOG_SUFFIX, NULL);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin file = mail_transaction_log_file_alloc(log, path);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if ((ret = mail_transaction_log_file_open(file, FALSE)) <= 0) {
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin /* leave the file for _create() */
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin log->open_file = file;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin return ret;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin }
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin mail_transaction_log_set_head(log, file);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin mail_transaction_log_2_unlink_old(log);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin return 1;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin}
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalinint mail_transaction_log_create(struct mail_transaction_log *log, bool reset)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin{
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin struct mail_transaction_log_file *file;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin const char *path;
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin if (MAIL_INDEX_IS_IN_MEMORY(log->index)) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin file = mail_transaction_log_file_alloc_in_memory(log);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin mail_transaction_log_set_head(log, file);
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin return 0;
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin }
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin path = t_strconcat(log->index->filepath,
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin MAIL_TRANSACTION_LOG_SUFFIX, NULL);
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin file = mail_transaction_log_file_alloc(log, path);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (log->open_file != NULL) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin /* remember what file we tried to open. if someone else created
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin a new file, use it instead of recreating it */
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin file->st_ino = log->open_file->st_ino;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin file->st_dev = log->open_file->st_dev;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin file->last_size = log->open_file->last_size;
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin file->last_mtime = log->open_file->last_mtime;
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin mail_transaction_log_file_free(&log->open_file);
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin }
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin if (mail_transaction_log_file_create(file, reset) < 0) {
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin mail_transaction_log_file_free(&file);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin return -1;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin }
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin mail_transaction_log_set_head(log, file);
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin return 1;
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin}
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalinvoid mail_transaction_log_close(struct mail_transaction_log *log)
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin{
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin mail_transaction_log_views_close(log);
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (log->open_file != NULL)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin mail_transaction_log_file_free(&log->open_file);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (log->head != NULL)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin log->head->refcount--;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin mail_transaction_logs_clean(log);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin i_assert(log->files == NULL);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin}
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalinvoid mail_transaction_log_free(struct mail_transaction_log **_log)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin{
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin struct mail_transaction_log *log = *_log;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin *_log = NULL;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin mail_transaction_log_close(log);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin log->index->log = NULL;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin i_free(log);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin}
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalinvoid mail_transaction_log_move_to_memory(struct mail_transaction_log *log)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin{
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin struct mail_transaction_log_file *file;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (!log->index->initial_mapped && log->files != NULL &&
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin log->files->hdr.prev_file_seq != 0) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin /* we couldn't read dovecot.index and we don't have the first
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin .log file, so just start from scratch */
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin mail_transaction_log_close(log);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin }
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (log->head != NULL)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin mail_transaction_log_file_move_to_memory(log->head);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin else {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin file = mail_transaction_log_file_alloc_in_memory(log);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin mail_transaction_log_set_head(log, file);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin }
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin}
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalinvoid mail_transaction_log_indexid_changed(struct mail_transaction_log *log)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin{
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin struct mail_transaction_log_file *file;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin mail_transaction_logs_clean(log);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin for (file = log->files; file != NULL; file = file->next) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (file->hdr.indexid != log->index->indexid) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin mail_transaction_log_file_set_corrupted(file,
44d397891e691ab994a69766cc72e57265b62da1Serge Hallyn "indexid changed: %u -> %u",
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin file->hdr.indexid, log->index->indexid);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin }
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin }
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (log->head != NULL &&
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin log->head->hdr.indexid != log->index->indexid) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (--log->head->refcount == 0)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin mail_transaction_log_file_free(&log->head);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin (void)mail_transaction_log_create(log, FALSE);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin }
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin}
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalinvoid mail_transaction_logs_clean(struct mail_transaction_log *log)
add1d11833394aaa3a3497c2fdf548e5b14c80d4Serge Hallyn{
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin struct mail_transaction_log_file *file, *next;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin /* remove only files from the beginning. this way if a view has
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin referenced an old file, it can still find the new files even if
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin there aren't any references to it currently. */
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin for (file = log->files; file != NULL; file = next) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin next = file->next;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin i_assert(file->refcount >= 0);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (file->refcount > 0)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin break;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin mail_transaction_log_file_free(&file);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin }
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin /* if we still have locked files with refcount=0, unlock them */
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin for (; file != NULL; file = file->next) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (file->locked && file->refcount == 0)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin mail_transaction_log_file_unlock(file);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin }
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin i_assert(log->head == NULL || log->files != NULL);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin}
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin#define LOG_WANT_ROTATE(file) \
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin (((file)->sync_offset > MAIL_TRANSACTION_LOG_ROTATE_MIN_SIZE && \
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin (time_t)(file)->hdr.create_stamp < \
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin ioloop_time - MAIL_TRANSACTION_LOG_ROTATE_TIME) || \
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin ((file)->sync_offset > MAIL_TRANSACTION_LOG_ROTATE_MAX_SIZE))
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalinbool mail_transaction_log_want_rotate(struct mail_transaction_log *log)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin{
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin return LOG_WANT_ROTATE(log->head);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin}
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalinint mail_transaction_log_rotate(struct mail_transaction_log *log, bool reset)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin{
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin struct mail_transaction_log_file *file;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin const char *path = log->head->filepath;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin struct stat st;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin i_assert(log->head->locked);
1881820ae4ff9004beef1bf7f04553580840441dSerge Hallyn
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (MAIL_INDEX_IS_IN_MEMORY(log->index)) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin file = mail_transaction_log_file_alloc_in_memory(log);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (reset) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin file->hdr.prev_file_seq = 0;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin file->hdr.prev_file_offset = 0;
f02ce27d4b1a9d01b88d0ffaf626e5bafa671bf0Stéphane Graber }
f02ce27d4b1a9d01b88d0ffaf626e5bafa671bf0Stéphane Graber } else {
f02ce27d4b1a9d01b88d0ffaf626e5bafa671bf0Stéphane Graber /* we're locked, we shouldn't need to worry about ESTALE
f02ce27d4b1a9d01b88d0ffaf626e5bafa671bf0Stéphane Graber problems in here. */
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (fstat(log->head->fd, &st) < 0) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin mail_index_file_set_syscall_error(log->index,
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin file->filepath, "fstat()");
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin return -1;
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin }
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin file = mail_transaction_log_file_alloc(log, path);
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin file->st_dev = st.st_dev;
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin file->st_ino = st.st_ino;
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin file->last_mtime = st.st_mtime;
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin file->last_size = st.st_size;
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin if (mail_transaction_log_file_create(file, reset) < 0) {
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin mail_transaction_log_file_free(&file);
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin return -1;
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin }
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin }
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin if (--log->head->refcount == 0)
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin mail_transaction_logs_clean(log);
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin else
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin mail_transaction_log_file_unlock(log->head);
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin mail_transaction_log_set_head(log, file);
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin return 0;
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin}
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalinstatic int
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalinmail_transaction_log_refresh(struct mail_transaction_log *log, bool nfs_flush)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin{
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin struct mail_transaction_log_file *file;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin struct stat st;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin const char *path;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin i_assert(log->head != NULL);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(log->head))
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin return 0;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin path = t_strconcat(log->index->filepath,
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin MAIL_TRANSACTION_LOG_SUFFIX, NULL);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (log->index->nfs_flush && nfs_flush)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin nfs_flush_file_handle_cache(path);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (nfs_safe_stat(path, &st) < 0) {
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin if (errno != ENOENT) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin mail_index_file_set_syscall_error(log->index, path,
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin "stat()");
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin return -1;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin }
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin /* the file should always exist at this point. if it doesn't,
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin someone deleted it manually while the index was open. try to
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin handle this nicely by creating a new log file. */
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin file = log->head;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (mail_transaction_log_create(log, FALSE) < 0)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin return -1;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin i_assert(file->refcount > 0);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin file->refcount--;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin log->index->need_recreate = TRUE;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin return 0;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin } else if (log->head->st_ino == st.st_ino &&
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin CMP_DEV_T(log->head->st_dev, st.st_dev)) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin /* NFS: log files get rotated to .log.2 files instead
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin of being unlinked, so we don't bother checking if
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin the existing file has already been unlinked here
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin (in which case inodes could match but point to
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin different files) */
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin return 0;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin }
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
add1d11833394aaa3a3497c2fdf548e5b14c80d4Serge Hallyn file = mail_transaction_log_file_alloc(log, path);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (mail_transaction_log_file_open(file, FALSE) <= 0) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin mail_transaction_log_file_free(&file);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin return -1;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin }
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin i_assert(!file->locked);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (--log->head->refcount == 0)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin mail_transaction_logs_clean(log);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin mail_transaction_log_set_head(log, file);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin return 0;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin}
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalinvoid mail_transaction_log_get_mailbox_sync_pos(struct mail_transaction_log *log,
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin uint32_t *file_seq_r,
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin uoff_t *file_offset_r)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin{
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin *file_seq_r = log->head->hdr.file_seq;
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin *file_offset_r = log->head->max_tail_offset;
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin}
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalinvoid mail_transaction_log_set_mailbox_sync_pos(struct mail_transaction_log *log,
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin uint32_t file_seq,
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin uoff_t file_offset)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin{
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin i_assert(file_seq == log->head->hdr.file_seq);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin i_assert(file_offset >= log->head->saved_tail_offset);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (file_offset >= log->head->max_tail_offset)
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin log->head->max_tail_offset = file_offset;
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin}
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalinint mail_transaction_log_find_file(struct mail_transaction_log *log,
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin uint32_t file_seq, bool nfs_flush,
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin struct mail_transaction_log_file **file_r)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin{
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin struct mail_transaction_log_file *file;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin const char *path;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin int ret;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (file_seq > log->head->hdr.file_seq) {
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin /* see if the .log file has been recreated */
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (log->head->locked) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin /* transaction log is locked. there's no way a newer
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin file exists. */
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin return 0;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin }
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (mail_transaction_log_refresh(log, FALSE) < 0)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin return -1;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (file_seq > log->head->hdr.file_seq) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (!nfs_flush || !log->index->nfs_flush)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin return 0;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin /* try again, this time flush attribute cache */
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (mail_transaction_log_refresh(log, TRUE) < 0)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin return -1;
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin if (file_seq > log->head->hdr.file_seq)
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin return 0;
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin }
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin }
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin for (file = log->files; file != NULL; file = file->next) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (file->hdr.file_seq == file_seq) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin *file_r = file;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin return 1;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin }
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin }
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (MAIL_INDEX_IS_IN_MEMORY(log->index))
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin return 0;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin /* see if we have it in log.2 file */
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin path = t_strconcat(log->index->filepath,
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin MAIL_TRANSACTION_LOG_SUFFIX".2", NULL);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin file = mail_transaction_log_file_alloc(log, path);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if ((ret = mail_transaction_log_file_open(file, TRUE)) <= 0) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin mail_transaction_log_file_free(&file);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin return ret;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin }
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin /* but is it what we expected? */
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (file->hdr.file_seq != file_seq)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin return 0;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin *file_r = file;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin return 1;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin}
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalinint mail_transaction_log_lock_head(struct mail_transaction_log *log)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin{
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin struct mail_transaction_log_file *file;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin int ret = 0;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin /* we want to get the head file locked. this is a bit racy,
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin since by the time we have it locked a new log file may have been
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin created.
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin creating new log file requires locking the head file, so if we
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin can lock it and don't see another file, we can be sure no-one is
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin creating a new log at the moment */
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin for (;;) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin file = log->head;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (mail_transaction_log_file_lock(file) < 0)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin return -1;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin file->refcount++;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin ret = mail_transaction_log_refresh(log, TRUE);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (--file->refcount == 0) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin mail_transaction_logs_clean(log);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin file = NULL;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin }
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (ret == 0 && log->head == file) {
1881820ae4ff9004beef1bf7f04553580840441dSerge Hallyn /* success */
1881820ae4ff9004beef1bf7f04553580840441dSerge Hallyn break;
1881820ae4ff9004beef1bf7f04553580840441dSerge Hallyn }
1881820ae4ff9004beef1bf7f04553580840441dSerge Hallyn
1881820ae4ff9004beef1bf7f04553580840441dSerge Hallyn if (file != NULL)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin mail_transaction_log_file_unlock(file);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (ret < 0)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin break;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin /* try again */
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin }
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin return ret;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin}
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalinint mail_transaction_log_sync_lock(struct mail_transaction_log *log,
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin uint32_t *file_seq_r, uoff_t *file_offset_r)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin{
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin i_assert(!log->index->log_locked);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (mail_transaction_log_lock_head(log) < 0)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin return -1;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin /* update sync_offset */
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (mail_transaction_log_file_map(log->head, log->head->sync_offset,
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin (uoff_t)-1) <= 0) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin mail_transaction_log_file_unlock(log->head);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin 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)
{
*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;
}