mail-transaction-log.c revision 837ea26bce080f166b2ec90d901faeff58beb22b
89a126810703c666309310d0f3189e9834d70b5bTimo Sirainen/* Copyright (c) 2003-2007 Dovecot authors, see the included COPYING file */
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen#include "lib.h"
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen#include "ioloop.h"
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen#include "buffer.h"
65988f5a8abed57e9894fec77105941e046d3490Timo Sirainen#include "file-dotlock.h"
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen#include "nfs-workarounds.h"
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen#include "close-keep-errno.h"
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen#include "mmap-util.h"
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen#include "mail-index-private.h"
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen#include "mail-transaction-log-private.h"
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen#include <stddef.h>
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen#include <stdio.h>
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen#include <sys/stat.h>
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen#define MAIL_TRANSACTION_LOG_SUFFIX ".log"
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen#define LOG_NEW_DOTLOCK_SUFFIX ".newlock"
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainenstatic void
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainenmail_transaction_log_set_head(struct mail_transaction_log *log,
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen struct mail_transaction_log_file *file)
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen{
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen i_assert(log->head != file);
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen file->refcount++;
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen log->head = file;
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen i_assert(log->files != NULL);
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen i_assert(log->files->next != NULL || log->files == file);
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen}
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainenstruct mail_transaction_log *
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainenmail_transaction_log_alloc(struct mail_index *index)
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen{
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen struct mail_transaction_log *log;
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen log = i_new(struct mail_transaction_log, 1);
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen log->index = index;
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen log->dotlock_settings.use_excl_lock = index->use_excl_dotlocks;
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen log->dotlock_settings.nfs_flush = index->nfs_flush;
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen log->dotlock_settings.timeout = MAIL_TRANSCATION_LOG_LOCK_TIMEOUT;
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen log->dotlock_settings.stale_timeout =
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen MAIL_TRANSCATION_LOG_LOCK_CHANGE_TIMEOUT;
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen log->new_dotlock_settings = log->dotlock_settings;
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen log->new_dotlock_settings.lock_suffix = LOG_NEW_DOTLOCK_SUFFIX;
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen return log;
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen}
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainenstatic void mail_transaction_log_2_unlink_old(struct mail_transaction_log *log)
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen{
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen struct stat st;
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen const char *path;
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen path = t_strconcat(log->index->filepath,
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen MAIL_TRANSACTION_LOG_SUFFIX".2", NULL);
7c424aa51c956c628e3512055841aa2f9eef4833Timo Sirainen if (stat(path, &st) < 0) {
f923659c0e5298263d80622c99f4dc4132b4675bTimo Sirainen if (errno != ENOENT && errno != ESTALE) {
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen mail_index_set_error(log->index,
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen "stat(%s) failed: %m", path);
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen }
2a3fc652e13a574ca14ff2405b5c29a59232db49Timo Sirainen return;
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen }
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen if (st.st_mtime + MAIL_TRANSACTION_LOG2_STALE_SECS <= ioloop_time) {
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen if (unlink(path) < 0 && errno != ENOENT) {
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen mail_index_set_error(log->index,
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen "unlink(%s) failed: %m", path);
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen }
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen }
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen}
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainenint mail_transaction_log_open(struct mail_transaction_log *log)
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen{
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen struct mail_transaction_log_file *file;
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen const char *path;
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen int ret;
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen if (log->open_file != NULL)
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen mail_transaction_log_file_free(&log->open_file);
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen if (MAIL_INDEX_IS_IN_MEMORY(log->index))
fab050cbfdf3da692441d2e2fb4b2a4c6ac9e0daTimo Sirainen return 0;
fab050cbfdf3da692441d2e2fb4b2a4c6ac9e0daTimo Sirainen
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen path = t_strconcat(log->index->filepath,
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen MAIL_TRANSACTION_LOG_SUFFIX, NULL);
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen file = mail_transaction_log_file_alloc(log, path);
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen if ((ret = mail_transaction_log_file_open(file, FALSE)) <= 0) {
2a3fc652e13a574ca14ff2405b5c29a59232db49Timo Sirainen /* leave the file for _create() */
2a3fc652e13a574ca14ff2405b5c29a59232db49Timo Sirainen log->open_file = file;
2a3fc652e13a574ca14ff2405b5c29a59232db49Timo Sirainen return ret;
2a3fc652e13a574ca14ff2405b5c29a59232db49Timo Sirainen }
2a3fc652e13a574ca14ff2405b5c29a59232db49Timo Sirainen mail_transaction_log_set_head(log, file);
2a3fc652e13a574ca14ff2405b5c29a59232db49Timo Sirainen mail_transaction_log_2_unlink_old(log);
2a3fc652e13a574ca14ff2405b5c29a59232db49Timo Sirainen return 1;
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen}
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainenint mail_transaction_log_create(struct mail_transaction_log *log)
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen{
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen struct mail_transaction_log_file *file;
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen const char *path;
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen if (MAIL_INDEX_IS_IN_MEMORY(log->index)) {
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen file = mail_transaction_log_file_alloc_in_memory(log);
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen mail_transaction_log_set_head(log, file);
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen return 0;
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen }
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen path = t_strconcat(log->index->filepath,
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen MAIL_TRANSACTION_LOG_SUFFIX, NULL);
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen
d65a556a5ec078cd7f1d0060adb16fc860d66b27Timo Sirainen file = mail_transaction_log_file_alloc(log, path);
d65a556a5ec078cd7f1d0060adb16fc860d66b27Timo Sirainen
d65a556a5ec078cd7f1d0060adb16fc860d66b27Timo Sirainen if (log->open_file != NULL) {
e4ded29bff0662a590c2439ef2df8cda8a7cdd9bTimo Sirainen /* remember what file we tried to open. if someone else created
e4ded29bff0662a590c2439ef2df8cda8a7cdd9bTimo Sirainen a new file, use it instead of recreating it */
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen file->st_ino = log->open_file->st_ino;
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen file->st_dev = log->open_file->st_dev;
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen file->last_size = log->open_file->last_size;
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen file->last_mtime = log->open_file->last_mtime;
bc2d4f1c18222a3bd2a6b2b8b5f6abb560a865b3Timo Sirainen mail_transaction_log_file_free(&log->open_file);
bc2d4f1c18222a3bd2a6b2b8b5f6abb560a865b3Timo Sirainen }
345253fb28498b2e0a60f4a2a8644c65feee7e75Timo Sirainen
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen if (mail_transaction_log_file_create(file, FALSE) < 0) {
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen mail_transaction_log_file_free(&file);
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen return -1;
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen }
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen mail_transaction_log_set_head(log, file);
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen return 1;
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen}
a4ee24a4d5eefa80bbefc5acba16587ae36c3b5bTimo Sirainen
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainenvoid mail_transaction_log_close(struct mail_transaction_log *log)
bc2d4f1c18222a3bd2a6b2b8b5f6abb560a865b3Timo Sirainen{
a93de780c3b78cfaace287026e468f3c3e34683aTimo Sirainen mail_transaction_log_views_close(log);
bc2d4f1c18222a3bd2a6b2b8b5f6abb560a865b3Timo Sirainen
bc2d4f1c18222a3bd2a6b2b8b5f6abb560a865b3Timo Sirainen if (log->open_file != NULL)
bc2d4f1c18222a3bd2a6b2b8b5f6abb560a865b3Timo Sirainen mail_transaction_log_file_free(&log->open_file);
bc2d4f1c18222a3bd2a6b2b8b5f6abb560a865b3Timo Sirainen if (log->head != NULL)
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen log->head->refcount--;
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen mail_transaction_logs_clean(log);
345253fb28498b2e0a60f4a2a8644c65feee7e75Timo Sirainen i_assert(log->files == NULL);
65988f5a8abed57e9894fec77105941e046d3490Timo Sirainen}
65988f5a8abed57e9894fec77105941e046d3490Timo Sirainen
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainenvoid mail_transaction_log_free(struct mail_transaction_log **_log)
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen{
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen struct mail_transaction_log *log = *_log;
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen *_log = NULL;
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen
a4ee24a4d5eefa80bbefc5acba16587ae36c3b5bTimo Sirainen mail_transaction_log_close(log);
a4ee24a4d5eefa80bbefc5acba16587ae36c3b5bTimo Sirainen log->index->log = NULL;
af6c7862e6160ffaecec458f4cec43b94272ad57Timo Sirainen i_free(log);
af6c7862e6160ffaecec458f4cec43b94272ad57Timo Sirainen}
af6c7862e6160ffaecec458f4cec43b94272ad57Timo Sirainen
af6c7862e6160ffaecec458f4cec43b94272ad57Timo Sirainenvoid mail_transaction_log_move_to_memory(struct mail_transaction_log *log)
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen{
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen struct mail_transaction_log_file *file;
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen if (log->head != NULL)
055f4599bba1874fa1148a8fa488517fa077619cTimo Sirainen mail_transaction_log_file_move_to_memory(log->head);
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen else {
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen file = mail_transaction_log_file_alloc_in_memory(log);
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen mail_transaction_log_set_head(log, file);
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen }
bc2d4f1c18222a3bd2a6b2b8b5f6abb560a865b3Timo Sirainen}
345253fb28498b2e0a60f4a2a8644c65feee7e75Timo Sirainen
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainenvoid mail_transaction_log_indexid_changed(struct mail_transaction_log *log)
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen{
a93de780c3b78cfaace287026e468f3c3e34683aTimo Sirainen struct mail_transaction_log_file *file;
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen
bc2d4f1c18222a3bd2a6b2b8b5f6abb560a865b3Timo Sirainen mail_transaction_logs_clean(log);
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen
345253fb28498b2e0a60f4a2a8644c65feee7e75Timo Sirainen for (file = log->files; file != NULL; file = file->next) {
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen if (file->hdr.indexid != log->index->indexid) {
a93de780c3b78cfaace287026e468f3c3e34683aTimo Sirainen mail_transaction_log_file_set_corrupted(file,
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen "indexid changed: %u -> %u",
file->hdr.indexid, log->index->indexid);
}
}
if (log->head != NULL &&
log->head->hdr.indexid != log->index->indexid) {
if (--log->head->refcount == 0)
mail_transaction_log_file_free(&log->head);
(void)mail_transaction_log_create(log);
}
}
void mail_transaction_logs_clean(struct mail_transaction_log *log)
{
struct mail_transaction_log_file *file, *next;
/* remove only files from the beginning. this way if a view has
referenced an old file, it can still find the new files even if
there aren't any references to it currently. */
for (file = log->files; file != NULL; file = next) {
next = file->next;
i_assert(file->refcount >= 0);
if (file->refcount > 0)
break;
mail_transaction_log_file_free(&file);
}
i_assert(log->head == NULL || log->files != NULL);
}
#define LOG_WANT_ROTATE(file) \
(((file)->sync_offset > MAIL_TRANSACTION_LOG_ROTATE_MIN_SIZE && \
(time_t)(file)->hdr.create_stamp < \
ioloop_time - MAIL_TRANSACTION_LOG_ROTATE_TIME) || \
((file)->sync_offset > MAIL_TRANSACTION_LOG_ROTATE_MAX_SIZE))
bool mail_transaction_log_want_rotate(struct mail_transaction_log *log)
{
return LOG_WANT_ROTATE(log->head);
}
int mail_transaction_log_rotate(struct mail_transaction_log *log, bool reset)
{
struct mail_transaction_log_file *file;
const char *path = log->head->filepath;
struct stat st;
i_assert(log->head->locked);
if (MAIL_INDEX_IS_IN_MEMORY(log->index)) {
file = mail_transaction_log_file_alloc_in_memory(log);
if (reset) {
file->hdr.prev_file_seq = 0;
file->hdr.prev_file_offset = 0;
}
} else {
/* we're locked, we shouldn't need to worry about ESTALE
problems in here. */
if (fstat(log->head->fd, &st) < 0) {
mail_index_file_set_syscall_error(log->index,
file->filepath, "fstat()");
return -1;
}
file = mail_transaction_log_file_alloc(log, path);
file->st_dev = st.st_dev;
file->st_ino = st.st_ino;
file->last_mtime = st.st_mtime;
file->last_size = st.st_size;
if (mail_transaction_log_file_create(file, reset) < 0) {
mail_transaction_log_file_free(&file);
return -1;
}
}
if (--log->head->refcount == 0)
mail_transaction_logs_clean(log);
else
mail_transaction_log_file_unlock(log->head);
mail_transaction_log_set_head(log, file);
return 0;
}
static int
mail_transaction_log_refresh(struct mail_transaction_log *log, bool nfs_flush)
{
struct mail_transaction_log_file *file;
struct stat st;
const char *path;
i_assert(log->head != NULL);
if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(log->head))
return 0;
path = t_strconcat(log->index->filepath,
MAIL_TRANSACTION_LOG_SUFFIX, NULL);
if (log->index->nfs_flush && nfs_flush)
nfs_flush_attr_cache(path, TRUE);
if (nfs_safe_stat(path, &st) < 0) {
if (errno != ENOENT) {
mail_index_file_set_syscall_error(log->index, path,
"stat()");
return -1;
}
/* the file should always exist at this point. if it doesn't,
someone deleted it manually while the index was open. try to
handle this nicely by creating a new log file. */
file = log->head;
if (mail_transaction_log_create(log) < 0)
return -1;
i_assert(file->refcount > 0);
file->refcount--;
log->index->need_recreate = TRUE;
return 0;
} else if (log->head->st_ino == st.st_ino &&
CMP_DEV_T(log->head->st_dev, st.st_dev)) {
/* NFS: log files get rotated to .log.2 files instead
of being unlinked, so we don't bother checking if
the existing file has already been unlinked here
(in which case inodes could match but point to
different files) */
return 0;
}
file = mail_transaction_log_file_alloc(log, path);
if (mail_transaction_log_file_open(file, FALSE) <= 0) {
mail_transaction_log_file_free(&file);
return -1;
}
i_assert(!file->locked);
if (--log->head->refcount == 0)
mail_transaction_logs_clean(log);
mail_transaction_log_set_head(log, file);
return 0;
}
void mail_transaction_log_get_mailbox_sync_pos(struct mail_transaction_log *log,
uint32_t *file_seq_r,
uoff_t *file_offset_r)
{
*file_seq_r = log->head->hdr.file_seq;
*file_offset_r = log->head->max_tail_offset;
}
void mail_transaction_log_set_mailbox_sync_pos(struct mail_transaction_log *log,
uint32_t file_seq,
uoff_t file_offset)
{
i_assert(file_seq == log->head->hdr.file_seq);
i_assert(file_offset >= log->head->saved_tail_offset);
if (file_offset >= log->head->max_tail_offset)
log->head->max_tail_offset = file_offset;
}
int mail_transaction_log_find_file(struct mail_transaction_log *log,
uint32_t file_seq, bool nfs_flush,
struct mail_transaction_log_file **file_r)
{
struct mail_transaction_log_file *file;
const char *path;
int ret;
if (file_seq > log->head->hdr.file_seq) {
/* see if the .log file has been recreated */
if (log->head->locked) {
/* transaction log is locked. there's no way a newer
file exists. */
return 0;
}
if (mail_transaction_log_refresh(log, FALSE) < 0)
return -1;
if (file_seq > log->head->hdr.file_seq) {
if (!nfs_flush || !log->index->nfs_flush)
return 0;
/* try again, this time flush attribute cache */
if (mail_transaction_log_refresh(log, TRUE) < 0)
return -1;
if (file_seq > log->head->hdr.file_seq)
return 0;
}
}
for (file = log->files; file != NULL; file = file->next) {
if (file->hdr.file_seq == file_seq) {
*file_r = file;
return 1;
}
}
if (MAIL_INDEX_IS_IN_MEMORY(log->index))
return 0;
/* see if we have it in log.2 file */
path = t_strconcat(log->index->filepath,
MAIL_TRANSACTION_LOG_SUFFIX".2", NULL);
file = mail_transaction_log_file_alloc(log, path);
if ((ret = mail_transaction_log_file_open(file, TRUE)) <= 0)
return ret;
/* but is it what we expected? */
if (file->hdr.file_seq != file_seq)
return 0;
*file_r = file;
return 1;
}
int mail_transaction_log_lock_head(struct mail_transaction_log *log)
{
struct mail_transaction_log_file *file;
int ret = 0;
/* we want to get the head file locked. this is a bit racy,
since by the time we have it locked a new log file may have been
created.
creating new log file requires locking the head file, so if we
can lock it and don't see another file, we can be sure no-one is
creating a new log at the moment */
for (;;) {
file = log->head;
if (mail_transaction_log_file_lock(file) < 0)
return -1;
file->refcount++;
ret = mail_transaction_log_refresh(log, TRUE);
if (--file->refcount == 0) {
mail_transaction_logs_clean(log);
file = NULL;
}
if (ret == 0 && log->head == file) {
/* success */
break;
}
if (file != NULL)
mail_transaction_log_file_unlock(file);
if (ret < 0)
break;
/* try again */
}
return ret;
}
int mail_transaction_log_sync_lock(struct mail_transaction_log *log,
uint32_t *file_seq_r, uoff_t *file_offset_r)
{
i_assert(!log->index->log_locked);
if (mail_transaction_log_lock_head(log) < 0)
return -1;
/* update sync_offset */
if (mail_transaction_log_file_map(log->head, log->head->sync_offset,
(uoff_t)-1) <= 0) {
mail_transaction_log_file_unlock(log->head);
return -1;
}
log->index->log_locked = TRUE;
*file_seq_r = log->head->hdr.file_seq;
*file_offset_r = log->head->sync_offset;
return 0;
}
void mail_transaction_log_sync_unlock(struct mail_transaction_log *log)
{
i_assert(log->index->log_locked);
log->index->log_locked = FALSE;
mail_transaction_log_file_unlock(log->head);
}
void mail_transaction_log_get_head(struct mail_transaction_log *log,
uint32_t *file_seq_r, uoff_t *file_offset_r)
{
*file_seq_r = log->head->hdr.file_seq;
*file_offset_r = log->head->sync_offset;
}
bool mail_transaction_log_is_head_prev(struct mail_transaction_log *log,
uint32_t file_seq, uoff_t file_offset)
{
return log->head->hdr.prev_file_seq == file_seq &&
log->head->hdr.prev_file_offset == file_offset;
}