bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2003-2018 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));
92dab926b2f2270057b40a907a00cf8eb2309ed6Timo Sirainen mail_transaction_update_modseq(&hdr, data, &ctx->new_highest_modseq,
92dab926b2f2270057b40a907a00cf8eb2309ed6Timo Sirainen MAIL_TRANSACTION_LOG_HDR_VERSION(&ctx->log->head->hdr));
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;
bd503f12eb667df389a99162f567bd8785798f55Timo Sirainen if (write_full(file->fd, ctx->output->data, ctx->output->used) < 0) {
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen /* write failure, fallback to in-memory indexes. */
ab11c996ff754af701b03c63db20e434469064e0Timo Sirainen mail_index_file_set_syscall_error(ctx->log->index,
bd503f12eb667df389a99162f567bd8785798f55Timo Sirainen "write_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()");
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)];
082e82792b8ac33ad42beac510441b37a3c50737Timo Sirainen /* this is a non-syncing transaction. update the tail offset
082e82792b8ac33ad42beac510441b37a3c50737Timo Sirainen only if we're already writing something else to transaction
082e82792b8ac33ad42beac510441b37a3c50737Timo Sirainen log anyway. */
082e82792b8ac33ad42beac510441b37a3c50737Timo Sirainen /* FIXME: For now we never do this update, because it would
082e82792b8ac33ad42beac510441b37a3c50737Timo Sirainen cause errors about shrinking tail offsets with old Dovecot
082e82792b8ac33ad42beac510441b37a3c50737Timo Sirainen versions. This is anyway just an optimization, so it doesn't
082e82792b8ac33ad42beac510441b37a3c50737Timo Sirainen matter all that much if we don't do it here. Finish this
082e82792b8ac33ad42beac510441b37a3c50737Timo Sirainen /*if (ctx->output->used == 0)*/
082e82792b8ac33ad42beac510441b37a3c50737Timo Sirainen } else if (file->max_tail_offset == file->sync_offset) {
082e82792b8ac33ad42beac510441b37a3c50737Timo Sirainen /* we're synced all the way to tail offset, so this sync
082e82792b8ac33ad42beac510441b37a3c50737Timo Sirainen transaction can also be included in the same tail offset. */
082e82792b8ac33ad42beac510441b37a3c50737Timo Sirainen if (ctx->output->used == 0 && !ctx->tail_offset_changed) {
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 */
082e82792b8ac33ad42beac510441b37a3c50737Timo Sirainen /* This is a syncing transaction. Since we're finishing a sync,
082e82792b8ac33ad42beac510441b37a3c50737Timo Sirainen we may need to update the tail offset even if we don't have
082e82792b8ac33ad42beac510441b37a3c50737Timo Sirainen anything else to do. */
3281669db44d09a087a203201248abbc81b3cc1aTimo Sirainen buffer_create_from_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,
bd503f12eb667df389a99162f567bd8785798f55Timo Sirainen /* don't include log_file_tail_offset update in the transaction */
bd503f12eb667df389a99162f567bd8785798f55Timo Sirainen boundary = buffer_get_space_unsafe(ctx->output,
bd503f12eb667df389a99162f567bd8785798f55Timo Sirainen /* 0-1 changes. don't bother with the boundary */
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)
6ded8819b9002150a95a7615e4f64f091c250464Timo Sirainen if (mail_transaction_log_lock_head(index->log, "appending") < 0)
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen ctx = i_new(struct mail_transaction_log_append_ctx, 1);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen ctx->output = buffer_create_dynamic(default_pool, 1024);
bd503f12eb667df389a99162f567bd8785798f55Timo Sirainen mail_transaction_log_append_add(ctx, MAIL_TRANSACTION_BOUNDARY,
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);