mail-index-transaction.c revision 9270ca3c33f27e2d1bbe4171941dab82be7cb0e3
e59faf65ce864fe95dc00f5d52b8323cdbd0608aTimo Sirainen/* Copyright (c) 2003-2008 Dovecot authors, see the included COPYING file */
c977374bd4651cafc1626ebe308aa66dfd8b30e0Timo Sirainen/* Inside transaction we keep messages stored in sequences in uid fields.
c977374bd4651cafc1626ebe308aa66dfd8b30e0Timo Sirainen Before they're written to transaction log the sequences are changed to
c977374bd4651cafc1626ebe308aa66dfd8b30e0Timo Sirainen UIDs. This is because we're able to compress sequence ranges better. */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenmail_index_transaction_has_ext_changes(struct mail_index_transaction *t);
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainenvoid mail_index_transaction_reset(struct mail_index_transaction *t)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mail_index_transaction_ext_hdr_update **ext_hdrs;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen recs = array_get_modifiable(&t->ext_rec_updates, &count);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen for (i = 0; i < count; i++) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ext_hdrs = array_get_modifiable(&t->ext_hdr_updates, &count);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen for (i = 0; i < count; i++)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mail_index_transaction_keyword_update *u;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen u = array_get_modifiable(&t->keyword_updates, &count);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen for (i = 0; i < count; i++) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen t->first_new_seq = mail_index_view_get_messages_count(t->view)+1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen memset(t->pre_hdr_mask, 0, sizeof(t->pre_hdr_mask));
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen memset(t->post_hdr_mask, 0, sizeof(t->post_hdr_mask));
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_cache_transaction_rollback(&t->cache_trans_ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic bool mail_index_transaction_has_changes(struct mail_index_transaction *t)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* flag updates aren't included in log_updates */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void mail_index_transaction_free(struct mail_index_transaction *t)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenmail_index_transaction_get_view(struct mail_index_transaction *t)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenbool mail_index_transaction_is_expunged(struct mail_index_transaction *t,
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainenvoid mail_index_transaction_ref(struct mail_index_transaction *t)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenvoid mail_index_transaction_unref(struct mail_index_transaction **_t)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (--t->refcount == 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic int mail_index_seq_record_cmp(const void *key, const void *data)
d22301419109ed4a38351715e6760011421dadecTimo Sirainenbool mail_index_seq_array_lookup(const ARRAY_TYPE(seq_array) *array,
73a87c2ff65c6116cde6fb158dfddb8ef7346901Timo Sirainen unsigned int count;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return bsearch_insert_pos(&seq, base, count, array->arr.element_size,
73a87c2ff65c6116cde6fb158dfddb8ef7346901Timo Sirainenstatic bool mail_index_seq_array_add(ARRAY_TYPE(seq_array) *array, uint32_t seq,
73a87c2ff65c6116cde6fb158dfddb8ef7346901Timo Sirainen /* records need to be 32bit aligned */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_assert(array->arr.element_size == sizeof(seq) + aligned_record_size);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (mail_index_seq_array_lookup(array, seq, &idx)) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* already there, update */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* save the old record before overwriting it */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen memcpy(old_record, PTR_OFFSET(p, sizeof(seq)),
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen memcpy(PTR_OFFSET(p, sizeof(seq)), record, record_size);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen memcpy(PTR_OFFSET(p, sizeof(seq)), record, record_size);
d22301419109ed4a38351715e6760011421dadecTimo Sirainenmail_index_transaction_get_uid(struct mail_index_transaction *t, uint32_t seq)
d22301419109ed4a38351715e6760011421dadecTimo Sirainen i_assert(seq <= t->view->map->hdr.messages_count);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen rec = MAIL_INDEX_MAP_IDX(t->view->map, seq - 1);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenmail_index_convert_to_uids(struct mail_index_transaction *t,
d22301419109ed4a38351715e6760011421dadecTimo Sirainen unsigned int i, count;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen for (i = 0; i < count; i++) {
3f91e60401495a4046c73992fabaa5e77200a451Timo Sirainen *seq = mail_index_transaction_get_uid(t, *seq);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenget_nonexpunged_uid2(struct mail_index_transaction *t,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen while (mail_index_transaction_get_uid(t, seq1) == uid1 + 1) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenmail_index_convert_to_uid_ranges(struct mail_index_transaction *t,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int i, count;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen for (i = 0; i < count; i++) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen uid1 = mail_index_transaction_get_uid(t, range->seq1);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen uid2 = mail_index_transaction_get_uid(t, range->seq2);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (uid2 - uid1 == range->seq2 - range->seq1) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* simple conversion */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* remove expunged UIDs */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen memcpy(new_range, range, array->arr.element_size);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen new_range->seq2 = get_nonexpunged_uid2(t, uid1,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* continue the range without the inserted seqs */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen range->seq1 += new_range->seq2 - new_range->seq1 + 1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void keyword_updates_convert_to_uids(struct mail_index_transaction *t)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mail_index_transaction_keyword_update *updates;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int i, count;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen updates = array_get_modifiable(&t->keyword_updates, &count);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen for (i = 0; i < count; i++) {
d22301419109ed4a38351715e6760011421dadecTimo Sirainen mail_index_convert_to_uid_ranges(t, &updates[i].add_seq);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_index_convert_to_uid_ranges(t, &updates[i].remove_seq);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenmail_index_transaction_convert_to_uids(struct mail_index_transaction *t)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int i, count;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen updates = array_get_modifiable(&t->ext_rec_updates, &count);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen for (i = 0; i < count; i++)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_index_convert_to_uids(t, (void *)&updates[i]);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_index_convert_to_uid_ranges(t, &t->expunges);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_index_convert_to_uid_ranges(t, (void *)&t->updates);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_index_convert_to_uid_ranges(t, &t->keyword_resets);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic int uid_map_cmp(const void *p1, const void *p2)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenmail_index_update_day_headers(struct mail_index_transaction *t)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const int max_days = N_ELEMENTS(hdr.day_first_uid);
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainen /* get beginning of today */
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainen /* get number of days since last message */
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainen /* @UNSAFE: move days forward and fill the missing days with old
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainen day_first_uid[0]. */
d1c08db8f581444104233f2380b4591eca836f6aTimo Sirainen memmove(hdr.day_first_uid + days, hdr.day_first_uid, max_days - days);
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainen offsetof(struct mail_index_header, day_stamp),
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainen &hdr.day_stamp, sizeof(hdr.day_stamp), FALSE);
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainen offsetof(struct mail_index_header, day_first_uid),
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainen hdr.day_first_uid, sizeof(hdr.day_first_uid), FALSE);
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainenmail_index_transaction_sort_appends_ext(struct mail_index_transaction *t,
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainen unsigned int i, j, count;
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainen ext_rec_arrays = array_get_modifiable(&t->ext_rec_updates, &count);
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainen for (j = 0; j < count; j++) {
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainen for (i = 0; i < ext_count; i++) {
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainen seq = *ext_rec < t->first_new_seq ? *ext_rec :
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainen old_to_newseq_map[*ext_rec - t->first_new_seq];
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainen mail_index_seq_array_add(&new_array, seq, ext_rec+1,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainensort_appends_seq_range(struct mail_index_transaction *t,
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainen unsigned int i, count;
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainen for (i = 0; i < count; i++) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* nothing to do */
8bdb2e6bb77bd40c891c39cd7911887bcfda656eTimo Sirainen array_append(&old_seqs, &range[i], count - i);
for (i = 0; i < count; i++) {
unsigned int i, count;
for (i = 0; i < count; i++) {
unsigned int i, count;
if (!t->appends_nonsorted)
for (i = 0; i < count; i++) {
for (i = 0; i < count; i++)
return next_uid;
int ret;
if (mail_index_transaction_convert_to_uids(t) < 0)
return ret;
t->v.rollback(t);
struct mail_index_record *
if (t->last_new_seq != 0)
if (uid != 0) {
if (!t->appends_nonsorted &&
unsigned int i, count;
for (i = 0; i < count; i++) {
for (; i < count; i++) {
for (i = 0; i < count; i++) {
for (i = 0; i < count; i++) {
seq);
t->last_new_seq--;
t->last_new_seq = 0;
const struct mail_transaction_flag_update *u)
return TRUE;
return TRUE;
return FALSE;
struct mail_transaction_flag_update u,
unsigned int count;
idx++;
tmp_update = u;
move = 0;
&count);
~u.remove_flags;
~u.add_flags;
idx--;
if (mail_transaction_update_want_add(t, &u)) {
count++;
switch (modify_type) {
case MODIFY_REPLACE:
case MODIFY_ADD:
case MODIFY_REMOVE:
memset(&u, 0, sizeof(u));
switch (modify_type) {
case MODIFY_REPLACE:
case MODIFY_ADD:
case MODIFY_REMOVE:
if (mail_transaction_update_want_add(t, &u))
if (mail_transaction_update_want_add(t, &u))
t->last_update_idx++;
last_update++;
if (mail_transaction_update_want_add(t, &u))
else if (t->last_update_idx > 0)
t->last_update_idx--;
first_idx = 0;
bool prepend)
if (prepend) {
unsigned int i, count;
for (i = 0; i < count; i++) {
return TRUE;
for (i = 0; i < count; i++) {
return TRUE;
for (i = 0; i < count; i++) {
if (ids[i] != 0)
return TRUE;
for (i = 0; i < count; i++) {
return TRUE;
return FALSE;
unsigned int count;
count = 0;
old_data_r)) {
struct mail_keywords *
const char *const keywords[])
struct mail_keywords *k;
if (count == 0) {
for (i = 0; i < src; i++) {
if (i == src)
dest++;
struct mail_keywords *
struct mail_keywords *k;
const unsigned int *indexes;
if (count == 0) {
for (i = 0; i < src; i++) {
if (i == src)
struct mail_index_transaction_keyword_update *u;
unsigned int i, ku_count;
switch (modify_type) {
case MODIFY_ADD:
case MODIFY_REMOVE:
case MODIFY_REPLACE:
&ku_count);
for (i = 0; i < ku_count; i++) {
struct mail_index_transaction *
struct mail_index_transaction *t;
t->v = trans_vfuncs;
t->first_new_seq =