mail-transaction-log-append.c revision 40a5aeebf6b4858b93f0ddff0bf12fba769cf903
45312f52ff3a3d4c137447be4c7556500c2f8bf2Timo Sirainen/* Copyright (c) 2003-2009 Dovecot authors, see the included COPYING file */
45155bb1250cf5a120278f349465aded513a100fTimo Sirainenvoid mail_transaction_log_append_add(struct mail_transaction_log_append_ctx *ctx,
ba90e657bc68a72ab3b3021e2f4a874fac9965baTimo Sirainen i_assert((type & MAIL_TRANSACTION_TYPE_MASK) != 0);
89795c6bbbc52bb382e88bc8617d22092223e9a5Timo Sirainen hdr.size = mail_index_uint32_to_offset(hdr.size);
89795c6bbbc52bb382e88bc8617d22092223e9a5Timo Sirainen buffer_append(ctx->output, &hdr, sizeof(hdr));
89795c6bbbc52bb382e88bc8617d22092223e9a5Timo Sirainenlog_buffer_move_to_memory(struct mail_transaction_log_append_ctx *ctx)
89795c6bbbc52bb382e88bc8617d22092223e9a5Timo Sirainen struct mail_transaction_log_file *file = ctx->log->head;
493123e38ca1f27b07ac30dcbc59663c5fcdcba2Timo Sirainen /* first we need to truncate this latest write so that log syncing
493123e38ca1f27b07ac30dcbc59663c5fcdcba2Timo Sirainen doesn't break */
89795c6bbbc52bb382e88bc8617d22092223e9a5Timo Sirainen if (ftruncate(file->fd, file->sync_offset) < 0) {
89795c6bbbc52bb382e88bc8617d22092223e9a5Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
89795c6bbbc52bb382e88bc8617d22092223e9a5Timo Sirainen "ftruncate()");
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen if (mail_index_move_to_memory(file->log->index) < 0)
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen i_assert(MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file));
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen i_assert(file->buffer_offset + file->buffer->used ==
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen buffer_append_buf(file->buffer, ctx->output, 0, (size_t)-1);
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen file->sync_offset = file->buffer_offset + file->buffer->used;
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainenstatic int log_buffer_write(struct mail_transaction_log_append_ctx *ctx)
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen struct mail_transaction_log_file *file = ctx->log->head;
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file)) {
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen file->buffer = buffer_create_dynamic(default_pool, 4096);
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen buffer_append_buf(file->buffer, ctx->output, 0, (size_t)-1);
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen file->sync_offset = file->buffer_offset + file->buffer->used;
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen /* size will be written later once everything is in disk */
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen hdr = buffer_get_space_unsafe(ctx->output, 0, sizeof(*hdr));
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen if (pwrite_full(file->fd, ctx->output->data, ctx->output->used,
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen /* write failure, fallback to in-memory indexes. */
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen "pwrite_full()");
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen /* now that the whole transaction has been written, rewrite the first
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen record's size so the transaction becomes visible */
53d564c421ca7292d7b1bd945f86894a34b75370Timo Sirainen if (pwrite_full(file->fd, &first_size, sizeof(uint32_t),
53d564c421ca7292d7b1bd945f86894a34b75370Timo Sirainen offsetof(struct mail_transaction_header, size)) < 0) {
53d564c421ca7292d7b1bd945f86894a34b75370Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen "pwrite_full()");
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen if ((ctx->want_fsync && !file->log->index->fsync_disable) ||
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen "fdatasync()");
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen /* FIXME: when we're relying on O_APPEND and someone else wrote a
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen transaction, we'll need to wait for it to commit its transaction.
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen if it crashes before doing that, we'll need to overwrite it with
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen a dummy record */
f30577ff7cf29858f1878abe963b4f40a436434fTimo Sirainenlog_append_sync_offset_if_needed(struct mail_transaction_log_append_ctx *ctx)
ba90e657bc68a72ab3b3021e2f4a874fac9965baTimo Sirainen struct mail_transaction_log_file *file = ctx->log->head;
f30577ff7cf29858f1878abe963b4f40a436434fTimo Sirainen if (file->max_tail_offset == file->sync_offset) {
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen /* FIXME: when we remove exclusive log locking, we
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen can't rely on this. then write non-changed offset + check
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen real offset + rewrite the new offset if other transactions
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen weren't written in the middle */
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen buf = buffer_create_static_hard(pool_datastack_create(),
f30577ff7cf29858f1878abe963b4f40a436434fTimo Sirainen sizeof(*u) + sizeof(offset));
8e50329e2c5e3a199674ae9f6d3dfcddab02487bTimo Sirainen u = buffer_append_space_unsafe(buf, sizeof(*u));
8e50329e2c5e3a199674ae9f6d3dfcddab02487bTimo Sirainen u->offset = offsetof(struct mail_index_header, log_file_tail_offset);
8e50329e2c5e3a199674ae9f6d3dfcddab02487bTimo Sirainen mail_transaction_log_append_add(ctx, MAIL_TRANSACTION_HEADER_UPDATE,
d67848ba944a3172c4834c591ddc921fa4ff16b1Timo Sirainenmail_transaction_log_append_locked(struct mail_transaction_log_append_ctx *ctx)
d67848ba944a3172c4834c591ddc921fa4ff16b1Timo Sirainen struct mail_transaction_log_file *file = ctx->log->head;
d67848ba944a3172c4834c591ddc921fa4ff16b1Timo Sirainen /* there is some garbage at the end of the transaction log
d67848ba944a3172c4834c591ddc921fa4ff16b1Timo Sirainen (eg. previous write failed). remove it so reader doesn't
d67848ba944a3172c4834c591ddc921fa4ff16b1Timo Sirainen break because of it. */
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen if (!MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file)) {
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen if (ftruncate(file->fd, file->sync_offset) < 0) {
1eff76c5dbd2ff14bbb7e40a164c290931bdf692Timo Sirainen mail_index_file_set_syscall_error(ctx->log->index,
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen file->sync_highest_modseq = ctx->new_highest_modseq;
6e8ad595d0603295f57bef576da8a3a00b55c5e2Timo Sirainenint mail_transaction_log_append_begin(struct mail_index *index, bool external,
6e8ad595d0603295f57bef576da8a3a00b55c5e2Timo Sirainen struct mail_transaction_log_append_ctx **ctx_r)
6e8ad595d0603295f57bef576da8a3a00b55c5e2Timo Sirainen if (mail_transaction_log_lock_head(index->log) < 0)
6e8ad595d0603295f57bef576da8a3a00b55c5e2Timo Sirainen ctx = i_new(struct mail_transaction_log_append_ctx, 1);
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen ctx->output = buffer_create_dynamic(default_pool, 1024);
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainenint mail_transaction_log_append_commit(struct mail_transaction_log_append_ctx **_ctx)
6e8ad595d0603295f57bef576da8a3a00b55c5e2Timo Sirainen struct mail_transaction_log_append_ctx *ctx = *_ctx;
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen ret = mail_transaction_log_append_locked(ctx);