mail-transaction-log.c revision 036626b19f14bef582f96e556913ae91b1d67881
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2003-2010 Dovecot authors, see the included COPYING file */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen#include "lib.h"
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen#include "ioloop.h"
b87761f9bbef949f31dae297e619ac3f5e9c2b2eTimo Sirainen#include "buffer.h"
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen#include "file-dotlock.h"
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen#include "nfs-workarounds.h"
e8434aad92ea6ff1c915b708294dbd0c7ff5908dMichael M Slusarz#include "close-keep-errno.h"
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen#include "mmap-util.h"
de5f478d9e7ae7b8e58082e0b30b6ce1f034236aTimo Sirainen#include "mail-index-private.h"
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen#include "mail-transaction-log-private.h"
f7d018e7e0980044e3d537958126e44ef4c45056Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen#include <stddef.h>
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen#include <stdio.h>
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen#include <sys/stat.h>
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen#define LOG_NEW_DOTLOCK_SUFFIX ".newlock"
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic void
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenmail_transaction_log_set_head(struct mail_transaction_log *log,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct mail_transaction_log_file *file)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_assert(log->head != file);
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen file->refcount++;
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen log->head = file;
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_assert(log->files != NULL);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_assert(log->files->next != NULL || log->files == file);
4db61af2cfe2b206113bcc4b6153521679702bb4Timo Sirainen}
4db61af2cfe2b206113bcc4b6153521679702bb4Timo Sirainen
4db61af2cfe2b206113bcc4b6153521679702bb4Timo Sirainenstruct mail_transaction_log *
4db61af2cfe2b206113bcc4b6153521679702bb4Timo Sirainenmail_transaction_log_alloc(struct mail_index *index)
4db61af2cfe2b206113bcc4b6153521679702bb4Timo Sirainen{
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen struct mail_transaction_log *log;
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen log = i_new(struct mail_transaction_log, 1);
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen log->index = index;
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen
4db61af2cfe2b206113bcc4b6153521679702bb4Timo Sirainen log->dotlock_settings.timeout =
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen I_MIN(MAIL_TRANSCATION_LOG_LOCK_TIMEOUT,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen index->max_lock_timeout_secs);;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen log->dotlock_settings.stale_timeout =
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen MAIL_TRANSCATION_LOG_LOCK_CHANGE_TIMEOUT;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen log->new_dotlock_settings = log->dotlock_settings;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen log->new_dotlock_settings.lock_suffix = LOG_NEW_DOTLOCK_SUFFIX;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return log;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic void mail_transaction_log_2_unlink_old(struct mail_transaction_log *log)
c72cfe4a2bda39fff3b8a8bd64b31a7cc14d7d11Timo Sirainen{
4db61af2cfe2b206113bcc4b6153521679702bb4Timo Sirainen struct stat st;
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen if (stat(log->filepath2, &st) < 0) {
f9eee365367f37b1692c07db6c23d30243844aaaTimo Sirainen if (errno != ENOENT && errno != ESTALE) {
f7d018e7e0980044e3d537958126e44ef4c45056Timo Sirainen mail_index_set_error(log->index,
7cd055a212d44067e2d94452c05691d696c9f699Timo Sirainen "stat(%s) failed: %m", log->filepath2);
e8434aad92ea6ff1c915b708294dbd0c7ff5908dMichael M Slusarz }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
f0e416aa42058e7ccc0dc6deec0d4f4a19ee6ebeTimo Sirainen if (st.st_mtime + MAIL_TRANSACTION_LOG2_STALE_SECS <= ioloop_time &&
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen !log->index->readonly) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (unlink(log->filepath2) < 0 && errno != ENOENT) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen mail_index_set_error(log->index,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen "unlink(%s) failed: %m", log->filepath2);
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainenint mail_transaction_log_open(struct mail_transaction_log *log)
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen{
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen struct mail_transaction_log_file *file;
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen int ret;
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen i_free(log->filepath);
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen i_free(log->filepath2);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen log->filepath = i_strconcat(log->index->filepath,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen MAIL_TRANSACTION_LOG_SUFFIX, NULL);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen log->filepath2 = i_strconcat(log->filepath, ".2", NULL);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen log->flags = log->index->flags;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen log->dotlock_settings.use_excl_lock =
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen (log->flags & MAIL_INDEX_OPEN_FLAG_DOTLOCK_USE_EXCL) != 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen log->dotlock_settings.nfs_flush =
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen (log->flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) != 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen log->new_dotlock_settings.use_excl_lock =
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen (log->flags & MAIL_INDEX_OPEN_FLAG_DOTLOCK_USE_EXCL) != 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen log->new_dotlock_settings.nfs_flush =
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen (log->flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) != 0;
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen
4db61af2cfe2b206113bcc4b6153521679702bb4Timo Sirainen if (log->open_file != NULL)
2ccb478c35972517721ce415d81fcbd11a73fad3Timo Sirainen mail_transaction_log_file_free(&log->open_file);
37e8420b32a0fa3442c405616980e45beb494104Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (MAIL_INDEX_IS_IN_MEMORY(log->index))
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
61f39b0358a72ebc693d84ba5bac74489ee7df41Timo Sirainen file = mail_transaction_log_file_alloc(log, log->filepath);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if ((ret = mail_transaction_log_file_open(file, FALSE)) <= 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* leave the file for _create() */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen log->open_file = file;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return ret;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen }
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen mail_transaction_log_set_head(log, file);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen mail_transaction_log_2_unlink_old(log);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return 1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenint mail_transaction_log_create(struct mail_transaction_log *log, bool reset)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct mail_transaction_log_file *file;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (MAIL_INDEX_IS_IN_MEMORY(log->index)) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen file = mail_transaction_log_file_alloc_in_memory(log);
e22ec7998afd426c53c658483ce66b6e404e27c6Timo Sirainen mail_transaction_log_set_head(log, file);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return 0;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen }
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen file = mail_transaction_log_file_alloc(log, log->filepath);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (log->open_file != NULL) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* remember what file we tried to open. if someone else created
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen a new file, use it instead of recreating it */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen file->st_ino = log->open_file->st_ino;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen file->st_dev = log->open_file->st_dev;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen file->last_size = log->open_file->last_size;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen file->last_mtime = log->open_file->last_mtime;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen mail_transaction_log_file_free(&log->open_file);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (mail_transaction_log_file_create(file, reset) < 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen mail_transaction_log_file_free(&file);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return -1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen mail_transaction_log_set_head(log, file);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return 1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenvoid mail_transaction_log_close(struct mail_transaction_log *log)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen mail_transaction_log_views_close(log);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (log->open_file != NULL)
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen mail_transaction_log_file_free(&log->open_file);
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen if (log->head != NULL)
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen log->head->refcount--;
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen mail_transaction_logs_clean(log);
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen i_assert(log->files == NULL);
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen}
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainenvoid mail_transaction_log_free(struct mail_transaction_log **_log)
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen{
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen struct mail_transaction_log *log = *_log;
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen *_log = NULL;
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen mail_transaction_log_close(log);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen log->index->log = NULL;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_free(log->filepath);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_free(log->filepath2);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_free(log);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenvoid mail_transaction_log_move_to_memory(struct mail_transaction_log *log)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct mail_transaction_log_file *file;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (!log->index->initial_mapped && log->files != NULL &&
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen log->files->hdr.prev_file_seq != 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* we couldn't read dovecot.index and we don't have the first
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen .log file, so just start from scratch */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen mail_transaction_log_close(log);
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen }
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen i_free(log->filepath);
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen i_free(log->filepath2);
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen log->filepath = i_strconcat(log->index->filepath,
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen MAIL_TRANSACTION_LOG_SUFFIX, NULL);
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen log->filepath2 = i_strconcat(log->filepath, ".2", NULL);
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen if (log->head != NULL)
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen mail_transaction_log_file_move_to_memory(log->head);
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen else {
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen file = mail_transaction_log_file_alloc_in_memory(log);
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen mail_transaction_log_set_head(log, file);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenvoid mail_transaction_log_indexid_changed(struct mail_transaction_log *log)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct mail_transaction_log_file *file;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen mail_transaction_logs_clean(log);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen for (file = log->files; file != NULL; file = file->next) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (file->hdr.indexid != log->index->indexid) {
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen mail_transaction_log_file_set_corrupted(file,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen "indexid changed: %u -> %u",
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen file->hdr.indexid, log->index->indexid);
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (log->head != NULL &&
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen log->head->hdr.indexid != log->index->indexid) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (--log->head->refcount == 0)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen mail_transaction_log_file_free(&log->head);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen (void)mail_transaction_log_create(log, FALSE);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen}
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainenvoid mail_transaction_logs_clean(struct mail_transaction_log *log)
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen{
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen struct mail_transaction_log_file *file, *next;
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen /* remove only files from the beginning. this way if a view has
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen referenced an old file, it can still find the new files even if
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen there aren't any references to it currently. */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen for (file = log->files; file != NULL; file = next) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen next = file->next;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_assert(file->refcount >= 0);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (file->refcount > 0)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen break;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen mail_transaction_log_file_free(&file);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* if we still have locked files with refcount=0, unlock them */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen for (; file != NULL; file = file->next) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (file->locked && file->refcount == 0)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen mail_transaction_log_file_unlock(file);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_assert(log->head == NULL || log->files != NULL);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen#define LOG_WANT_ROTATE(file) \
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen (((file)->sync_offset > MAIL_TRANSACTION_LOG_ROTATE_MIN_SIZE && \
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen (time_t)(file)->hdr.create_stamp < \
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ioloop_time - MAIL_TRANSACTION_LOG_ROTATE_TIME) || \
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ((file)->sync_offset > MAIL_TRANSACTION_LOG_ROTATE_MAX_SIZE))
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenbool mail_transaction_log_want_rotate(struct mail_transaction_log *log)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return LOG_WANT_ROTATE(log->head);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenint mail_transaction_log_rotate(struct mail_transaction_log *log, bool reset)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct mail_transaction_log_file *file;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen const char *path = log->head->filepath;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct stat st;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_assert(log->head->locked);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (MAIL_INDEX_IS_IN_MEMORY(log->index)) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen file = mail_transaction_log_file_alloc_in_memory(log);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (reset) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen file->hdr.prev_file_seq = 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen file->hdr.prev_file_offset = 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen } else {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* we're locked, we shouldn't need to worry about ESTALE
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen problems in here. */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (fstat(log->head->fd, &st) < 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen mail_index_file_set_syscall_error(log->index,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen log->head->filepath, "fstat()");
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return -1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen file = mail_transaction_log_file_alloc(log, path);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen file->st_dev = st.st_dev;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen file->st_ino = st.st_ino;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen file->last_mtime = st.st_mtime;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen file->last_size = st.st_size;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (mail_transaction_log_file_create(file, reset) < 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen mail_transaction_log_file_free(&file);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return -1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (--log->head->refcount == 0)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen mail_transaction_logs_clean(log);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen else
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen mail_transaction_log_file_unlock(log->head);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen mail_transaction_log_set_head(log, file);
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen return 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic int
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenmail_transaction_log_refresh(struct mail_transaction_log *log, bool nfs_flush)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct mail_transaction_log_file *file;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct stat st;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_assert(log->head != NULL);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(log->head))
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (nfs_flush && (log->flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) != 0)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen nfs_flush_file_handle_cache(log->filepath);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (nfs_safe_stat(log->filepath, &st) < 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (errno != ENOENT) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen mail_index_file_set_syscall_error(log->index,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen log->filepath,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen "stat()");
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return -1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* see if the whole directory got deleted */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (nfs_safe_stat(log->index->dir, &st) < 0 &&
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen errno == ENOENT) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen log->index->index_deleted = TRUE;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return -1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* the file should always exist at this point. if it doesn't,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen someone deleted it manually while the index was open. try to
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen handle this nicely by creating a new log file. */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen file = log->head;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (mail_transaction_log_create(log, FALSE) < 0)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return -1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_assert(file->refcount > 0);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen file->refcount--;
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen log->index->need_recreate = TRUE;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen } else if (log->head->st_ino == st.st_ino &&
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen CMP_DEV_T(log->head->st_dev, st.st_dev)) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* NFS: log files get rotated to .log.2 files instead
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen of being unlinked, so we don't bother checking if
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen the existing file has already been unlinked here
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen (in which case inodes could match but point to
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen different files) */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen file = mail_transaction_log_file_alloc(log, log->filepath);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (mail_transaction_log_file_open(file, FALSE) <= 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen mail_transaction_log_file_free(&file);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return -1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_assert(!file->locked);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (--log->head->refcount == 0)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen mail_transaction_logs_clean(log);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen mail_transaction_log_set_head(log, file);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenvoid mail_transaction_log_get_mailbox_sync_pos(struct mail_transaction_log *log,
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen uint32_t *file_seq_r,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uoff_t *file_offset_r)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen *file_seq_r = log->head->hdr.file_seq;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen *file_offset_r = log->head->max_tail_offset;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenvoid mail_transaction_log_set_mailbox_sync_pos(struct mail_transaction_log *log,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uint32_t file_seq,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uoff_t file_offset)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_assert(file_seq == log->head->hdr.file_seq);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_assert(file_offset >= log->head->saved_tail_offset);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (file_offset >= log->head->max_tail_offset)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen log->head->max_tail_offset = file_offset;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenint mail_transaction_log_find_file(struct mail_transaction_log *log,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uint32_t file_seq, bool nfs_flush,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct mail_transaction_log_file **file_r)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct mail_transaction_log_file *file;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen int ret;
f7d018e7e0980044e3d537958126e44ef4c45056Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (file_seq > log->head->hdr.file_seq) {
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen /* see if the .log file has been recreated */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (log->head->locked) {
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen /* transaction log is locked. there's no way a newer
6ea145a99eeee923602f04d3c9183bbdba6cd190Timo Sirainen file exists. */
6ea145a99eeee923602f04d3c9183bbdba6cd190Timo Sirainen return 0;
4db61af2cfe2b206113bcc4b6153521679702bb4Timo Sirainen }
7cd055a212d44067e2d94452c05691d696c9f699Timo Sirainen
7cd055a212d44067e2d94452c05691d696c9f699Timo Sirainen if (mail_transaction_log_refresh(log, FALSE) < 0)
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen return -1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (file_seq > log->head->hdr.file_seq) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (!nfs_flush ||
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen (log->flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) == 0)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* try again, this time flush attribute cache */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (mail_transaction_log_refresh(log, TRUE) < 0)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return -1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (file_seq > log->head->hdr.file_seq)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen for (file = log->files; file != NULL; file = file->next) {
e8434aad92ea6ff1c915b708294dbd0c7ff5908dMichael M Slusarz if (file->hdr.file_seq == file_seq) {
e8434aad92ea6ff1c915b708294dbd0c7ff5908dMichael M Slusarz *file_r = file;
e8434aad92ea6ff1c915b708294dbd0c7ff5908dMichael M Slusarz return 1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (MAIL_INDEX_IS_IN_MEMORY(log->index))
c72cfe4a2bda39fff3b8a8bd64b31a7cc14d7d11Timo Sirainen return 0;
c72cfe4a2bda39fff3b8a8bd64b31a7cc14d7d11Timo Sirainen
c72cfe4a2bda39fff3b8a8bd64b31a7cc14d7d11Timo Sirainen /* see if we have it in log.2 file */
c72cfe4a2bda39fff3b8a8bd64b31a7cc14d7d11Timo Sirainen file = mail_transaction_log_file_alloc(log, log->filepath2);
c72cfe4a2bda39fff3b8a8bd64b31a7cc14d7d11Timo Sirainen if ((ret = mail_transaction_log_file_open(file, TRUE)) <= 0) {
c72cfe4a2bda39fff3b8a8bd64b31a7cc14d7d11Timo Sirainen mail_transaction_log_file_free(&file);
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen return ret;
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen }
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen /* but is it what we expected? */
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen if (file->hdr.file_seq != file_seq)
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen return 0;
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen *file_r = file;
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen return 1;
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen}
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainenint mail_transaction_log_lock_head(struct mail_transaction_log *log)
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen{
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen struct mail_transaction_log_file *file;
4db61af2cfe2b206113bcc4b6153521679702bb4Timo Sirainen int ret = 0;
4db61af2cfe2b206113bcc4b6153521679702bb4Timo Sirainen
4db61af2cfe2b206113bcc4b6153521679702bb4Timo Sirainen /* we want to get the head file locked. this is a bit racy,
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen since by the time we have it locked a new log file may have been
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen created.
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen creating new log file requires locking the head file, so if we
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen can lock it and don't see another file, we can be sure no-one is
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen creating a new log at the moment */
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen
f9eee365367f37b1692c07db6c23d30243844aaaTimo Sirainen for (;;) {
f9eee365367f37b1692c07db6c23d30243844aaaTimo Sirainen file = log->head;
f9eee365367f37b1692c07db6c23d30243844aaaTimo Sirainen if (mail_transaction_log_file_lock(file) < 0)
f7d018e7e0980044e3d537958126e44ef4c45056Timo Sirainen return -1;
f7d018e7e0980044e3d537958126e44ef4c45056Timo Sirainen
f7d018e7e0980044e3d537958126e44ef4c45056Timo Sirainen file->refcount++;
f7d018e7e0980044e3d537958126e44ef4c45056Timo Sirainen ret = mail_transaction_log_refresh(log, TRUE);
7cd055a212d44067e2d94452c05691d696c9f699Timo Sirainen if (--file->refcount == 0) {
f7d018e7e0980044e3d537958126e44ef4c45056Timo Sirainen mail_transaction_logs_clean(log);
f7d018e7e0980044e3d537958126e44ef4c45056Timo Sirainen file = NULL;
7cd055a212d44067e2d94452c05691d696c9f699Timo Sirainen }
f7d018e7e0980044e3d537958126e44ef4c45056Timo Sirainen
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen if (ret == 0 && log->head == file) {
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen /* success */
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen break;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (file != NULL)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen mail_transaction_log_file_unlock(file);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen if (ret < 0)
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen break;
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen /* try again */
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen }
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen return ret;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenint mail_transaction_log_sync_lock(struct mail_transaction_log *log,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uint32_t *file_seq_r, uoff_t *file_offset_r)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_assert(!log->index->log_locked);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen if (mail_transaction_log_lock_head(log) < 0)
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen return -1;
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen /* update sync_offset */
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen if (mail_transaction_log_file_map(log->head, log->head->sync_offset,
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen (uoff_t)-1) <= 0) {
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen mail_transaction_log_file_unlock(log->head);
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen return -1;
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen }
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen log->index->log_locked = TRUE;
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen *file_seq_r = log->head->hdr.file_seq;
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen *file_offset_r = log->head->sync_offset;
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen return 0;
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen}
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainenvoid mail_transaction_log_sync_unlock(struct mail_transaction_log *log)
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen{
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen i_assert(log->index->log_locked);
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen log->index->log_locked = FALSE;
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen mail_transaction_log_file_unlock(log->head);
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen}
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainenvoid mail_transaction_log_get_head(struct mail_transaction_log *log,
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen uint32_t *file_seq_r, uoff_t *file_offset_r)
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen{
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen *file_seq_r = log->head->hdr.file_seq;
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen *file_offset_r = log->head->sync_offset;
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen}
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainenvoid mail_transaction_log_get_tail(struct mail_transaction_log *log,
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen uint32_t *file_seq_r)
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen{
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen struct mail_transaction_log_file *tail, *file = log->files;
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen for (tail = file; file->next != NULL; file = file->next) {
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen if (file->hdr.file_seq + 1 != file->next->hdr.file_seq)
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen tail = file->next;
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen }
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen *file_seq_r = tail->hdr.file_seq;
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen}
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainenbool mail_transaction_log_is_head_prev(struct mail_transaction_log *log,
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen uint32_t file_seq, uoff_t file_offset)
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen{
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen return log->head->hdr.prev_file_seq == file_seq &&
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen log->head->hdr.prev_file_offset == file_offset;
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen}
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainenint mail_transaction_log_get_mtime(struct mail_transaction_log *log,
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen time_t *mtime_r)
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen{
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen struct stat st;
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen *mtime_r = 0;
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen if (stat(log->filepath, &st) < 0) {
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen if (errno == ENOENT)
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen return 0;
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen mail_index_file_set_syscall_error(log->index, log->filepath,
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen "stat()");
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen return -1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen *mtime_r = st.st_mtime;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen