mail-transaction-log-append.c revision e169102fb38ce788b76c2a344bee7d77079dea05
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2003-2012 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));
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen mail_transaction_update_modseq(&hdr, data, &ctx->new_highest_modseq);
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()");
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen file->log->index->fsync_mode != FSYNC_MODE_NEVER) ||
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen file->log->index->fsync_mode == FSYNC_MODE_ALWAYS) {
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 */
d6370c8138546e27119c6da3d482b7ea7c0b2289Timo Sirainen if (file->mmap_base == NULL && file->buffer != NULL) {
d8a786d2069fab818d0b62cd3eaa3ed08fe7c620Timo Sirainen /* we're reading from a file. avoid re-reading the data that
d8a786d2069fab818d0b62cd3eaa3ed08fe7c620Timo Sirainen we just wrote. this is also important for some NFS clients,
d8a786d2069fab818d0b62cd3eaa3ed08fe7c620Timo Sirainen which for some reason sometimes can't read() this data we
d8a786d2069fab818d0b62cd3eaa3ed08fe7c620Timo Sirainen just wrote in the same process */
d8a786d2069fab818d0b62cd3eaa3ed08fe7c620Timo Sirainen buffer_append(file->buffer, ctx->output->data,
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;
02752bc8d64df8cd361f464e55422f7b3f2f143eTimo Sirainen unsigned char update_data[sizeof(*u) + sizeof(offset)];
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if (file->max_tail_offset == file->sync_offset) {
8f430e257605b2fd2b54cdf4c2a20ef8b53cf0baTimo Sirainen file->saved_tail_offset == file->max_tail_offset) {
8f430e257605b2fd2b54cdf4c2a20ef8b53cf0baTimo Sirainen /* nothing to write here after all (e.g. all unchanged
8f430e257605b2fd2b54cdf4c2a20ef8b53cf0baTimo Sirainen flag updates were dropped by export) */
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 */
02752bc8d64df8cd361f464e55422f7b3f2f143eTimo Sirainen buffer_create_data(&buf, update_data, sizeof(update_data));
02752bc8d64df8cd361f464e55422f7b3f2f143eTimo 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;
e169102fb38ce788b76c2a344bee7d77079dea05Timo Sirainenint mail_transaction_log_append_begin(struct mail_index *index,
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);