mail-index-transaction.c revision 39d5fa228fa404c0ddfdb212bb1f396dbeb419e3
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2003-2008 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);
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainenvoid mail_index_transaction_reset(struct mail_index_transaction *t)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo 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 ext_hdrs = array_get_modifiable(&t->ext_hdr_updates, &count);
7631f16156aca373004953fe6b01a7f343fb47e0Timo Sirainen for (i = 0; i < count; i++)
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen struct mail_index_transaction_keyword_update *u;
a12399903f415a7e14c2816cffa2f7a09dcbb097Timo Sirainen u = array_get_modifiable(&t->keyword_updates, &count);
a12399903f415a7e14c2816cffa2f7a09dcbb097Timo Sirainen for (i = 0; i < count; i++) {
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen t->first_new_seq = mail_index_view_get_messages_count(t->view)+1;
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen memset(t->pre_hdr_mask, 0, sizeof(t->pre_hdr_mask));
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen memset(t->post_hdr_mask, 0, sizeof(t->post_hdr_mask));
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen mail_cache_transaction_rollback(&t->cache_trans_ctx);
a757f31393b9d6fc7760a9dec8363404ab3ae576Timo Sirainenstatic bool mail_index_transaction_has_changes(struct mail_index_transaction *t)
a757f31393b9d6fc7760a9dec8363404ab3ae576Timo Sirainen /* flag updates aren't included in log_updates */
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenstatic void mail_index_transaction_free(struct mail_index_transaction *t)
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainenmail_index_transaction_get_view(struct mail_index_transaction *t)
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainenbool mail_index_transaction_is_expunged(struct mail_index_transaction *t,
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainenvoid mail_index_transaction_ref(struct mail_index_transaction *t)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenvoid mail_index_transaction_unref(struct mail_index_transaction **_t)
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo 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,
dce5a2719df4fc64a8762d2aa94ba98dcf9cd6feTimo Sirainen unsigned int count;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen return bsearch_insert_pos(&seq, base, count, array->arr.element_size,
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainenstatic bool mail_index_seq_array_add(ARRAY_TYPE(seq_array) *array, uint32_t seq,
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen /* records need to be 32bit aligned */
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen i_assert(array->arr.element_size == sizeof(seq) + aligned_record_size);
87460b08cb97b31cde640d4975a6aa2c1d0e7226Timo Sirainen if (mail_index_seq_array_lookup(array, seq, &idx)) {
87460b08cb97b31cde640d4975a6aa2c1d0e7226Timo Sirainen /* already there, update */
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen /* save the old record before overwriting it */
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen memcpy(old_record, PTR_OFFSET(p, sizeof(seq)),
ebe6df72f1309135f02b6a4d2aef1e81a073f91cTimo Sirainen memcpy(PTR_OFFSET(p, sizeof(seq)), record, record_size);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen memcpy(PTR_OFFSET(p, sizeof(seq)), record, record_size);
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainenmail_index_transaction_get_uid(struct mail_index_transaction *t, uint32_t seq)
6df0ab0c1ab91f06b6418cb30eff44405a1b8f02Timo Sirainen i_assert(seq <= t->view->map->hdr.messages_count);
6df0ab0c1ab91f06b6418cb30eff44405a1b8f02Timo Sirainen rec = MAIL_INDEX_MAP_IDX(t->view->map, seq - 1);
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainenmail_index_convert_to_uids(struct mail_index_transaction *t,
6e8f0036cad59d1d6bcd9ef69bfe712d01656ca3Timo Sirainen unsigned int i, count;
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainen for (i = 0; i < count; i++) {
6e8f0036cad59d1d6bcd9ef69bfe712d01656ca3Timo Sirainen *seq = mail_index_transaction_get_uid(t, *seq);
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainenget_nonexpunged_uid2(struct mail_index_transaction *t,
6e8f0036cad59d1d6bcd9ef69bfe712d01656ca3Timo Sirainen while (mail_index_transaction_get_uid(t, seq1) == uid1 + 1) {
6e8f0036cad59d1d6bcd9ef69bfe712d01656ca3Timo Sirainenmail_index_convert_to_uid_ranges(struct mail_index_transaction *t,
6e8f0036cad59d1d6bcd9ef69bfe712d01656ca3Timo Sirainen unsigned int i, count;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen for (i = 0; i < count; i++) {
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen uid1 = mail_index_transaction_get_uid(t, range->seq1);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen uid2 = mail_index_transaction_get_uid(t, range->seq2);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen if (uid2 - uid1 == range->seq2 - range->seq1) {
9af6cc9ebc9986c1275ebdfa29c39e152af1557eTimo Sirainen /* simple conversion */
9af6cc9ebc9986c1275ebdfa29c39e152af1557eTimo Sirainen /* remove expunged UIDs */
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen memcpy(new_range, range, array->arr.element_size);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen new_range->seq2 = get_nonexpunged_uid2(t, uid1,
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen /* continue the range without the inserted seqs */
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen range->seq1 += new_range->seq2 - new_range->seq1 + 1;
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainenstatic void keyword_updates_convert_to_uids(struct mail_index_transaction *t)
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen struct mail_index_transaction_keyword_update *updates;
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen unsigned int i, count;
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen updates = array_get_modifiable(&t->keyword_updates, &count);
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen for (i = 0; i < count; i++) {
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen mail_index_convert_to_uid_ranges(t, &updates[i].add_seq);
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen mail_index_convert_to_uid_ranges(t, &updates[i].remove_seq);
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainenmail_index_transaction_convert_to_uids(struct mail_index_transaction *t)
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen unsigned int i, count;
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen updates = array_get_modifiable(&t->ext_rec_updates, &count);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen for (i = 0; i < count; i++)
910fa4e4204a73d3d24c03f3059dd24e727ca057Timo Sirainen mail_index_convert_to_uids(t, (void *)&updates[i]);
910fa4e4204a73d3d24c03f3059dd24e727ca057Timo Sirainen mail_index_convert_to_uid_ranges(t, &t->expunges);
910fa4e4204a73d3d24c03f3059dd24e727ca057Timo Sirainen mail_index_convert_to_uid_ranges(t, (void *)&t->updates);
838e367716bbd5e44b4a1691db9cbf72af53e9f0Timo Sirainen mail_index_convert_to_uid_ranges(t, &t->keyword_resets);
838e367716bbd5e44b4a1691db9cbf72af53e9f0Timo Sirainenstatic int uid_map_cmp(const void *p1, const void *p2)
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainenmail_index_update_day_headers(struct mail_index_transaction *t)
3281669db44d09a087a203201248abbc81b3cc1aTimo Sirainen const int max_days = N_ELEMENTS(hdr.day_first_uid);
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen /* get beginning of today */
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++)
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;
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++) {
struct mail_index_transaction *
struct mail_index_transaction *t;
t->v = trans_vfuncs;
t->first_new_seq =