mail-transaction-log.c revision 2bc03d667b58c0a8765a66c52c5718cf62a79cfb
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (C) 2003-2004 Timo Sirainen */
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainen/* this lock should never exist for a long time.. */
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainenmail_transaction_log_file_open_or_create(struct mail_transaction_log *log,
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainen const char *path);
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainenmail_transaction_log_file_alloc_in_memory(struct mail_transaction_log *log);
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainenmail_transaction_log_file_create(struct mail_transaction_log_file *file,
d6cc34b076dced6ebf8af47d72c8242357288312Timo Sirainenmail_transaction_log_file_fd_open_or_create(struct mail_transaction_log_file
4babe70b863c71ea330cbf32ac0b71876f4f9137Timo Sirainenmail_transaction_log_file_read(struct mail_transaction_log_file *file,
3320f4770d1f6c2cdd10f3c4ca5a324beb335339Timo Sirainenmail_transaction_log_file_set_corrupted(struct mail_transaction_log_file *file,
d6cc34b076dced6ebf8af47d72c8242357288312Timo Sirainen const char *fmt, ...)
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainen if (!MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file)) {
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainen "Corrupted transaction log file %s: %s",
4babe70b863c71ea330cbf32ac0b71876f4f9137Timo Sirainen if (file->log->index->log != NULL && file->log->index->map != NULL) {
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainen /* this may have happened because of broken index.
3320f4770d1f6c2cdd10f3c4ca5a324beb335339Timo Sirainen make sure it's ok. */
b66412da78711db8423288847ecfb08469609a03Timo Sirainenmail_transaction_log_file_alloc(struct mail_transaction_log *log,
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainen file = i_new(struct mail_transaction_log_file, 1);
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainenmail_transaction_log_file_free(struct mail_transaction_log_file *file)
b66412da78711db8423288847ecfb08469609a03Timo Sirainen for (p = &file->log->files; *p != NULL; p = &(*p)->next) {
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainen if (munmap(file->mmap_base, file->mmap_size) < 0) {
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainenmail_transaction_log_file_dotlock(struct mail_transaction_log_file *file)
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainen ret = file_dotlock_create(&file->log->dotlock_settings,
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainen "file_dotlock_create()");
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainen "Timeout while waiting for release of "
b66412da78711db8423288847ecfb08469609a03Timo Sirainen "dotlock for transaction log file %s",
b66412da78711db8423288847ecfb08469609a03Timo Sirainenmail_transaction_log_file_undotlock(struct mail_transaction_log_file *file)
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainen ret = file_dotlock_delete(&file->log->dotlock);
5bd2cf0f30371cb0374b026322a6f52fdb20755fTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen "Dotlock was lost for transaction log file %s",
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainenmail_transaction_log_file_lock(struct mail_transaction_log_file *file)
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file)) {
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen if (file->log->index->lock_method == FILE_LOCK_METHOD_DOTLOCK)
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainen return mail_transaction_log_file_dotlock(file);
9c0716dfcd6b575419776848dd7157186ef58d57Timo Sirainen ret = mail_index_lock_fd(file->log->index, file->filepath, file->fd,
9c0716dfcd6b575419776848dd7157186ef58d57Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
9c0716dfcd6b575419776848dd7157186ef58d57Timo Sirainen "mail_index_wait_lock_fd()");
9c0716dfcd6b575419776848dd7157186ef58d57Timo Sirainen "Timeout while waiting for lock for transaction log file %s",
9c0716dfcd6b575419776848dd7157186ef58d57Timo Sirainenvoid mail_transaction_log_file_unlock(struct mail_transaction_log_file *file)
9c0716dfcd6b575419776848dd7157186ef58d57Timo Sirainen if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file))
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen if (file->log->index->lock_method == FILE_LOCK_METHOD_DOTLOCK) {
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen !(((file)->hdr.file_seq == (index)->hdr->log_file_seq && \
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen (index)->hdr->log_file_int_offset >= (file)->hdr.hdr_size) || \
9c0716dfcd6b575419776848dd7157186ef58d57Timo Sirainen ((file)->hdr.prev_file_seq == (index)->hdr->log_file_seq && \
9c0716dfcd6b575419776848dd7157186ef58d57Timo Sirainen (file)->hdr.prev_file_offset == (index)->hdr->log_file_int_offset))
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainenstatic int mail_transaction_log_check_file_seq(struct mail_transaction_log *log)
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen unsigned int lock_id;
afb7901ecb5d5566d4cf19be969654946fbaad4bTimo Sirainen ret = mail_index_lock_shared(index, TRUE, &lock_id);
b66412da78711db8423288847ecfb08469609a03Timo Sirainen else if (INDEX_HAS_MISSING_LOGS(index, file)) {
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen /* broken - fix it by creating a new log file */
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen ret = mail_transaction_log_rotate(log, FALSE);
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainenmail_transaction_log_open_int(struct mail_index *index, bool create)
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen log->dotlock_settings.use_excl_lock = index->use_excl_dotlocks;
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen log->dotlock_settings.timeout = LOG_DOTLOCK_TIMEOUT;
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen log->dotlock_settings.stale_timeout = LOG_DOTLOCK_STALE_TIMEOUT;
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen log->new_dotlock_settings = log->dotlock_settings;
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen log->new_dotlock_settings.lock_suffix = LOG_NEW_DOTLOCK_SUFFIX;
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen file = mail_transaction_log_file_alloc_in_memory(log);
df02611c44e9432e7961223bf9bfa3fb233b1789Timo Sirainen file = mail_transaction_log_file_alloc(log, path);
d6cc34b076dced6ebf8af47d72c8242357288312Timo Sirainen if (mail_transaction_log_file_create(file, FALSE,
d6cc34b076dced6ebf8af47d72c8242357288312Timo Sirainen mail_transaction_log_file_fd_open_or_create(file,
d6cc34b076dced6ebf8af47d72c8242357288312Timo Sirainen file = mail_transaction_log_file_open_or_create(log, path);
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen /* fallback to in-memory indexes */
d6cc34b076dced6ebf8af47d72c8242357288312Timo Sirainen file = mail_transaction_log_file_open_or_create(log, path);
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen /* head log file isn't same as head index file -
df02611c44e9432e7961223bf9bfa3fb233b1789Timo Sirainen shouldn't happen except in race conditions.
df02611c44e9432e7961223bf9bfa3fb233b1789Timo Sirainen lock them and check again */
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen if (mail_transaction_log_check_file_seq(log) < 0) {
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainenmail_transaction_log_open_or_create(struct mail_index *index)
3320f4770d1f6c2cdd10f3c4ca5a324beb335339Timo Sirainen return mail_transaction_log_open_int(index, FALSE);
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainenmail_transaction_log_create(struct mail_index *index)
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen return mail_transaction_log_open_int(index, TRUE);
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainenvoid mail_transaction_log_close(struct mail_transaction_log **_log)
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainenint mail_transaction_log_move_to_memory(struct mail_transaction_log *log)
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen struct mail_transaction_log_file *file = log->head;
df02611c44e9432e7961223bf9bfa3fb233b1789Timo Sirainen if (file == NULL || MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file))
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen /* read the whole file to memory. we might currently be appending
1f6c210c30992e95b806d2f517e2b3625ed941c5Timo Sirainen data into it, so we want to read it up to end of file */
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen if (munmap(file->mmap_base, file->mmap_size) < 0) {
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
1f6c210c30992e95b806d2f517e2b3625ed941c5Timo Sirainen if (mail_transaction_log_file_read(file, 0) <= 0)
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen /* after we've read the file into memory, make it into in-memory
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
d6cc34b076dced6ebf8af47d72c8242357288312Timo Sirainenmail_transaction_log_file_read_hdr(struct mail_transaction_log_file *file,
d6cc34b076dced6ebf8af47d72c8242357288312Timo Sirainen i_assert(!MAIL_INDEX_IS_IN_MEMORY(file->log->index));
d6cc34b076dced6ebf8af47d72c8242357288312Timo Sirainen ret = pread_full(file->fd, &file->hdr, sizeof(file->hdr), 0);
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainen "pread_full()");
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen "unexpected end of file while reading header");
d6cc34b076dced6ebf8af47d72c8242357288312Timo Sirainen if (file->hdr.major_version != MAIL_TRANSACTION_LOG_MAJOR_VERSION) {
d6cc34b076dced6ebf8af47d72c8242357288312Timo Sirainen /* incompatible version - fix silently */
d6cc34b076dced6ebf8af47d72c8242357288312Timo Sirainen if (file->hdr.hdr_size < MAIL_TRANSACTION_LOG_HEADER_MIN_SIZE) {
d6cc34b076dced6ebf8af47d72c8242357288312Timo Sirainen "Header size too small");
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen /* @UNSAFE: smaller than we expected - zero out the fields we
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainen shouldn't have filled */
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen memset(PTR_OFFSET(&file->hdr, file->hdr.hdr_size), 0,
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen /* corrupted */
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen "Transaction log file %s: marked corrupted",
4babe70b863c71ea330cbf32ac0b71876f4f9137Timo Sirainen if (file->hdr.indexid != file->log->index->indexid) {
4babe70b863c71ea330cbf32ac0b71876f4f9137Timo Sirainen /* index file was probably just rebuilt and we don't
4babe70b863c71ea330cbf32ac0b71876f4f9137Timo Sirainen know about it yet */
4babe70b863c71ea330cbf32ac0b71876f4f9137Timo Sirainen "invalid indexid (%u != %u)",
4babe70b863c71ea330cbf32ac0b71876f4f9137Timo Sirainen file->hdr.indexid, file->log->index->indexid);
4babe70b863c71ea330cbf32ac0b71876f4f9137Timo Sirainen /* creating index file. since transaction log is created
4babe70b863c71ea330cbf32ac0b71876f4f9137Timo Sirainen first, use the indexid in it to create the main index
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen to avoid races. */
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen file->log->index->indexid = file->hdr.indexid;
b66412da78711db8423288847ecfb08469609a03Timo Sirainen /* make sure we already don't have a file with the same sequence
b66412da78711db8423288847ecfb08469609a03Timo Sirainen opened. it shouldn't happen unless the old log file was
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen If we're opening head log file, make sure the sequence is larger
bfe4a97ad6731012202b830c1219a4c10f91d72cTimo Sirainen than any existing one. */
df02611c44e9432e7961223bf9bfa3fb233b1789Timo Sirainen for (f = file->log->files; f != NULL; f = f->next) {
206ac4273fa102500fa017f0c21a4fd72e94665aTimo Sirainen "invalid new transaction log sequence "
82b990b0bb2a1dad5c2634a508a5ad87715db402Timo Sirainen "(%u >= %u)",
82b990b0bb2a1dad5c2634a508a5ad87715db402Timo Sirainen for (f = file->log->files; f != NULL; f = f->next) {
82b990b0bb2a1dad5c2634a508a5ad87715db402Timo Sirainen "old transaction log already opened "
82b990b0bb2a1dad5c2634a508a5ad87715db402Timo Sirainen "(%u == %u)",
f60ed9d5330a6167693b047d8138769fb596d41cTimo Sirainenmail_transaction_log_init_hdr(struct mail_transaction_log *log,
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen unsigned int lock_id;
b66412da78711db8423288847ecfb08469609a03Timo Sirainen hdr->major_version = MAIL_TRANSACTION_LOG_MAJOR_VERSION;
b66412da78711db8423288847ecfb08469609a03Timo Sirainen hdr->minor_version = MAIL_TRANSACTION_LOG_MINOR_VERSION;
b66412da78711db8423288847ecfb08469609a03Timo Sirainen hdr->hdr_size = sizeof(struct mail_transaction_log_header);
df02611c44e9432e7961223bf9bfa3fb233b1789Timo Sirainen /* not creating index - make sure we have latest header */
df02611c44e9432e7961223bf9bfa3fb233b1789Timo Sirainen if (mail_index_lock_shared(index, TRUE, &lock_id) < 0)
23fdad6c7e2581921f511e24cd9371c9eaebcef9Timo Sirainen hdr->prev_file_seq = index->hdr->log_file_seq;
const char *path2;
bool rename_existing;
if (lock) {
if (ret < 0) {
if (lock) {
if (ret < 0)
if (rename_existing) {
path2);
int fd;
struct mail_transaction_log_file **p;
*p = file;
struct mail_transaction_log_file **p;
*p = file;
int ret;
if (ret == 0) {
FALSE);
if (ret == 0) {
if (ret < 0)
static struct mail_transaction_log_file *
return NULL;
return file;
static struct mail_transaction_log_file *
const char *path)
int ret;
path,
if (ret > 0)
return file;
if (ret < 0)
return NULL;
static struct mail_transaction_log_file *
const char *path)
int ret;
if (ret > 0) {
return file;
if (ret == 0) {
i == MAIL_INDEX_ESTALE_RETRY_COUNT) {
return NULL;
int ret;
if (lock)
if (ret <= 0) {
bool create_if_needed)
const char *path;
const char *path;
if (ret <= 0) {
if (ret == 0) {
if (stale) {
const void *data;
if (hdr_size == 0) {
if (hdr_size != 0) {
void *data;
int ret;
if (ret == 0) {
if (ret < 0) {
if (ret > 0)
if (ret == 0) {
if (use_mmap) {
if (!use_mmap) {
if (ret <= 0) {
return ret;
MADV_SEQUENTIAL) < 0) {
int ret = 0;
if (ret < 0)
return ret;