mail-transaction-log.c revision 7a027685e685fbbdb90cf7539ad4b406deaa6484
bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (C) 2003-2004 Timo Sirainen */
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen/* this lock should never exist for a long time.. */
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen#define LOG_DOTLOCK_IMMEDIATE_STALE_TIMEOUT 300
0ebeb1831a56e020b0958ed1ced50e86ee9347ecTimo Sirainenmail_transaction_log_file_open_or_create(struct mail_transaction_log *log,
0ebeb1831a56e020b0958ed1ced50e86ee9347ecTimo Sirainen const char *path);
0ebeb1831a56e020b0958ed1ced50e86ee9347ecTimo Sirainenstatic int mail_transaction_log_rotate(struct mail_transaction_log *log,
0ebeb1831a56e020b0958ed1ced50e86ee9347ecTimo Sirainenstatic int mail_transaction_log_lock_head(struct mail_transaction_log *log);
0ebeb1831a56e020b0958ed1ced50e86ee9347ecTimo Sirainenmail_transaction_log_file_set_corrupted(struct mail_transaction_log_file *file,
0ebeb1831a56e020b0958ed1ced50e86ee9347ecTimo Sirainen const char *fmt, ...)
4ba3717a04823875c2a1d60ff9dc8177ae033d12Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen "Corrupted transaction log file %s: %s",
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainenmail_transaction_log_file_dotlock(struct mail_transaction_log_file *file)
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen ret = file_lock_dotlock(file->filepath, NULL, FALSE,
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen "file_lock_dotlock()");
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen "Timeout while waiting for release of "
57dc9669d34de7d08a44be9d7d3c9f6a0c34cc87Timo Sirainen "dotlock for transaction log file %s",
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainenmail_transaction_log_file_undotlock(struct mail_transaction_log_file *file)
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen ret = file_unlock_dotlock(file->filepath, &file->log->dotlock);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen "Dotlock was lost for transaction log file %s",
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainenmail_transaction_log_file_lock(struct mail_transaction_log_file *file)
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen return mail_transaction_log_file_dotlock(file);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen ret = file_wait_lock_full(file->fd, F_WRLCK, DEFAULT_LOCK_TIMEOUT,
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen "file_wait_lock()");
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila "Timeout while waiting for release of "
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen "fcntl() lock for transaction log file %s",
0ebeb1831a56e020b0958ed1ced50e86ee9347ecTimo Sirainenmail_transaction_log_file_unlock(struct mail_transaction_log_file *file)
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila mail_index_file_set_syscall_error(file->log->index,
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila "file_wait_lock()");
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila !(((file)->hdr.file_seq == (index)->hdr->log_file_seq && \
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila sizeof(struct mail_transaction_log_header)) || \
957b0b4c9aeff7153bb9ebf91d8aea550bd07865Teemu Huovila ((file)->hdr.prev_file_seq == (index)->hdr->log_file_seq && \
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen (file)->hdr.prev_file_offset == (index)->hdr->log_file_offset))
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainenstatic int mail_transaction_log_check_file_seq(struct mail_transaction_log *log)
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila unsigned int lock_id;
fac865bad1ba10e85d80b63dedfd3493a65510d4Timo Sirainen ret = mail_index_lock_shared(index, TRUE, &lock_id);
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila else if (INDEX_HAS_MISSING_LOGS(index, file)) {
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila /* broken - fix it by creating a new log file */
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila ret = mail_transaction_log_rotate(log, F_UNLCK);
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainenmail_transaction_log_open_or_create(struct mail_index *index)
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila log->head = mail_transaction_log_file_open_or_create(log, path);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen /* head log file isn't same as head index file -
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen shouldn't happen except in race conditions. lock them and
09aed882b99e865ff6d7140ae2f77a42c9e7d1a7Teemu Huovila check again - FIXME: missing error handling. */
09aed882b99e865ff6d7140ae2f77a42c9e7d1a7Teemu Huovila (void)mail_transaction_log_check_file_seq(log);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainenvoid mail_transaction_log_close(struct mail_transaction_log *log)
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainenmail_transaction_log_file_close(struct mail_transaction_log_file *file)
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen if (munmap(file->mmap_base, file->mmap_size) < 0) {
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainenmail_transaction_log_file_read_hdr(struct mail_transaction_log_file *file)
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen ret = pread_full(file->fd, &file->hdr, sizeof(file->hdr), 0);
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen // FIXME: handle ESTALE
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen "pread_full()");
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen "unexpected end of file while reading header");
ebcd7cf40e53c2bbc98f7f686e206cda5c0e3111Timo Sirainen /* corrupted */
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen "Transaction log file %s: marked corrupted",
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen if (file->hdr.indexid != file->log->index->indexid) {
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen /* creating index file, silently rebuild
084431105a179063aeb08f45eb5f506c61ea8602Aki Tuomi transaction log as well */
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen /* index file was probably just rebuilt and we don't know
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen about it yet */
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen "Transaction log file %s: invalid indexid (%u != %u)",
ebcd7cf40e53c2bbc98f7f686e206cda5c0e3111Timo Sirainenmail_transaction_log_file_create2(struct mail_transaction_log *log,
60ba197d17023594231d9805d889817782e41859Timo Sirainen unsigned int lock_id;
084431105a179063aeb08f45eb5f506c61ea8602Aki Tuomi /* log creation is locked now - see if someone already created it */
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen mail_index_file_set_syscall_error(index, path,
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen } else if (st.st_ino == ino && CMP_DEV_T(st.st_dev, dev)) {
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen /* same file, still broken */
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen (void)file_dotlock_delete(path, LOG_NEW_DOTLOCK_SUFFIX,
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen mail_index_file_set_syscall_error(index, path, "open()");
6634e45500e81cfa36932203ee69c81745efd3e6Timo Sirainen if (mail_index_lock_shared(index, TRUE, &lock_id) < 0)
6634e45500e81cfa36932203ee69c81745efd3e6Timo Sirainen hdr.prev_file_offset = index->hdr->log_file_offset;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen if (log->head != NULL && hdr.file_seq <= log->head->hdr.file_seq) {
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen /* make sure the sequence grows */
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen mail_index_file_set_syscall_error(index, path,
09aed882b99e865ff6d7140ae2f77a42c9e7d1a7Teemu Huovila "write_full()");
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen mail_index_file_set_syscall_error(index, path, "dup()");
eeb03434472130f9631f164440566fd8d09e6380Timo Sirainen if (file_dotlock_replace(path, LOG_NEW_DOTLOCK_SUFFIX, fd, FALSE) <= 0)
6634e45500e81cfa36932203ee69c81745efd3e6Timo Sirainen /* success */
if (fd2 < 0) {
return fd2;
static struct mail_transaction_log_file *
struct mail_transaction_log_file **p;
int ret;
return NULL;
if (ret == 0) {
if (ret <= 0) {
return NULL;
*p = file;
return file;
static struct mail_transaction_log_file *
const char *path)
int fd;
return NULL;
return NULL;
if ((*p)->refcount != 0)
p = &(*p)->next;
*p = next;
int fd;
if (lock) {
unsigned int lock_id;
int ret;
return ret;
const char *path;
const void *data;
if (hdr_size == 0) {
void *data;
int ret;
if (ret == 0) {
if (ret < 0) {
if (ret > 0)
if (ret == 0) {
if (!use_mmap) {
if (ret <= 0) {
return ret;
MADV_SEQUENTIAL) < 0) {
int ret = 0;
if (ret < 0)
return ret;
const void *data)
if (deleted) {
dest++;
struct mail_index_transaction *t)
const void *data;
int ret;
case MAIL_TRANSACTION_APPEND:
case MAIL_TRANSACTION_CACHE_RESET: {
return ret;
if (size == 0)
hdr_data_size = 0;
if (external)
hdr_size =
if (hdr_data_size > 0) {
struct mail_transaction_cache_reset u;
memset(&u, 0, sizeof(u));
return buf;
static const buffer_t *
struct mail_transaction_header_update u;
int state = 0;
memset(&u, 0, sizeof(u));
if (state == 0) {
state++;
if (state > 0) {
u.size);
state = 0;
return buf;
unsigned int i, lock_id;
int ret;
*log_file_seq_r = 0;
*log_file_offset_r = 0;
ret = 0;
if (t->new_cache_file_seq != 0) {
if (ret < 0) {
t->hide_transaction) {
if (ret < 0) {
if (ret < 0) {
return ret;