mail-transaction-log.c revision 1be964ec6d835f95b4fdebf02add9265d58ad290
89a126810703c666309310d0f3189e9834d70b5bTimo Sirainen/* Copyright (c) 2003-2011 Dovecot authors, see the included COPYING file */
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainenmail_transaction_log_set_head(struct mail_transaction_log *log,
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen i_assert(log->files->next != NULL || log->files == file);
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainenmail_transaction_log_alloc(struct mail_index *index)
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainenstatic void mail_transaction_log_2_unlink_old(struct mail_transaction_log *log)
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen if (st.st_mtime + MAIL_TRANSACTION_LOG2_STALE_SECS <= ioloop_time &&
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen if (unlink(log->filepath2) < 0 && errno != ENOENT) {
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainenint mail_transaction_log_open(struct mail_transaction_log *log)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen log->filepath = i_strconcat(log->index->filepath,
8d6cb44a0161d88743756733f83c4fb278485987Timo Sirainen log->filepath2 = i_strconcat(log->filepath, ".2", NULL);
be889d9b142fbb5604a922c6955bd7f6ea32f163Timo Sirainen /* these settings aren't available at alloc() time, so we need to
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen set them here: */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen (log->index->flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) != 0;
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen mail_transaction_log_file_free(&log->open_file);
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen file = mail_transaction_log_file_alloc(log, log->filepath);
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen if ((ret = mail_transaction_log_file_open(file, FALSE)) <= 0) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* leave the file for _create() */
be889d9b142fbb5604a922c6955bd7f6ea32f163Timo Sirainenint mail_transaction_log_create(struct mail_transaction_log *log, bool reset)
be889d9b142fbb5604a922c6955bd7f6ea32f163Timo Sirainen file = mail_transaction_log_file_alloc_in_memory(log);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen file = mail_transaction_log_file_alloc(log, log->filepath);
0cea9b1f4fa0495a48f5f097e40492517d67e1baTimo Sirainen /* remember what file we tried to open. if someone else created
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen a new file, use it instead of recreating it */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen file->last_mtime = log->open_file->last_mtime;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail_transaction_log_file_free(&log->open_file);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (mail_transaction_log_file_create(file, reset) < 0) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvoid mail_transaction_log_close(struct mail_transaction_log *log)
8d6cb44a0161d88743756733f83c4fb278485987Timo Sirainen mail_transaction_log_file_free(&log->open_file);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvoid mail_transaction_log_free(struct mail_transaction_log **_log)
16598a1fb870ae40d6177755a4306216e4d6a4cdTimo Sirainenvoid mail_transaction_log_move_to_memory(struct mail_transaction_log *log)
bc793bfcee945ce8871edfa298fe7235744425b6Timo Sirainen if (!log->index->initial_mapped && log->files != NULL &&
bc793bfcee945ce8871edfa298fe7235744425b6Timo Sirainen /* we couldn't read dovecot.index and we don't have the first
16598a1fb870ae40d6177755a4306216e4d6a4cdTimo Sirainen .log file, so just start from scratch */
16598a1fb870ae40d6177755a4306216e4d6a4cdTimo Sirainen log->filepath = i_strconcat(log->index->filepath,
16598a1fb870ae40d6177755a4306216e4d6a4cdTimo Sirainen log->filepath2 = i_strconcat(log->filepath, ".2", NULL);
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen mail_transaction_log_file_move_to_memory(log->head);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen file = mail_transaction_log_file_alloc_in_memory(log);
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainenvoid mail_transaction_log_indexid_changed(struct mail_transaction_log *log)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen for (file = log->files; file != NULL; file = file->next) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (file->hdr.indexid != log->index->indexid) {
6e235046e1d8e9d89fc948f5c623676c20421a28Timo Sirainen "indexid changed: %u -> %u",
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen log->head->hdr.indexid != log->index->indexid) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen (void)mail_transaction_log_create(log, FALSE);
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainenvoid mail_transaction_logs_clean(struct mail_transaction_log *log)
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen struct mail_transaction_log_file *file, *next;
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen /* remove only files from the beginning. this way if a view has
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen referenced an old file, it can still find the new files even if
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen there aren't any references to it currently. */
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen for (file = log->files; file != NULL; file = next) {
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen /* if we still have locked files with refcount=0, unlock them */
114a0f74e0f825c6bd8aeadfafb248a030762a1fTimo Sirainen i_assert(log->head == NULL || log->files != NULL);
abb83d133dd082527d500916fca66a72fbbbaa8dTimo Sirainen (((file)->sync_offset > MAIL_TRANSACTION_LOG_ROTATE_MIN_SIZE && \
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen ioloop_time - MAIL_TRANSACTION_LOG_ROTATE_TIME) || \
6e235046e1d8e9d89fc948f5c623676c20421a28Timo Sirainen ((file)->sync_offset > MAIL_TRANSACTION_LOG_ROTATE_MAX_SIZE))
6e235046e1d8e9d89fc948f5c623676c20421a28Timo Sirainenbool mail_transaction_log_want_rotate(struct mail_transaction_log *log)
abb83d133dd082527d500916fca66a72fbbbaa8dTimo Sirainenint mail_transaction_log_rotate(struct mail_transaction_log *log, bool reset)
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen file = mail_transaction_log_file_alloc_in_memory(log);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* we're locked, we shouldn't need to worry about ESTALE
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen problems in here. */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen file = mail_transaction_log_file_alloc(log, path);
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen if (mail_transaction_log_file_create(file, reset) < 0) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenmail_transaction_log_refresh(struct mail_transaction_log *log, bool nfs_flush)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(log->head))
265e9d8457aa5ce01b7aad954632aed8c36deeb8Timo Sirainen /* see if the whole directory got deleted */
11768c622a8e5aaf0e5d9b3c9a872867b62b4830Timo Sirainen if (nfs_safe_stat(log->index->dir, &st) < 0 &&
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen /* the file should always exist at this point. if it doesn't,
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen someone deleted it manually while the index was open. try to
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen handle this nicely by creating a new log file. */
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen if (mail_transaction_log_create(log, FALSE) < 0)
6ebcdea168735ee76e32b871c1f50f3526690447Timo Sirainen /* NFS: log files get rotated to .log.2 files instead
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen of being unlinked, so we don't bother checking if
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen the existing file has already been unlinked here
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen (in which case inodes could match but point to
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen different files) */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen file = mail_transaction_log_file_alloc(log, log->filepath);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (mail_transaction_log_file_open(file, FALSE) <= 0) {
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainenvoid mail_transaction_log_get_mailbox_sync_pos(struct mail_transaction_log *log,
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainenvoid mail_transaction_log_set_mailbox_sync_pos(struct mail_transaction_log *log,
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen i_assert(file_seq == log->head->hdr.file_seq);
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen i_assert(file_offset >= log->head->saved_tail_offset);
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen if (file_offset >= log->head->max_tail_offset)
8e574a603c2c02105b073906a7ca91904271b80eTimo Sirainenint mail_transaction_log_find_file(struct mail_transaction_log *log,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* see if the .log file has been recreated */
a04b6515c20b431294626400e173d81f3d25889bTimo Sirainen /* transaction log is locked. there's no way a newer
a04b6515c20b431294626400e173d81f3d25889bTimo Sirainen file exists. */
9c4c535b86e9473ad97c6e9242ed84f3d9d69d0dTimo Sirainen /* we're opening the index and we just opened the
9c4c535b86e9473ad97c6e9242ed84f3d9d69d0dTimo Sirainen log file. don't waste time checking if there's a
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen newer one. */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (mail_transaction_log_refresh(log, FALSE) < 0)
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen /* try again, this time flush attribute cache */
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen if (mail_transaction_log_refresh(log, TRUE) < 0)
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen for (file = log->files; file != NULL; file = file->next) {
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen /* see if we have it in log.2 file */
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen file = mail_transaction_log_file_alloc(log, log->filepath2);
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen if ((ret = mail_transaction_log_file_open(file, TRUE)) <= 0) {
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen /* but is it what we expected? */
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainenint mail_transaction_log_lock_head(struct mail_transaction_log *log)
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen /* we need to check once in a while if .log.2 should be deleted
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen to avoid wasting space on such old files. but we also don't
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen want to waste time on checking it when the same mailbox
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen gets opened over and over again rapidly (e.g. pop3). so
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen do this only when there have actually been some changes
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen to mailbox (i.e. when it's being locked here) */
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen /* we want to get the head file locked. this is a bit racy,
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen since by the time we have it locked a new log file may have been
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen creating new log file requires locking the head file, so if we
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen can lock it and don't see another file, we can be sure no-one is
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen creating a new log at the moment */
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen ret = mail_transaction_log_refresh(log, TRUE);
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen /* success */
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen /* try again */
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainenint mail_transaction_log_sync_lock(struct mail_transaction_log *log,
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen /* update sync_offset */
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen if (mail_transaction_log_file_map(log->head, log->head->sync_offset,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvoid mail_transaction_log_sync_unlock(struct mail_transaction_log *log)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvoid mail_transaction_log_get_head(struct mail_transaction_log *log,
6157a322f2ac1ea1332d9003ecb0b11466aa8fe7Timo Sirainenvoid mail_transaction_log_get_tail(struct mail_transaction_log *log,
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen struct mail_transaction_log_file *tail, *file = log->files;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen for (tail = file; file->next != NULL; file = file->next) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (file->hdr.file_seq + 1 != file->next->hdr.file_seq)
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainenbool mail_transaction_log_is_head_prev(struct mail_transaction_log *log,
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen return log->head->hdr.prev_file_seq == file_seq &&
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen log->head->hdr.prev_file_offset == file_offset;
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainenint mail_transaction_log_get_mtime(struct mail_transaction_log *log,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail_index_file_set_syscall_error(log->index, log->filepath,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenint mail_transaction_log_unlink(struct mail_transaction_log *log)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail_index_file_set_syscall_error(log->index, log->filepath,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvoid mail_transaction_log_get_dotlock_set(struct mail_transaction_log *log,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen set_r->timeout = I_MIN(MAIL_TRANSCATION_LOG_LOCK_TIMEOUT,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen set_r->stale_timeout = MAIL_TRANSCATION_LOG_LOCK_CHANGE_TIMEOUT;