mail-transaction-log-append.c revision 8562da433e7659ce8ad6044ff5d8f44869c8cb73
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen/* Copyright (c) 2003-2009 Dovecot authors, see the included COPYING file */
bdb026e2dc8a7c77585ed5ba489f0056df8074d4Timo Sirainenstatic void log_append_buffer(struct log_append_context *ctx,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_assert((type & MAIL_TRANSACTION_TYPE_MASK) != 0);
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen i_assert(hdr_buf == NULL || (hdr_buf->used % 4) == 0);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if ((ctx->trans->flags & MAIL_INDEX_TRANSACTION_FLAG_EXTERNAL) != 0)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen buffer_append(ctx->output, &hdr, sizeof(hdr));
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen buffer_append(ctx->output, hdr_buf->data, hdr_buf->used);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen buffer_append(ctx->output, buf->data, buf->used);
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen if (mail_transaction_header_has_modseq(buf->data,
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen CONST_PTR_OFFSET(buf->data, sizeof(hdr)), ctx->modseq))
d92f33f13830ba23d814342bf3ea8db721a15bb1Timo Sirainen /* update the size */
d92f33f13830ba23d814342bf3ea8db721a15bb1Timo Sirainen hdr_size = mail_index_uint32_to_offset(hdr.size);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (!MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(ctx->file) &&
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* size will be written later once everything
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen is in disk */
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen buffer_write(ctx->output, hdr_pos, &hdr, sizeof(hdr));
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainenstatic int log_buffer_move_to_memory(struct log_append_context *ctx)
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen struct mail_transaction_log_file *file = ctx->file;
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen /* first we need to truncate this latest write so that log syncing
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen doesn't break */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (ftruncate(file->fd, file->sync_offset) < 0) {
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
0b25846ba794ce19536a24d4065beaf2a0bd9464Timo Sirainen "ftruncate()");
8854395cdd21ca521b37ce669f3acb8445792b20Timo Sirainen if (mail_index_move_to_memory(file->log->index) < 0)
8854395cdd21ca521b37ce669f3acb8445792b20Timo Sirainen i_assert(MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file));
8854395cdd21ca521b37ce669f3acb8445792b20Timo Sirainen i_assert(file->buffer_offset + file->buffer->used ==
8854395cdd21ca521b37ce669f3acb8445792b20Timo Sirainen buffer_append_buf(file->buffer, ctx->output, 0, (size_t)-1);
8854395cdd21ca521b37ce669f3acb8445792b20Timo Sirainen buffer_write(file->buffer, file->sync_offset - file->buffer_offset,
58a89627905e3590381cdd5eb931b9537c4b4ea6Timo 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;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file)) {
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen buffer_append_buf(file->buffer, ctx->output, 0, (size_t)-1);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen file->sync_offset = file->buffer_offset + file->buffer->used;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (pwrite_full(file->fd, ctx->output->data, ctx->output->used,
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen /* write failure, fallback to in-memory indexes. */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen "pwrite_full()");
5694eeb99b69dea8033ca77ad69743c6b4871370Timo 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,
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen "pwrite_full()");
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen if ((want_fsync && !file->log->index->fsync_disable) ||
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
8ca217bf3aa23c7922d0d4aa44fcd2320416d61cMartti Rannanjärvi "fdatasync()");
4654cf737f538f5de032b8c9908913f121917366Timo 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.
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen if it crashes before doing that, we'll need to overwrite it with
4d84348ffcbb60de566108562c95ad64629e7a53Timo Sirainen a dummy record */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenlog_get_hdr_update_buffer(struct mail_index_transaction *t, bool prepend)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen memset(&u, 0, sizeof(u));
f8a67af9b7bde79c186e6b82ea200d7fcf85571bTimo Sirainen data = prepend ? t->pre_hdr_change : t->post_hdr_change;
9f46aa48a9982567a37bb08dd95af8bee5100c7eTimo Sirainen mask = prepend ? t->pre_hdr_mask : t->post_hdr_mask;
eb1572d7c44ebc7b0b039d085c3dbab2ef7043ddTimo Sirainen buf = buffer_create_dynamic(pool_datastack_create(), 256);
ed354926406e28254b581f821bb052f38d9c14e8Timo Sirainen for (offset = 0; offset <= sizeof(t->pre_hdr_change); offset++) {
9f46aa48a9982567a37bb08dd95af8bee5100c7eTimo Sirainen if (offset < sizeof(t->pre_hdr_change) && mask[offset]) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenext_reset_update_atomic(struct mail_index_transaction *t,
4645cc6c911a95991d7af43b40f88e99506ea5e9Timo Sirainen if (!mail_index_map_get_ext_idx(t->view->index->map, ext_id, &idx)) {
d3e5a14ea363264dcc7640ca7226249d0c27a793Timo Sirainen /* new extension */
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen map_ext = array_idx(&t->view->index->map->extensions, idx);
d3e5a14ea363264dcc7640ca7226249d0c27a793Timo Sirainen /* ignore this extension update */
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen array_idx_set(&t->ext_reset_ids, ext_id, &reset_id);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* reseting existing data is optional */
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen reset = array_idx_modifiable(&t->ext_resets, ext_id);
4366a21968093172d9b757fe6894b1ee8916434eTimo Sirainentransaction_update_atomic_reset_ids(struct mail_index_transaction *t)
77b5fd56e5a06d624f3ab92198272287333114f4Timo Sirainen expected_reset_ids = array_get(&t->ext_reset_atomic, &count);
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainenstatic void log_append_ext_intro(struct log_append_context *ctx,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct mail_index_transaction *t = ctx->trans;
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen unsigned int count;
b5c6ce2ab8dc1a5817e8adc989d21a9f603a6673Aki Tuomi !mail_index_map_get_ext_idx(t->view->map, ext_id, &idx)) {
b5c6ce2ab8dc1a5817e8adc989d21a9f603a6673Aki Tuomi /* new extension */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen rext = array_idx(&t->view->index->extensions, ext_id);
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;