mail-transaction-log.c revision 1be964ec6d835f95b4fdebf02add9265d58ad290
89a126810703c666309310d0f3189e9834d70b5bTimo Sirainen/* Copyright (c) 2003-2011 Dovecot authors, see the included COPYING file */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen#include "lib.h"
6157a322f2ac1ea1332d9003ecb0b11466aa8fe7Timo Sirainen#include "ioloop.h"
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen#include "buffer.h"
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen#include "file-dotlock.h"
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen#include "nfs-workarounds.h"
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen#include "close-keep-errno.h"
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen#include "mmap-util.h"
c4cfee078c4a185b5ba8f0c55f51275b7e885b2cTimo Sirainen#include "mail-index-private.h"
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen#include "mail-transaction-log-private.h"
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen#include <stddef.h>
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen#include <stdio.h>
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen#include <sys/stat.h>
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainenstatic void
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainenmail_transaction_log_set_head(struct mail_transaction_log *log,
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen struct mail_transaction_log_file *file)
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen{
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen i_assert(log->head != file);
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen file->refcount++;
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen log->head = file;
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen i_assert(log->files != NULL);
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen i_assert(log->files->next != NULL || log->files == file);
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen}
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainenstruct mail_transaction_log *
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainenmail_transaction_log_alloc(struct mail_index *index)
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen{
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen struct mail_transaction_log *log;
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen log = i_new(struct mail_transaction_log, 1);
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen log->index = index;
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen return log;
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen}
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainenstatic void mail_transaction_log_2_unlink_old(struct mail_transaction_log *log)
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen{
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen struct stat st;
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen if (MAIL_INDEX_IS_IN_MEMORY(log->index))
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen return;
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen if (stat(log->filepath2, &st) < 0) {
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen if (errno != ENOENT && errno != ESTALE) {
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen mail_index_set_error(log->index,
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen "stat(%s) failed: %m", log->filepath2);
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen }
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen return;
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen }
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen if (st.st_mtime + MAIL_TRANSACTION_LOG2_STALE_SECS <= ioloop_time &&
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen !log->index->readonly) {
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen if (unlink(log->filepath2) < 0 && errno != ENOENT) {
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen mail_index_set_error(log->index,
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen "unlink(%s) failed: %m", log->filepath2);
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen }
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen }
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen}
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainenint mail_transaction_log_open(struct mail_transaction_log *log)
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen{
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen struct mail_transaction_log_file *file;
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen int ret;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen i_free(log->filepath);
9d3ccd79130199ffdb19a688027d49bf20a4aaaaTimo Sirainen i_free(log->filepath2);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen log->filepath = i_strconcat(log->index->filepath,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen MAIL_TRANSACTION_LOG_SUFFIX, NULL);
8d6cb44a0161d88743756733f83c4fb278485987Timo Sirainen log->filepath2 = i_strconcat(log->filepath, ".2", NULL);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
be889d9b142fbb5604a922c6955bd7f6ea32f163Timo Sirainen /* these settings aren't available at alloc() time, so we need to
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen set them here: */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen log->nfs_flush =
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen (log->index->flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) != 0;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (log->open_file != NULL)
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen mail_transaction_log_file_free(&log->open_file);
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (MAIL_INDEX_IS_IN_MEMORY(log->index))
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return 0;
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen file = mail_transaction_log_file_alloc(log, log->filepath);
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen if ((ret = mail_transaction_log_file_open(file, FALSE)) <= 0) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* leave the file for _create() */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen log->open_file = file;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return ret;
be889d9b142fbb5604a922c6955bd7f6ea32f163Timo Sirainen }
be889d9b142fbb5604a922c6955bd7f6ea32f163Timo Sirainen mail_transaction_log_set_head(log, file);
be889d9b142fbb5604a922c6955bd7f6ea32f163Timo Sirainen return 1;
be889d9b142fbb5604a922c6955bd7f6ea32f163Timo Sirainen}
be889d9b142fbb5604a922c6955bd7f6ea32f163Timo Sirainen
be889d9b142fbb5604a922c6955bd7f6ea32f163Timo Sirainenint mail_transaction_log_create(struct mail_transaction_log *log, bool reset)
be889d9b142fbb5604a922c6955bd7f6ea32f163Timo Sirainen{
be889d9b142fbb5604a922c6955bd7f6ea32f163Timo Sirainen struct mail_transaction_log_file *file;
be889d9b142fbb5604a922c6955bd7f6ea32f163Timo Sirainen
be889d9b142fbb5604a922c6955bd7f6ea32f163Timo Sirainen if (MAIL_INDEX_IS_IN_MEMORY(log->index)) {
be889d9b142fbb5604a922c6955bd7f6ea32f163Timo Sirainen file = mail_transaction_log_file_alloc_in_memory(log);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail_transaction_log_set_head(log, file);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return 0;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen file = mail_transaction_log_file_alloc(log, log->filepath);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (log->open_file != NULL) {
0cea9b1f4fa0495a48f5f097e40492517d67e1baTimo Sirainen /* remember what file we tried to open. if someone else created
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen a new file, use it instead of recreating it */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen file->st_ino = log->open_file->st_ino;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen file->st_dev = log->open_file->st_dev;
0cea9b1f4fa0495a48f5f097e40492517d67e1baTimo Sirainen file->last_size = log->open_file->last_size;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen file->last_mtime = log->open_file->last_mtime;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail_transaction_log_file_free(&log->open_file);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (mail_transaction_log_file_create(file, reset) < 0) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail_transaction_log_file_free(&file);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return -1;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail_transaction_log_set_head(log, file);
8d6cb44a0161d88743756733f83c4fb278485987Timo Sirainen return 1;
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen}
8d6cb44a0161d88743756733f83c4fb278485987Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvoid mail_transaction_log_close(struct mail_transaction_log *log)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen i_assert(log->views == NULL);
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (log->open_file != NULL)
8d6cb44a0161d88743756733f83c4fb278485987Timo Sirainen mail_transaction_log_file_free(&log->open_file);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (log->head != NULL)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen log->head->refcount--;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail_transaction_logs_clean(log);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen i_assert(log->files == NULL);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen}
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvoid mail_transaction_log_free(struct mail_transaction_log **_log)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct mail_transaction_log *log = *_log;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen *_log = NULL;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail_transaction_log_close(log);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen log->index->log = NULL;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen i_free(log->filepath);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen i_free(log->filepath2);
16598a1fb870ae40d6177755a4306216e4d6a4cdTimo Sirainen i_free(log);
16598a1fb870ae40d6177755a4306216e4d6a4cdTimo Sirainen}
16598a1fb870ae40d6177755a4306216e4d6a4cdTimo Sirainen
16598a1fb870ae40d6177755a4306216e4d6a4cdTimo Sirainenvoid mail_transaction_log_move_to_memory(struct mail_transaction_log *log)
16598a1fb870ae40d6177755a4306216e4d6a4cdTimo Sirainen{
16598a1fb870ae40d6177755a4306216e4d6a4cdTimo Sirainen struct mail_transaction_log_file *file;
16598a1fb870ae40d6177755a4306216e4d6a4cdTimo Sirainen
bc793bfcee945ce8871edfa298fe7235744425b6Timo Sirainen if (!log->index->initial_mapped && log->files != NULL &&
bc793bfcee945ce8871edfa298fe7235744425b6Timo Sirainen log->files->hdr.prev_file_seq != 0) {
bc793bfcee945ce8871edfa298fe7235744425b6Timo Sirainen /* we couldn't read dovecot.index and we don't have the first
16598a1fb870ae40d6177755a4306216e4d6a4cdTimo Sirainen .log file, so just start from scratch */
ea4ca37ec14913354f3a0deebc0df96097eb9468Timo Sirainen mail_transaction_log_close(log);
16598a1fb870ae40d6177755a4306216e4d6a4cdTimo Sirainen }
ea4ca37ec14913354f3a0deebc0df96097eb9468Timo Sirainen
ea4ca37ec14913354f3a0deebc0df96097eb9468Timo Sirainen i_free(log->filepath);
16598a1fb870ae40d6177755a4306216e4d6a4cdTimo Sirainen i_free(log->filepath2);
16598a1fb870ae40d6177755a4306216e4d6a4cdTimo Sirainen log->filepath = i_strconcat(log->index->filepath,
16598a1fb870ae40d6177755a4306216e4d6a4cdTimo Sirainen MAIL_TRANSACTION_LOG_SUFFIX, NULL);
16598a1fb870ae40d6177755a4306216e4d6a4cdTimo Sirainen log->filepath2 = i_strconcat(log->filepath, ".2", NULL);
16598a1fb870ae40d6177755a4306216e4d6a4cdTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (log->head != NULL)
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen mail_transaction_log_file_move_to_memory(log->head);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen else {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen file = mail_transaction_log_file_alloc_in_memory(log);
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen mail_transaction_log_set_head(log, file);
6e235046e1d8e9d89fc948f5c623676c20421a28Timo Sirainen }
abb83d133dd082527d500916fca66a72fbbbaa8dTimo Sirainen}
e4423c16a4f798ecf75ca2b0c3ef834000faed4bTimo Sirainen
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainenvoid mail_transaction_log_indexid_changed(struct mail_transaction_log *log)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct mail_transaction_log_file *file;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail_transaction_logs_clean(log);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen for (file = log->files; file != NULL; file = file->next) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (file->hdr.indexid != log->index->indexid) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail_transaction_log_file_set_corrupted(file,
6e235046e1d8e9d89fc948f5c623676c20421a28Timo Sirainen "indexid changed: %u -> %u",
6e235046e1d8e9d89fc948f5c623676c20421a28Timo Sirainen file->hdr.indexid, log->index->indexid);
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen if (log->head != NULL &&
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen log->head->hdr.indexid != log->index->indexid) {
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen if (--log->head->refcount == 0)
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen mail_transaction_log_file_free(&log->head);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen (void)mail_transaction_log_create(log, FALSE);
e4423c16a4f798ecf75ca2b0c3ef834000faed4bTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen}
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainenvoid mail_transaction_logs_clean(struct mail_transaction_log *log)
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen{
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen struct mail_transaction_log_file *file, *next;
c4cfee078c4a185b5ba8f0c55f51275b7e885b2cTimo Sirainen
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen /* remove only files from the beginning. this way if a view has
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen referenced an old file, it can still find the new files even if
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen there aren't any references to it currently. */
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen for (file = log->files; file != NULL; file = next) {
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen next = file->next;
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen i_assert(file->refcount >= 0);
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen if (file->refcount > 0)
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen break;
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen mail_transaction_log_file_free(&file);
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen }
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen /* if we still have locked files with refcount=0, unlock them */
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen for (; file != NULL; file = file->next) {
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen if (file->locked && file->refcount == 0)
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen mail_transaction_log_file_unlock(file);
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen }
114a0f74e0f825c6bd8aeadfafb248a030762a1fTimo Sirainen i_assert(log->head == NULL || log->files != NULL);
c4cfee078c4a185b5ba8f0c55f51275b7e885b2cTimo Sirainen}
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen#define LOG_WANT_ROTATE(file) \
abb83d133dd082527d500916fca66a72fbbbaa8dTimo Sirainen (((file)->sync_offset > MAIL_TRANSACTION_LOG_ROTATE_MIN_SIZE && \
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen (time_t)(file)->hdr.create_stamp < \
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen ioloop_time - MAIL_TRANSACTION_LOG_ROTATE_TIME) || \
6e235046e1d8e9d89fc948f5c623676c20421a28Timo Sirainen ((file)->sync_offset > MAIL_TRANSACTION_LOG_ROTATE_MAX_SIZE))
6e235046e1d8e9d89fc948f5c623676c20421a28Timo Sirainen
6e235046e1d8e9d89fc948f5c623676c20421a28Timo Sirainenbool mail_transaction_log_want_rotate(struct mail_transaction_log *log)
6e235046e1d8e9d89fc948f5c623676c20421a28Timo Sirainen{
6e235046e1d8e9d89fc948f5c623676c20421a28Timo Sirainen return LOG_WANT_ROTATE(log->head);
6e235046e1d8e9d89fc948f5c623676c20421a28Timo Sirainen}
abb83d133dd082527d500916fca66a72fbbbaa8dTimo Sirainen
abb83d133dd082527d500916fca66a72fbbbaa8dTimo Sirainenint mail_transaction_log_rotate(struct mail_transaction_log *log, bool reset)
abb83d133dd082527d500916fca66a72fbbbaa8dTimo Sirainen{
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen struct mail_transaction_log_file *file;
e4423c16a4f798ecf75ca2b0c3ef834000faed4bTimo Sirainen const char *path = log->head->filepath;
e4423c16a4f798ecf75ca2b0c3ef834000faed4bTimo Sirainen struct stat st;
e4423c16a4f798ecf75ca2b0c3ef834000faed4bTimo Sirainen
e4423c16a4f798ecf75ca2b0c3ef834000faed4bTimo Sirainen i_assert(log->head->locked);
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen if (MAIL_INDEX_IS_IN_MEMORY(log->index)) {
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen file = mail_transaction_log_file_alloc_in_memory(log);
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen if (reset) {
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen file->hdr.prev_file_seq = 0;
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen file->hdr.prev_file_offset = 0;
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen } else {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* we're locked, we shouldn't need to worry about ESTALE
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen problems in here. */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (fstat(log->head->fd, &st) < 0) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail_index_file_set_syscall_error(log->index,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen log->head->filepath, "fstat()");
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return -1;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen file = mail_transaction_log_file_alloc(log, path);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen file->st_dev = st.st_dev;
a04b6515c20b431294626400e173d81f3d25889bTimo Sirainen file->st_ino = st.st_ino;
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen file->last_mtime = st.st_mtime;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen file->last_size = st.st_size;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen if (mail_transaction_log_file_create(file, reset) < 0) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail_transaction_log_file_free(&file);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return -1;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (--log->head->refcount == 0)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail_transaction_logs_clean(log);
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen else
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail_transaction_log_file_unlock(log->head);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail_transaction_log_set_head(log, file);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return 0;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen}
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstatic int
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenmail_transaction_log_refresh(struct mail_transaction_log *log, bool nfs_flush)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct mail_transaction_log_file *file;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct stat st;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen i_assert(log->head != NULL);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(log->head))
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen return 0;
11768c622a8e5aaf0e5d9b3c9a872867b62b4830Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (nfs_flush && log->nfs_flush)
11768c622a8e5aaf0e5d9b3c9a872867b62b4830Timo Sirainen nfs_flush_file_handle_cache(log->filepath);
265e9d8457aa5ce01b7aad954632aed8c36deeb8Timo Sirainen if (nfs_safe_stat(log->filepath, &st) < 0) {
265e9d8457aa5ce01b7aad954632aed8c36deeb8Timo Sirainen if (errno != ENOENT) {
265e9d8457aa5ce01b7aad954632aed8c36deeb8Timo Sirainen mail_index_file_set_syscall_error(log->index,
265e9d8457aa5ce01b7aad954632aed8c36deeb8Timo Sirainen log->filepath,
11768c622a8e5aaf0e5d9b3c9a872867b62b4830Timo Sirainen "stat()");
265e9d8457aa5ce01b7aad954632aed8c36deeb8Timo Sirainen return -1;
265e9d8457aa5ce01b7aad954632aed8c36deeb8Timo Sirainen }
265e9d8457aa5ce01b7aad954632aed8c36deeb8Timo Sirainen /* see if the whole directory got deleted */
11768c622a8e5aaf0e5d9b3c9a872867b62b4830Timo Sirainen if (nfs_safe_stat(log->index->dir, &st) < 0 &&
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen errno == ENOENT) {
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen log->index->index_deleted = TRUE;
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen return -1;
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen }
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen /* the file should always exist at this point. if it doesn't,
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen someone deleted it manually while the index was open. try to
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen handle this nicely by creating a new log file. */
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen file = log->head;
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen if (mail_transaction_log_create(log, FALSE) < 0)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return -1;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen i_assert(file->refcount > 0);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen file->refcount--;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen log->index->need_recreate = TRUE;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return 0;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen } else if (log->head->st_ino == st.st_ino &&
6ebcdea168735ee76e32b871c1f50f3526690447Timo Sirainen CMP_DEV_T(log->head->st_dev, st.st_dev)) {
6ebcdea168735ee76e32b871c1f50f3526690447Timo Sirainen /* NFS: log files get rotated to .log.2 files instead
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen of being unlinked, so we don't bother checking if
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen the existing file has already been unlinked here
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen (in which case inodes could match but point to
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen different files) */
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen return 0;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen file = mail_transaction_log_file_alloc(log, log->filepath);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (mail_transaction_log_file_open(file, FALSE) <= 0) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail_transaction_log_file_free(&file);
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen return -1;
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen }
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen i_assert(!file->locked);
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen if (--log->head->refcount == 0)
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen mail_transaction_logs_clean(log);
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen mail_transaction_log_set_head(log, file);
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen return 0;
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen}
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainenvoid mail_transaction_log_get_mailbox_sync_pos(struct mail_transaction_log *log,
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen uint32_t *file_seq_r,
a04b6515c20b431294626400e173d81f3d25889bTimo Sirainen uoff_t *file_offset_r)
a04b6515c20b431294626400e173d81f3d25889bTimo Sirainen{
a04b6515c20b431294626400e173d81f3d25889bTimo Sirainen *file_seq_r = log->head->hdr.file_seq;
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen *file_offset_r = log->head->max_tail_offset;
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen}
a04b6515c20b431294626400e173d81f3d25889bTimo Sirainen
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainenvoid mail_transaction_log_set_mailbox_sync_pos(struct mail_transaction_log *log,
7bb939ef70752f2731d27b18c944ea94e5b23eb5Timo Sirainen uint32_t file_seq,
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen uoff_t file_offset)
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen{
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen i_assert(file_seq == log->head->hdr.file_seq);
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen i_assert(file_offset >= log->head->saved_tail_offset);
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen if (file_offset >= log->head->max_tail_offset)
a04b6515c20b431294626400e173d81f3d25889bTimo Sirainen log->head->max_tail_offset = file_offset;
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen}
a04b6515c20b431294626400e173d81f3d25889bTimo Sirainen
8e574a603c2c02105b073906a7ca91904271b80eTimo Sirainenint mail_transaction_log_find_file(struct mail_transaction_log *log,
8e574a603c2c02105b073906a7ca91904271b80eTimo Sirainen uint32_t file_seq, bool nfs_flush,
8e574a603c2c02105b073906a7ca91904271b80eTimo Sirainen struct mail_transaction_log_file **file_r)
8e574a603c2c02105b073906a7ca91904271b80eTimo Sirainen{
a04b6515c20b431294626400e173d81f3d25889bTimo Sirainen struct mail_transaction_log_file *file;
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen int ret;
a04b6515c20b431294626400e173d81f3d25889bTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (file_seq > log->head->hdr.file_seq) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* see if the .log file has been recreated */
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen if (log->head->locked) {
a04b6515c20b431294626400e173d81f3d25889bTimo Sirainen /* transaction log is locked. there's no way a newer
a04b6515c20b431294626400e173d81f3d25889bTimo Sirainen file exists. */
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen return 0;
a04b6515c20b431294626400e173d81f3d25889bTimo Sirainen }
a04b6515c20b431294626400e173d81f3d25889bTimo Sirainen if (log->index->open_count == 0) {
9c4c535b86e9473ad97c6e9242ed84f3d9d69d0dTimo Sirainen /* we're opening the index and we just opened the
9c4c535b86e9473ad97c6e9242ed84f3d9d69d0dTimo Sirainen log file. don't waste time checking if there's a
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen newer one. */
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen return 0;
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen }
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (mail_transaction_log_refresh(log, FALSE) < 0)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return -1;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (file_seq > log->head->hdr.file_seq) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (!nfs_flush || !log->nfs_flush)
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen return 0;
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen /* try again, this time flush attribute cache */
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen if (mail_transaction_log_refresh(log, TRUE) < 0)
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen return -1;
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen if (file_seq > log->head->hdr.file_seq)
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen return 0;
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen }
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen }
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen for (file = log->files; file != NULL; file = file->next) {
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen if (file->hdr.file_seq == file_seq) {
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen *file_r = file;
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen return 1;
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen }
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen }
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen if (MAIL_INDEX_IS_IN_MEMORY(log->index))
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen return 0;
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen /* see if we have it in log.2 file */
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen file = mail_transaction_log_file_alloc(log, log->filepath2);
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen if ((ret = mail_transaction_log_file_open(file, TRUE)) <= 0) {
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen mail_transaction_log_file_free(&file);
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen return ret;
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen }
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen /* but is it what we expected? */
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen if (file->hdr.file_seq != file_seq)
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen return 0;
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen *file_r = file;
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen return 1;
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen}
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainenint mail_transaction_log_lock_head(struct mail_transaction_log *log)
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen{
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen struct mail_transaction_log_file *file;
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen int ret = 0;
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen if (!log->log_2_unlink_checked) {
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen /* we need to check once in a while if .log.2 should be deleted
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen to avoid wasting space on such old files. but we also don't
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen want to waste time on checking it when the same mailbox
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen gets opened over and over again rapidly (e.g. pop3). so
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen do this only when there have actually been some changes
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen to mailbox (i.e. when it's being locked here) */
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen log->log_2_unlink_checked = TRUE;
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen mail_transaction_log_2_unlink_old(log);
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen }
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen /* we want to get the head file locked. this is a bit racy,
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen since by the time we have it locked a new log file may have been
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen created.
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen creating new log file requires locking the head file, so if we
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen can lock it and don't see another file, we can be sure no-one is
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen creating a new log at the moment */
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen for (;;) {
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen file = log->head;
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen if (mail_transaction_log_file_lock(file) < 0)
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen return -1;
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen file->refcount++;
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen ret = mail_transaction_log_refresh(log, TRUE);
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen if (--file->refcount == 0) {
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen mail_transaction_logs_clean(log);
dbd9604da561399cc6255289d5b6f6f662ab2d00Timo Sirainen file = NULL;
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen }
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen if (ret == 0 && log->head == file) {
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen /* success */
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen break;
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen }
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen if (file != NULL)
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen mail_transaction_log_file_unlock(file);
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen
2c20ffcb5bb1ccdfdcd0b0ff0c7296f65b990362Timo Sirainen if (ret < 0)
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen break;
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen /* try again */
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen }
114a0f74e0f825c6bd8aeadfafb248a030762a1fTimo Sirainen
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen return ret;
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen}
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainenint mail_transaction_log_sync_lock(struct mail_transaction_log *log,
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen uint32_t *file_seq_r, uoff_t *file_offset_r)
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen{
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen i_assert(!log->index->log_sync_locked);
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen if (mail_transaction_log_lock_head(log) < 0)
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen return -1;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen /* update sync_offset */
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen if (mail_transaction_log_file_map(log->head, log->head->sync_offset,
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen (uoff_t)-1) <= 0) {
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen mail_transaction_log_file_unlock(log->head);
df6478c4cf605bd81b3891c148b84c14eb6c4035Timo Sirainen return -1;
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen }
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen log->index->log_sync_locked = TRUE;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen *file_seq_r = log->head->hdr.file_seq;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen *file_offset_r = log->head->sync_offset;
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen return 0;
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen}
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvoid mail_transaction_log_sync_unlock(struct mail_transaction_log *log)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen i_assert(log->index->log_sync_locked);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen log->index->log_sync_locked = FALSE;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail_transaction_log_file_unlock(log->head);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen}
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvoid mail_transaction_log_get_head(struct mail_transaction_log *log,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen uint32_t *file_seq_r, uoff_t *file_offset_r)
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen{
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen *file_seq_r = log->head->hdr.file_seq;
6157a322f2ac1ea1332d9003ecb0b11466aa8fe7Timo Sirainen *file_offset_r = log->head->sync_offset;
6157a322f2ac1ea1332d9003ecb0b11466aa8fe7Timo Sirainen}
6157a322f2ac1ea1332d9003ecb0b11466aa8fe7Timo Sirainen
6157a322f2ac1ea1332d9003ecb0b11466aa8fe7Timo Sirainenvoid mail_transaction_log_get_tail(struct mail_transaction_log *log,
6157a322f2ac1ea1332d9003ecb0b11466aa8fe7Timo Sirainen uint32_t *file_seq_r)
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen{
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen struct mail_transaction_log_file *tail, *file = log->files;
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen for (tail = file; file->next != NULL; file = file->next) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (file->hdr.file_seq + 1 != file->next->hdr.file_seq)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen tail = file->next;
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen }
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen *file_seq_r = tail->hdr.file_seq;
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen}
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainenbool mail_transaction_log_is_head_prev(struct mail_transaction_log *log,
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen uint32_t file_seq, uoff_t file_offset)
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen{
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen return log->head->hdr.prev_file_seq == file_seq &&
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen log->head->hdr.prev_file_offset == file_offset;
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen}
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainenint mail_transaction_log_get_mtime(struct mail_transaction_log *log,
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen time_t *mtime_r)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen struct stat st;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen *mtime_r = 0;
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen if (stat(log->filepath, &st) < 0) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (errno == ENOENT)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return 0;
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail_index_file_set_syscall_error(log->index, log->filepath,
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen "stat()");
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen return -1;
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen }
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen *mtime_r = st.st_mtime;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return 0;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen}
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenint mail_transaction_log_unlink(struct mail_transaction_log *log)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (unlink(log->filepath) < 0 &&
d5ac54ef50db16b50689b5c8b7bb64d344190832Timo Sirainen errno != ENOENT && errno != ESTALE) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail_index_file_set_syscall_error(log->index, log->filepath,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen "unlink()");
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return -1;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return 0;
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen}
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvoid mail_transaction_log_get_dotlock_set(struct mail_transaction_log *log,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct dotlock_settings *set_r)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct mail_index *index = log->index;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen memset(set_r, 0, sizeof(*set_r));
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen set_r->timeout = I_MIN(MAIL_TRANSCATION_LOG_LOCK_TIMEOUT,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen index->max_lock_timeout_secs);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen set_r->stale_timeout = MAIL_TRANSCATION_LOG_LOCK_CHANGE_TIMEOUT;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen set_r->nfs_flush = (index->flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) != 0;
set_r->use_excl_lock =
(index->flags & MAIL_INDEX_OPEN_FLAG_DOTLOCK_USE_EXCL) != 0;
}