mail-index-transaction.c revision 5b1980a4dd8baad683578351d7f154b87c5f35e0
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (C) 2003-2004 Timo Sirainen */
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen#include "lib.h"
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen#include "buffer.h"
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen#include "mail-index-view-private.h"
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen#include "mail-transaction-log.h"
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen#include "mail-index-transaction-private.h"
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainenstatic void mail_index_transaction_add_last(struct mail_index_transaction *t);
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainenstruct mail_index_transaction *
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainenmail_index_transaction_begin(struct mail_index_view *view, int hide)
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen{
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen struct mail_index_transaction *t;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen /* don't allow syncing view while there's ongoing transactions */
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen mail_index_view_transaction_ref(view);
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen t = i_new(struct mail_index_transaction, 1);
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen t->view = view;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen t->hide_transaction = hide;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen return t;
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen}
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainenstatic void mail_index_transaction_free(struct mail_index_transaction *t)
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen{
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen mail_index_view_transaction_unref(t->view);
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen if (t->appends != NULL)
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen buffer_free(t->appends);
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen if (t->expunges != NULL)
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen buffer_free(t->expunges);
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen if (t->updates != NULL)
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen buffer_free(t->updates);
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen i_free(t);
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen}
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainenint mail_index_transaction_commit(struct mail_index_transaction *t,
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen uint32_t *log_file_seq_r,
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen uoff_t *log_file_offset_r)
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen{
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen int ret;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen if (mail_index_view_is_inconsistent(t->view)) {
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen mail_index_transaction_free(t);
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen return -1;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen }
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen if (t->last_update.seq1 != 0)
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen mail_index_transaction_add_last(t);
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen ret = mail_transaction_log_append(t, log_file_seq_r, log_file_offset_r);
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen mail_index_transaction_free(t);
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen return ret;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen}
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainenvoid mail_index_transaction_rollback(struct mail_index_transaction *t)
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen{
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen mail_index_transaction_free(t);
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen}
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainenvoid mail_index_append(struct mail_index_transaction *t, uint32_t uid,
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch uint32_t *seq_r)
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen{
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen struct mail_index_record *rec;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen if (t->appends == NULL) {
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen t->appends = buffer_create_dynamic(default_pool,
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen 4096, (size_t)-1);
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen }
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen /* sequence number is visible only inside given view,
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen so let it generate it */
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen if (t->last_new_seq != 0)
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen *seq_r = ++t->last_new_seq;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen else {
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen *seq_r = t->first_new_seq = t->last_new_seq =
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen mail_index_view_get_message_count(t->view)+1;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen }
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen rec = buffer_append_space_unsafe(t->appends, sizeof(*rec));
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen memset(rec, 0, sizeof(*rec));
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen rec->uid = uid;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen}
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainenvoid mail_index_expunge(struct mail_index_transaction *t, uint32_t seq)
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen{
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen struct mail_transaction_expunge exp, *data;
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen unsigned int idx, left_idx, right_idx;
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen uint32_t uid;
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen size_t size;
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen i_assert(seq > 0 && seq <= mail_index_view_get_message_count(t->view));
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen uid = t->view->map->records[seq-1].uid;
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen exp.seq1 = exp.seq2 = seq;
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen exp.uid1 = exp.uid2 = uid;
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen /* expunges is a sorted array of {seq1, seq2, ..}, .. */
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen
b8b005887cd7f72520c6dcc325461faeecc5f9e9Timo Sirainen if (t->expunges == NULL) {
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen t->expunges = buffer_create_dynamic(default_pool,
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen 1024, (size_t)-1);
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen buffer_append(t->expunges, &exp, sizeof(exp));
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen return;
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen }
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen data = buffer_get_modifyable_data(t->expunges, &size);
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen size /= sizeof(*data);
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen i_assert(size > 0);
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen /* quick checks */
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen if (data[size-1].seq2 == seq-1) {
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen /* grow last range */
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen data[size-1].seq2 = seq;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen data[size-1].uid2 = uid;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen return;
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen }
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen if (data[size-1].seq2 < seq) {
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen buffer_append(t->expunges, &exp, sizeof(exp));
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen return;
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen }
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen if (data[0].seq1 == seq+1) {
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen /* grow down first range */
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen data[0].seq1 = seq;
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen data[0].uid1 = uid;
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen return;
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen }
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen if (data[0].seq1 > seq) {
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen buffer_insert(t->expunges, 0, &exp, sizeof(exp));
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen return;
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen }
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen /* somewhere in the middle, array is sorted so find it with
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen binary search */
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen idx = 0; left_idx = 0; right_idx = size;
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen while (left_idx < right_idx) {
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen idx = (left_idx + right_idx) / 2;
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen if (data[idx].seq1 < seq)
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen left_idx = idx+1;
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen else if (data[idx].seq1 > seq)
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen right_idx = idx;
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen else
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen break;
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen }
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen if (data[idx].seq2 < seq)
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen idx++;
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen /* idx == size couldn't happen because we already handle it above */
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen i_assert(idx < size && data[idx].seq1 >= seq);
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen if (data[idx].seq1 <= seq && data[idx].seq2 >= seq) {
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen /* already expunged */
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen return;
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen }
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen if (data[idx].seq1 == seq+1) {
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen data[idx].seq1 = seq;
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen data[idx].uid1 = uid;
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen if (idx > 0 && data[idx-1].seq2 == seq-1) {
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen /* merge */
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen data[idx-1].seq2 = data[idx].seq2;
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen data[idx-1].uid2 = data[idx].uid2;
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen buffer_delete(t->expunges, idx * sizeof(*data),
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen sizeof(*data));
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen }
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen } else if (data[idx].seq2 == seq-1) {
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen i_assert(idx+1 < size); /* already handled above */
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen data[idx].seq2 = seq;
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen data[idx].uid2 = uid;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen if (data[idx+1].seq1 == seq+1) {
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen /* merge */
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen data[idx+1].seq1 = data[idx].seq1;
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen data[idx+1].uid1 = data[idx].uid1;
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen buffer_delete(t->expunges, idx * sizeof(*data),
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen sizeof(*data));
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen }
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen } else {
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen buffer_insert(t->expunges, idx * sizeof(*data),
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen &exp, sizeof(exp));
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen }
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen}
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainenstatic void mail_index_record_modify_flags(struct mail_index_record *rec,
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen enum modify_type modify_type,
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen enum mail_flags flags,
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen keywords_mask_t keywords)
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen{
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen int i;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen switch (modify_type) {
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen case MODIFY_REPLACE:
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen rec->flags = flags;
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen memcpy(rec->keywords, keywords, INDEX_KEYWORDS_BYTE_COUNT);
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen break;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen case MODIFY_ADD:
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen rec->flags |= flags;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen for (i = 0; i < INDEX_KEYWORDS_BYTE_COUNT; i++)
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen rec->keywords[i] |= keywords[i];
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen break;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen case MODIFY_REMOVE:
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen rec->flags &= ~flags;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen for (i = 0; i < INDEX_KEYWORDS_BYTE_COUNT; i++)
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen rec->keywords[i] &= ~keywords[i];
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen break;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen }
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen}
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen#define IS_COMPATIBLE_UPDATE(t, modify_type, flags, keywords) \
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen ((t)->last_update_modify_type == (modify_type) && \
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen (t)->last_update.add_flags == (flags) && \
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen memcmp((t)->last_update.add_keywords, keywords, \
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen INDEX_KEYWORDS_BYTE_COUNT) == 0)
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainenvoid mail_index_update_flags(struct mail_index_transaction *t, uint32_t seq,
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen enum modify_type modify_type,
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen enum mail_flags flags, keywords_mask_t keywords)
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen{
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen struct mail_index_record *rec;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen size_t pos;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen if (t->first_new_seq != 0 && seq >= t->first_new_seq) {
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen /* just appended message, modify it directly */
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen i_assert(seq > 0 && seq <= t->last_new_seq);
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen pos = (seq - t->first_new_seq) * sizeof(*rec);
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen rec = buffer_get_space_unsafe(t->appends, pos, sizeof(*rec));
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen mail_index_record_modify_flags(rec, modify_type,
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen flags, keywords);
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen return;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen }
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen i_assert(seq > 0 && seq <= mail_index_view_get_message_count(t->view));
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen /* first get group updates into same structure. this allows faster
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen updates if same mails have multiple flag updates during same
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen transaction (eg. 1:10 +seen, 1:10 +deleted) */
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen if (t->last_update.seq2 == seq-1) {
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen if (t->last_update.seq1 != 0 &&
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen IS_COMPATIBLE_UPDATE(t, modify_type, flags, keywords)) {
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen t->last_update.seq2 = seq;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen return;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen }
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen } else if (t->last_update.seq1 == seq+1) {
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen if (t->last_update.seq1 != 0 &&
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen IS_COMPATIBLE_UPDATE(t, modify_type, flags, keywords)) {
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen t->last_update.seq1 = seq;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen return;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen }
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen }
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen if (t->last_update.seq1 != 0)
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen mail_index_transaction_add_last(t);
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen t->last_update_modify_type = modify_type;
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen t->last_update.seq1 = t->last_update.seq2 = seq;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen t->last_update.add_flags = flags;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen memcpy(t->last_update.add_keywords, keywords,
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen INDEX_KEYWORDS_BYTE_COUNT);
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen}
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainenstatic void
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainenmail_index_transaction_get_last(struct mail_index_transaction *t,
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen struct mail_transaction_flag_update *update)
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen{
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen int i;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen *update = t->last_update;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen switch (t->last_update_modify_type) {
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen case MODIFY_REPLACE:
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen /* remove_flags = ~add_flags */
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen update->remove_flags =
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen ~update->add_flags & MAIL_INDEX_FLAGS_MASK;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen for (i = 0; i < INDEX_KEYWORDS_BYTE_COUNT; i++)
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen update->remove_keywords[i] = ~update->add_keywords[i];
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen break;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen case MODIFY_ADD:
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen /* already in add_flags */
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen break;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen case MODIFY_REMOVE:
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen /* add_flags -> remove_flags */
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen update->remove_flags = update->add_flags;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen memcpy(&update->remove_keywords, &update->add_keywords,
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen INDEX_KEYWORDS_BYTE_COUNT);
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen update->add_flags = 0;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen memset(&update->add_keywords, 0, INDEX_KEYWORDS_BYTE_COUNT);
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen break;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen }
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen}
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainenstatic void mail_index_transaction_add_last(struct mail_index_transaction *t)
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen{
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen struct mail_transaction_flag_update update, *data;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen unsigned int idx, left_idx, right_idx;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen uint32_t last;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen size_t size;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen mail_index_transaction_get_last(t, &update);
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen if (t->updates == NULL) {
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen t->updates = buffer_create_dynamic(default_pool,
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen 4096, (size_t)-1);
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen }
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen data = buffer_get_modifyable_data(t->updates, &size);
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen size /= sizeof(*data);
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen /* find the nearest sequence from existing updates */
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen idx = 0; left_idx = 0; right_idx = size;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen while (left_idx < right_idx) {
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen idx = (left_idx + right_idx) / 2;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen if (data[idx].seq1 < update.seq1)
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen left_idx = idx+1;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen else if (data[idx].seq1 > update.seq1)
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen right_idx = idx;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen else
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen break;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen }
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen if (idx < size && data[idx].seq2 < update.seq1)
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen idx++;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen i_assert(idx == size || data[idx].seq1 < update.seq1);
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen /* insert it into buffer, split it in multiple parts if needed
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen to make sure the ordering stays the same */
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen for (; idx < size; idx++) {
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen if (data[idx].seq1 > update.seq2)
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen break;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen /* partial */
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen last = update.seq2;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen update.seq2 = data[idx].seq1-1;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen
632018810af689442569cbb0139c55868923ccfeTimo Sirainen buffer_insert(t->updates, idx * sizeof(update),
632018810af689442569cbb0139c55868923ccfeTimo Sirainen &update, sizeof(update));
632018810af689442569cbb0139c55868923ccfeTimo Sirainen data = buffer_get_modifyable_data(t->updates, NULL);
632018810af689442569cbb0139c55868923ccfeTimo Sirainen size++;
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen
632018810af689442569cbb0139c55868923ccfeTimo Sirainen update.seq1 = update.seq2+1;
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen update.seq2 = last;
b8b005887cd7f72520c6dcc325461faeecc5f9e9Timo Sirainen }
632018810af689442569cbb0139c55868923ccfeTimo Sirainen
632018810af689442569cbb0139c55868923ccfeTimo Sirainen buffer_insert(t->updates, idx * sizeof(update),
632018810af689442569cbb0139c55868923ccfeTimo Sirainen &update, sizeof(update));
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen}
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainenvoid mail_index_update_cache(struct mail_index_transaction *t,
632018810af689442569cbb0139c55868923ccfeTimo Sirainen uint32_t seq, uint32_t offset)
632018810af689442569cbb0139c55868923ccfeTimo Sirainen{
632018810af689442569cbb0139c55868923ccfeTimo Sirainen struct mail_transaction_cache_update *data, update;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen unsigned int idx, left_idx, right_idx;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen size_t size;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen
632018810af689442569cbb0139c55868923ccfeTimo Sirainen if (t->cache_updates == NULL) {
632018810af689442569cbb0139c55868923ccfeTimo Sirainen t->cache_updates = buffer_create_dynamic(default_pool,
632018810af689442569cbb0139c55868923ccfeTimo Sirainen 1024, (size_t)-1);
632018810af689442569cbb0139c55868923ccfeTimo Sirainen }
632018810af689442569cbb0139c55868923ccfeTimo Sirainen
632018810af689442569cbb0139c55868923ccfeTimo Sirainen data = buffer_get_modifyable_data(t->cache_updates, &size);
632018810af689442569cbb0139c55868923ccfeTimo Sirainen size /= sizeof(*data);
632018810af689442569cbb0139c55868923ccfeTimo Sirainen
632018810af689442569cbb0139c55868923ccfeTimo Sirainen /* we're probably appending it, check */
632018810af689442569cbb0139c55868923ccfeTimo Sirainen if (size == 0 || data[size-1].seq < seq)
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen idx = size;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen else {
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen idx = 0; left_idx = 0; right_idx = size;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen while (left_idx < right_idx) {
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen idx = (left_idx + right_idx) / 2;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen
8d3af185ae454653fad60e41c5f36edb1d45c868Timo Sirainen if (data[idx].seq < seq)
8d3af185ae454653fad60e41c5f36edb1d45c868Timo Sirainen left_idx = idx+1;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen else if (data[idx].seq > seq)
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen right_idx = idx;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen else {
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen /* already there, update */
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen data[idx].cache_offset = offset;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen return;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen }
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen }
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen }
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen update.seq = seq;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen update.cache_offset = offset;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen buffer_insert(t->updates, idx * sizeof(update),
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen &update, sizeof(update));
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen}
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen