mail-transaction-log.c revision 97d1089f42026a767dc24a5eed1d34fceb1f71a1
a8c5a86d183db25a57bf193c06b41e092ec2e151Timo Sirainen/* Copyright (C) 2003-2004 Timo Sirainen */
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen/* this lock should never exist for a long time.. */
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen#define LOG_DOTLOCK_IMMEDIATE_STALE_TIMEOUT 300
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainenmail_transaction_log_file_open_or_create(struct mail_transaction_log *log,
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainen const char *path);
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainenstatic int mail_transaction_log_rotate(struct mail_transaction_log *log,
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainenmail_transaction_log_file_lock(struct mail_transaction_log_file *file,
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainenstatic int mail_transaction_log_lock_head(struct mail_transaction_log *log);
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainenmail_transaction_log_file_set_corrupted(struct mail_transaction_log_file *file,
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainen const char *fmt, ...)
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen "Corrupted transaction log file %s: %s",
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen !(((file)->hdr.file_seq == (index)->hdr->log_file_seq && \
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen sizeof(struct mail_transaction_log_header)) || \
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen ((file)->hdr.prev_file_seq == (index)->hdr->log_file_seq && \
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen (file)->hdr.prev_file_offset == (index)->hdr->log_file_offset))
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainenstatic int mail_transaction_log_check_file_seq(struct mail_transaction_log *log)
b397665e90fa0fc7c6a9156fdd6cf28b571e8e39Timo Sirainen unsigned int lock_id;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen ret = mail_index_lock_shared(index, TRUE, &lock_id);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen else if (INDEX_HAS_MISSING_LOGS(index, file)) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* broken - fix it by creating a new log file */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen ret = mail_transaction_log_rotate(log, F_UNLCK);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen (void)mail_transaction_log_file_lock(file, F_UNLCK);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenmail_transaction_log_open_or_create(struct mail_index *index)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen log->head = mail_transaction_log_file_open_or_create(log, path);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* head log file isn't same as head index file -
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen shouldn't happen except in race conditions. lock them and
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen check again - FIXME: missing error handling. */
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen (void)mail_transaction_log_check_file_seq(log);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenvoid mail_transaction_log_close(struct mail_transaction_log *log)
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainenmail_transaction_log_file_dotlock(struct mail_transaction_log_file *file,
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen ret = file_unlock_dotlock(file->filepath, &file->log->dotlock);
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen "Dotlock was lost for transaction log file %s",
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen ret = file_lock_dotlock(file->filepath, NULL, FALSE,
dffa503fd4ce31334346e539496084c80a2d8d37Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen "file_lock_dotlock()");
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen "Timeout while waiting for release of "
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen "dotlock for transaction log file %s",
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenmail_transaction_log_file_lock(struct mail_transaction_log_file *file,
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen return mail_transaction_log_file_dotlock(file, lock_type);
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen ret = file_wait_lock_full(file->fd, lock_type, DEFAULT_LOCK_TIMEOUT,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen "file_wait_lock()");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "Timeout while waiting for release of "
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "%s fcntl() lock for transaction log file %s",
40ad2c4902e9d83557f2e8a4bff3d98fea2c8aa1Timo Sirainen lock_type == F_WRLCK ? "exclusive" : "shared",
14c474d9f4591c397ed0b5206af6537c7b52c924Timo Sirainenmail_transaction_log_file_close(struct mail_transaction_log_file *file)
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen (void)mail_transaction_log_file_lock(file, F_UNLCK);
8d131435ba4648c8821160ec38d508c97177c715Timo Sirainen if (munmap(file->mmap_base, file->mmap_size) < 0) {
8d131435ba4648c8821160ec38d508c97177c715Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
b5b3b4c9159f506cdfdce7399faaeeffdf73faf7Timo Sirainenmail_transaction_log_file_read_hdr(struct mail_transaction_log_file *file,
e64d7b6f388fecd0c83a4f2acb54e30d5ac98c6cTimo Sirainen ret = pread_full(file->fd, &file->hdr, sizeof(file->hdr), 0);
e64d7b6f388fecd0c83a4f2acb54e30d5ac98c6cTimo Sirainen if (mail_transaction_log_file_lock(file, F_RDLCK) < 0)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* we have to fstat() again since it may have changed after
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen (void)mail_transaction_log_file_lock(file, F_UNLCK);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen (void)mail_transaction_log_file_lock(file, F_UNLCK);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen // FIXME: handle ESTALE
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "pread_full()");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "unexpected end of file while reading header");
bdd7a96c363346f7c38f389791be1487ca08775bTimo Sirainen /* corrupted */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "Transaction log file %s: marked corrupted",
d9fda7e3a0fa5551547ac3e3054b837fc77f4bfbTimo Sirainen if (file->hdr.indexid != file->log->index->indexid) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* creating index file, silently rebuild
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen transaction log as well */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* index file was probably just rebuilt and we don't know
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen about it yet */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "Transaction log file %s: invalid indexid (%u != %u)",
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "used_size (%u) < old_size (%u)",
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenmail_transaction_log_file_create(struct mail_transaction_log *log,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen unsigned int lock_id;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* With dotlocking we might already have path.lock created, so this
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen filename has to be different. */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen fd = file_dotlock_open(path, NULL, LOG_NEW_DOTLOCK_SUFFIX,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen LOG_DOTLOCK_IMMEDIATE_STALE_TIMEOUT, NULL, NULL);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_index_file_set_syscall_error(index, path,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "file_dotlock_open()");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* log creation is locked now - see if someone already created it */
1deffbbcd7affd2ec89284f3c644cc73db0a2b90Timo Sirainen mail_index_file_set_syscall_error(index, path,
1deffbbcd7affd2ec89284f3c644cc73db0a2b90Timo Sirainen } else if (st.st_dev == dev && st.st_ino == ino) {
1deffbbcd7affd2ec89284f3c644cc73db0a2b90Timo Sirainen /* same file, still broken */
97cb20eb77d486ef67eac50567e3080faca025c1Timo Sirainen (void)file_dotlock_delete(path, LOG_NEW_DOTLOCK_SUFFIX,
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen mail_index_file_set_syscall_error(index, path, "open()");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (mail_index_lock_shared(index, TRUE, &lock_id) < 0)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen hdr.prev_file_offset = index->hdr->log_file_offset;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (log->head != NULL && hdr.file_seq <= log->head->hdr.file_seq) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* make sure the sequence grows */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_index_file_set_syscall_error(index, path,
d9fda7e3a0fa5551547ac3e3054b837fc77f4bfbTimo Sirainen "write_full()");
97cb20eb77d486ef67eac50567e3080faca025c1Timo Sirainen (void)file_dotlock_delete(path, LOG_NEW_DOTLOCK_SUFFIX, fd);
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen mail_index_file_set_syscall_error(index, path, "dup()");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen (void)file_dotlock_delete(path, LOG_NEW_DOTLOCK_SUFFIX, fd);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (file_dotlock_replace(path, LOG_NEW_DOTLOCK_SUFFIX, fd, FALSE) <= 0)
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen /* success */
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainenmail_transaction_log_file_fd_open(struct mail_transaction_log *log,
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen mail_index_file_set_syscall_error(log->index, path, "fstat()");
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen file = i_new(struct mail_transaction_log_file, 1);
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen ret = mail_transaction_log_file_read_hdr(file, &st);
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen /* corrupted header */
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen fd = mail_transaction_log_file_create(log, path,
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen mail_index_file_set_syscall_error(log->index, path,
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen ret = mail_transaction_log_file_read_hdr(file, &st);
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen for (p = &log->tail; *p != NULL; p = &(*p)->next) {
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen if ((*p)->hdr.file_seq >= file->hdr.file_seq) {
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen /* log replaced with file having same sequence as
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen previous one. shouldn't happen unless previous
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen log file was corrupted.. */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenmail_transaction_log_file_open_or_create(struct mail_transaction_log *log,
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen mail_index_file_set_syscall_error(log->index, path,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen fd = mail_transaction_log_file_create(log, path, 0, 0);
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen return mail_transaction_log_file_fd_open(log, path, fd);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenvoid mail_transaction_logs_clean(struct mail_transaction_log *log)
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen if ((*p)->refcount != 0)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenstatic int mail_transaction_log_rotate(struct mail_transaction_log *log,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen fd = mail_transaction_log_file_create(log, log->head->filepath,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file = mail_transaction_log_file_fd_open(log, log->head->filepath, fd);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (mail_transaction_log_file_lock(file, lock_type) < 0) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen (void)mail_transaction_log_file_lock(log->head, F_UNLCK);
8f0e6d627f3646e559ac5224c306839669d1a5e0Timo Sirainenstatic int mail_transaction_log_recreate(struct mail_transaction_log *log)
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen unsigned int lock_id;
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen if (mail_index_lock_shared(log->index, TRUE, &lock_id) < 0)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen ret = mail_transaction_log_rotate(log, F_UNLCK);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenstatic int mail_transaction_log_refresh(struct mail_transaction_log *log)
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen mail_index_file_set_syscall_error(log->index, path, "stat()");
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (errno == ENOENT && log->head->lock_type == F_WRLCK) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* same file */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen ret = mail_transaction_log_file_read_hdr(log->head, &st);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (ret == 0 && log->head->lock_type == F_WRLCK) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* corrupted, recreate */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen file = mail_transaction_log_file_open_or_create(log, path);
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainenint mail_transaction_log_file_find(struct mail_transaction_log *log,
5921647936e3d9a2dc60c0e49c66dd33efca234dTimo Sirainen for (file = log->tail; file != NULL; file = file->next) {
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainenmail_transaction_log_file_read(struct mail_transaction_log_file *file,
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (file->buffer != NULL && file->buffer_offset > offset) {
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen /* we have to insert missing data to beginning of buffer */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen buffer_copy(file->buffer, size, file->buffer, 0, (size_t)-1);
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen data = buffer_get_space_unsafe(file->buffer, 0, size);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen ret = pread_full(file->fd, data, size, offset);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* log file was deleted in NFS server, fail silently */
04b8a90af181cc4c7959266855e8ed50a22ed413Timo Sirainen file->buffer = buffer_create_dynamic(default_pool,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (file->buffer_offset + size >= file->hdr.used_size) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* caller should have checked this.. */
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen size = file->hdr.used_size - file->buffer_offset - size;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen data = buffer_append_space_unsafe(file->buffer, size);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen ret = pread_full(file->fd, data, size, offset);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* log file was deleted in NFS server, fail silently */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenint mail_transaction_log_file_map(struct mail_transaction_log_file *file,
347acd14d8da653ce3757b3e29981326502bed6bTimo Sirainen /* corrupted */
8cd0a1a2200e65cd134d03fe3f93ec02f1746359Timo Sirainen /* with mmap_no_write we could alternatively just write to log with
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen msync() rather than pwrite(). that'd cause slightly more disk I/O,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen so rather use more memory. */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen use_mmap = !index->mmap_disable && !index->mmap_no_write;
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen if (file->buffer != NULL && file->buffer_offset <= start_offset) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* see if we already have it */
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen mail_index_file_set_syscall_error(index, file->filepath,
bf8f4f90cb5e5f32c2611ba3425557964b9c47fcTimo Sirainen file->buffer_offset <= start_offset && end_offset == (uoff_t)-1) {
bf8f4f90cb5e5f32c2611ba3425557964b9c47fcTimo Sirainen /* we've seen the whole file.. do we have all of it mapped? */
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (file->buffer_offset + size == file->hdr.used_size)
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen if (munmap(file->mmap_base, file->mmap_size) < 0) {
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen mail_index_file_set_syscall_error(index, file->filepath,
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen if (mail_transaction_log_file_read_hdr(file, &st) <= 0)
629600d9a85e8025c15a5eaeb80329e116e022c9Timo Sirainen "offset (%"PRIuUOFF_T") < header size (%"PRIuSIZE_T")",
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen ret = mail_transaction_log_file_read(file, start_offset);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "Unexpected EOF");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* make sure we don't leave ourself in
9716b2665ee3938d3dfe64bda44d7c3ae3b55d30Timo Sirainen inconsistent state */
b222354c9553cd60b7dd418885e10c0473f73985Timo Sirainen file->mmap_base = mmap(NULL, file->mmap_size, PROT_READ,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_index_file_set_syscall_error(index, file->filepath,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->buffer = buffer_create_const_data(default_pool, file->mmap_base,
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainenstatic int mail_transaction_log_lock_head(struct mail_transaction_log *log)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* we want to get the head file locked. this is a bit racy,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen since by the time we have it locked a new log file may have been
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen creating new log file requires locking the head file, so if we
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen can lock it and don't see another file, we can be sure no-one is
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen creating a new log at the moment */
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen if (mail_transaction_log_file_lock(file, F_WRLCK) < 0)
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen /* success */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (mail_transaction_log_file_lock(file, F_UNLCK) < 0)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* try again */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenstatic int mail_transaction_log_fix_appends(struct mail_transaction_log *log,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen const struct mail_index_record *old, *old_end;
bd503f12eb667df389a99162f567bd8785798f55Timo Sirainen struct mail_index_record *appends, *end, *rec, *dest;
94d5a3fe15ff7096f3a2c7edcf790b5d3b8d1acbTimo Sirainen appends = buffer_get_modifyable_data(t->appends, &size);
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen /* we'll just check that none of the appends are already in
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen transaction log. this could happen if we crashed before we had
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen a chance to update index file */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen sync_view = mail_transaction_log_view_open(log);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen ret = mail_transaction_log_view_set(sync_view, t->view->log_file_seq,
b222354c9553cd60b7dd418885e10c0473f73985Timo Sirainen while ((ret = mail_transaction_log_view_next(sync_view,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if ((hdr->type & MAIL_TRANSACTION_TYPE_MASK) !=
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* appends are sorted */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* compress deleted appends away */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen for (rec = dest = appends; rec != end; rec++) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenlog_append_buffer(struct mail_transaction_log_file *file, const buffer_t *buf,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen enum mail_transaction_type type, int external)
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen i_assert((type & MAIL_TRANSACTION_TYPE_MASK) != 0);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* write only the header */
082e82792b8ac33ad42beac510441b37a3c50737Timo Sirainen if (pwrite_full(file->fd, &hdr, sizeof(hdr), file->hdr.used_size) < 0)
f153a2cec0319f549388d28f8cfd4d50229d1132Timo Sirainen if (pwrite_full(file->fd, data, size, file->hdr.used_size) < 0)
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainenlog_get_hdr_update_buffer(struct mail_index_transaction *t)
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen memset(&u, 0, sizeof(u));
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen buf = buffer_create_dynamic(pool_datastack_create(), 256, (size_t)-1);
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen for (offset = 0; offset <= sizeof(t->hdr_change); offset++) {
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen if (offset < sizeof(t->hdr_change) && t->hdr_mask[offset]) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainenint mail_transaction_log_append(struct mail_index_transaction *t,
8bb360f9e5de1c25e4f875205bb06e8bf15dae14Timo Sirainen if (t->updates == NULL && t->cache_updates == NULL &&
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen t->expunges == NULL && t->appends == NULL && !t->hdr_changed) {
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen /* nothing to append */
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (log->head->hdr.used_size > MAIL_TRANSACTION_LOG_ROTATE_SIZE &&
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen ioloop_time - MAIL_TRANSACTION_LOG_ROTATE_MIN_TIME) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen /* we might want to rotate, but check first that head file
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen sequence matches the one in index header, ie. we have
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen everything synced in index. */
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen unsigned int lock_id;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (mail_index_lock_shared(log->index, TRUE, &lock_id) == 0) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (mail_transaction_log_rotate(log, F_WRLCK) < 0) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen /* that didn't work. well, try to continue
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (mail_transaction_log_fix_appends(log, t) < 0) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen (void)mail_transaction_log_file_lock(file, F_UNLCK);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen ret = log_append_buffer(file, t->cache_updates,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen ret = log_append_buffer(file, log_get_hdr_update_buffer(t),
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen /* rewrite used_size */
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen offset = offsetof(struct mail_transaction_log_header,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen ret = pwrite_full(file->fd, &file->hdr.used_size,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (ret == 0 && (t->updates != NULL || t->appends != NULL) &&
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_index_view_add_synced_transaction(view, file->hdr.file_seq,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen mail_index_file_set_syscall_error(log->index, file->filepath,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen /* we don't know how much of it got written,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen it may be corrupted now.. */
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen mail_index_file_set_syscall_error(log->index, file->filepath,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen (void)mail_transaction_log_file_lock(file, F_UNLCK);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainenint mail_transaction_log_sync_lock(struct mail_transaction_log *log,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainenvoid mail_transaction_log_sync_unlock(struct mail_transaction_log *log)
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen (void)mail_transaction_log_file_lock(log->head, F_UNLCK);