mail-transaction-log-file.c revision 8c7000574087d5702cc3830e7f80c695ff8e9221
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (C) 2003-2007 Timo Sirainen */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#define MEMORY_LOG_NAME "(in-memory transaction log file)"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenmail_transaction_log_file_set_corrupted(struct mail_transaction_log_file *file,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *fmt, ...)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (!MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file)) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* indexid=0 marks the log file as corrupted */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen "Corrupted transaction log file %s: %s",
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainenmail_transaction_log_file_alloc(struct mail_transaction_log *log,
104318260228780a5c6b3181b3401e8e504e2776Timo Sirainen file = i_new(struct mail_transaction_log_file, 1);
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainenvoid mail_transaction_log_file_free(struct mail_transaction_log_file **_file)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct mail_transaction_log_file *file = *_file;
f46363f428d8f2784146d36692b21936a48a7006Timo Sirainen for (p = &file->log->files; *p != NULL; p = &(*p)->next) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (munmap(file->mmap_base, file->mmap_size) < 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenmail_transaction_log_file_add_to_list(struct mail_transaction_log_file *file)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (map != NULL && file->hdr.file_seq == map->hdr.log_file_seq &&
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* we can get a valid log offset from index file. initialize
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen sync_offset from it so we don't have to read the whole log
0c22bef8f5b35c645de8affd8746307fc53bd222Timo Sirainen file from beginning. */
0c22bef8f5b35c645de8affd8746307fc53bd222Timo Sirainen if (map->hdr.log_file_head_offset >= file->hdr.hdr_size)
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen file->sync_offset = map->hdr.log_file_head_offset;
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen "%s: log_file_head_offset too small",
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen file->saved_tail_offset = map->hdr.log_file_tail_offset;
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen /* insert it to correct position */
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen for (p = &log->files; *p != NULL; p = &(*p)->next) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_assert((*p)->hdr.file_seq < file->hdr.file_seq);
40a8e6948d662339c0c5e2c7abfb84ae7c1803fdTimo Sirainenmail_transaction_log_init_hdr(struct mail_transaction_log *log,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen unsigned int lock_id = 0;
a3fe8c0c54d87822f4b4f8f0d10caac611861b2bTimo Sirainen hdr->major_version = MAIL_TRANSACTION_LOG_MAJOR_VERSION;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen hdr->minor_version = MAIL_TRANSACTION_LOG_MINOR_VERSION;
e6b4168ba670d9e51ea7877661def039ae6b53c3Timo Sirainen hdr->hdr_size = sizeof(struct mail_transaction_log_header);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* not creating index - make sure we have latest header */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (mail_index_map(index, MAIL_INDEX_SYNC_HANDLER_HEAD,
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen hdr->prev_file_seq = index->map->hdr.log_file_seq;
b8efab7ea8876c0a33a73ee0d08eddada31320f8Timo Sirainen hdr->prev_file_offset = index->map->hdr.log_file_head_offset;
b8efab7ea8876c0a33a73ee0d08eddada31320f8Timo Sirainen hdr->file_seq = index->map->hdr.log_file_seq + 1;
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen if (log->head != NULL && hdr->file_seq <= log->head->hdr.file_seq) {
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen /* make sure the sequence grows */
f7423cbbd9dea363a5df18ebb96da055a977ae79Timo Sirainenmail_transaction_log_file_alloc_in_memory(struct mail_transaction_log *log)
f7423cbbd9dea363a5df18ebb96da055a977ae79Timo Sirainen file = mail_transaction_log_file_alloc(log, MEMORY_LOG_NAME);
32b78da5dfbbf6a06b3dbdc9278c60b55714f9bcTimo Sirainen if (mail_transaction_log_init_hdr(log, &file->hdr) < 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen file->buffer = buffer_create_dynamic(default_pool, 4096);
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainenmail_transaction_log_file_dotlock(struct mail_transaction_log_file *file)
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen ret = file_dotlock_create(&file->log->dotlock_settings,
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen "file_dotlock_create()");
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen "Timeout while waiting for release of "
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainen "dotlock for transaction log file %s",
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainenmail_transaction_log_file_undotlock(struct mail_transaction_log_file *file)
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen ret = file_dotlock_delete(&file->log->dotlock);
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen "Dotlock was lost for transaction log file %s",
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenint mail_transaction_log_file_lock(struct mail_transaction_log_file *file)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file)) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (file->log->index->lock_method == FILE_LOCK_METHOD_DOTLOCK)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return mail_transaction_log_file_dotlock(file);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ret = mail_index_lock_fd(file->log->index, file->filepath, file->fd,
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen "mail_index_wait_lock_fd()");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "Timeout while waiting for lock for transaction log file %s",
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainenvoid mail_transaction_log_file_unlock(struct mail_transaction_log_file *file)
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file))
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen if (file->log->index->lock_method == FILE_LOCK_METHOD_DOTLOCK) {
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainenmail_transaction_log_file_read_hdr(struct mail_transaction_log_file *file,
3f603ef00e35fca21605afa0ad8d76e94fee2b96Timo Sirainen i_assert(!MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file));
3f603ef00e35fca21605afa0ad8d76e94fee2b96Timo Sirainen ret = pread_full(file->fd, &file->hdr, sizeof(file->hdr), 0);
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen "pread_full()");
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen "unexpected end of file while reading header");
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen if (file->hdr.major_version != MAIL_TRANSACTION_LOG_MAJOR_VERSION) {
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen /* incompatible version - fix silently */
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen if (file->hdr.hdr_size < MAIL_TRANSACTION_LOG_HEADER_MIN_SIZE) {
d9515a2eaa94c8287188c38fc28028727671e729Timo Sirainen "Header size too small");
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen /* @UNSAFE: smaller than we expected - zero out the fields we
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen shouldn't have filled */
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen memset(PTR_OFFSET(&file->hdr, file->hdr.hdr_size), 0,
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen /* corrupted */
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen "Transaction log file %s: marked corrupted",
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen if (file->hdr.indexid != file->log->index->indexid) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* index file was probably just rebuilt and we don't
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen know about it yet */
b8efab7ea8876c0a33a73ee0d08eddada31320f8Timo Sirainen "invalid indexid (%u != %u)",
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen file->hdr.indexid, file->log->index->indexid);
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen /* creating index file. since transaction log is created
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen first, use the indexid in it to create the main index
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen to avoid races. */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen file->log->index->indexid = file->hdr.indexid;
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen /* make sure we already don't have a file with the same sequence
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen opened. it shouldn't happen unless the old log file was
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen corrupted. */
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen for (f = file->log->files; f != NULL; f = f->next) {
047c00cd3f7f403672f81569413669238df8c15aTimo Sirainen /* mark the old file corrupted. we can't safely remove
17fe695b985e9d6e9dc39c05b24e6b3c3b7e1ba1Timo Sirainen it from the list however, so return failure. */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "duplicate transaction log sequence (%u)",
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainenmail_transaction_log_file_stat(struct mail_transaction_log_file *file,
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenmail_transaction_log_file_is_dupe(struct mail_transaction_log_file *file)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen for (tmp = file->log->files; tmp != NULL; tmp = tmp->next) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenmail_transaction_log_file_create2(struct mail_transaction_log_file *file,
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen /* log creation is locked now - see if someone already created it.
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen note that if we're rotating, we need to keep the log locked until
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen the file has been rewritten. and because fcntl() locks are stupid,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if we go and open()+close() the file and we had it already opened,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen its locks are lost. so we use stat() to check if the file has been
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen recreated, although it almost never is. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_index_file_set_syscall_error(index, file->filepath,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* inode/dev checks are enough when we're rotating the file,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen but not when we're replacing a broken log file */
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen /* no-one else recreated the file */
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen /* recreated. use the file if its header is ok */
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen /* yes, it was ok */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (mail_transaction_log_init_hdr(file->log, &file->hdr) < 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (write_full(new_fd, &file->hdr, sizeof(file->hdr)) < 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_index_file_set_syscall_error(index, file->filepath,
1ffb2afe6d7e8860a2231a4827078cf2ef9c22cdTimo Sirainen "write_full()");
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainen ret = mail_transaction_log_file_stat(file, FALSE);
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainen /* if we return -1 the dotlock deletion code closes the fd */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* keep two log files */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* rename() would be nice and easy way to do this, except then
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen there's a race condition between the rename and
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen file_dotlock_replace(). during that time the log file
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen doesn't exist, which could cause problems. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen path2 = t_strconcat(file->filepath, ".2", NULL);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_index_set_error(index, "unlink(%s) failed: %m",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* try to link() anyway */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_index_set_error(index, "link(%s, %s) failed: %m",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* ignore the error. we don't care that much about the
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen second log file and we're going to overwrite this
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen first one. */
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen /* success */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenint mail_transaction_log_file_create(struct mail_transaction_log_file *file)
b2d562f9c7fd13f9a16e9b3bcee904630b80b1feTimo Sirainen /* With dotlocking we might already have path.lock created, so this
b2d562f9c7fd13f9a16e9b3bcee904630b80b1feTimo Sirainen filename has to be different. */
b2d562f9c7fd13f9a16e9b3bcee904630b80b1feTimo Sirainen fd = file_dotlock_open(&file->log->new_dotlock_settings,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_index_file_set_syscall_error(index, file->filepath,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "file_dotlock_open()");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_index_file_set_syscall_error(index, file->filepath,
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen /* either fd gets used or the dotlock gets deleted and returned fd
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen is for the existing file */
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen if (mail_transaction_log_file_create2(file, fd, &dotlock) < 0) {
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainenint mail_transaction_log_file_open(struct mail_transaction_log_file *file,
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen unsigned int i;
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen for (i = 0;; i++) {
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen file->fd = nfs_safe_open(file->filepath, O_RDWR);
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen ignore_estale = i < MAIL_INDEX_ESTALE_RETRY_COUNT;
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen if (mail_transaction_log_file_stat(file, ignore_estale) < 0)
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen ret = mail_transaction_log_file_read_hdr(file,
1bea4b9c24fbe2b457950c09cf072292a6701cffTimo Sirainen /* success */
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen /* corrupted */
1bea4b9c24fbe2b457950c09cf072292a6701cffTimo Sirainen if (unlink(file->filepath) < 0 && errno != ENOENT) {
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen "unlink(%s) failed: %m",
21e6b4fd844fd074583b17f09e1f27b9835ee238Timo Sirainen /* syscall error */
21e6b4fd844fd074583b17f09e1f27b9835ee238Timo Sirainen /* ESTALE - try again */
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainenlog_file_track_mailbox_sync_offset_hdr(struct mail_transaction_log_file *file,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const struct mail_transaction_header_update *u = data;
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen const unsigned int offset_pos =
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen offsetof(struct mail_index_header, log_file_tail_offset);
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen const unsigned int offset_size = sizeof(ihdr->log_file_tail_offset);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (size < sizeof(*u) || size < sizeof(*u) + u->size) {
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen "header update extends beyond record size");
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen u->offset + u->size >= offset_pos + offset_size) {
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen CONST_PTR_OFFSET(u + 1, offset_pos - u->offset),
c668292359474a4aa8c608b30a858337fa3fc813Timo Sirainen "log_file_tail_offset shrinked");
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenlog_file_track_mailbox_sync_offset(struct mail_transaction_log_file *file,
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen i_assert((hdr->type & MAIL_TRANSACTION_EXTERNAL) != 0);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if ((hdr->type & MAIL_TRANSACTION_TYPE_MASK) ==
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen /* see if this updates mailbox_sync_offset */
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen ret = log_file_track_mailbox_sync_offset_hdr(file, hdr + 1,
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (file->max_tail_offset == file->sync_offset) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen /* external transactions aren't synced to mailbox. we can
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen update mailbox sync offset to skip this transaction to
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen avoid re-reading it at the next sync. */
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenmail_transaction_log_file_sync(struct mail_transaction_log_file *file)
6a6e3c2538a08cc4880a8db7e0a9a3392122ea04Timo Sirainen while (file->sync_offset - file->buffer_offset + sizeof(*hdr) <= size) {
6a6e3c2538a08cc4880a8db7e0a9a3392122ea04Timo Sirainen hdr = CONST_PTR_OFFSET(data, file->sync_offset -
6a6e3c2538a08cc4880a8db7e0a9a3392122ea04Timo Sirainen trans_size = mail_index_offset_to_uint32(hdr->size);
6a6e3c2538a08cc4880a8db7e0a9a3392122ea04Timo Sirainen /* unfinished */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (file->sync_offset - file->buffer_offset + trans_size > size)
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen /* transaction has been fully written */
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if ((hdr->type & MAIL_TRANSACTION_EXTERNAL) != 0) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (log_file_track_mailbox_sync_offset(file, hdr,
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen avail = file->sync_offset - file->buffer_offset;
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen /* There's more data than we could sync at the moment. If the
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen last record's size wasn't valid, we can't know if it will
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen be updated unless we've locked the log.
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen Without locking we can be sure only if we're not using
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mmaping, because with mmaping the data and the file size
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen can get updated at any time. */
0c96e2994ab4e25c9042ce21e9d39ca5054df3b6Timo Sirainen (trans_size != 0 && file->mmap_base == NULL)) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "Unexpected garbage at EOF");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen // FIXME: here we probably want to flush NFS data cache
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainenmail_transaction_log_file_insert_read(struct mail_transaction_log_file *file,
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen buffer_copy(file->buffer, size, file->buffer, 0, (size_t)-1);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen data = buffer_get_space_unsafe(file->buffer, 0, size);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ret = pread_full(file->fd, data, size, offset);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* success */
835ba470fb6a73b74e258e12678236106d0df09eTimo Sirainen /* failure. don't leave ourself to inconsistent state */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen buffer_copy(file->buffer, 0, file->buffer, size, (size_t)-1);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen buffer_set_used_size(file->buffer, file->buffer->used - size);
835ba470fb6a73b74e258e12678236106d0df09eTimo Sirainen mail_transaction_log_file_set_corrupted(file, "file shrinked");
835ba470fb6a73b74e258e12678236106d0df09eTimo Sirainen /* log file was deleted in NFS server, fail silently */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
835ba470fb6a73b74e258e12678236106d0df09eTimo Sirainenmail_transaction_log_file_read(struct mail_transaction_log_file *file,
e4eb49e29197c6783ec93b868100394e189f4e0cTimo Sirainen if (file->buffer != NULL && file->buffer_offset > start_offset) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* we have to insert missing data to beginning of buffer */
21e6b4fd844fd074583b17f09e1f27b9835ee238Timo Sirainen ret = mail_transaction_log_file_insert_read(file, start_offset);
db693bf6fcae96d834567f1782257517b7207655Timo Sirainen buffer_create_dynamic(default_pool, LOG_PREFETCH);
93aa246b98205afab357471ecaaf51291a35bfa0Timo Sirainen /* read all records */
93aa246b98205afab357471ecaaf51291a35bfa0Timo Sirainen read_offset = file->buffer_offset + buffer_get_used_size(file->buffer);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen data = buffer_append_space_unsafe(file->buffer, LOG_PREFETCH);
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen ret = pread(file->fd, data, LOG_PREFETCH, read_offset);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen } while (ret > 0 || (ret < 0 && errno == EINTR));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* log file was deleted in NFS server, fail silently */
f7423cbbd9dea363a5df18ebb96da055a977ae79Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen i_assert(file->sync_offset >= file->buffer_offset);
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainenlog_file_map_check_offsets(struct mail_transaction_log_file *file,
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen /* broken start offset */
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen file->filepath, start_offset, file->sync_offset);
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen if (end_offset != (uoff_t)-1 && end_offset > file->sync_offset) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen file->filepath, start_offset, file->sync_offset);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenint mail_transaction_log_file_map(struct mail_transaction_log_file *file,
f29756821a4c6b12b73e4a2a3e1c230117a43773Timo Sirainen /* corrupted */
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen if (index->log_locked && file == file->log->head &&
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen /* we're not interested of going further than sync_offset */
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen if (log_file_map_check_offsets(file, start_offset,
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen if (file->buffer != NULL && file->buffer_offset <= start_offset) {
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen /* see if we already have it */
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file)) {
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen /* we had moved the log to memory but failed to read
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen the beginning of the log file */
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen "%s: Beginning of the log isn't available",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return log_file_map_check_offsets(file, start_offset,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* we are going to mmap() this file, but it's not necessarily
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mmaped currently. */
3ba9a079592f46e94ce846e5aa80e4d479cd5e41Timo Sirainen i_assert(file->buffer_offset == 0 || file->mmap_base == NULL);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(file->mmap_size == 0 || file->mmap_base != NULL);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_index_file_set_syscall_error(index, file->filepath,
e2bdca8201e4aa1cd31332ffbdd4c6eef9151d5eTimo Sirainen "file size shrinked");
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen /* we already have the whole file mmaped */
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen return log_file_map_check_offsets(file, start_offset,
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen if (munmap(file->mmap_base, file->mmap_size) < 0) {
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen mail_index_file_set_syscall_error(index, file->filepath,
a7bf18c0a462e4069675dec5038c474f8eb0a60dTimo Sirainen ret = mail_transaction_log_file_read(file, start_offset);
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen /* in case we just switched to mmaping */
a7bf18c0a462e4069675dec5038c474f8eb0a60dTimo Sirainen file->mmap_base = mmap(NULL, file->mmap_size, PROT_READ,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_index_file_set_syscall_error(index, file->filepath,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen file->buffer = buffer_create_const_data(default_pool,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return log_file_map_check_offsets(file, start_offset, end_offset);
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainenvoid mail_transaction_log_file_move_to_memory(struct mail_transaction_log_file
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file))
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen /* just copy to memory */
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen buf = buffer_create_dynamic(default_pool, file->mmap_size);
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen buffer_append(buf, file->mmap_base, file->mmap_size);
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen /* and lose the mmap */
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen if (munmap(file->mmap_base, file->mmap_size) < 0) {