mail-transaction-log.c revision 96975ce7b258b4ed09040bd1dc9a453106dee581
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2003-2010 Dovecot authors, see the included COPYING file */
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenmail_transaction_log_set_head(struct mail_transaction_log *log,
8b247780e911909a9fdc47f69ce6d1478902ad98Timo Sirainen i_assert(log->files->next != NULL || log->files == file);
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainenmail_transaction_log_alloc(struct mail_index *index)
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainenstatic void mail_transaction_log_2_unlink_old(struct mail_transaction_log *log)
9a48c2243fe98ca8393be7908f84d20c634bcdf9Timo Sirainen if (st.st_mtime + MAIL_TRANSACTION_LOG2_STALE_SECS <= ioloop_time &&
59e26ff34b05cd971a111f8a42fc60c13d9f688bTimo Sirainen if (unlink(log->filepath2) < 0 && errno != ENOENT) {
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainenint mail_transaction_log_open(struct mail_transaction_log *log)
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen log->filepath = i_strconcat(log->index->filepath,
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen log->filepath2 = i_strconcat(log->filepath, ".2", NULL);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* these settings aren't available at alloc() time, so we need to
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen set them here: */
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen (log->index->flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) != 0;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen mail_transaction_log_file_free(&log->open_file);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen file = mail_transaction_log_file_alloc(log, log->filepath);
5a1b498b646b5c5dbd1b3f3861df766f560578c5Timo Sirainen if ((ret = mail_transaction_log_file_open(file, FALSE)) <= 0) {
5a1b498b646b5c5dbd1b3f3861df766f560578c5Timo Sirainen /* leave the file for _create() */
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainenint mail_transaction_log_create(struct mail_transaction_log *log, bool reset)
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen file = mail_transaction_log_file_alloc_in_memory(log);
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen file = mail_transaction_log_file_alloc(log, log->filepath);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* remember what file we tried to open. if someone else created
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen a new file, use it instead of recreating it */
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen file->last_mtime = log->open_file->last_mtime;
211ed7806d8715ec2280ffbf5d10f0d6e4f1beb2Timo Sirainen mail_transaction_log_file_free(&log->open_file);
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen if (mail_transaction_log_file_create(file, reset) < 0) {
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainenvoid mail_transaction_log_close(struct mail_transaction_log *log)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen mail_transaction_log_file_free(&log->open_file);
556f95092c3bc850517d5ab2bb502024a55645f1Timo Sirainenvoid mail_transaction_log_free(struct mail_transaction_log **_log)
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainenvoid mail_transaction_log_move_to_memory(struct mail_transaction_log *log)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (!log->index->initial_mapped && log->files != NULL &&
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* we couldn't read dovecot.index and we don't have the first
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen .log file, so just start from scratch */
10ff47d5d6146995e16da00d36eca7d162064a7bTimo Sirainen log->filepath = i_strconcat(log->index->filepath,
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen log->filepath2 = i_strconcat(log->filepath, ".2", NULL);
8f32e59200da904613506f5649ffa4d9f5989cebTimo Sirainen mail_transaction_log_file_move_to_memory(log->head);
3d77cc0d502dc69ffe2afe318605964dd40b7b20Timo Sirainen file = mail_transaction_log_file_alloc_in_memory(log);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenvoid mail_transaction_log_indexid_changed(struct mail_transaction_log *log)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen for (file = log->files; file != NULL; file = file->next) {
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen if (file->hdr.indexid != log->index->indexid) {
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen "indexid changed: %u -> %u",
5238111c460098d9cc8cc22527026138a278b9a4Timo Sirainen log->head->hdr.indexid != log->index->indexid) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen (void)mail_transaction_log_create(log, FALSE);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenvoid mail_transaction_logs_clean(struct mail_transaction_log *log)
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen struct mail_transaction_log_file *file, *next;
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen /* remove only files from the beginning. this way if a view has
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen referenced an old file, it can still find the new files even if
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen there aren't any references to it currently. */
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen for (file = log->files; file != NULL; file = next) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* if we still have locked files with refcount=0, unlock them */
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen i_assert(log->head == NULL || log->files != NULL);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen (((file)->sync_offset > MAIL_TRANSACTION_LOG_ROTATE_MIN_SIZE && \
b92e979748a22925b0770d3004eaab043ed69574Timo Sirainen ioloop_time - MAIL_TRANSACTION_LOG_ROTATE_TIME) || \
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen ((file)->sync_offset > MAIL_TRANSACTION_LOG_ROTATE_MAX_SIZE))
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenbool mail_transaction_log_want_rotate(struct mail_transaction_log *log)
35283613d4c04ce18836e9fc431582c87b3710a0Timo Sirainenint mail_transaction_log_rotate(struct mail_transaction_log *log, bool reset)
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen file = mail_transaction_log_file_alloc_in_memory(log);
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen /* we're locked, we shouldn't need to worry about ESTALE
0dbcf4026ff8471b4d6d2e14f7e52321396bf087Timo Sirainen problems in here. */
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen file = mail_transaction_log_file_alloc(log, path);
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen if (mail_transaction_log_file_create(file, reset) < 0) {
b92e979748a22925b0770d3004eaab043ed69574Timo Sirainenmail_transaction_log_refresh(struct mail_transaction_log *log, bool nfs_flush)
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(log->head))
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen /* see if the whole directory got deleted */
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen if (nfs_safe_stat(log->index->dir, &st) < 0 &&
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen /* the file should always exist at this point. if it doesn't,
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen someone deleted it manually while the index was open. try to
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen handle this nicely by creating a new log file. */
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen if (mail_transaction_log_create(log, FALSE) < 0)
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen /* NFS: log files get rotated to .log.2 files instead
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen of being unlinked, so we don't bother checking if
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen the existing file has already been unlinked here
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen (in which case inodes could match but point to
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen different files) */
98a73e104c7b9c3747053e63113451e24daf7f36Timo Sirainen file = mail_transaction_log_file_alloc(log, log->filepath);
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen if (mail_transaction_log_file_open(file, FALSE) <= 0) {
98a73e104c7b9c3747053e63113451e24daf7f36Timo Sirainenvoid mail_transaction_log_get_mailbox_sync_pos(struct mail_transaction_log *log,
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainenvoid mail_transaction_log_set_mailbox_sync_pos(struct mail_transaction_log *log,
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen i_assert(file_seq == log->head->hdr.file_seq);
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen i_assert(file_offset >= log->head->saved_tail_offset);
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen if (file_offset >= log->head->max_tail_offset)
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainenint mail_transaction_log_find_file(struct mail_transaction_log *log,
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen /* see if the .log file has been recreated */
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen /* transaction log is locked. there's no way a newer
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen file exists. */
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen if (mail_transaction_log_refresh(log, FALSE) < 0)
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen /* try again, this time flush attribute cache */
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen if (mail_transaction_log_refresh(log, TRUE) < 0)
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen for (file = log->files; file != NULL; file = file->next) {
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainen /* see if we have it in log.2 file */
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen file = mail_transaction_log_file_alloc(log, log->filepath2);
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainen if ((ret = mail_transaction_log_file_open(file, TRUE)) <= 0) {
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainen /* but is it what we expected? */
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainenint mail_transaction_log_lock_head(struct mail_transaction_log *log)
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen /* we need to check once in a while if .log.2 should be deleted
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen to avoid wasting space on such old files. but we also don't
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen want to waste time on checking it when the same mailbox
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen gets opened over and over again rapidly (e.g. pop3). so
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen do this only when there have actually been some changes
3d77cc0d502dc69ffe2afe318605964dd40b7b20Timo Sirainen to mailbox (i.e. when it's being locked here) */
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen /* we want to get the head file locked. this is a bit racy,
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen since by the time we have it locked a new log file may have been
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen creating new log file requires locking the head file, so if we
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen can lock it and don't see another file, we can be sure no-one is
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen creating a new log at the moment */
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen ret = mail_transaction_log_refresh(log, TRUE);
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen /* success */
71da447014454c84828d9dface77219875554d7dTimo Sirainen /* try again */
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenint mail_transaction_log_sync_lock(struct mail_transaction_log *log,
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen /* update sync_offset */
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen if (mail_transaction_log_file_map(log->head, log->head->sync_offset,
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenvoid mail_transaction_log_sync_unlock(struct mail_transaction_log *log)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenvoid mail_transaction_log_get_head(struct mail_transaction_log *log,
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenvoid mail_transaction_log_get_tail(struct mail_transaction_log *log,
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen struct mail_transaction_log_file *tail, *file = log->files;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen for (tail = file; file->next != NULL; file = file->next) {
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (file->hdr.file_seq + 1 != file->next->hdr.file_seq)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenbool mail_transaction_log_is_head_prev(struct mail_transaction_log *log,
2d2ebe91d56e9a158de000c9d0026f65600fbcfaTimo Sirainen return log->head->hdr.prev_file_seq == file_seq &&
2d2ebe91d56e9a158de000c9d0026f65600fbcfaTimo Sirainen log->head->hdr.prev_file_offset == file_offset;
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainenint mail_transaction_log_get_mtime(struct mail_transaction_log *log,
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen mail_index_file_set_syscall_error(log->index, log->filepath,
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenvoid mail_transaction_log_get_dotlock_set(struct mail_transaction_log *log,
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen set_r->timeout = I_MIN(MAIL_TRANSCATION_LOG_LOCK_TIMEOUT,
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen set_r->stale_timeout = MAIL_TRANSCATION_LOG_LOCK_CHANGE_TIMEOUT;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen set_r->nfs_flush = (index->flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) != 0;