mail-transaction-log-append.c revision 5e96e0a8a59aa5d3e2d38a21a211335a023fbbc8
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (C) 2003-2004 Timo Sirainen */
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainenstatic void log_append_buffer(struct log_append_context *ctx,
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen i_assert((type & MAIL_TRANSACTION_TYPE_MASK) != 0);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen i_assert(hdr_buf == NULL || (hdr_buf->used % 4) == 0);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen hdr_size = mail_index_uint32_to_offset(sizeof(hdr) + buf->used +
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if (!MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(ctx->file) &&
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen /* size will be written later once everything
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen is in disk */
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen buffer_append(ctx->output, &hdr, sizeof(hdr));
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen buffer_append(ctx->output, hdr_buf->data, hdr_buf->used);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen buffer_append(ctx->output, buf->data, buf->used);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainenstatic int log_buffer_move_to_memory(struct log_append_context *ctx)
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen struct mail_transaction_log_file *file = ctx->file;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen /* first we need to truncate this latest write so that log syncing
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen doesn't break */
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if (ftruncate(file->fd, file->sync_offset) < 0) {
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen "ftruncate()");
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if (mail_index_move_to_memory(file->log->index) < 0)
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen i_assert(MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file));
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen i_assert(file->buffer_offset + file->buffer->used ==
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen buffer_append_buf(file->buffer, ctx->output, 0, (size_t)-1);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen file->sync_offset = file->buffer_offset + file->buffer->used;
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainenstatic int log_buffer_write(struct log_append_context *ctx)
54b51a9c2705a19dfb1639647bc7e9378e37f881Timo Sirainen struct mail_transaction_log_file *file = ctx->file;
54b51a9c2705a19dfb1639647bc7e9378e37f881Timo Sirainen if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file)) {
54b51a9c2705a19dfb1639647bc7e9378e37f881Timo Sirainen buffer_append_buf(file->buffer, ctx->output, 0, (size_t)-1);
54b51a9c2705a19dfb1639647bc7e9378e37f881Timo Sirainen file->sync_offset = file->buffer_offset + file->buffer->used;
54b51a9c2705a19dfb1639647bc7e9378e37f881Timo Sirainen if (pwrite_full(file->fd, ctx->output->data, ctx->output->used,
54b51a9c2705a19dfb1639647bc7e9378e37f881Timo Sirainen /* write failure, fallback to in-memory indexes. */
54b51a9c2705a19dfb1639647bc7e9378e37f881Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
54b51a9c2705a19dfb1639647bc7e9378e37f881Timo Sirainen "pwrite_full()");
54b51a9c2705a19dfb1639647bc7e9378e37f881Timo Sirainen if (!file->log->index->fsync_disable && fdatasync(file->fd) < 0) {
54b51a9c2705a19dfb1639647bc7e9378e37f881Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
54b51a9c2705a19dfb1639647bc7e9378e37f881Timo Sirainen /* now that the whole transaction has been written, rewrite the first
54b51a9c2705a19dfb1639647bc7e9378e37f881Timo Sirainen record's size so the transaction becomes visible */
54b51a9c2705a19dfb1639647bc7e9378e37f881Timo Sirainen if (pwrite_full(file->fd, &ctx->first_append_size,
eab880d75fd73a80c7803289796d13e08e4b52cbTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
54b51a9c2705a19dfb1639647bc7e9378e37f881Timo Sirainen "pwrite_full()");
54b51a9c2705a19dfb1639647bc7e9378e37f881Timo Sirainen /* FIXME: when we're relying on O_APPEND and someone else wrote a
54b51a9c2705a19dfb1639647bc7e9378e37f881Timo Sirainen transaction, we'll need to wait for it to commit its transaction.
54b51a9c2705a19dfb1639647bc7e9378e37f881Timo Sirainen if it crashes before doing that, we'll need to overwrite it with
54b51a9c2705a19dfb1639647bc7e9378e37f881Timo Sirainen a dummy record */
54b51a9c2705a19dfb1639647bc7e9378e37f881Timo Sirainenlog_get_hdr_update_buffer(struct mail_index_transaction *t, bool prepend)
54b51a9c2705a19dfb1639647bc7e9378e37f881Timo Sirainen memset(&u, 0, sizeof(u));
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen data = prepend ? t->pre_hdr_change : t->post_hdr_change;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mask = prepend ? t->pre_hdr_mask : t->post_hdr_mask;
02bb8313a711dfe50c7f01e8132e13ca93ecfb42Timo Sirainen buf = buffer_create_dynamic(pool_datastack_create(), 256);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen for (offset = 0; offset <= sizeof(t->pre_hdr_change); offset++) {
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if (offset < sizeof(t->pre_hdr_change) && mask[offset]) {
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainenstatic void log_append_ext_intro(struct log_append_context *ctx,
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen struct mail_index_transaction *t = ctx->trans;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen unsigned int count;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen !mail_index_map_get_ext_idx(t->view->map, ext_id, &idx)) {
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen /* new extension */
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen rext = array_idx(&t->view->index->extensions, ext_id);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen intro = array_get_modifiable(&t->ext_resizes, &count);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen buf = buffer_create_dynamic(pool_datastack_create(), 128);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if (ext_id < count && intro[ext_id].name_size != 0) {
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen /* we're resizing it */
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen /* generate a new intro structure */
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen intro = buffer_append_space_unsafe(buf, sizeof(*intro));
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen /* we're going to reset this extension in this transaction */
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen /* use the existing reset_id */
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen /* new extension, reset_id defaults to 0 */
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen buffer_append(buf, rext->name, intro->name_size);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen log_append_buffer(ctx, buf, NULL, MAIL_TRANSACTION_EXT_INTRO);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainenlog_append_ext_hdr_update(struct log_append_context *ctx,
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen struct mail_index_transaction_ext_hdr_update *hdr)
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen struct mail_transaction_ext_hdr_update *trans_hdr;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen buf = buffer_create_static_hard(pool_datastack_create(), hdr_size);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen trans_hdr = buffer_append_space_unsafe(buf, sizeof(*trans_hdr));
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen log_append_buffer(ctx, buf, NULL, MAIL_TRANSACTION_EXT_HDR_UPDATE);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainenmail_transaction_log_append_ext_intros(struct log_append_context *ctx)
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen struct mail_index_transaction *t = ctx->trans;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen const struct mail_transaction_ext_intro *resize;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen struct mail_index_transaction_ext_hdr_update *const *hdrs;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen unsigned int update_count, resize_count, ext_count = 0;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen unsigned int hdrs_count, reset_id_count, reset_count;
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen update = array_get(&t->ext_rec_updates, &update_count);
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen resize = array_get(&t->ext_resizes, &resize_count);
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen reset_ids = array_get(&t->ext_reset_ids, &reset_id_count);
3a017aa592823edf0363d77f13458d569637915eTimo Sirainen reset = array_get(&t->ext_resets, &reset_count);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen hdrs = array_get(&t->ext_hdr_updates, &hdrs_count);
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen buf = buffer_create_data(pool_datastack_create(),
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen for (ext_id = 0; ext_id < ext_count; ext_id++) {
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen if ((ext_id < resize_count && resize[ext_id].name_size) ||
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen (ext_id < hdrs_count && hdrs[ext_id] != NULL)) {
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if (ext_id < hdrs_count && hdrs[ext_id] != NULL)
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainenstatic void log_append_ext_rec_updates(struct log_append_context *ctx)
4b89231f4ec9cc69f4aea715e1d34f405c7e317dTimo Sirainen struct mail_index_transaction *t = ctx->trans;
count = 0;
reset_id_count = 0;
const char *const *keywords;
for (i = 0; i < count; i++) {
struct mail_transaction_header_update *u;
sizeof(struct mail_transaction_header) +
sizeof(*u) + sizeof(offset);
sizeof(*u) + sizeof(offset));
if (t->reset) {
if (t->pre_hdr_changed) {
if (t->post_hdr_changed) {
if (t->external)
if (t->hide_transaction) {
int ret;
if (!t->log_updates) {
*log_file_seq_r = 0;
*log_file_offset_r = 0;
return ret;