mail-transaction-log.c revision fd71a4ab1c89b6a8cf7f3864a84868b2043fcc60
5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294Timo Sirainen/* Copyright (c) 2003-2017 Dovecot authors, see the included COPYING file */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "lib.h"
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen#include "ioloop.h"
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen#include "buffer.h"
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen#include "file-dotlock.h"
0536ccb51d41e3078c3a9fa33e509fb4b2420f95Timo Sirainen#include "nfs-workarounds.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "mmap-util.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "mail-index-private.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "mail-transaction-log-private.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include <stddef.h>
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include <stdio.h>
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include <sys/stat.h>
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainenstatic void
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainenmail_transaction_log_set_head(struct mail_transaction_log *log,
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen struct mail_transaction_log_file *file)
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen{
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen i_assert(log->head != file);
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen file->refcount++;
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen log->head = file;
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen i_assert(log->files != NULL);
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen i_assert(log->files->next != NULL || log->files == file);
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen}
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainenstruct mail_transaction_log *
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainenmail_transaction_log_alloc(struct mail_index *index)
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen{
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen struct mail_transaction_log *log;
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen log = i_new(struct mail_transaction_log, 1);
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen log->index = index;
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen return log;
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen}
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainenstatic void mail_transaction_log_2_unlink_old(struct mail_transaction_log *log)
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct stat st;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (MAIL_INDEX_IS_IN_MEMORY(log->index))
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (nfs_safe_stat(log->filepath2, &st) < 0) {
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen if (errno != ENOENT) {
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen mail_index_set_error(log->index,
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen "stat(%s) failed: %m", log->filepath2);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen }
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen return;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen }
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen if (ioloop_time - st.st_mtime >= (time_t)log->index->log_rotate_log2_stale_secs &&
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen !log->index->readonly)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_unlink_if_exists(log->filepath2);
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen}
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainenint mail_transaction_log_open(struct mail_transaction_log *log)
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen{
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen struct mail_transaction_log_file *file;
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen const char *reason;
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen int ret;
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen i_free(log->filepath);
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen i_free(log->filepath2);
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen log->filepath = i_strconcat(log->index->filepath,
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen MAIL_TRANSACTION_LOG_SUFFIX, NULL);
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen log->filepath2 = i_strconcat(log->filepath, ".2", NULL);
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen /* these settings aren't available at alloc() time, so we need to
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen set them here: */
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen log->nfs_flush =
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen (log->index->flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) != 0;
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen if (log->open_file != NULL)
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen mail_transaction_log_file_free(&log->open_file);
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen if (MAIL_INDEX_IS_IN_MEMORY(log->index))
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen return 0;
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen file = mail_transaction_log_file_alloc(log, log->filepath);
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen if ((ret = mail_transaction_log_file_open(file, &reason)) <= 0) {
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen /* leave the file for _create() */
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen log->open_file = file;
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen return ret;
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen }
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen mail_transaction_log_set_head(log, file);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return 1;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenint mail_transaction_log_create(struct mail_transaction_log *log, bool reset)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct mail_transaction_log_file *file;
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen if (MAIL_INDEX_IS_IN_MEMORY(log->index)) {
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen file = mail_transaction_log_file_alloc_in_memory(log);
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen mail_transaction_log_set_head(log, file);
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen return 0;
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen }
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen file = mail_transaction_log_file_alloc(log, log->filepath);
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen if (log->open_file != NULL) {
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen /* remember what file we tried to open. if someone else created
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen a new file, use it instead of recreating it */
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen file->st_ino = log->open_file->st_ino;
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen file->st_dev = log->open_file->st_dev;
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen file->last_size = log->open_file->last_size;
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen file->last_mtime = log->open_file->last_mtime;
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen mail_transaction_log_file_free(&log->open_file);
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen }
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen if (mail_transaction_log_file_create(file, reset) < 0) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mail_transaction_log_file_free(&file);
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen return -1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen mail_transaction_log_set_head(log, file);
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen return 1;
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen}
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainenvoid mail_transaction_log_close(struct mail_transaction_log *log)
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_assert(log->views == NULL);
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (log->open_file != NULL)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mail_transaction_log_file_free(&log->open_file);
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainen if (log->head != NULL)
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainen log->head->refcount--;
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainen mail_transaction_logs_clean(log);
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainen i_assert(log->files == NULL);
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainen}
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainenvoid mail_transaction_log_free(struct mail_transaction_log **_log)
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen{
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen struct mail_transaction_log *log = *_log;
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen *_log = NULL;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen mail_transaction_log_close(log);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen log->index->log = NULL;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen i_free(log->filepath);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen i_free(log->filepath2);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen i_free(log);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen}
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainenint mail_transaction_log_move_to_memory(struct mail_transaction_log *log)
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen{
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct mail_transaction_log_file *file;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen if (!log->index->initial_mapped && log->files != NULL &&
0892446b45c195461bb7be6599f02d97e1e2c9b2Timo Sirainen log->files->hdr.prev_file_seq != 0) {
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen /* we couldn't read dovecot.index and we don't have the first
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen .log file, so just start from scratch */
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen mail_transaction_log_close(log);
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen i_free(log->filepath);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_free(log->filepath2);
9e095dd6a77097356aca8216356d4d71ef1bea45Timo Sirainen log->filepath = i_strconcat(log->index->filepath,
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen MAIL_TRANSACTION_LOG_SUFFIX, NULL);
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen log->filepath2 = i_strconcat(log->filepath, ".2", NULL);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen if (log->head != NULL)
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen return mail_transaction_log_file_move_to_memory(log->head);
0892446b45c195461bb7be6599f02d97e1e2c9b2Timo Sirainen else {
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen file = mail_transaction_log_file_alloc_in_memory(log);
7af4788b402346c94496095dd819f95ce03fe431Timo Sirainen mail_transaction_log_set_head(log, file);
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen return 0;
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen }
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen}
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainenvoid mail_transaction_log_indexid_changed(struct mail_transaction_log *log)
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen{
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen struct mail_transaction_log_file *file;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen mail_transaction_logs_clean(log);
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen for (file = log->files; file != NULL; file = file->next) {
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen if (file->hdr.indexid != log->index->indexid) {
c24ef531ca58abad996482f5c2e8992be9ae8981Timo Sirainen mail_transaction_log_file_set_corrupted(file,
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen "indexid changed: %u -> %u",
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen file->hdr.indexid, log->index->indexid);
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen }
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen }
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen
e4c81823af1fc43ca3f2ce9eb4af7fc8f57b13a5Timo Sirainen if (log->head != NULL &&
e4c81823af1fc43ca3f2ce9eb4af7fc8f57b13a5Timo Sirainen log->head->hdr.indexid != log->index->indexid) {
2524ef7b34965a1b1895d6140fd8296bf57c78d2Timo Sirainen if (--log->head->refcount == 0)
0892446b45c195461bb7be6599f02d97e1e2c9b2Timo Sirainen mail_transaction_log_file_free(&log->head);
e4c81823af1fc43ca3f2ce9eb4af7fc8f57b13a5Timo Sirainen (void)mail_transaction_log_create(log, FALSE);
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen }
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen}
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainenvoid mail_transaction_logs_clean(struct mail_transaction_log *log)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct mail_transaction_log_file *file, *next;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen /* remove only files from the beginning. this way if a view has
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen referenced an old file, it can still find the new files even if
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen there aren't any references to it currently. */
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen for (file = log->files; file != NULL; file = next) {
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen next = file->next;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen i_assert(file->refcount >= 0);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen if (file->refcount > 0)
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen break;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen mail_transaction_log_file_free(&file);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen }
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen /* sanity check: we shouldn't have locked refcount=0 files */
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen for (; file != NULL; file = file->next) {
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen i_assert(!file->locked || file->refcount > 0);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen }
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen i_assert(log->head == NULL || log->files != NULL);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen}
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainenbool mail_transaction_log_want_rotate(struct mail_transaction_log *log)
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen{
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen struct mail_transaction_log_file *file = log->head;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen if (file->hdr.major_version < MAIL_TRANSACTION_LOG_MAJOR_VERSION ||
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen (file->hdr.major_version == MAIL_TRANSACTION_LOG_MAJOR_VERSION &&
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen file->hdr.minor_version < MAIL_TRANSACTION_LOG_MINOR_VERSION)) {
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen /* upgrade immediately to a new log file format */
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen return TRUE;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen }
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen if (file->sync_offset > log->index->log_rotate_max_size) {
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen /* file is too large, definitely rotate */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return TRUE;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (file->sync_offset < log->index->log_rotate_min_size) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* file is still too small */
20344c0e814139e3c365fbb9287478f91512089eTimo Sirainen return FALSE;
20344c0e814139e3c365fbb9287478f91512089eTimo Sirainen }
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* rotate if the timestamp is old enough */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return file->hdr.create_stamp <
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ioloop_time - log->index->log_rotate_min_created_ago_secs;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenint mail_transaction_log_rotate(struct mail_transaction_log *log, bool reset)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct mail_transaction_log_file *file;
20344c0e814139e3c365fbb9287478f91512089eTimo Sirainen const char *path = log->head->filepath;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct stat st;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen int ret;
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(log->head->locked);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen if (MAIL_INDEX_IS_IN_MEMORY(log->index)) {
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen file = mail_transaction_log_file_alloc_in_memory(log);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (reset) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen file->hdr.prev_file_seq = 0;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen file->hdr.prev_file_offset = 0;
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen }
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen } else {
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen /* we're locked, we shouldn't need to worry about ESTALE
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen problems in here. */
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen if (fstat(log->head->fd, &st) < 0) {
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen mail_index_file_set_syscall_error(log->index,
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen log->head->filepath, "fstat()");
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen return -1;
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen }
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen file = mail_transaction_log_file_alloc(log, path);
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen file->st_dev = st.st_dev;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen file->st_ino = st.st_ino;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen file->last_mtime = st.st_mtime;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen file->last_size = st.st_size;
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen if ((ret = mail_transaction_log_file_create(file, reset)) < 0) {
601f5f14c6cde28f0e0c6ca7c5d735315d3d48dfTimo Sirainen mail_transaction_log_file_free(&file);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen return -1;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen }
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen if (ret == 0) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mail_index_set_error(log->index,
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen "Transaction log %s was recreated while we had it locked - "
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen "locking is broken (lock_method=%s)", path,
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen file_lock_method_to_str(log->index->lock_method));
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen mail_transaction_log_file_free(&file);
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen return -1;
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen }
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen i_assert(file->locked);
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen }
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen if (--log->head->refcount == 0)
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen mail_transaction_logs_clean(log);
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen else {
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen /* the newly created log file is already locked */
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen mail_transaction_log_file_unlock(log->head,
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen !log->index->log_sync_locked ? "rotating" :
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen "rotating while syncing");
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mail_transaction_log_set_head(log, file);
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen return 0;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen}
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenstatic int
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainenmail_transaction_log_refresh(struct mail_transaction_log *log, bool nfs_flush,
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen const char **reason_r)
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen{
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen struct mail_transaction_log_file *file;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen struct stat st;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen i_assert(log->head != NULL);
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(log->head)) {
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen *reason_r = "Log is in memory";
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen return 0;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen }
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen if (nfs_flush && log->nfs_flush)
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen nfs_flush_file_handle_cache(log->filepath);
548e394330621952db0f03dd667b70184c4a37b6Timo Sirainen if (nfs_safe_stat(log->filepath, &st) < 0) {
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen if (errno != ENOENT) {
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen mail_index_file_set_syscall_error(log->index,
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen log->filepath,
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen "stat()");
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen *reason_r = t_strdup_printf("stat(%s) failed: %m", log->filepath);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen return -1;
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen }
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen /* see if the whole directory got deleted */
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen if (nfs_safe_stat(log->index->dir, &st) < 0 &&
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen errno == ENOENT) {
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen log->index->index_deleted = TRUE;
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen *reason_r = "Index directory was deleted";
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen return -1;
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen }
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen /* the file should always exist at this point. if it doesn't,
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen someone deleted it manually while the index was open. try to
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen handle this nicely by creating a new log file. */
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen file = log->head;
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen if (mail_transaction_log_create(log, FALSE) < 0) {
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen *reason_r = "Failed to create log";
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen return -1;
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen }
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen i_assert(file->refcount > 0);
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen file->refcount--;
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen log->index->need_recreate = TRUE;
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen *reason_r = "Log created";
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen return 0;
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen } else if (log->head->st_ino == st.st_ino &&
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen CMP_DEV_T(log->head->st_dev, st.st_dev)) {
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen /* NFS: log files get rotated to .log.2 files instead
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen of being unlinked, so we don't bother checking if
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainen the existing file has already been unlinked here
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainen (in which case inodes could match but point to
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainen different files) */
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainen *reason_r = "Log inode is unchanged";
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainen return 0;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen }
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen file = mail_transaction_log_file_alloc(log, log->filepath);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen if (mail_transaction_log_file_open(file, reason_r) <= 0) {
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen mail_transaction_log_file_free(&file);
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen return -1;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen }
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen i_assert(!file->locked);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen if (--log->head->refcount == 0)
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen mail_transaction_logs_clean(log);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen mail_transaction_log_set_head(log, file);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen *reason_r = "Log reopened";
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen return 0;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen}
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainenvoid mail_transaction_log_get_mailbox_sync_pos(struct mail_transaction_log *log,
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen uint32_t *file_seq_r,
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen uoff_t *file_offset_r)
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen{
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen *file_seq_r = log->head->hdr.file_seq;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen *file_offset_r = log->head->max_tail_offset;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen}
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainenvoid mail_transaction_log_set_mailbox_sync_pos(struct mail_transaction_log *log,
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen uint32_t file_seq,
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen uoff_t file_offset)
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen{
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen i_assert(file_seq == log->head->hdr.file_seq);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen i_assert(file_offset >= log->head->saved_tail_offset);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen if (file_offset >= log->head->max_tail_offset)
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen log->head->max_tail_offset = file_offset;
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen}
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainenint mail_transaction_log_find_file(struct mail_transaction_log *log,
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen uint32_t file_seq, bool nfs_flush,
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen struct mail_transaction_log_file **file_r,
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen const char **reason_r)
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen{
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen struct mail_transaction_log_file *file;
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen const char *reason;
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen int ret;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (file_seq > log->head->hdr.file_seq) {
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen /* see if the .log file has been recreated */
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainen if (log->head->locked) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* transaction log is locked. there's no way a newer
0611067f385a37773800225256dcd5cf6aa34212Timo Sirainen file exists. */
df16c7e87511fed827e6890a2a47d13ca48716deTimo Sirainen *reason_r = "Log is locked - newer log can't exist";
df16c7e87511fed827e6890a2a47d13ca48716deTimo Sirainen return 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
0611067f385a37773800225256dcd5cf6aa34212Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (mail_transaction_log_refresh(log, FALSE, &reason) < 0) {
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainen *reason_r = reason;
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainen return -1;
b7651d283ca261015ef3c445f1f27f340f0864e2Timo Sirainen }
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainen if (file_seq > log->head->hdr.file_seq) {
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainen if (!nfs_flush || !log->nfs_flush) {
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainen *reason_r = t_strdup_printf(
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen "Requested newer log than exists: %s", reason);
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainen return 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* try again, this time flush attribute cache */
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen if (mail_transaction_log_refresh(log, TRUE, &reason) < 0) {
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen *reason_r = t_strdup_printf(
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen "Log refresh with NFS flush failed: %s", reason);
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen return -1;
1036ad17ac837a451f6b045cac504d3efa2edb8eTimo Sirainen }
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen if (file_seq > log->head->hdr.file_seq) {
1036ad17ac837a451f6b045cac504d3efa2edb8eTimo Sirainen *reason_r = t_strdup_printf(
1036ad17ac837a451f6b045cac504d3efa2edb8eTimo Sirainen "Requested newer log than exists - "
1036ad17ac837a451f6b045cac504d3efa2edb8eTimo Sirainen "still after NFS flush: %s", reason);
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen return 0;
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen }
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen }
c0b1543512bc3e0a3a9f526056a3678a07ce32f5Timo Sirainen }
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen for (file = log->files; file != NULL; file = file->next) {
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen if (file->hdr.file_seq == file_seq) {
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen *file_r = file;
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen return 1;
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen }
1036ad17ac837a451f6b045cac504d3efa2edb8eTimo Sirainen }
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen if (MAIL_INDEX_IS_IN_MEMORY(log->index)) {
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen *reason_r = "Logs are only in memory";
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen return 0;
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen }
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen /* see if we have it in log.2 file */
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen file = mail_transaction_log_file_alloc(log, log->filepath2);
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen if ((ret = mail_transaction_log_file_open(file, reason_r)) <= 0) {
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen mail_transaction_log_file_free(&file);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return ret;
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* but is it what we expected? */
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen if (file->hdr.file_seq != file_seq) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen *reason_r = t_strdup_printf(".log.2 contains file_seq=%u",
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen file->hdr.file_seq);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return 0;
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen *file_r = file;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return 1;
3785910c303507db5f629684e6dde2cc7f83668eTimo Sirainen}
3785910c303507db5f629684e6dde2cc7f83668eTimo Sirainen
3785910c303507db5f629684e6dde2cc7f83668eTimo Sirainenint mail_transaction_log_lock_head(struct mail_transaction_log *log,
3785910c303507db5f629684e6dde2cc7f83668eTimo Sirainen const char *lock_reason)
3785910c303507db5f629684e6dde2cc7f83668eTimo Sirainen{
3785910c303507db5f629684e6dde2cc7f83668eTimo Sirainen struct mail_transaction_log_file *file;
3785910c303507db5f629684e6dde2cc7f83668eTimo Sirainen time_t lock_wait_started, lock_secs = 0;
3785910c303507db5f629684e6dde2cc7f83668eTimo Sirainen const char *reason;
3785910c303507db5f629684e6dde2cc7f83668eTimo Sirainen int ret = 0;
3785910c303507db5f629684e6dde2cc7f83668eTimo Sirainen
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen /* we want to get the head file locked. this is a bit racy,
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen since by the time we have it locked a new log file may have been
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen created.
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen creating new log file requires locking the head file, so if we
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen can lock it and don't see another file, we can be sure no-one is
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen creating a new log at the moment */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen lock_wait_started = time(NULL);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen for (;;) {
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen file = log->head;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (mail_transaction_log_file_lock(file) < 0)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return -1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen file->refcount++;
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen ret = mail_transaction_log_refresh(log, TRUE, &reason);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (--file->refcount == 0) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mail_transaction_log_file_unlock(file, t_strdup_printf(
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen "trying to lock head for %s", lock_reason));
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mail_transaction_logs_clean(log);
37ab3cde96bfa4bc5304c0c348fc420aec79572dTimo Sirainen file = NULL;
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen }
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen
37ab3cde96bfa4bc5304c0c348fc420aec79572dTimo Sirainen if (ret == 0 && log->head == file) {
37ab3cde96bfa4bc5304c0c348fc420aec79572dTimo Sirainen /* success */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_assert(file != NULL);
f4bbeadda12fbd7c219063db68f3e78646d83c2cTimo Sirainen lock_secs = file->lock_created - lock_wait_started;
0b47e9f5e0181053b4d9ca7b426b0e5c185e820eTimo Sirainen break;
0b47e9f5e0181053b4d9ca7b426b0e5c185e820eTimo Sirainen }
abe8754852e70763e92f74caabbcc13d0917714cTimo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (file != NULL) {
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen mail_transaction_log_file_unlock(file, t_strdup_printf(
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen "trying to lock head for %s", lock_reason));
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen }
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen if (ret < 0)
90b8f131849540fa374aede95edd86d47d35c09dTimo Sirainen break;
90b8f131849540fa374aede95edd86d47d35c09dTimo Sirainen
90b8f131849540fa374aede95edd86d47d35c09dTimo Sirainen /* try again */
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen }
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen if (lock_secs > MAIL_TRANSACTION_LOG_LOCK_WARN_SECS) {
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen i_warning("Locking transaction log file %s took %ld seconds (%s)",
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen log->head->filepath, (long)lock_secs, lock_reason);
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen }
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen i_assert(ret < 0 || log->head != NULL);
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen return ret;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen}
90b8f131849540fa374aede95edd86d47d35c09dTimo Sirainen
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainenint mail_transaction_log_sync_lock(struct mail_transaction_log *log,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen const char *lock_reason,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen uint32_t *file_seq_r, uoff_t *file_offset_r)
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen{
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen const char *reason;
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen i_assert(!log->index->log_sync_locked);
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen if (!log->log_2_unlink_checked) {
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen /* we need to check once in a while if .log.2 should be deleted
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen to avoid wasting space on such old files. but we also don't
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen want to waste time on checking it when the same mailbox
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen gets opened over and over again rapidly (e.g. pop3). so
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen do this only when there have actually been some changes
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen to mailbox (i.e. when it's being locked here) */
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen log->log_2_unlink_checked = TRUE;
97e62b2b36dda0acb3215667042f5c80cdee8155Timo Sirainen mail_transaction_log_2_unlink_old(log);
97e62b2b36dda0acb3215667042f5c80cdee8155Timo Sirainen }
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen if (mail_transaction_log_lock_head(log, lock_reason) < 0)
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen return -1;
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen /* update sync_offset */
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen if (mail_transaction_log_file_map(log->head, log->head->sync_offset,
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen (uoff_t)-1, &reason) <= 0) {
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen mail_index_set_error(log->index,
97e62b2b36dda0acb3215667042f5c80cdee8155Timo Sirainen "Failed to map transaction log %s at "
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen "sync_offset=%"PRIuUOFF_T" after locking: %s",
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen log->head->filepath, log->head->sync_offset, reason);
7d5d50dd9a8c2539d7025a69e39d34fca56daeafTimo Sirainen mail_transaction_log_file_unlock(log->head, t_strdup_printf(
7d5d50dd9a8c2539d7025a69e39d34fca56daeafTimo Sirainen "%s - map failed", lock_reason));
7d5d50dd9a8c2539d7025a69e39d34fca56daeafTimo Sirainen return -1;
7d5d50dd9a8c2539d7025a69e39d34fca56daeafTimo Sirainen }
7d5d50dd9a8c2539d7025a69e39d34fca56daeafTimo Sirainen
7d5d50dd9a8c2539d7025a69e39d34fca56daeafTimo Sirainen log->index->log_sync_locked = TRUE;
7d5d50dd9a8c2539d7025a69e39d34fca56daeafTimo Sirainen *file_seq_r = log->head->hdr.file_seq;
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen *file_offset_r = log->head->sync_offset;
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen return 0;
dd2df6a67f10792ce31a3666197c0b6885893a3aTimo Sirainen}
dd2df6a67f10792ce31a3666197c0b6885893a3aTimo Sirainen
14175321ddb88619015866978c05a27786ca4814Timo Sirainenvoid mail_transaction_log_sync_unlock(struct mail_transaction_log *log,
14175321ddb88619015866978c05a27786ca4814Timo Sirainen const char *lock_reason)
14175321ddb88619015866978c05a27786ca4814Timo Sirainen{
14175321ddb88619015866978c05a27786ca4814Timo Sirainen i_assert(log->index->log_sync_locked);
14175321ddb88619015866978c05a27786ca4814Timo Sirainen
14175321ddb88619015866978c05a27786ca4814Timo Sirainen log->index->log_sync_locked = FALSE;
14175321ddb88619015866978c05a27786ca4814Timo Sirainen mail_transaction_log_file_unlock(log->head, lock_reason);
14175321ddb88619015866978c05a27786ca4814Timo Sirainen}
14175321ddb88619015866978c05a27786ca4814Timo Sirainen
14175321ddb88619015866978c05a27786ca4814Timo Sirainenvoid mail_transaction_log_get_head(struct mail_transaction_log *log,
14175321ddb88619015866978c05a27786ca4814Timo Sirainen uint32_t *file_seq_r, uoff_t *file_offset_r)
14175321ddb88619015866978c05a27786ca4814Timo Sirainen{
14175321ddb88619015866978c05a27786ca4814Timo Sirainen *file_seq_r = log->head->hdr.file_seq;
14175321ddb88619015866978c05a27786ca4814Timo Sirainen *file_offset_r = log->head->sync_offset;
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen}
439dd06aec3301e65d650f6dc1d4a1a00b356b4fTimo Sirainen
439dd06aec3301e65d650f6dc1d4a1a00b356b4fTimo Sirainenvoid mail_transaction_log_get_tail(struct mail_transaction_log *log,
439dd06aec3301e65d650f6dc1d4a1a00b356b4fTimo Sirainen uint32_t *file_seq_r)
439dd06aec3301e65d650f6dc1d4a1a00b356b4fTimo Sirainen{
14175321ddb88619015866978c05a27786ca4814Timo Sirainen struct mail_transaction_log_file *tail, *file = log->files;
14175321ddb88619015866978c05a27786ca4814Timo Sirainen
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen for (tail = file; file->next != NULL; file = file->next) {
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen if (file->hdr.file_seq + 1 != file->next->hdr.file_seq)
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen tail = file->next;
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen }
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen *file_seq_r = tail->hdr.file_seq;
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen}
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainenbool mail_transaction_log_is_head_prev(struct mail_transaction_log *log,
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen uint32_t file_seq, uoff_t file_offset)
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen{
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen return log->head->hdr.prev_file_seq == file_seq &&
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen log->head->hdr.prev_file_offset == file_offset;
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen}
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainenint mail_transaction_log_get_mtime(struct mail_transaction_log *log,
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen time_t *mtime_r)
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen{
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen struct stat st;
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen *mtime_r = 0;
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen if (stat(log->filepath, &st) < 0) {
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen if (errno == ENOENT)
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen return 0;
dd2df6a67f10792ce31a3666197c0b6885893a3aTimo Sirainen
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen mail_index_file_set_syscall_error(log->index, log->filepath,
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen "stat()");
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen return -1;
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen }
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen *mtime_r = st.st_mtime;
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen return 0;
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen}
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainenint mail_transaction_log_unlink(struct mail_transaction_log *log)
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen{
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen if (unlink(log->filepath) < 0 &&
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen errno != ENOENT && errno != ESTALE) {
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen mail_index_file_set_syscall_error(log->index, log->filepath,
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen "unlink()");
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen return -1;
01e606cda5192c4254c090624a0b2ca92da6da8eTimo Sirainen }
01e606cda5192c4254c090624a0b2ca92da6da8eTimo Sirainen return 0;
01e606cda5192c4254c090624a0b2ca92da6da8eTimo Sirainen}
01e606cda5192c4254c090624a0b2ca92da6da8eTimo Sirainen
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainenvoid mail_transaction_log_get_dotlock_set(struct mail_transaction_log *log,
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen struct dotlock_settings *set_r)
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen{
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen struct mail_index *index = log->index;
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen i_zero(set_r);
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen set_r->timeout = I_MIN(MAIL_TRANSACTION_LOG_LOCK_TIMEOUT,
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen index->max_lock_timeout_secs);
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen set_r->stale_timeout = MAIL_TRANSACTION_LOG_LOCK_CHANGE_TIMEOUT;
01e606cda5192c4254c090624a0b2ca92da6da8eTimo Sirainen set_r->nfs_flush = (index->flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) != 0;
01e606cda5192c4254c090624a0b2ca92da6da8eTimo Sirainen set_r->use_excl_lock =
01e606cda5192c4254c090624a0b2ca92da6da8eTimo Sirainen (index->flags & MAIL_INDEX_OPEN_FLAG_DOTLOCK_USE_EXCL) != 0;
01e606cda5192c4254c090624a0b2ca92da6da8eTimo Sirainen}
01e606cda5192c4254c090624a0b2ca92da6da8eTimo Sirainen