changeset 7128:98788fdcc3a6 HEAD

When syncing a mailbox, sync the view internally first completely and just get a list of messages that have changed. Then just have mailbox_sync_next() return flag updates from that list. This avoids duplicate notifications and also fixes some bugs in previous implementation. MAILBOX_SYNC_TYPE_KEYWORDS no longer exists, keyword changes are included in MAILBOX_SYNC_TYPE_FLAGS.
author Timo Sirainen <tss@iki.fi>
date Sun, 06 Jan 2008 11:04:07 +0200
parents 010485455f75
children 0c1859ca8ee9
files src/imap/imap-sync.c src/lib-storage/index/index-storage.h src/lib-storage/index/index-sync-changes.c src/lib-storage/index/index-sync-changes.h src/lib-storage/index/index-sync.c src/lib-storage/index/maildir/maildir-sync-index.c src/lib-storage/index/mbox/mbox-sync-update.c src/lib-storage/index/mbox/mbox-sync.c src/lib-storage/mail-storage.h
diffstat 9 files changed, 83 insertions(+), 97 deletions(-) [+]
line wrap: on
line diff
--- a/src/imap/imap-sync.c	Sun Jan 06 11:00:44 2008 +0200
+++ b/src/imap/imap-sync.c	Sun Jan 06 11:04:07 2008 +0200
@@ -146,7 +146,6 @@
 
 		switch (ctx->sync_rec.type) {
 		case MAILBOX_SYNC_TYPE_FLAGS:
-		case MAILBOX_SYNC_TYPE_KEYWORDS:
 			if (ctx->seq == 0)
 				ctx->seq = ctx->sync_rec.seq1;
 
--- a/src/lib-storage/index/index-storage.h	Sun Jan 06 11:00:44 2008 +0200
+++ b/src/lib-storage/index/index-storage.h	Sun Jan 06 11:04:07 2008 +0200
@@ -136,7 +136,7 @@
 			      struct mailbox_status *status_r);
 
 int index_storage_sync(struct mailbox *box, enum mailbox_sync_flags flags);
-
+enum mailbox_sync_type index_sync_type_convert(enum mail_index_sync_type type);
 void index_storage_get_status(struct mailbox *box,
 			      enum mailbox_status_items items,
 			      struct mailbox_status *status_r);
--- a/src/lib-storage/index/index-sync-changes.c	Sun Jan 06 11:00:44 2008 +0200
+++ b/src/lib-storage/index/index-sync-changes.c	Sun Jan 06 11:04:07 2008 +0200
@@ -163,7 +163,7 @@
 void index_sync_changes_apply(struct index_sync_changes_context *ctx,
 			      pool_t pool, uint8_t *flags,
 			      ARRAY_TYPE(keyword_indexes) *keywords,
-			      enum mailbox_sync_type *sync_type_r)
+			      enum mail_index_sync_type *sync_type_r)
 {
 	const struct mail_index_sync_rec *syncs;
 	unsigned int i, count;
@@ -174,7 +174,7 @@
 		switch (syncs[i].type) {
 		case MAIL_INDEX_SYNC_TYPE_FLAGS:
 			mail_index_sync_flags_apply(&syncs[i], flags);
-			sync_type |= MAILBOX_SYNC_TYPE_FLAGS;
+			sync_type |= MAIL_INDEX_SYNC_TYPE_FLAGS;
 			break;
 		case MAIL_INDEX_SYNC_TYPE_KEYWORD_ADD:
 		case MAIL_INDEX_SYNC_TYPE_KEYWORD_REMOVE:
@@ -190,7 +190,7 @@
 					     I_MIN(10, count - i));
 			}
 			if (mail_index_sync_keywords_apply(&syncs[i], keywords))
-				sync_type |= MAILBOX_SYNC_TYPE_KEYWORDS;
+				sync_type |= syncs[i].type;
 			break;
 		default:
 			break;
--- a/src/lib-storage/index/index-sync-changes.h	Sun Jan 06 11:00:44 2008 +0200
+++ b/src/lib-storage/index/index-sync-changes.h	Sun Jan 06 11:04:07 2008 +0200
@@ -22,6 +22,6 @@
 void index_sync_changes_apply(struct index_sync_changes_context *ctx,
 			      pool_t pool, uint8_t *flags,
 			      ARRAY_TYPE(keyword_indexes) *keywords,
-			      enum mailbox_sync_type *sync_type_r);
+			      enum mail_index_sync_type *sync_type_r);
 
 #endif
--- a/src/lib-storage/index/index-sync.c	Sun Jan 06 11:00:44 2008 +0200
+++ b/src/lib-storage/index/index-sync.c	Sun Jan 06 11:04:07 2008 +0200
@@ -12,9 +12,9 @@
 	struct mail_index_view_sync_ctx *sync_ctx;
 	uint32_t messages_count;
 
+	ARRAY_TYPE(seq_range) flag_updates;
 	const ARRAY_TYPE(seq_range) *expunges;
-	unsigned int expunge_pos;
-	uint32_t last_seq1, last_seq2;
+	unsigned int flag_update_pos, expunge_pos;
 
 	bool failed;
 };
@@ -93,6 +93,41 @@
 	}
 }
 
+static void index_view_sync_recs_get(struct index_mailbox_sync_context *ctx)
+{
+	struct mail_index_view_sync_rec sync;
+	uint32_t seq1, seq2;
+
+	i_array_init(&ctx->flag_updates, 128);
+	while (mail_index_view_sync_next(ctx->sync_ctx, &sync)) {
+		switch (sync.type) {
+		case MAIL_INDEX_SYNC_TYPE_APPEND:
+			/* not interested */
+			break;
+		case MAIL_INDEX_SYNC_TYPE_EXPUNGE:
+			/* later */
+			break;
+		case MAIL_INDEX_SYNC_TYPE_FLAGS:
+		case MAIL_INDEX_SYNC_TYPE_KEYWORD_ADD:
+		case MAIL_INDEX_SYNC_TYPE_KEYWORD_REMOVE:
+		case MAIL_INDEX_SYNC_TYPE_KEYWORD_RESET:
+			if (mail_index_lookup_seq_range(ctx->ibox->view,
+							sync.uid1, sync.uid2,
+							&seq1, &seq2)) {
+				seq_range_array_add_range(&ctx->flag_updates,
+							  seq1, seq2);
+			}
+			break;
+		}
+	}
+
+	/* remove expunged messages from flag updates */
+	if (ctx->expunges != NULL) {
+		seq_range_array_remove_seq_range(&ctx->flag_updates,
+						 ctx->expunges);
+	}
+}
+
 struct mailbox_sync_context *
 index_mailbox_sync_init(struct mailbox *box, enum mailbox_sync_flags flags,
 			bool failed)
@@ -133,58 +168,10 @@
 						  &ctx->expunges);
 		ctx->expunge_pos = array_count(ctx->expunges);
 	}
+	index_view_sync_recs_get(ctx);
 	return &ctx->ctx;
 }
 
-static bool sync_rec_check_skips(struct index_mailbox_sync_context *ctx,
-				 struct mailbox_sync_rec *sync_rec)
-{
-	uint32_t seq, new_seq1, new_seq2;
-
-	if (sync_rec->seq1 >= ctx->last_seq1 &&
-	    sync_rec->seq1 <= ctx->last_seq2)
-		new_seq1 = ctx->last_seq2 + 1;
-	else
-		new_seq1 = sync_rec->seq1;
-	if (sync_rec->seq2 >= ctx->last_seq1 &&
-	    sync_rec->seq2 <= ctx->last_seq2)
-		new_seq2 = ctx->last_seq1 - 1;
-	else
-		new_seq2 = sync_rec->seq2;
-
-	if (new_seq1 > new_seq2)
-		return FALSE;
-
-	ctx->last_seq1 = sync_rec->seq1;
-	ctx->last_seq2 = sync_rec->seq2;
-
-	sync_rec->seq1 = new_seq1;
-	sync_rec->seq2 = new_seq2;
-
-	/* FIXME: we're only skipping messages from the beginning and from
-	   the end. we should skip also the middle ones. This takes care of
-	   the most common repeats though. */
-	if (ctx->expunges != NULL) {
-		/* skip expunged messages from the beginning and the end */
-		for (seq = sync_rec->seq1; seq <= sync_rec->seq2; seq++) {
-			if (!seq_range_exists(ctx->expunges, seq))
-				break;
-		}
-		if (seq > sync_rec->seq2) {
-			/* everything skipped */
-			return FALSE;
-		}
-		sync_rec->seq1 = seq;
-
-		for (seq = sync_rec->seq2; seq >= sync_rec->seq1; seq--) {
-			if (!seq_range_exists(ctx->expunges, seq))
-				break;
-		}
-		sync_rec->seq2 = seq;
-	}
-	return TRUE;
-}
-
 static int
 index_mailbox_sync_next_expunge(struct index_mailbox_sync_context *ctx,
 				struct mailbox_sync_rec *sync_rec_r)
@@ -214,41 +201,21 @@
 {
 	struct index_mailbox_sync_context *ctx =
 		(struct index_mailbox_sync_context *)_ctx;
-	struct mail_index_view_sync_rec sync;
+	const struct seq_range *flag_updates;
+	unsigned int count;
 
 	if (ctx->failed)
 		return FALSE;
 
-	while (mail_index_view_sync_next(ctx->sync_ctx, &sync)) {
-		switch (sync.type) {
-		case MAIL_INDEX_SYNC_TYPE_APPEND:
-			/* not interested */
-			break;
-		case MAIL_INDEX_SYNC_TYPE_EXPUNGE:
-			/* later */
-			break;
-		case MAIL_INDEX_SYNC_TYPE_FLAGS:
-		case MAIL_INDEX_SYNC_TYPE_KEYWORD_ADD:
-		case MAIL_INDEX_SYNC_TYPE_KEYWORD_REMOVE:
-		case MAIL_INDEX_SYNC_TYPE_KEYWORD_RESET:
-			/* FIXME: hide the flag updates for expunged messages */
-			mail_index_lookup_seq_range(ctx->ibox->view,
-						    sync.uid1, sync.uid2,
-						    &sync_rec_r->seq1,
-						    &sync_rec_r->seq2);
-			if (sync_rec_r->seq1 == 0)
-				break;
+	flag_updates = array_get(&ctx->flag_updates, &count);
+	if (ctx->flag_update_pos < count) {
+		sync_rec_r->type = MAILBOX_SYNC_TYPE_FLAGS;
+		sync_rec_r->seq1 = flag_updates[ctx->flag_update_pos].seq1;
+		sync_rec_r->seq2 = flag_updates[ctx->flag_update_pos].seq2;
+		ctx->flag_update_pos++;
+		return 1;
+	}
 
-			if (!sync_rec_check_skips(ctx, sync_rec_r))
-				break;
-
-			sync_rec_r->type =
-				sync.type == MAIL_INDEX_SYNC_TYPE_FLAGS ?
-				MAILBOX_SYNC_TYPE_FLAGS :
-				MAILBOX_SYNC_TYPE_KEYWORDS;
-			return 1;
-		}
-	}
 	return index_mailbox_sync_next_expunge(ctx, sync_rec_r);
 }
 
@@ -353,6 +320,7 @@
 	if (ret == 0 && status_items != 0)
 		mailbox_get_status(_ctx->box, status_items, status_r);
 
+	array_free(&ctx->flag_updates);
 	i_free(ctx);
 	return ret;
 }
@@ -389,3 +357,17 @@
 	}
 	return TRUE;
 }
+
+enum mailbox_sync_type index_sync_type_convert(enum mail_index_sync_type type)
+{
+	enum mailbox_sync_type ret = 0;
+
+	if ((type & MAIL_INDEX_SYNC_TYPE_EXPUNGE) != 0)
+		ret |= MAILBOX_SYNC_TYPE_EXPUNGE;
+	if ((type & (MAIL_INDEX_SYNC_TYPE_FLAGS |
+		     MAIL_INDEX_SYNC_TYPE_KEYWORD_ADD |
+		     MAIL_INDEX_SYNC_TYPE_KEYWORD_REMOVE |
+		     MAIL_INDEX_SYNC_TYPE_KEYWORD_RESET)) != 0)
+		ret |= MAILBOX_SYNC_TYPE_FLAGS;
+	return ret;
+}
--- a/src/lib-storage/index/maildir/maildir-sync-index.c	Sun Jan 06 11:00:44 2008 +0200
+++ b/src/lib-storage/index/maildir/maildir-sync-index.c	Sun Jan 06 11:04:07 2008 +0200
@@ -65,7 +65,7 @@
 {
 	struct mailbox *box = &mbox->ibox.box;
 	const char *dir, *fname, *newfname, *newpath;
-	enum mailbox_sync_type sync_type;
+	enum mail_index_sync_type sync_type;
 	uint8_t flags8;
 
 	fname = strrchr(path, '/');
@@ -88,8 +88,10 @@
 					      ctx->flags, &ctx->keywords);
 	newpath = t_strconcat(dir, newfname, NULL);
 	if (rename(path, newpath) == 0) {
-		if (box->v.sync_notify != NULL)
-			box->v.sync_notify(box, ctx->uid, sync_type);
+		if (box->v.sync_notify != NULL) {
+			box->v.sync_notify(box, ctx->uid,
+					   index_sync_type_convert(sync_type));
+		}
 		ctx->changed = TRUE;
 		return 1;
 	}
--- a/src/lib-storage/index/mbox/mbox-sync-update.c	Sun Jan 06 11:00:44 2008 +0200
+++ b/src/lib-storage/index/mbox/mbox-sync-update.c	Sun Jan 06 11:04:07 2008 +0200
@@ -376,7 +376,7 @@
 static void mbox_sync_update_header_real(struct mbox_sync_mail_context *ctx)
 {
 	uint8_t old_flags;
-	enum mailbox_sync_type sync_type;
+	enum mail_index_sync_type sync_type;
 
 	i_assert(ctx->mail.uid != 0 || ctx->mail.pseudo);
 
@@ -390,7 +390,9 @@
 	if ((old_flags & XSTATUS_FLAGS_MASK) !=
 	    (ctx->mail.flags & XSTATUS_FLAGS_MASK))
 		mbox_sync_update_xstatus(ctx);
-	if ((sync_type & MAILBOX_SYNC_TYPE_KEYWORDS) != 0)
+	if ((sync_type & (MAIL_INDEX_SYNC_TYPE_KEYWORD_ADD |
+			  MAIL_INDEX_SYNC_TYPE_KEYWORD_REMOVE |
+			  MAIL_INDEX_SYNC_TYPE_KEYWORD_RESET)) != 0)
 		mbox_sync_update_xkeywords(ctx);
 
 	if (!ctx->sync_ctx->mbox->ibox.keep_recent)
--- a/src/lib-storage/index/mbox/mbox-sync.c	Sun Jan 06 11:00:44 2008 +0200
+++ b/src/lib-storage/index/mbox/mbox-sync.c	Sun Jan 06 11:04:07 2008 +0200
@@ -347,7 +347,7 @@
 		   sync records are automatically applied to rec->flags at the
 		   end of index syncing, so calculate those new flags first */
 		struct mbox_sync_mail idx_mail;
-		enum mailbox_sync_type sync_type;
+		enum mail_index_sync_type sync_type;
 
 		memset(&idx_mail, 0, sizeof(idx_mail));
 		idx_mail.flags = rec->flags & ~MAIL_RECENT;
@@ -361,8 +361,10 @@
 					 sync_ctx->mail_keyword_pool,
 					 &idx_mail.flags, &idx_mail.keywords,
 					 &sync_type);
-		if (sync_type != 0 && box->v.sync_notify != NULL)
-			box->v.sync_notify(box, rec->uid, sync_type);
+		if (sync_type != 0 && box->v.sync_notify != NULL) {
+			box->v.sync_notify(box, rec->uid,
+					   index_sync_type_convert(sync_type));
+		}
 
 		if ((idx_mail.flags & MAIL_INDEX_MAIL_FLAG_DIRTY) != 0) {
 			/* flags are dirty. ignore whatever was in the mbox,
--- a/src/lib-storage/mail-storage.h	Sun Jan 06 11:00:44 2008 +0200
+++ b/src/lib-storage/mail-storage.h	Sun Jan 06 11:04:07 2008 +0200
@@ -140,8 +140,7 @@
 
 enum mailbox_sync_type {
 	MAILBOX_SYNC_TYPE_EXPUNGE	= 0x01,
-	MAILBOX_SYNC_TYPE_FLAGS		= 0x02,
-	MAILBOX_SYNC_TYPE_KEYWORDS	= 0x04
+	MAILBOX_SYNC_TYPE_FLAGS		= 0x02
 };
 
 struct message_part;