bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2003-2018 Dovecot authors, see the included COPYING file */
a102d189881a35d72ac3106a9e7e00577ae69310Aki Tuomistatic ARRAY(hook_mail_index_transaction_created_t *)
a102d189881a35d72ac3106a9e7e00577ae69310Aki Tuomivoid mail_index_transaction_hook_register(hook_mail_index_transaction_created_t *hook)
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomi if (!array_is_created(&hook_mail_index_transaction_created))
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomi i_array_init(&hook_mail_index_transaction_created, 8);
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomi array_append(&hook_mail_index_transaction_created, &hook, 1);
a102d189881a35d72ac3106a9e7e00577ae69310Aki Tuomivoid mail_index_transaction_hook_unregister(hook_mail_index_transaction_created_t *hook)
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomi i_assert(array_is_created(&hook_mail_index_transaction_created));
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomi for(idx = 0; idx < array_count(&hook_mail_index_transaction_created); idx++) {
a102d189881a35d72ac3106a9e7e00577ae69310Aki Tuomi hook_mail_index_transaction_created_t *const *hook_ptr =
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomi array_idx(&hook_mail_index_transaction_created, idx);
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomi array_delete(&hook_mail_index_transaction_created, idx, 1);
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomi if (array_count(&hook_mail_index_transaction_created) == 0)
2674b4f0cf8f3c203d8e56b29735f5e267038dafTimo Sirainenmail_index_transaction_get_view(struct mail_index_transaction *t)
e376693bfa3985232c41df99c7010fca22612c89Timo Sirainenbool mail_index_transaction_is_expunged(struct mail_index_transaction *t,
09c3a491f4f6ccebe290c7709bdc0d79a187610bTimo Sirainenvoid mail_index_transaction_ref(struct mail_index_transaction *t)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainenvoid mail_index_transaction_unref(struct mail_index_transaction **_t)
ef4d0eafab4d26bba047551db1e23ceff8aa9404Timo Sirainen DLLIST_REMOVE(&t->view->transactions_list, t);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainenuint32_t mail_index_transaction_get_next_uid(struct mail_index_transaction *t)
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen const struct mail_index_header *head_hdr, *hdr;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen next_uid = t->reset || head_hdr->uid_validity != hdr->uid_validity ?
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if (array_is_created(&t->appends) && t->highest_append_uid != 0) {
d1baa8c6f97cdb1b3c2c44a73cc21f9dfc7a963fTimo Sirainen /* get next_uid from appends if they have UIDs. it's possible
d1baa8c6f97cdb1b3c2c44a73cc21f9dfc7a963fTimo Sirainen that some appends have too low UIDs, they'll be caught
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen /* see if it's been updated in pre/post header changes */
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen offset = offsetof(struct mail_index_header, next_uid);
515f81466f673c1b4f72e053f1a9686e6fca6b61Timo Sirainenvoid mail_index_transaction_lookup_latest_keywords(struct mail_index_transaction *t,
4253a4a66323bc5ff1103af7d7f77fe7c78b9b2bTimo Sirainen /* seq points to the transaction's primary view */
4253a4a66323bc5ff1103af7d7f77fe7c78b9b2bTimo Sirainen /* get the latest keywords from the updated index, or fallback to the
4253a4a66323bc5ff1103af7d7f77fe7c78b9b2bTimo Sirainen primary view if the message is already expunged */
515f81466f673c1b4f72e053f1a9686e6fca6b61Timo Sirainen t->latest_view = mail_index_view_open(t->view->index);
93d08c32afb545ba32e9a1d973b34756c4b01983Timo Sirainen if (mail_index_lookup_seq(t->latest_view, uid, &latest_seq))
93d08c32afb545ba32e9a1d973b34756c4b01983Timo Sirainen mail_index_lookup_keywords(t->latest_view, latest_seq, keywords);
4253a4a66323bc5ff1103af7d7f77fe7c78b9b2bTimo Sirainen mail_index_lookup_keywords(t->view, seq, keywords);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainenmail_transaction_log_file_refresh(struct mail_index_transaction *t,
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen /* Reset the whole index, preserving only indexid. Begin by
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen rotating the log. We don't care if we skip some non-synced
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen transactions. */
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if (mail_transaction_log_rotate(t->view->index->log, TRUE) < 0)
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen /* we only wanted to reset */
5e88e4624aa6d482b5b195acd2f4e02aeb385f20Timo Sirainen /* make sure we have everything mapped */
5e88e4624aa6d482b5b195acd2f4e02aeb385f20Timo Sirainen if (mail_index_map(t->view->index, MAIL_INDEX_SYNC_HANDLER_HEAD) <= 0)
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen i_assert(file->sync_offset >= file->buffer_offset);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen ctx->new_highest_modseq = file->sync_highest_modseq;
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainenmail_index_transaction_commit_real(struct mail_index_transaction *t,
6a0855a04d75bce3c0a2f68517d02f86ae72087fTimo Sirainen enum mail_index_transaction_change *changes_r)
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen struct mail_transaction_log *log = t->view->index->log;
e169102fb38ce788b76c2a344bee7d77079dea05Timo Sirainen if ((t->flags & MAIL_INDEX_TRANSACTION_FLAG_EXTERNAL) != 0)
e169102fb38ce788b76c2a344bee7d77079dea05Timo Sirainen if ((t->flags & MAIL_INDEX_TRANSACTION_FLAG_SYNC) != 0)
e169102fb38ce788b76c2a344bee7d77079dea05Timo Sirainen if (mail_transaction_log_append_begin(log->index, trans_flags, &ctx) < 0)
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen ret = mail_transaction_log_file_refresh(t, ctx);
6a0855a04d75bce3c0a2f68517d02f86ae72087fTimo Sirainen mail_index_transaction_export(t, ctx, changes_r);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mail_transaction_log_get_head(log, &log_seq1, &log_offset1);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if (mail_transaction_log_append_commit(&ctx) < 0 || ret < 0)
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mail_transaction_log_get_head(log, &log_seq2, &log_offset2);
9e6d83a3ef6abb393eeebca423cfd0d8cb08d430Timo Sirainen i_assert(expected_highest_modseq == log->head->sync_highest_modseq);
3b426f49d36187895debdda67fff09f97941881cTimo Sirainen /* get rid of the old index. it might just confuse readers,
3b426f49d36187895debdda67fff09f97941881cTimo Sirainen especially if it's broken. */
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if ((t->flags & MAIL_INDEX_TRANSACTION_FLAG_HIDE) != 0 &&
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen /* mark the area covered by this transaction hidden */
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mail_index_view_add_hidden_transaction(t->view, log_seq1,
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainenstatic int mail_index_transaction_commit_v(struct mail_index_transaction *t,
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen struct mail_index_transaction_commit_result *result_r)
61ddcdc28f50d9cb9994fcc4ad63f9dff0e80628Timo Sirainen changed = MAIL_INDEX_TRANSACTION_HAS_CHANGES(t) || t->reset;
6a0855a04d75bce3c0a2f68517d02f86ae72087fTimo Sirainen mail_index_transaction_commit_real(t, &result_r->commit_size,
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen mail_transaction_log_get_head(index->log, &result_r->log_file_seq,
5d1833b98fa85d8061626aa986f38dcbcd70553eTimo Sirainen /* if we're committing a normal transaction, we want to
5d1833b98fa85d8061626aa986f38dcbcd70553eTimo Sirainen have those changes in the index mapping immediately. this
5d1833b98fa85d8061626aa986f38dcbcd70553eTimo Sirainen is especially important when committing cache offset
5d1833b98fa85d8061626aa986f38dcbcd70553eTimo Sirainen however if we're syncing the index now, the mapping must
5d1833b98fa85d8061626aa986f38dcbcd70553eTimo Sirainen be done later as MAIL_INDEX_SYNC_HANDLER_FILE so that
5d1833b98fa85d8061626aa986f38dcbcd70553eTimo Sirainen expunge handlers get run for the newly expunged messages
5d1833b98fa85d8061626aa986f38dcbcd70553eTimo Sirainen (and sync handlers that require HANDLER_FILE as well). */
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainenstatic void mail_index_transaction_rollback_v(struct mail_index_transaction *t)
9404a7b90dcb80d31bd37ee2493f03751acdb1bdTimo Sirainenint mail_index_transaction_commit(struct mail_index_transaction **t)
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen struct mail_index_transaction_commit_result result;
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen return mail_index_transaction_commit_full(t, &result);
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainenint mail_index_transaction_commit_full(struct mail_index_transaction **_t,
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen struct mail_index_transaction_commit_result *result_r)
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen if (mail_index_view_is_inconsistent(t->view)) {
491178793199e62320f7bc6292e7b8fd843ae5bcTimo Sirainen if (!index_undeleted && !t->commit_deleted_index) {
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen /* no further changes allowed */
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainenvoid mail_index_transaction_rollback(struct mail_index_transaction **_t)
ab0d9eecd85f74acae18fe88529302e0776cc500Timo Sirainenstatic struct mail_index_transaction_vfuncs trans_vfuncs = {
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainenmail_index_transaction_begin(struct mail_index_view *view,
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen /* don't allow syncing view while there's ongoing transactions */
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen /* transaction view cannot work if new records are being added
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen in two places. make sure it doesn't happen. */
439942f89a77180719644e7af3752a8329259eb9Timo Sirainen mail_index_view_get_messages_count(t->view) + 1;
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomi if (array_is_created(&hook_mail_index_transaction_created)) {
26e5bdf37d7d0deed1e2e8483366c83631b9d251Aki Tuomi hook_build_init((void *)&t->v, sizeof(t->v));
a102d189881a35d72ac3106a9e7e00577ae69310Aki Tuomi hook_mail_index_transaction_created_t *const *ptr;