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