mail-index-transaction.c revision 346ee8b23fe6187632efe5930e59dafa17625138
a8c5a86d183db25a57bf193c06b41e092ec2e151Timo Sirainen/* Copyright (c) 2003-2009 Dovecot authors, see the included COPYING file */
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen/* Inside transaction we keep messages stored in sequences in uid fields.
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen Before they're written to transaction log the sequences are changed to
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen UIDs. This is because we're able to compress sequence ranges better. */
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainenmail_index_transaction_has_ext_changes(struct mail_index_transaction *t);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainenvoid mail_index_transaction_reset(struct mail_index_transaction *t)
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen struct mail_index_transaction_ext_hdr_update *ext_hdrs;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen recs = array_get_modifiable(&t->ext_rec_updates, &count);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen for (i = 0; i < count; i++) {
7631f16156aca373004953fe6b01a7f343fb47e0Timo Sirainen recs = array_get_modifiable(&t->ext_rec_atomics, &count);
7631f16156aca373004953fe6b01a7f343fb47e0Timo Sirainen for (i = 0; i < count; i++) {
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen ext_hdrs = array_get_modifiable(&t->ext_hdr_updates, &count);
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen for (i = 0; i < count; i++) {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen struct mail_index_transaction_keyword_update *u;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen u = array_get_modifiable(&t->keyword_updates, &count);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen for (i = 0; i < count; i++) {
f46885a5b78b15a8d2419f6e5d13b643bd85e41fTimo Sirainen t->first_new_seq = mail_index_view_get_messages_count(t->view)+1;
f46885a5b78b15a8d2419f6e5d13b643bd85e41fTimo Sirainen memset(t->pre_hdr_mask, 0, sizeof(t->pre_hdr_mask));
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen memset(t->post_hdr_mask, 0, sizeof(t->post_hdr_mask));
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen mail_cache_transaction_rollback(&t->cache_trans_ctx);
a757f31393b9d6fc7760a9dec8363404ab3ae576Timo Sirainenstatic bool mail_index_transaction_has_changes(struct mail_index_transaction *t)
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen /* flag updates aren't included in log_updates */
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainenstatic void mail_index_transaction_free(struct mail_index_transaction *t)
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainenmail_index_transaction_get_view(struct mail_index_transaction *t)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenbool mail_index_transaction_is_expunged(struct mail_index_transaction *t,
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenvoid mail_index_transaction_ref(struct mail_index_transaction *t)
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainenvoid mail_index_transaction_unref(struct mail_index_transaction **_t)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (--t->refcount == 0)
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainenstatic int mail_index_seq_record_cmp(const void *key, const void *data)
dce5a2719df4fc64a8762d2aa94ba98dcf9cd6feTimo Sirainenbool mail_index_seq_array_lookup(const ARRAY_TYPE(seq_array) *array,
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen unsigned int count;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen return bsearch_insert_pos(&seq, base, count, array->arr.element_size,
dce5a2719df4fc64a8762d2aa94ba98dcf9cd6feTimo Sirainenstatic bool mail_index_seq_array_add(ARRAY_TYPE(seq_array) *array, uint32_t seq,
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen /* records need to be 32bit aligned */
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen i_assert(array->arr.element_size == sizeof(seq) + aligned_record_size);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen if (mail_index_seq_array_lookup(array, seq, &idx)) {
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen /* already there, update */
ebe6df72f1309135f02b6a4d2aef1e81a073f91cTimo Sirainen /* save the old record before overwriting it */
ebe6df72f1309135f02b6a4d2aef1e81a073f91cTimo Sirainen memcpy(old_record, PTR_OFFSET(p, sizeof(seq)),
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen memcpy(PTR_OFFSET(p, sizeof(seq)), record, record_size);
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen memcpy(PTR_OFFSET(p, sizeof(seq)), record, record_size);
6e8f0036cad59d1d6bcd9ef69bfe712d01656ca3Timo Sirainenmail_index_transaction_get_uid(struct mail_index_transaction *t, uint32_t seq)
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen i_assert(seq <= t->view->map->hdr.messages_count);
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen rec = MAIL_INDEX_MAP_IDX(t->view->map, seq - 1);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainenmail_index_convert_to_uids(struct mail_index_transaction *t,
e53ab6c7081246c865917f9aa0eff031a08ad1e7Timo Sirainen unsigned int i, count;
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainen for (i = 0; i < count; i++) {
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainen *seq = mail_index_transaction_get_uid(t, *seq);
6e8f0036cad59d1d6bcd9ef69bfe712d01656ca3Timo Sirainenget_nonexpunged_uid2(struct mail_index_transaction *t,
e53ab6c7081246c865917f9aa0eff031a08ad1e7Timo Sirainen while (mail_index_transaction_get_uid(t, seq1) == uid1 + 1) {
e53ab6c7081246c865917f9aa0eff031a08ad1e7Timo Sirainenmail_index_convert_to_uid_ranges(struct mail_index_transaction *t,
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainen unsigned int i, count;
c161661e74ed29504a461110670f816ffa408b42Timo Sirainen for (i = 0; i < count; i++) {
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen uid1 = mail_index_transaction_get_uid(t, range->seq1);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen uid2 = mail_index_transaction_get_uid(t, range->seq2);
541b251a99a55cb0fa2eaf02645a7c39ad997092Timo Sirainen if (uid2 - uid1 == range->seq2 - range->seq1) {
9af6cc9ebc9986c1275ebdfa29c39e152af1557eTimo Sirainen /* simple conversion */
ceac44e7560fcbf6fc2f932c7b624a5055dc3bc9Timo Sirainen /* remove expunged UIDs */
541b251a99a55cb0fa2eaf02645a7c39ad997092Timo Sirainen memcpy(new_range, range, array->arr.element_size);
541b251a99a55cb0fa2eaf02645a7c39ad997092Timo Sirainen new_range->seq2 = get_nonexpunged_uid2(t, uid1,
541b251a99a55cb0fa2eaf02645a7c39ad997092Timo Sirainen /* continue the range without the inserted seqs */
541b251a99a55cb0fa2eaf02645a7c39ad997092Timo Sirainen range->seq1 += new_range->seq2 - new_range->seq1 + 1;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainenstatic void keyword_updates_convert_to_uids(struct mail_index_transaction *t)
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen struct mail_index_transaction_keyword_update *updates;
efb373fd7e30df171452c9f40881a8bd06b81780Timo Sirainen unsigned int i, count;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen updates = array_get_modifiable(&t->keyword_updates, &count);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen for (i = 0; i < count; i++) {
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen mail_index_convert_to_uid_ranges(t, &updates[i].add_seq);
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen mail_index_convert_to_uid_ranges(t, &updates[i].remove_seq);
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainenvoid mail_index_transaction_convert_to_uids(struct mail_index_transaction *t)
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen unsigned int i, count;
f46885a5b78b15a8d2419f6e5d13b643bd85e41fTimo Sirainen updates = array_get_modifiable(&t->ext_rec_updates, &count);
f46885a5b78b15a8d2419f6e5d13b643bd85e41fTimo Sirainen for (i = 0; i < count; i++)
f46885a5b78b15a8d2419f6e5d13b643bd85e41fTimo Sirainen mail_index_convert_to_uids(t, (void *)&updates[i]);
f46885a5b78b15a8d2419f6e5d13b643bd85e41fTimo Sirainen updates = array_get_modifiable(&t->ext_rec_atomics, &count);
f46885a5b78b15a8d2419f6e5d13b643bd85e41fTimo Sirainen for (i = 0; i < count; i++)
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen mail_index_convert_to_uids(t, (void *)&updates[i]);
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen mail_index_convert_to_uid_ranges(t, &t->expunges);
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen mail_index_convert_to_uid_ranges(t, (void *)&t->updates);
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen mail_index_convert_to_uid_ranges(t, &t->keyword_resets);
910fa4e4204a73d3d24c03f3059dd24e727ca057Timo Sirainenstatic int uid_map_cmp(const void *p1, const void *p2)
c7e14824e4e1ca9dc5d48d1eddc4a38d3041218fTimo Sirainenmail_index_update_day_headers(struct mail_index_transaction *t)
b6c6c4f6483b8340eec4c16c50ea078fe8297da2Timo Sirainen const int max_days = N_ELEMENTS(hdr.day_first_uid);
838e367716bbd5e44b4a1691db9cbf72af53e9f0Timo Sirainen /* get beginning of today */
0f83592ccc280a29bdf01c4475805f6a4bad9abdTimo Sirainen /* get number of days since last message */
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen /* @UNSAFE: move days forward and fill the missing days with old
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen day_first_uid[0]. */
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen memmove(hdr.day_first_uid + days, hdr.day_first_uid, max_days - days);
unsigned int ext_count;
unsigned int i, j, count;
for (j = 0; j < count; j++) {
for (i = 0; i < ext_count; i++) {
unsigned int i, count;
for (i = 0; i < count; i++) {
if (i == count) {
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++)
unsigned int offset;
return next_uid;
int ret;
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++) {
unsigned int i, count;
for (i = 0; i < count; i++) {
seq);
t->last_new_seq--;
t->last_new_seq = 0;
if (t->min_flagupdate_seq == 0) {
const struct mail_transaction_flag_update *u)
return TRUE;
return TRUE;
return FALSE;
unsigned int left_idx,
unsigned int right_idx,
idx++;
return idx;
struct mail_transaction_flag_update u,
unsigned int idx)
unsigned int count;
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;
return FALSE;
unsigned int i, count;
return TRUE;
return TRUE;
for (i = 0; i < count; i++) {
return TRUE;
for (i = 0; i < count; i++) {
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;
const unsigned int *existing_idx;
unsigned int i, j, existing_count;
bool found;
return TRUE;
return TRUE;
for (j = 0; j < existing_count; j++) {
switch (modify_type) {
case MODIFY_ADD:
case MODIFY_REPLACE:
if (!found)
return TRUE;
case MODIFY_REMOVE:
if (found)
return TRUE;
return FALSE;
struct mail_index_transaction_keyword_update *u;
unsigned int i, ku_count;
bool changed;
T_BEGIN {
keywords);
} T_END;
if (!changed)
switch (modify_type) {
case MODIFY_ADD:
case MODIFY_REMOVE:
case MODIFY_REPLACE:
&ku_count);
for (i = 0; i < ku_count; i++) {
return TRUE;
return FALSE;
unsigned int i, count;
for (i = 0; i < count; i++) {
seq))
if (!have_kw_changes)
return ret;
return ret;
if (t->min_flagupdate_seq == 0) {
struct mail_index_transaction *
struct mail_index_transaction *t;
t->v = trans_vfuncs;
t->first_new_seq =