mail-transaction-log-append.c revision 61cfcb75224b54bf20e864e85e1a343c72a84066
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen/* Copyright (c) 2003-2009 Dovecot authors, see the included COPYING file */
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainenstatic void log_append_buffer(struct log_append_context *ctx,
a91bd6256b33729531c33ff8bc66ee1ae95840f9Timo Sirainen i_assert((type & MAIL_TRANSACTION_TYPE_MASK) != 0);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_assert(hdr_buf == NULL || (hdr_buf->used % 4) == 0);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if ((ctx->trans->flags & MAIL_INDEX_TRANSACTION_FLAG_EXTERNAL) != 0)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen buffer_append(ctx->output, &hdr, sizeof(hdr));
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen buffer_append(ctx->output, hdr_buf->data, hdr_buf->used);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen buffer_append(ctx->output, buf->data, buf->used);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (mail_transaction_header_has_modseq(buf->data,
c040ee67d0ac0fb7375bb543965bf67dcae6affaTimo Sirainen CONST_PTR_OFFSET(buf->data, sizeof(hdr)), ctx->modseq))
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* update the size */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen hdr_size = mail_index_uint32_to_offset(hdr.size);
d92f33f13830ba23d814342bf3ea8db721a15bb1Timo Sirainen if (!MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(ctx->file) &&
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* size will be written later once everything
61e84692827b6a64912343f515c984853021483aTimo Sirainen is in disk */
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen buffer_write(ctx->output, hdr_pos, &hdr, sizeof(hdr));
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainenstatic int log_buffer_move_to_memory(struct log_append_context *ctx)
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen struct mail_transaction_log_file *file = ctx->file;
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen /* first we need to truncate this latest write so that log syncing
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen doesn't break */
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen if (ftruncate(file->fd, file->sync_offset) < 0) {
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen "ftruncate()");
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen if (mail_index_move_to_memory(file->log->index) < 0)
0b25846ba794ce19536a24d4065beaf2a0bd9464Timo Sirainen i_assert(MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file));
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen i_assert(file->buffer_offset + file->buffer->used ==
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen buffer_append_buf(file->buffer, ctx->output, 0, (size_t)-1);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen buffer_write(file->buffer, file->sync_offset - file->buffer_offset,
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen file->sync_offset = file->buffer_offset + file->buffer->used;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainenstatic int log_buffer_write(struct log_append_context *ctx, bool want_fsync)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen struct mail_transaction_log_file *file = ctx->file;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file)) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen buffer_append_buf(file->buffer, ctx->output, 0, (size_t)-1);
bbd0a870f8639767e4e4011d2aedadac08d5c66fTimo Sirainen file->sync_offset = file->buffer_offset + file->buffer->used;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (pwrite_full(file->fd, ctx->output->data, ctx->output->used,
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen /* write failure, fallback to in-memory indexes. */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen "pwrite_full()");
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen /* now that the whole transaction has been written, rewrite the first
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen record's size so the transaction becomes visible */
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen if (pwrite_full(file->fd, &ctx->first_append_size,
3fe67ec75ccae1230bb9eb9f16affc48377f6441Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen "pwrite_full()");
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen if ((want_fsync && !file->log->index->fsync_disable) ||
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
9f46aa48a9982567a37bb08dd95af8bee5100c7eTimo Sirainen "fdatasync()");
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* FIXME: when we're relying on O_APPEND and someone else wrote a
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen transaction, we'll need to wait for it to commit its transaction.
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if it crashes before doing that, we'll need to overwrite it with
9f46aa48a9982567a37bb08dd95af8bee5100c7eTimo Sirainen a dummy record */
4366a21968093172d9b757fe6894b1ee8916434eTimo Sirainenlog_get_hdr_update_buffer(struct mail_index_transaction *t, bool prepend)
4366a21968093172d9b757fe6894b1ee8916434eTimo Sirainen memset(&u, 0, sizeof(u));
4366a21968093172d9b757fe6894b1ee8916434eTimo Sirainen data = prepend ? t->pre_hdr_change : t->post_hdr_change;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mask = prepend ? t->pre_hdr_mask : t->post_hdr_mask;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen buf = buffer_create_dynamic(pool_datastack_create(), 256);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen for (offset = 0; offset <= sizeof(t->pre_hdr_change); offset++) {
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen if (offset < sizeof(t->pre_hdr_change) && mask[offset]) {
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainenext_reset_update_atomic(struct mail_index_transaction *t,
4366a21968093172d9b757fe6894b1ee8916434eTimo Sirainen if (!mail_index_map_get_ext_idx(t->view->index->map, ext_id, &idx)) {
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen /* new extension */
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen map_ext = array_idx(&t->view->index->map->extensions, idx);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* ignore this extension update */
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen array_idx_set(&t->ext_reset_ids, ext_id, &reset_id);
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen /* reseting existing data is optional */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen reset = array_idx_modifiable(&t->ext_resets, ext_id);
unsigned int count;
if (t->reset ||
count = 0;
if (reset_id != 0) {
struct mail_transaction_ext_hdr_update u;
memset(&u, 0, sizeof(u));
if (!started) {
if (started) {
update_count = 0;
resize_count = 0;
reset_id_count = 0;
reset_count = 0;
hdrs_count = 0;
T_BEGIN {
} T_END;
count = 0;
reset_id_count = 0;
static enum mail_index_sync_type
const char *const *keywords;
for (i = 0; i < count; i++) {
return change_mask;
struct mail_transaction_header_update *u;
sizeof(struct mail_transaction_header) +
sizeof(*u) + sizeof(offset);
sizeof(*u) + sizeof(offset));
#define TRANSACTION_HAS_CHANGES(t) \
bool want_fsync;
if (t->reset) {
if (!TRANSACTION_HAS_CHANGES(t)) {
MAIL_INDEX_SYNC_HANDLER_HEAD) <= 0)
if (t->max_modseq != 0)
if (!TRANSACTION_HAS_CHANGES(t)) {
if (t->pre_hdr_changed) {
if (t->post_hdr_changed) {
int ret;
*log_file_seq_r = 0;
*log_file_offset_r = 0;
return ret;