mail-transaction-log.c revision 07e80e04c8876b6bf3f95266f48b41e1a681e445
27e89b6925334565c73c407a9ae2809358789c81Jakub Hrozek/* Copyright (c) 2003-2010 Dovecot authors, see the included COPYING file */
27e89b6925334565c73c407a9ae2809358789c81Jakub Hrozekmail_transaction_log_set_head(struct mail_transaction_log *log,
27e89b6925334565c73c407a9ae2809358789c81Jakub Hrozek i_assert(log->files->next != NULL || log->files == file);
05d935cc9d04f03522d0bb44598d22d99b085926Jakub Hrozekmail_transaction_log_alloc(struct mail_index *index)
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozekstatic void mail_transaction_log_2_unlink_old(struct mail_transaction_log *log)
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozek if (st.st_mtime + MAIL_TRANSACTION_LOG2_STALE_SECS <= ioloop_time &&
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozek if (unlink(log->filepath2) < 0 && errno != ENOENT) {
05d935cc9d04f03522d0bb44598d22d99b085926Jakub Hrozekint mail_transaction_log_open(struct mail_transaction_log *log)
05d935cc9d04f03522d0bb44598d22d99b085926Jakub Hrozek log->filepath = i_strconcat(log->index->filepath,
05d935cc9d04f03522d0bb44598d22d99b085926Jakub Hrozek log->filepath2 = i_strconcat(log->filepath, ".2", NULL);
05d935cc9d04f03522d0bb44598d22d99b085926Jakub Hrozek /* these settings aren't available at alloc() time, so we need to
05d935cc9d04f03522d0bb44598d22d99b085926Jakub Hrozek set them here: */
05d935cc9d04f03522d0bb44598d22d99b085926Jakub Hrozek (log->index->flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) != 0;
05d935cc9d04f03522d0bb44598d22d99b085926Jakub Hrozek mail_transaction_log_file_free(&log->open_file);
05d935cc9d04f03522d0bb44598d22d99b085926Jakub Hrozek file = mail_transaction_log_file_alloc(log, log->filepath);
05d935cc9d04f03522d0bb44598d22d99b085926Jakub Hrozek if ((ret = mail_transaction_log_file_open(file, FALSE)) <= 0) {
05d935cc9d04f03522d0bb44598d22d99b085926Jakub Hrozek /* leave the file for _create() */
05d935cc9d04f03522d0bb44598d22d99b085926Jakub Hrozekint mail_transaction_log_create(struct mail_transaction_log *log, bool reset)
05d935cc9d04f03522d0bb44598d22d99b085926Jakub Hrozek file = mail_transaction_log_file_alloc_in_memory(log);
05d935cc9d04f03522d0bb44598d22d99b085926Jakub Hrozek file = mail_transaction_log_file_alloc(log, log->filepath);
05d935cc9d04f03522d0bb44598d22d99b085926Jakub Hrozek /* remember what file we tried to open. if someone else created
05d935cc9d04f03522d0bb44598d22d99b085926Jakub Hrozek a new file, use it instead of recreating it */
05d935cc9d04f03522d0bb44598d22d99b085926Jakub Hrozek mail_transaction_log_file_free(&log->open_file);
05d935cc9d04f03522d0bb44598d22d99b085926Jakub Hrozek if (mail_transaction_log_file_create(file, reset) < 0) {
05d935cc9d04f03522d0bb44598d22d99b085926Jakub Hrozekvoid mail_transaction_log_close(struct mail_transaction_log *log)
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozek mail_transaction_log_file_free(&log->open_file);
d2c552edde275e6c0de904760147afb2992796e9Jakub Hrozekvoid mail_transaction_log_free(struct mail_transaction_log **_log)
d2c552edde275e6c0de904760147afb2992796e9Jakub Hrozekvoid mail_transaction_log_move_to_memory(struct mail_transaction_log *log)
d2c552edde275e6c0de904760147afb2992796e9Jakub Hrozek if (!log->index->initial_mapped && log->files != NULL &&
d2c552edde275e6c0de904760147afb2992796e9Jakub Hrozek /* we couldn't read dovecot.index and we don't have the first
d2c552edde275e6c0de904760147afb2992796e9Jakub Hrozek .log file, so just start from scratch */
d2c552edde275e6c0de904760147afb2992796e9Jakub Hrozek log->filepath = i_strconcat(log->index->filepath,
d2c552edde275e6c0de904760147afb2992796e9Jakub Hrozek log->filepath2 = i_strconcat(log->filepath, ".2", NULL);
d2c552edde275e6c0de904760147afb2992796e9Jakub Hrozek mail_transaction_log_file_move_to_memory(log->head);
d2c552edde275e6c0de904760147afb2992796e9Jakub Hrozek file = mail_transaction_log_file_alloc_in_memory(log);
d2c552edde275e6c0de904760147afb2992796e9Jakub Hrozekvoid mail_transaction_log_indexid_changed(struct mail_transaction_log *log)
cc4caf88344210ea9777d618f0f71935ca5e7f8bSumit Bose for (file = log->files; file != NULL; file = file->next) {
d2c552edde275e6c0de904760147afb2992796e9Jakub Hrozek "indexid changed: %u -> %u",
d2c552edde275e6c0de904760147afb2992796e9Jakub Hrozek log->head->hdr.indexid != log->index->indexid) {
d2c552edde275e6c0de904760147afb2992796e9Jakub Hrozekvoid mail_transaction_logs_clean(struct mail_transaction_log *log)
27e89b6925334565c73c407a9ae2809358789c81Jakub Hrozek /* remove only files from the beginning. this way if a view has
27e89b6925334565c73c407a9ae2809358789c81Jakub Hrozek referenced an old file, it can still find the new files even if
27e89b6925334565c73c407a9ae2809358789c81Jakub Hrozek there aren't any references to it currently. */
27e89b6925334565c73c407a9ae2809358789c81Jakub Hrozek for (file = log->files; file != NULL; file = next) {
27e89b6925334565c73c407a9ae2809358789c81Jakub Hrozek /* if we still have locked files with refcount=0, unlock them */
d2c552edde275e6c0de904760147afb2992796e9Jakub Hrozek i_assert(log->head == NULL || log->files != NULL);
27e89b6925334565c73c407a9ae2809358789c81Jakub Hrozek (((file)->sync_offset > MAIL_TRANSACTION_LOG_ROTATE_MIN_SIZE && \
27e89b6925334565c73c407a9ae2809358789c81Jakub Hrozek ioloop_time - MAIL_TRANSACTION_LOG_ROTATE_TIME) || \
27e89b6925334565c73c407a9ae2809358789c81Jakub Hrozek ((file)->sync_offset > MAIL_TRANSACTION_LOG_ROTATE_MAX_SIZE))
27e89b6925334565c73c407a9ae2809358789c81Jakub Hrozekbool mail_transaction_log_want_rotate(struct mail_transaction_log *log)
27e89b6925334565c73c407a9ae2809358789c81Jakub Hrozekint mail_transaction_log_rotate(struct mail_transaction_log *log, bool reset)
27e89b6925334565c73c407a9ae2809358789c81Jakub Hrozek file = mail_transaction_log_file_alloc_in_memory(log);
27e89b6925334565c73c407a9ae2809358789c81Jakub Hrozek /* we're locked, we shouldn't need to worry about ESTALE
27e89b6925334565c73c407a9ae2809358789c81Jakub Hrozek problems in here. */
149174acae677d1e72a0da431bf0850d55f2ccb4Sumit Bose file = mail_transaction_log_file_alloc(log, path);
27e89b6925334565c73c407a9ae2809358789c81Jakub Hrozek if (mail_transaction_log_file_create(file, reset) < 0) {
27e89b6925334565c73c407a9ae2809358789c81Jakub Hrozekmail_transaction_log_refresh(struct mail_transaction_log *log, bool nfs_flush)
27e89b6925334565c73c407a9ae2809358789c81Jakub Hrozek if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(log->head))
27e89b6925334565c73c407a9ae2809358789c81Jakub Hrozek /* see if the whole directory got deleted */
27e89b6925334565c73c407a9ae2809358789c81Jakub Hrozek /* the file should always exist at this point. if it doesn't,
27e89b6925334565c73c407a9ae2809358789c81Jakub Hrozek someone deleted it manually while the index was open. try to
27e89b6925334565c73c407a9ae2809358789c81Jakub Hrozek handle this nicely by creating a new log file. */
27e89b6925334565c73c407a9ae2809358789c81Jakub Hrozek if (mail_transaction_log_create(log, FALSE) < 0)
27e89b6925334565c73c407a9ae2809358789c81Jakub Hrozek /* NFS: log files get rotated to .log.2 files instead
27e89b6925334565c73c407a9ae2809358789c81Jakub Hrozek of being unlinked, so we don't bother checking if
27e89b6925334565c73c407a9ae2809358789c81Jakub Hrozek the existing file has already been unlinked here
27e89b6925334565c73c407a9ae2809358789c81Jakub Hrozek (in which case inodes could match but point to
27e89b6925334565c73c407a9ae2809358789c81Jakub Hrozek different files) */
27e89b6925334565c73c407a9ae2809358789c81Jakub Hrozek file = mail_transaction_log_file_alloc(log, log->filepath);
27e89b6925334565c73c407a9ae2809358789c81Jakub Hrozek if (mail_transaction_log_file_open(file, FALSE) <= 0) {
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozekvoid mail_transaction_log_get_mailbox_sync_pos(struct mail_transaction_log *log,
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozekvoid mail_transaction_log_set_mailbox_sync_pos(struct mail_transaction_log *log,
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozek i_assert(file_offset >= log->head->saved_tail_offset);
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozekint mail_transaction_log_find_file(struct mail_transaction_log *log,
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozek /* see if the .log file has been recreated */
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozek /* transaction log is locked. there's no way a newer
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozek file exists. */
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozek /* we're opening the index and we just opened the
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozek log file. don't waste time checking if there's a
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozek newer one. */
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozek if (mail_transaction_log_refresh(log, FALSE) < 0)
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozek /* try again, this time flush attribute cache */
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozek if (mail_transaction_log_refresh(log, TRUE) < 0)
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozek for (file = log->files; file != NULL; file = file->next) {
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozek /* see if we have it in log.2 file */
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozek file = mail_transaction_log_file_alloc(log, log->filepath2);
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozek if ((ret = mail_transaction_log_file_open(file, TRUE)) <= 0) {
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozek /* but is it what we expected? */
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozekint mail_transaction_log_lock_head(struct mail_transaction_log *log)
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozek /* we need to check once in a while if .log.2 should be deleted
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozek to avoid wasting space on such old files. but we also don't
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozek want to waste time on checking it when the same mailbox
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozek gets opened over and over again rapidly (e.g. pop3). so
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozek do this only when there have actually been some changes
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozek to mailbox (i.e. when it's being locked here) */
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozek /* we want to get the head file locked. this is a bit racy,
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozek since by the time we have it locked a new log file may have been
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozek creating new log file requires locking the head file, so if we
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozek can lock it and don't see another file, we can be sure no-one is
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozek creating a new log at the moment */
db5f9ab3feb85aa444eab20428ca2b98801b6783Jakub Hrozek /* success */
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozek /* try again */
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozekint mail_transaction_log_sync_lock(struct mail_transaction_log *log,
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozek /* update sync_offset */
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozek if (mail_transaction_log_file_map(log->head, log->head->sync_offset,
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozekvoid mail_transaction_log_sync_unlock(struct mail_transaction_log *log)
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozekvoid mail_transaction_log_get_head(struct mail_transaction_log *log,
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozekvoid mail_transaction_log_get_tail(struct mail_transaction_log *log,
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozek struct mail_transaction_log_file *tail, *file = log->files;
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozek for (tail = file; file->next != NULL; file = file->next) {
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozek if (file->hdr.file_seq + 1 != file->next->hdr.file_seq)
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozekbool mail_transaction_log_is_head_prev(struct mail_transaction_log *log,
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozek return log->head->hdr.prev_file_seq == file_seq &&
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozek log->head->hdr.prev_file_offset == file_offset;
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozekint mail_transaction_log_get_mtime(struct mail_transaction_log *log,
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozek mail_index_file_set_syscall_error(log->index, log->filepath,
64ea4127f463798410a2c20e0261c6b15f60257fJakub Hrozekvoid mail_transaction_log_get_dotlock_set(struct mail_transaction_log *log,
6ed964cf2e5a68e92e220f3b9f55029731bcabaaJakub Hrozek set_r->timeout = I_MIN(MAIL_TRANSCATION_LOG_LOCK_TIMEOUT,
6ed964cf2e5a68e92e220f3b9f55029731bcabaaJakub Hrozek set_r->stale_timeout = MAIL_TRANSCATION_LOG_LOCK_CHANGE_TIMEOUT;
6ed964cf2e5a68e92e220f3b9f55029731bcabaaJakub Hrozek set_r->nfs_flush = (index->flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) != 0;