mail-transaction-log-file.c revision 8cd0a1a2200e65cd134d03fe3f93ec02f1746359
76b43e4417bab52e913da39b5f5bc2a130d3f149Timo Sirainen/* Copyright (C) 2003-2007 Timo Sirainen */
7ca2a9f1cca63cbc2ebffc185c7e5a2b32bc2780Timo Sirainen#define MEMORY_LOG_NAME "(in-memory transaction log file)"
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenmail_transaction_log_file_set_corrupted(struct mail_transaction_log_file *file,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen const char *fmt, ...)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen if (!MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file)) {
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen /* indexid=0 marks the log file as corrupted */
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen "Corrupted transaction log file %s: %s",
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenmail_transaction_log_file_alloc(struct mail_transaction_log *log,
b87436ebb957a9eb182be72ba00e2c8eae59a2e4Timo Sirainen file = i_new(struct mail_transaction_log_file, 1);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainenvoid mail_transaction_log_file_free(struct mail_transaction_log_file **_file)
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen struct mail_transaction_log_file *file = *_file;
8a1c866a4c429f26c8746525f82024bc387f1407Timo Sirainen for (p = &file->log->files; *p != NULL; p = &(*p)->next) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (munmap(file->mmap_base, file->mmap_size) < 0) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainenmail_transaction_log_file_add_to_list(struct mail_transaction_log_file *file)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (map != NULL && file->hdr.file_seq == map->hdr.log_file_seq &&
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* we can get a valid log offset from index file. initialize
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen sync_offset from it so we don't have to read the whole log
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen file from beginning. */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (map->hdr.log_file_head_offset >= file->hdr.hdr_size)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen file->sync_offset = map->hdr.log_file_head_offset;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen "%s: log_file_head_offset too small",
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen file->saved_tail_offset = map->hdr.log_file_tail_offset;
e3077468777f5d324224365e34d7bbc449168e52Timo Sirainen /* insert it to correct position */
e3077468777f5d324224365e34d7bbc449168e52Timo Sirainen for (p = &log->files; *p != NULL; p = &(*p)->next) {
e3077468777f5d324224365e34d7bbc449168e52Timo Sirainen i_assert((*p)->hdr.file_seq < file->hdr.file_seq);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenmail_transaction_log_init_hdr(struct mail_transaction_log *log,
608aa112aa7d94a1720c909747dcd0b61c079453Timo Sirainen hdr->major_version = MAIL_TRANSACTION_LOG_MAJOR_VERSION;
608aa112aa7d94a1720c909747dcd0b61c079453Timo Sirainen hdr->minor_version = MAIL_TRANSACTION_LOG_MINOR_VERSION;
608aa112aa7d94a1720c909747dcd0b61c079453Timo Sirainen hdr->hdr_size = sizeof(struct mail_transaction_log_header);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen /* not creating index - make sure we have latest header */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* if we got here from mapping, the .log file is
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen corrupted. use whatever values we got from index
8a1c866a4c429f26c8746525f82024bc387f1407Timo Sirainen hdr->prev_file_seq = index->map->hdr.log_file_seq;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen hdr->prev_file_offset = index->map->hdr.log_file_head_offset;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen hdr->file_seq = index->map->hdr.log_file_seq + 1;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen if (log->head != NULL && hdr->file_seq <= log->head->hdr.file_seq) {
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen /* make sure the sequence grows */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenmail_transaction_log_file_alloc_in_memory(struct mail_transaction_log *log)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen file = mail_transaction_log_file_alloc(log, MEMORY_LOG_NAME);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen if (mail_transaction_log_init_hdr(log, &file->hdr) < 0) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen file->buffer = buffer_create_dynamic(default_pool, 4096);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenmail_transaction_log_file_dotlock(struct mail_transaction_log_file *file)
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen ret = file_dotlock_create(&file->log->dotlock_settings,
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen "file_dotlock_create()");
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen "Timeout while waiting for release of "
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen "dotlock for transaction log file %s",
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainenmail_transaction_log_file_undotlock(struct mail_transaction_log_file *file)
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen ret = file_dotlock_delete(&file->log->dotlock);
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen "Dotlock was lost for transaction log file %s",
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainenint mail_transaction_log_file_lock(struct mail_transaction_log_file *file)
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file)) {
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen if (file->log->index->lock_method == FILE_LOCK_METHOD_DOTLOCK)
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen return mail_transaction_log_file_dotlock(file);
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen ret = mail_index_lock_fd(file->log->index, file->filepath, file->fd,
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen "mail_index_wait_lock_fd()");
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen "Timeout while waiting for lock for transaction log file %s",
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainenvoid mail_transaction_log_file_unlock(struct mail_transaction_log_file *file)
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file))
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen if (file->log->index->lock_method == FILE_LOCK_METHOD_DOTLOCK) {
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainenmail_transaction_log_file_read_hdr(struct mail_transaction_log_file *file,
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen i_assert(!MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file));
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen ret = pread_full(file->fd, &file->hdr, sizeof(file->hdr), 0);
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen "pread_full()");
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen "unexpected end of file while reading header");
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (file->hdr.major_version != MAIL_TRANSACTION_LOG_MAJOR_VERSION) {
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen /* incompatible version - fix silently */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (file->hdr.hdr_size < MAIL_TRANSACTION_LOG_HEADER_MIN_SIZE) {
f3bf2314198da2877ce640360581a61d60c90991Timo Sirainen "Header size too small");
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen /* @UNSAFE: smaller than we expected - zero out the fields we
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen shouldn't have filled */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen memset(PTR_OFFSET(&file->hdr, file->hdr.hdr_size), 0,
7ca2a9f1cca63cbc2ebffc185c7e5a2b32bc2780Timo Sirainen /* corrupted */
7ca2a9f1cca63cbc2ebffc185c7e5a2b32bc2780Timo Sirainen "Transaction log file %s: marked corrupted",
f3bf2314198da2877ce640360581a61d60c90991Timo Sirainen if (file->hdr.indexid != file->log->index->indexid) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* index file was probably just rebuilt and we don't
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen know about it yet */
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen "indexid changed %u -> %u",
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen file->log->index->indexid, file->hdr.indexid);
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen /* creating index file. since transaction log is created
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen first, use the indexid in it to create the main index
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen to avoid races. */
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen file->log->index->indexid = file->hdr.indexid;
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen /* make sure we already don't have a file with the same sequence
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen opened. it shouldn't happen unless the old log file was
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen corrupted. */
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen for (f = file->log->files; f != NULL; f = f->next) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* mark the old file corrupted. we can't safely remove
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen it from the list however, so return failure. */
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen "duplicate transaction log sequence (%u)",
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenmail_transaction_log_file_stat(struct mail_transaction_log_file *file,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainenmail_transaction_log_file_is_dupe(struct mail_transaction_log_file *file)
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen for (tmp = file->log->files; tmp != NULL; tmp = tmp->next) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenmail_transaction_log_file_create2(struct mail_transaction_log_file *file,
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen /* log creation is locked now - see if someone already created it.
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen note that if we're rotating, we need to keep the log locked until
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen the file has been rewritten. and because fcntl() locks are stupid,
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen if we go and open()+close() the file and we had it already opened,
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen its locks are lost. so we use stat() to check if the file has been
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen recreated, although it almost never is. */
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen else if (nfs_safe_stat(file->filepath, &st) < 0) {
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen mail_index_file_set_syscall_error(index, file->filepath,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* inode/dev checks are enough when we're rotating the file,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen but not when we're replacing a broken log file */
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen /* no-one else recreated the file */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* recreated. use the file if its header is ok */
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen /* yes, it was ok */
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen if (mail_transaction_log_init_hdr(file->log, &file->hdr) < 0)
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen if (write_full(new_fd, &file->hdr, sizeof(file->hdr)) < 0) {
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen mail_index_file_set_syscall_error(index, file->filepath,
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen "write_full()");
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen ret = mail_transaction_log_file_stat(file, FALSE);
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen /* if we return -1 the dotlock deletion code closes the fd */
337d77f9903bf56ccd686479dffaf6069991edf2Timo Sirainen /* keep two log files */
337d77f9903bf56ccd686479dffaf6069991edf2Timo Sirainen /* rename() would be nice and easy way to do this, except then
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen there's a race condition between the rename and
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen file_dotlock_replace(). during that time the log file
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen doesn't exist, which could cause problems. */
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen path2 = t_strconcat(file->filepath, ".2", NULL);
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen mail_index_set_error(index, "unlink(%s) failed: %m",
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen /* try to link() anyway */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen mail_index_set_error(index, "link(%s, %s) failed: %m",
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* ignore the error. we don't care that much about the
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen second log file and we're going to overwrite this
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen first one. */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* success */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenint mail_transaction_log_file_create(struct mail_transaction_log_file *file,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* With dotlocking we might already have path.lock created, so this
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen filename has to be different. */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen fd = file_dotlock_open(&file->log->new_dotlock_settings,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen mail_index_file_set_syscall_error(index, file->filepath,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen "file_dotlock_open()");
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen mail_index_file_set_syscall_error(index, file->filepath,
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen /* either fd gets used or the dotlock gets deleted and returned fd
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen is for the existing file */
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen if (mail_transaction_log_file_create2(file, fd, reset, &dotlock) < 0) {
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainenint mail_transaction_log_file_open(struct mail_transaction_log_file *file,
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen unsigned int i;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen for (i = 0;; i++) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen file->fd = nfs_safe_open(file->filepath, O_RDWR);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen ignore_estale = i < MAIL_INDEX_ESTALE_RETRY_COUNT;
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen if (mail_transaction_log_file_stat(file, ignore_estale) < 0)
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen ret = mail_transaction_log_file_read_hdr(file,
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen /* success */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* corrupted */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (unlink(file->filepath) < 0 && errno != ENOENT) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen "unlink(%s) failed: %m",
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* syscall error */
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen /* ESTALE - try again */
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenlog_file_track_mailbox_sync_offset_hdr(struct mail_transaction_log_file *file,
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen const struct mail_transaction_header_update *u = data;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen const unsigned int offset_pos =
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen offsetof(struct mail_index_header, log_file_tail_offset);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen const unsigned int offset_size = sizeof(ihdr->log_file_tail_offset);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen if (size < sizeof(*u) || size < sizeof(*u) + u->size) {
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen "header update extends beyond record size");
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen u->offset + u->size >= offset_pos + offset_size) {
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen CONST_PTR_OFFSET(u + 1, offset_pos - u->offset),
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen "log_file_tail_offset shrinked");
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainenlog_file_track_mailbox_sync_offset(struct mail_transaction_log_file *file,
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen i_assert((hdr->type & MAIL_TRANSACTION_EXTERNAL) != 0);
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen if ((hdr->type & MAIL_TRANSACTION_TYPE_MASK) ==
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen /* see if this updates mailbox_sync_offset */
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen ret = log_file_track_mailbox_sync_offset_hdr(file, hdr + 1,
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen if (file->max_tail_offset == file->sync_offset) {
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen /* external transactions aren't synced to mailbox. we can
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen update mailbox sync offset to skip this transaction to
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen avoid re-reading it at the next sync. */
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainenmail_transaction_log_file_sync(struct mail_transaction_log_file *file)
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen while (file->sync_offset - file->buffer_offset + sizeof(*hdr) <= size) {
20dd6f6726db692904794d7daafe5b6e7238b720Timo Sirainen hdr = CONST_PTR_OFFSET(data, file->sync_offset -
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen trans_size = mail_index_offset_to_uint32(hdr->size);
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen /* unfinished */
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen if (file->sync_offset - file->buffer_offset + trans_size > size)
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen /* transaction has been fully written */
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen if ((hdr->type & MAIL_TRANSACTION_EXTERNAL) != 0) {
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen if (log_file_track_mailbox_sync_offset(file, hdr,
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen if (file->mmap_base != NULL && !file->locked) {
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen /* Now that all the mmaped pages have page faulted, check if
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen the file had changed while doing that. Only after the last
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen page has faulted, the size returned by fstat() can be
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen trusted. Otherwise it might point to a page boundary while
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen the next page is still being written.
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen Without this check we might see partial transactions,
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen sometimes causing "Extension record updated without intro
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen prefix" errors. */
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen avail = file->sync_offset - file->buffer_offset;
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen /* There's more data than we could sync at the moment. If the
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen last record's size wasn't valid, we can't know if it will
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen be updated unless we've locked the log.
d8548e14925a06e44c4f1983d7b118b0180939e0Timo Sirainen If the record size was valid, this is an error because the
d8548e14925a06e44c4f1983d7b118b0180939e0Timo Sirainen pread()s or the above fstat() check for mmaps should have
d8548e14925a06e44c4f1983d7b118b0180939e0Timo Sirainen guaranteed that this doesn't happen. */
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen "Unexpected garbage at EOF");
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen // FIXME: here we probably want to flush NFS data cache
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen file->hdr.file_seq == file->next->hdr.prev_file_seq &&
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen file->next->hdr.prev_file_offset != file->sync_offset) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen "Invalid transaction log size "
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen "(%"PRIuUOFF_T" vs %u): %s", file->sync_offset,
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen file->log->head->hdr.prev_file_offset, file->filepath);
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainenmail_transaction_log_file_insert_read(struct mail_transaction_log_file *file,
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen buffer_copy(file->buffer, size, file->buffer, 0, (size_t)-1);
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen data = buffer_get_space_unsafe(file->buffer, 0, size);
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen ret = pread_full(file->fd, data, size, offset);
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen /* success */
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen /* failure. don't leave ourself to inconsistent state */
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen buffer_copy(file->buffer, 0, file->buffer, size, (size_t)-1);
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen buffer_set_used_size(file->buffer, file->buffer->used - size);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen mail_transaction_log_file_set_corrupted(file, "file shrinked");
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen /* log file was deleted in NFS server, fail silently */
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenmail_transaction_log_file_read(struct mail_transaction_log_file *file,
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen if (file->buffer != NULL && file->buffer_offset > start_offset) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* we have to insert missing data to beginning of buffer */
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen ret = mail_transaction_log_file_insert_read(file, start_offset);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen buffer_create_dynamic(default_pool, LOG_PREFETCH);
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen /* read all records */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen read_offset = file->buffer_offset + buffer_get_used_size(file->buffer);
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen data = buffer_append_space_unsafe(file->buffer, LOG_PREFETCH);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen ret = pread(file->fd, data, LOG_PREFETCH, read_offset);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen } while (ret > 0 || (ret < 0 && errno == EINTR));
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen /* log file was deleted in NFS server, fail silently */
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
MADV_SEQUENTIAL) < 0) {
int ret;
end_offset) == 0)
if (ret > 0) {
if (ret <= 0)
return ret;
} while (ret == 0);
*file)