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