dovecot-2.0: mail_index_update_flags*() now does a better job of...
dovecot at dovecot.org
dovecot at dovecot.org
Tue Jul 14 01:22:18 EEST 2009
details: http://hg.dovecot.org/dovecot-2.0/rev/1f8629349b41
changeset: 9616:1f8629349b41
user: Timo Sirainen <tss at iki.fi>
date: Mon Jul 13 18:21:19 2009 -0400
description:
mail_index_update_flags*() now does a better job of merging flag changes together.
diffstat:
3 files changed, 103 insertions(+), 49 deletions(-)
src/lib-index/mail-index-transaction-finish.c | 59 +++++++++++++++
src/lib-index/mail-index-transaction-private.h | 1
src/lib-index/mail-index-transaction.c | 92 +++++++++++-------------
diffs (287 lines):
diff -r 2f54270904bf -r 1f8629349b41 src/lib-index/mail-index-transaction-finish.c
--- a/src/lib-index/mail-index-transaction-finish.c Mon Jul 13 15:06:33 2009 -0400
+++ b/src/lib-index/mail-index-transaction-finish.c Mon Jul 13 18:21:19 2009 -0400
@@ -55,6 +55,64 @@ transaction_update_atomic_reset_ids(stru
ext_reset_update_atomic(t, ext_id,
expected_reset_ids[ext_id]);
}
+ }
+}
+
+static unsigned int
+mail_transaction_drop_range(struct mail_index_transaction *t,
+ struct mail_transaction_flag_update update,
+ unsigned int update_idx,
+ ARRAY_TYPE(seq_range) *keeps)
+{
+ const struct seq_range *keep_range;
+ unsigned int i, keep_count;
+
+ keep_range = array_get(keeps, &keep_count);
+ if (keep_count == 1 &&
+ update.uid1 == keep_range[0].seq1 &&
+ update.uid2 == keep_range[0].seq2) {
+ /* evereything is kept */
+ return update_idx + 1;
+ }
+
+ array_delete(&t->updates, update_idx, 1);
+
+ /* add back all the updates we want to keep */
+ for (i = 0; i < keep_count; i++, update_idx++) {
+ update.uid1 = keep_range[i].seq1;
+ update.uid2 = keep_range[i].seq2;
+ array_insert(&t->updates, update_idx, &update, 1);
+ }
+ return update_idx;
+}
+
+static void
+mail_index_transaction_finish_flag_updates(struct mail_index_transaction *t)
+{
+ const struct mail_transaction_flag_update *updates, *u;
+ const struct mail_index_record *rec;
+ unsigned int i, count;
+ ARRAY_TYPE(seq_range) keeps;
+ uint32_t seq;
+
+ if (!t->drop_unnecessary_flag_updates)
+ return;
+
+ t_array_init(&keeps, 64);
+ updates = array_get(&t->updates, &count);
+ for (i = 0; i < count; ) {
+ /* first get the list of changes to drop */
+ u = &updates[i];
+ array_clear(&keeps);
+ for (seq = u->uid1; seq <= u->uid2; seq++) {
+ rec = mail_index_lookup(t->view, seq);
+ if ((rec->flags & u->add_flags) != u->add_flags ||
+ (rec->flags & u->remove_flags) != 0) {
+ /* keep this change */
+ seq_range_array_add(&keeps, 0, seq);
+ }
+ }
+ i = mail_transaction_drop_range(t, updates[i], i, &keeps);
}
}
@@ -277,6 +335,7 @@ int mail_index_transaction_finish(struct
int mail_index_transaction_finish(struct mail_index_transaction *t)
{
mail_index_transaction_sort_appends(t);
+ mail_index_transaction_finish_flag_updates(t);
if (array_is_created(&t->ext_reset_atomic) || t->max_modseq != 0) {
if (mail_index_map(t->view->index,
diff -r 2f54270904bf -r 1f8629349b41 src/lib-index/mail-index-transaction-private.h
--- a/src/lib-index/mail-index-transaction-private.h Mon Jul 13 15:06:33 2009 -0400
+++ b/src/lib-index/mail-index-transaction-private.h Mon Jul 13 18:21:19 2009 -0400
@@ -77,6 +77,7 @@ struct mail_index_transaction {
unsigned int sync_transaction:1;
unsigned int appends_nonsorted:1;
+ unsigned int drop_unnecessary_flag_updates:1;
unsigned int pre_hdr_changed:1;
unsigned int post_hdr_changed:1;
unsigned int reset:1;
diff -r 2f54270904bf -r 1f8629349b41 src/lib-index/mail-index-transaction.c
--- a/src/lib-index/mail-index-transaction.c Mon Jul 13 15:06:33 2009 -0400
+++ b/src/lib-index/mail-index-transaction.c Mon Jul 13 18:21:19 2009 -0400
@@ -526,26 +526,6 @@ static void update_minmax_flagupdate_seq
}
}
-static bool
-mail_transaction_update_want_add(struct mail_index_transaction *t,
- const struct mail_transaction_flag_update *u)
-{
- const struct mail_index_record *rec;
- uint32_t seq;
-
- if ((t->flags & MAIL_INDEX_TRANSACTION_FLAG_AVOID_FLAG_UPDATES) == 0)
- return TRUE;
-
- for (seq = u->uid1; seq <= u->uid2; seq++) {
- rec = mail_index_lookup(t->view, seq);
- if ((rec->flags & u->add_flags) != u->add_flags ||
- (rec->flags & u->remove_flags) != 0)
- return TRUE;
- }
-
- return FALSE;
-}
-
unsigned int
mail_index_transaction_get_flag_update_pos(struct mail_index_transaction *t,
unsigned int left_idx,
@@ -571,7 +551,7 @@ mail_index_transaction_get_flag_update_p
else
break;
}
- if (idx < count && updates[idx].uid2 < seq)
+ if (left_idx > idx)
idx++;
return idx;
}
@@ -582,8 +562,7 @@ mail_index_insert_flag_update(struct mai
unsigned int idx)
{
struct mail_transaction_flag_update *updates, tmp_update;
- unsigned int count;
- uint32_t move;
+ unsigned int count, first_idx, max;
updates = array_get_modifiable(&t->updates, &count);
@@ -591,7 +570,10 @@ mail_index_insert_flag_update(struct mai
i_assert(idx == 0 || updates[idx-1].uid2 < u.uid1);
i_assert(idx == count || updates[idx].uid2 >= u.uid1);
+ /* first we'll just add the changes without trying to merge anything */
+ first_idx = idx;
for (; idx < count && u.uid2 >= updates[idx].uid1; idx++) {
+ i_assert(u.uid1 <= updates[idx].uid2);
if (u.uid1 != updates[idx].uid1 &&
(updates[idx].add_flags != u.add_flags ||
updates[idx].remove_flags != u.remove_flags)) {
@@ -599,24 +581,19 @@ mail_index_insert_flag_update(struct mai
/* insert new update */
tmp_update = u;
tmp_update.uid2 = updates[idx].uid1 - 1;
- move = 0;
} else {
/* split existing update from beginning */
tmp_update = updates[idx];
tmp_update.uid2 = u.uid1 - 1;
updates[idx].uid1 = u.uid1;
- move = 1;
}
i_assert(tmp_update.uid1 <= tmp_update.uid2);
i_assert(updates[idx].uid1 <= updates[idx].uid2);
- if (mail_transaction_update_want_add(t, &tmp_update)) {
- array_insert(&t->updates, idx, &tmp_update, 1);
- updates = array_get_modifiable(&t->updates,
- &count);
- idx += move;
- }
+ array_insert(&t->updates, idx, &tmp_update, 1);
+ updates = array_get_modifiable(&t->updates, &count);
+ idx++;
} else if (u.uid1 < updates[idx].uid1) {
updates[idx].uid1 = u.uid1;
}
@@ -632,8 +609,7 @@ mail_index_insert_flag_update(struct mai
i_assert(tmp_update.uid1 <= tmp_update.uid2);
i_assert(updates[idx].uid1 <= updates[idx].uid2);
- if (mail_transaction_update_want_add(t, &tmp_update))
- array_insert(&t->updates, idx, &tmp_update, 1);
+ array_insert(&t->updates, idx, &tmp_update, 1);
updates = array_get_modifiable(&t->updates, &count);
}
@@ -650,7 +626,6 @@ mail_index_insert_flag_update(struct mai
/* we can remove this update completely */
array_delete(&t->updates, idx, 1);
updates = array_get_modifiable(&t->updates, &count);
- idx--;
}
if (u.uid1 > u.uid2) {
@@ -664,12 +639,29 @@ mail_index_insert_flag_update(struct mai
if (u.uid1 <= u.uid2) {
i_assert(idx == 0 || updates[idx-1].uid2 < u.uid1);
i_assert(idx == count || updates[idx].uid1 > u.uid2);
- if (mail_transaction_update_want_add(t, &u)) {
- array_insert(&t->updates, idx, &u, 1);
- count++;
- }
- }
+ array_insert(&t->updates, idx, &u, 1);
+ }
+ updates = array_get_modifiable(&t->updates, &count);
t->last_update_idx = idx == count ? count-1 : idx;
+
+ /* merge everything */
+ idx = first_idx == 0 ? 0 : first_idx - 1;
+ max = I_MIN(t->last_update_idx + 1, count);
+ for (; idx < max; ) {
+ if (updates[idx].uid2 + 1 == updates[idx+1].uid1 &&
+ updates[idx].add_flags == updates[idx+1].add_flags &&
+ updates[idx].remove_flags == updates[idx+1].remove_flags) {
+ /* merge */
+ updates[idx].uid2 = updates[idx+1].uid2;
+ array_delete(&t->updates, idx + 1, 1);
+ max--;
+ if (t->last_update_idx > idx)
+ t->last_update_idx--;
+ updates = array_get_modifiable(&t->updates, &count);
+ } else {
+ idx++;
+ }
+ }
}
static void mail_index_record_modify_flags(struct mail_index_record *rec,
@@ -717,6 +709,9 @@ void mail_index_update_flags_range(struc
i_assert(seq1 <= seq2 && seq1 > 0);
i_assert(seq2 <= mail_index_view_get_messages_count(t->view));
+ if ((t->flags & MAIL_INDEX_TRANSACTION_FLAG_AVOID_FLAG_UPDATES) != 0)
+ t->drop_unnecessary_flag_updates = TRUE;
+
memset(&u, 0, sizeof(u));
u.uid1 = seq1;
u.uid2 = seq2;
@@ -727,17 +722,20 @@ void mail_index_update_flags_range(struc
u.remove_flags = ~flags & MAIL_INDEX_FLAGS_MASK;
break;
case MODIFY_ADD:
+ if (flags == 0)
+ return;
u.add_flags = flags;
break;
case MODIFY_REMOVE:
+ if (flags == 0)
+ return;
u.remove_flags = flags;
break;
}
if (!array_is_created(&t->updates)) {
i_array_init(&t->updates, 256);
- if (mail_transaction_update_want_add(t, &u))
- array_append(&t->updates, &u, 1);
+ array_append(&t->updates, &u, 1);
return;
}
@@ -752,8 +750,7 @@ void mail_index_update_flags_range(struc
(t->last_update_idx + 1 == count ||
last_update[1].uid1 > seq2)) {
/* we can just update the UID range */
- if (mail_transaction_update_want_add(t, &u))
- last_update->uid2 = seq2;
+ last_update->uid2 = seq2;
return;
}
} else if (seq1 > last_update->uid2) {
@@ -763,12 +760,9 @@ void mail_index_update_flags_range(struc
}
}
- if (t->last_update_idx == count) {
- if (mail_transaction_update_want_add(t, &u))
- array_append(&t->updates, &u, 1);
- else if (t->last_update_idx > 0)
- t->last_update_idx--;
- } else {
+ if (t->last_update_idx == count)
+ array_append(&t->updates, &u, 1);
+ else {
i_assert(t->last_update_idx < count);
/* slow path */
More information about the dovecot-cvs
mailing list