mail-index-transaction.c revision ba665db60cf64cbe6e3ac67822de72101ec6fd36
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Copyright (C) 2003-2004 Timo Sirainen */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Inside transaction we keep messages stored in sequences in uid fields.
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen Before they're written to transaction log the sequences are changed to
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen UIDs. This is because we're able to compress sequence ranges better. */
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainenmail_index_transaction_begin(struct mail_index_view *view,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* don't allow syncing view while there's ongoing transactions */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen t->first_new_seq = mail_index_view_get_messages_count(t->view)+1;
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen /* transaction view cannot work if new records are being added
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen in two places. make sure it doesn't happen. */
ea546eaab672d441e180b7619d4750be813c08d8Timo Sirainenstatic void mail_keyword_transaction_free(struct mail_keyword_transaction *kt)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (p = &kt->keywords->kt; *p != NULL; p = &(*p)->next) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (*p == kt) {
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen /* no transactions left, free mail_keywords */
0add8c99ca65e56dbf613595fc37c41aafff3f7fTimo Sirainenstatic void mail_index_transaction_free(struct mail_index_transaction *t)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen recs = buffer_get_modifyable_data(t->ext_rec_updates, &size);
f99575e1d6cd251bd7b6d0654bd75b475e6a894cTimo Sirainen for (i = 0; i < size; i++) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen kt = buffer_get_modifyable_data(t->keyword_updates, &size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (i = 0; i < size; i++)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid mail_index_transaction_ref(struct mail_index_transaction *t)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid mail_index_transaction_unref(struct mail_index_transaction *t)
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen if (--t->refcount == 0)
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainenmail_index_buffer_convert_to_uids(struct mail_index_transaction *t,
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen unsigned char *data;
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen /* @UNSAFE */
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen data = buffer_get_modifyable_data(buf, &size);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainenmail_index_transaction_convert_to_uids(struct mail_index_transaction *t)
5a58037ad75b88356d82240fab2bc604de03107eTimo Sirainen extensions = buffer_get_data(index->extensions, NULL);
5a58037ad75b88356d82240fab2bc604de03107eTimo Sirainen updates = buffer_get_modifyable_data(t->ext_rec_updates, &size);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen for (i = 0; i < size; i++) {
5a58037ad75b88356d82240fab2bc604de03107eTimo Sirainen mail_index_buffer_convert_to_uids(t, updates[i],
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen kt = buffer_get_modifyable_data(t->keyword_updates, &size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (i = 0; i < size; i++) {
f99575e1d6cd251bd7b6d0654bd75b475e6a894cTimo Sirainen mail_index_buffer_convert_to_uids(t, kt[i]->messages,
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen mail_index_buffer_convert_to_uids(t, t->expunges,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen sizeof(struct mail_transaction_expunge), TRUE);
b5ea11802f2bafbec06282a7b3b6704dc5fae584Timo Sirainen mail_index_buffer_convert_to_uids(t, t->updates,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen sizeof(struct mail_transaction_flag_update), TRUE);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint mail_index_transaction_commit(struct mail_index_transaction *t,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (mail_index_view_is_inconsistent(t->view)) {
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen mail_cache_transaction_commit(t->cache_trans_ctx);
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen if (mail_index_transaction_convert_to_uids(t) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = mail_transaction_log_append(t, log_file_seq_r,
b5ea11802f2bafbec06282a7b3b6704dc5fae584Timo Sirainenvoid mail_index_transaction_rollback(struct mail_index_transaction *t)
b5ea11802f2bafbec06282a7b3b6704dc5fae584Timo Sirainen mail_cache_transaction_rollback(t->cache_trans_ctx);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainenmail_index_transaction_lookup(struct mail_index_transaction *t, uint32_t seq)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(seq >= t->first_new_seq && seq <= t->last_new_seq);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen pos = (seq - t->first_new_seq) * sizeof(struct mail_index_record);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return buffer_get_space_unsafe(t->appends, pos,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen sizeof(struct mail_index_record));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid mail_index_append(struct mail_index_transaction *t, uint32_t uid,
62950eeff28f00989a17b20eeade3af7e200c6bcTimo Sirainen t->appends = buffer_create_dynamic(default_pool, 4096);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* sequence number is visible only inside given view,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen so let it generate it */
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen rec = buffer_append_space_unsafe(t->appends, sizeof(*rec));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid mail_index_append_assign_uids(struct mail_index_transaction *t,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen rec = buffer_get_modifyable_data(t->appends, &size);
5a58037ad75b88356d82240fab2bc604de03107eTimo Sirainen /* find the first mail with uid = 0 */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void mail_index_update_seq_range_buffer(buffer_t *buffer, uint32_t seq)
b0a446671b8f09a1d2ed1d8c86a47298309e989dTimo Sirainen data = buffer_get_modifyable_data(buffer, &size);
b0a446671b8f09a1d2ed1d8c86a47298309e989dTimo Sirainen /* quick checks */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* grow last range */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* grow down first range */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_insert(buffer, 0, &value, sizeof(value));
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen /* somewhere in the middle, array is sorted so find it with
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen binary search */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* it's already expunged */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* idx == size couldn't happen because we already handle it above */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(idx < size && data[idx].seq1 >= seq);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(data[idx].seq1 > seq || data[idx].seq2 < seq);
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen i_assert(idx+1 < size); /* already handled above */
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainenvoid mail_index_expunge(struct mail_index_transaction *t, uint32_t seq)
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen i_assert(seq > 0 && seq <= mail_index_view_get_messages_count(t->view));
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen /* expunges is a sorted array of {seq1, seq2, ..}, .. */
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen t->expunges = buffer_create_dynamic(default_pool, 1024);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen buffer_append(t->expunges, &seq, sizeof(seq));
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen buffer_append(t->expunges, &seq, sizeof(seq));
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen mail_index_update_seq_range_buffer(t->expunges, seq);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainenmail_index_insert_flag_update(struct mail_index_transaction *t,
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen struct mail_transaction_flag_update *updates, tmp_update;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen updates = buffer_get_modifyable_data(t->updates, &size);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen i_assert(left_idx <= right_idx && right_idx <= size);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen /* find the first update with either overlapping range,
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen or the update which will come after our insert */
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen /* overlapping ranges, split/merge them */
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen i_assert(idx == 0 || updates[idx-1].uid2 < u.uid1);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen for (; idx < size && u.uid2 >= updates[idx].uid1; idx++) {
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen updates[idx].remove_flags != u.remove_flags)) {
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen /* insert new update */
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen /* split existing update from beginning */
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen i_assert(updates[idx].uid1 <= updates[idx].uid2);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen buffer_insert(t->updates, idx * sizeof(tmp_update),
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen updates = buffer_get_modifyable_data(t->updates, NULL);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen updates[idx].remove_flags != u.remove_flags)) {
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen /* split existing update from end */
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen i_assert(updates[idx].uid1 <= updates[idx].uid2);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen buffer_insert(t->updates, idx * sizeof(tmp_update),
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen updates = buffer_get_modifyable_data(t->updates, NULL);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen (updates[idx].remove_flags | u.remove_flags) &
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen /* break here before idx++ so last_update_idx is set
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen i_assert(idx == 0 || updates[idx-1].uid2 < u.uid1);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen i_assert(idx == size || updates[idx].uid1 > u.uid2);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen buffer_insert(t->updates, idx * sizeof(u), &u, sizeof(u));
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainenstatic void mail_index_record_modify_flags(struct mail_index_record *rec,
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainenvoid mail_index_update_flags_range(struct mail_index_transaction *t,
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen struct mail_transaction_flag_update u, *last_update;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen /* updates for appended messages, modify them directly */
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen for (seq = I_MAX(t->first_new_seq, seq1); seq <= seq2; seq++) {
2a734f36105e33ab452d057df6bc7a2b7d9f96f0Timo Sirainen mail_index_record_modify_flags(rec, modify_type, flags);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen /* range contains also existing messages. update them next. */
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen i_assert(seq2 <= mail_index_view_get_messages_count(t->view));
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen memset(&u, 0, sizeof(u));
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen u.remove_flags = ~flags & MAIL_INDEX_FLAGS_MASK;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen t->updates = buffer_create_dynamic(default_pool, 4096);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen last_update = buffer_get_modifyable_data(t->updates, &size);
t->last_update_idx++;
last_update++;
size);
void *data;
if (size == 0)
idx = 0;
return TRUE;
return FALSE;
void *old_record)
return FALSE;
return TRUE;
return FALSE;
size = 0;
sizeof(buffer_t *));
old_data_r)) {
static struct mail_keyword_transaction *
return kt;
static struct mail_keywords *
struct mail_keywords k;
uint8_t *b;
if (count == 0)
t_push();
memset(&k, 0, sizeof(k));
for (i = 0; i < count; i++) {
k.start = j;
} else if (j < k.start) {
k.start = j;
k.end = j;
k.count++;
if (missing_count > 0) {
j = size / sizeof(const char *);
k.end = j;
k.count++;
t_pop();
struct mail_keywords *
const char *const keywords[])
struct mail_keywords *k;
(void)mail_keyword_transaction_new(t, k);