diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 09:51:24 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 09:51:24 +0000 |
commit | f7548d6d28c313cf80e6f3ef89aed16a19815df1 (patch) | |
tree | a3f6f2a3f247293bee59ecd28e8cd8ceb6ca064a /src/lib-index/mail-index-transaction-finish.c | |
parent | Initial commit. (diff) | |
download | dovecot-f7548d6d28c313cf80e6f3ef89aed16a19815df1.tar.xz dovecot-f7548d6d28c313cf80e6f3ef89aed16a19815df1.zip |
Adding upstream version 1:2.3.19.1+dfsg1.upstream/1%2.3.19.1+dfsg1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/lib-index/mail-index-transaction-finish.c')
-rw-r--r-- | src/lib-index/mail-index-transaction-finish.c | 350 |
1 files changed, 350 insertions, 0 deletions
diff --git a/src/lib-index/mail-index-transaction-finish.c b/src/lib-index/mail-index-transaction-finish.c new file mode 100644 index 0000000..360e597 --- /dev/null +++ b/src/lib-index/mail-index-transaction-finish.c @@ -0,0 +1,350 @@ +/* Copyright (c) 2003-2018 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "array.h" +#include "ioloop.h" +#include "mail-index-private.h" +#include "mail-index-modseq.h" +#include "mail-index-transaction-private.h" + +int mail_transaction_expunge_guid_cmp(const struct mail_transaction_expunge_guid *e1, + const struct mail_transaction_expunge_guid *e2) +{ + if (e1->uid < e2->uid) + return -1; + else if (e1->uid > e2->uid) + return 1; + else + return 0; +} + +void mail_index_transaction_sort_expunges(struct mail_index_transaction *t) +{ + if (!t->expunges_nonsorted) + return; + + array_sort(&t->expunges, mail_transaction_expunge_guid_cmp); + t->expunges_nonsorted = FALSE; +} + +static void +ext_reset_update_atomic(struct mail_index_transaction *t, + uint32_t ext_id, uint32_t expected_reset_id) +{ + const struct mail_index_ext *map_ext; + struct mail_transaction_ext_reset *reset; + uint32_t idx, reset_id; + + if (!mail_index_map_get_ext_idx(t->view->index->map, ext_id, &idx)) { + /* new extension */ + reset_id = 1; + } else { + map_ext = array_idx(&t->view->index->map->extensions, idx); + reset_id = map_ext->reset_id + 1; + } + if (reset_id != expected_reset_id) { + /* ignore this extension update */ + mail_index_ext_set_reset_id(t, ext_id, 0); + return; + } + + if (reset_id == 0) + reset_id++; + + array_idx_set(&t->ext_reset_ids, ext_id, &reset_id); + + /* reseting existing data is optional */ + if (array_is_created(&t->ext_resets)) { + reset = array_idx_modifiable(&t->ext_resets, ext_id); + if (reset->new_reset_id == (uint32_t)-1) + reset->new_reset_id = reset_id; + } +} + +static void +transaction_update_atomic_reset_ids(struct mail_index_transaction *t) +{ + const uint32_t *expected_reset_ids; + unsigned int ext_id, count; + + if (!array_is_created(&t->ext_reset_atomic)) + return; + + expected_reset_ids = array_get(&t->ext_reset_atomic, &count); + for (ext_id = 0; ext_id < count; ext_id++) { + if (expected_reset_ids[ext_id] != 0) { + ext_reset_update_atomic(t, ext_id, + expected_reset_ids[ext_id]); + } + } +} + +static unsigned int +mail_transaction_drop_range(struct mail_index_transaction *t, + struct mail_index_flag_update update, + unsigned int update_idx, + ARRAY_TYPE(seq_range) *keeps) +{ + const struct seq_range *keep_range; + unsigned int i, keep_count; + + keep_range = array_get(keeps, &keep_count); + if (keep_count == 1 && + update.uid1 == keep_range[0].seq1 && + update.uid2 == keep_range[0].seq2) { + /* everything is kept */ + return update_idx + 1; + } + + array_delete(&t->updates, update_idx, 1); + + /* add back all the updates we want to keep */ + for (i = 0; i < keep_count; i++, update_idx++) { + update.uid1 = keep_range[i].seq1; + update.uid2 = keep_range[i].seq2; + array_insert(&t->updates, update_idx, &update, 1); + } + return update_idx; +} + +static void +mail_index_transaction_finish_flag_updates(struct mail_index_transaction *t) +{ + const struct mail_index_flag_update *updates, *u; + const struct mail_index_record *rec; + unsigned int i, count; + ARRAY_TYPE(seq_range) keeps; + uint32_t seq; + + if (!t->drop_unnecessary_flag_updates || !array_is_created(&t->updates)) + return; + + t_array_init(&keeps, 64); + updates = array_get(&t->updates, &count); + for (i = 0; i < count; ) { + /* first get the list of changes to drop */ + u = &updates[i]; + array_clear(&keeps); + for (seq = u->uid1; seq <= u->uid2; seq++) { + rec = mail_index_lookup(t->view, seq); + if ((rec->flags & u->add_flags) != u->add_flags || + (rec->flags & u->remove_flags) != 0) { + /* keep this change */ + seq_range_array_add(&keeps, seq); + } + } + i = mail_transaction_drop_range(t, updates[i], i, &keeps); + updates = array_get(&t->updates, &count); + } + + if (array_count(&t->updates) == 0) + array_free(&t->updates); +} + +static void +mail_index_transaction_check_conflicts(struct mail_index_transaction *t) +{ + uint32_t seq; + bool ret1, ret2; + + i_assert(t->max_modseq != 0); + i_assert(t->conflict_seqs != NULL); + + if (t->max_modseq == mail_index_modseq_get_highest(t->view)) { + /* no conflicts possible */ + return; + } + if (t->min_flagupdate_seq == 0) { + /* no flag updates */ + return; + } + + for (seq = t->min_flagupdate_seq; seq <= t->max_flagupdate_seq; seq++) { + if (mail_index_modseq_lookup(t->view, seq) > t->max_modseq) { + ret1 = mail_index_cancel_flag_updates(t, seq); + ret2 = mail_index_cancel_keyword_updates(t, seq); + if (ret1 || ret2) { + seq_range_array_add_with_init(t->conflict_seqs, + 16, seq); + } + } + } + mail_index_transaction_set_log_updates(t); +} + +static uint32_t +mail_index_transaction_get_uid(struct mail_index_transaction *t, uint32_t seq) +{ + const struct mail_index_record *rec; + + i_assert(seq > 0); + + if (seq >= t->first_new_seq) + rec = mail_index_transaction_lookup(t, seq); + else { + i_assert(seq <= t->view->map->hdr.messages_count); + rec = MAIL_INDEX_REC_AT_SEQ(t->view->map, seq); + } + i_assert(rec->uid != 0); + return rec->uid; +} + +static void +mail_index_convert_to_uids(struct mail_index_transaction *t, + ARRAY_TYPE(seq_array) *array) +{ + uint32_t *seq; + unsigned int i, count; + + if (!array_is_created(array)) + return; + + count = array_count(array); + for (i = 0; i < count; i++) { + seq = array_idx_modifiable(array, i); + *seq = mail_index_transaction_get_uid(t, *seq); + } +} + +static uint32_t +get_nonexpunged_uid2(struct mail_index_transaction *t, + uint32_t uid1, uint32_t seq1) +{ + seq1++; + + while (mail_index_transaction_get_uid(t, seq1) == uid1 + 1) { + seq1++; + uid1++; + } + return uid1; +} + +void mail_index_transaction_seq_range_to_uid(struct mail_index_transaction *t, + ARRAY_TYPE(seq_range) *array) +{ + struct seq_range *range, *new_range; + unsigned int i, count; + uint32_t uid1, uid2, prev_uid = 0; + + if (!array_is_created(array)) + return; + + count = array_count(array); + for (i = 0; i < count; i++) { + range = array_idx_modifiable(array, i); + + uid1 = mail_index_transaction_get_uid(t, range->seq1); + uid2 = mail_index_transaction_get_uid(t, range->seq2); + i_assert(uid1 > prev_uid); + if (uid2 - uid1 == range->seq2 - range->seq1) { + /* simple conversion */ + range->seq1 = uid1; + range->seq2 = uid2; + prev_uid = uid2; + } else { + /* remove expunged UIDs */ + new_range = array_insert_space(array, i); + range = array_idx_modifiable(array, i + 1); + count++; + + memcpy(new_range, range, array->arr.element_size); + new_range->seq1 = uid1; + new_range->seq2 = get_nonexpunged_uid2(t, uid1, + range->seq1); + i_assert(new_range->seq2 < uid2); + + /* continue the range without the inserted seqs */ + range->seq1 += new_range->seq2 - new_range->seq1 + 1; + prev_uid = new_range->seq2; + } + } +} + +static void keyword_updates_convert_to_uids(struct mail_index_transaction *t) +{ + struct mail_index_transaction_keyword_update *update; + + if (!array_is_created(&t->keyword_updates)) + return; + + array_foreach_modifiable(&t->keyword_updates, update) { + mail_index_transaction_seq_range_to_uid(t, &update->add_seq); + mail_index_transaction_seq_range_to_uid(t, &update->remove_seq); + } +} + +static void expunges_convert_to_uids(struct mail_index_transaction *t) +{ + struct mail_transaction_expunge_guid *expunges; + unsigned int src, dest, count; + + if (!array_is_created(&t->expunges)) + return; + + mail_index_transaction_sort_expunges(t); + + expunges = array_get_modifiable(&t->expunges, &count); + if (count == 0) + return; + + /* convert uids and drop duplicates */ + expunges[0].uid = mail_index_transaction_get_uid(t, expunges[0].uid); + for (src = dest = 1; src < count; src++) { + expunges[dest].uid = + mail_index_transaction_get_uid(t, expunges[src].uid); + if (expunges[dest-1].uid != expunges[dest].uid) { + if (dest != src) { + memcpy(expunges[dest].guid_128, expunges[src].guid_128, + sizeof(expunges[dest].guid_128)); + } + dest++; + } + } + array_delete(&t->expunges, dest, count-dest); +} + +static void +mail_index_transaction_convert_to_uids(struct mail_index_transaction *t) +{ + ARRAY_TYPE(seq_array) *update; + + if (array_is_created(&t->ext_rec_updates)) { + array_foreach_modifiable(&t->ext_rec_updates, update) + mail_index_convert_to_uids(t, update); + } + if (array_is_created(&t->ext_rec_atomics)) { + array_foreach_modifiable(&t->ext_rec_atomics, update) + mail_index_convert_to_uids(t, update); + } + + keyword_updates_convert_to_uids(t); + expunges_convert_to_uids(t); + mail_index_convert_to_uids(t, (void *)&t->modseq_updates); + mail_index_transaction_seq_range_to_uid(t, (void *)&t->updates); +} + +void mail_index_transaction_finish_so_far(struct mail_index_transaction *t) +{ + if (array_is_created(&t->appends)) + mail_index_transaction_sort_appends(t); + mail_index_transaction_finish_flag_updates(t); + if (t->max_modseq != 0) + mail_index_transaction_check_conflicts(t); +} + +void mail_index_transaction_finish(struct mail_index_transaction *t) +{ + mail_index_transaction_finish_so_far(t); + + if (array_is_created(&t->appends)) + mail_index_update_day_headers(t, ioloop_time); + if (array_is_created(&t->ext_reset_atomic)) + transaction_update_atomic_reset_ids(t); + /* finally convert all sequences to UIDs before we write them, + but after we've checked and removed conflicts */ + mail_index_transaction_convert_to_uids(t); + + /* and kind of ugly way to update highest modseq */ + if (t->min_highest_modseq != 0) + mail_index_update_modseq(t, 0, t->min_highest_modseq); +} |