dovecot-2.2: lib-storage: Fixes to handling private message flag...

dovecot at dovecot.org dovecot at dovecot.org
Tue Jul 31 19:32:19 EEST 2012


details:   http://hg.dovecot.org/dovecot-2.2/rev/c3a781ef0aeb
changeset: 14738:c3a781ef0aeb
user:      Timo Sirainen <tss at iki.fi>
date:      Tue Jul 31 19:32:03 2012 +0300
description:
lib-storage: Fixes to handling private message flag indexes.

diffstat:

 src/lib-storage/index/index-search.c   |  56 ++++++++++------------
 src/lib-storage/index/index-status.c   |  81 ++++++++++++++++++++++++++++-----
 src/lib-storage/index/index-sync-pvt.c |   9 +++
 src/lib-storage/index/index-sync.c     |   7 +-
 4 files changed, 107 insertions(+), 46 deletions(-)

diffs (282 lines):

diff -r 1af9d08e67d7 -r c3a781ef0aeb src/lib-storage/index/index-search.c
--- a/src/lib-storage/index/index-search.c	Tue Jul 31 02:46:21 2012 +0300
+++ b/src/lib-storage/index/index-search.c	Tue Jul 31 19:32:03 2012 +0300
@@ -151,10 +151,7 @@
 static bool
 index_search_get_pvt(struct index_search_context *ctx, uint32_t uid)
 {
-	if (ctx->box->view_pvt == NULL) {
-		/* no private view (set by view syncing) -> no private flags */
-		return FALSE;
-	}
+	index_transaction_init_pvt(ctx->mail_ctx.transaction);
 
 	if (ctx->pvt_uid == uid)
 		return ctx->pvt_seq != 0;
@@ -183,12 +180,17 @@
 		if ((arg->value.flags & MAIL_RECENT) != 0 &&
 		    index_mailbox_is_recent(ctx->box, rec->uid))
 			flags |= MAIL_RECENT;
-		if (index_search_get_pvt(ctx, rec->uid)) {
+		if (ctx->box->view_pvt == NULL) {
+			/* no private view (set by view syncing) ->
+			   no private flags */
+		} else {
 			pvt_flags_mask = mailbox_get_private_flags_mask(ctx->box);
 			flags &= ~pvt_flags_mask;
-			rec = mail_index_lookup(ctx->mail_ctx.transaction->view_pvt,
-						ctx->pvt_seq);
-			flags |= rec->flags & pvt_flags_mask;
+			if (index_search_get_pvt(ctx, rec->uid)) {
+				rec = mail_index_lookup(ctx->mail_ctx.transaction->view_pvt,
+							ctx->pvt_seq);
+				flags |= rec->flags & pvt_flags_mask;
+			}
 		}
 		return (flags & arg->value.flags) == arg->value.flags;
 	case SEARCH_KEYWORDS:
@@ -892,20 +894,14 @@
 				  struct mail_search_arg *args,
 				  uint32_t *seq1, uint32_t *seq2)
 {
-	const struct mail_index_header *hdr_seen, *hdr_del, *hdr_pvt;
+	const struct mail_index_header *hdr;
 	enum mail_flags pvt_flags_mask;
 
-	hdr_seen = hdr_del = mail_index_get_header(ctx->view);
-
-	if (ctx->box->view_pvt != NULL) {
-		pvt_flags_mask = mailbox_get_private_flags_mask(ctx->box);
-		index_transaction_init_pvt(ctx->mail_ctx.transaction);
-		hdr_pvt = mail_index_get_header(ctx->mail_ctx.transaction->view_pvt);
-		if ((pvt_flags_mask & MAIL_SEEN) != 0)
-			hdr_seen = hdr_pvt;
-		if ((pvt_flags_mask & MAIL_DELETED) != 0)
-			hdr_del = hdr_pvt;
-	}
+	hdr = mail_index_get_header(ctx->view);
+	/* we can't trust that private view's header is fully up to date,
+	   so do this optimization only for non-private flags */
+	pvt_flags_mask = ctx->box->view_pvt == NULL ? 0 :
+		mailbox_get_private_flags_mask(ctx->box);
 
 	for (; args != NULL; args = args->next) {
 		if (args->type != SEARCH_FLAGS) {
@@ -915,13 +911,13 @@
 			}
 			continue;
 		}
-		if ((args->value.flags & MAIL_SEEN) != 0) {
+		if ((args->value.flags & MAIL_SEEN) != 0 &&
+		    (pvt_flags_mask & MAIL_SEEN) == 0) {
 			/* SEEN with 0 seen? */
-			if (!args->match_not && hdr_seen->seen_messages_count == 0)
+			if (!args->match_not && hdr->seen_messages_count == 0)
 				return FALSE;
 
-			if (hdr_seen->seen_messages_count ==
-			    hdr_seen->messages_count) {
+			if (hdr->seen_messages_count == hdr->messages_count) {
 				/* UNSEEN with all seen? */
 				if (args->match_not)
 					return FALSE;
@@ -931,17 +927,17 @@
 			} else if (args->match_not) {
 				/* UNSEEN with lowwater limiting */
 				search_limit_lowwater(ctx,
-                                	hdr_seen->first_unseen_uid_lowwater, seq1);
+                                	hdr->first_unseen_uid_lowwater, seq1);
 			}
 		}
-		if ((args->value.flags & MAIL_DELETED) != 0) {
+		if ((args->value.flags & MAIL_DELETED) != 0 &&
+		    (pvt_flags_mask & MAIL_DELETED) == 0) {
 			/* DELETED with 0 deleted? */
 			if (!args->match_not &&
-			    hdr_del->deleted_messages_count == 0)
+			    hdr->deleted_messages_count == 0)
 				return FALSE;
 
-			if (hdr_del->deleted_messages_count ==
-			    hdr_del->messages_count) {
+			if (hdr->deleted_messages_count == hdr->messages_count) {
 				/* UNDELETED with all deleted? */
 				if (args->match_not)
 					return FALSE;
@@ -951,7 +947,7 @@
 			} else if (!args->match_not) {
 				/* DELETED with lowwater limiting */
 				search_limit_lowwater(ctx,
-                                	hdr_del->first_deleted_uid_lowwater, seq1);
+                                	hdr->first_deleted_uid_lowwater, seq1);
 			}
 		}
 	}
diff -r 1af9d08e67d7 -r c3a781ef0aeb src/lib-storage/index/index-status.c
--- a/src/lib-storage/index/index-status.c	Tue Jul 31 02:46:21 2012 +0300
+++ b/src/lib-storage/index/index-status.c	Tue Jul 31 19:32:03 2012 +0300
@@ -43,18 +43,72 @@
 	return 0;
 }
 
+static unsigned int index_storage_count_pvt_unseen(struct mailbox *box)
+{
+	const struct mail_index_record *pvt_rec;
+	uint32_t shared_seq, pvt_seq, shared_count, pvt_count;
+	uint32_t shared_uid;
+	unsigned int unseen_count = 0;
+
+	/* we can't trust private index to be up to date. we'll need to go
+	   through the shared index and for each existing mail lookup its
+	   private flags. if a mail doesn't exist in private index then its
+	   flags are 0. */
+	shared_count = mail_index_view_get_messages_count(box->view);
+	pvt_count = mail_index_view_get_messages_count(box->view_pvt);
+	shared_seq = pvt_seq = 1;
+	while (shared_seq <= shared_count && pvt_seq <= pvt_count) {
+		mail_index_lookup_uid(box->view, shared_seq, &shared_uid);
+		pvt_rec = mail_index_lookup(box->view_pvt, pvt_seq);
+
+		if (shared_uid == pvt_rec->uid) {
+			if ((pvt_rec->flags & MAIL_SEEN) == 0)
+				unseen_count++;
+			shared_seq++; pvt_seq++;
+		} else if (shared_uid < pvt_rec->uid) {
+			shared_seq++;
+		} else {
+			pvt_seq++;
+		}
+	}
+	unseen_count += (shared_count+1) - shared_seq;
+	return unseen_count;
+}
+
+static uint32_t index_storage_find_first_pvt_unseen_seq(struct mailbox *box)
+{
+	const struct mail_index_header *pvt_hdr;
+	const struct mail_index_record *pvt_rec;
+	uint32_t pvt_seq, pvt_count, shared_seq, seq2;
+
+	pvt_count = mail_index_view_get_messages_count(box->view_pvt);
+	mail_index_lookup_first(box->view_pvt, 0, MAIL_SEEN, &pvt_seq);
+	for (; pvt_seq <= pvt_count; pvt_seq++) {
+		pvt_rec = mail_index_lookup(box->view_pvt, pvt_seq);
+		if ((pvt_rec->flags & MAIL_SEEN) == 0 &&
+		    mail_index_lookup_seq(box->view, pvt_rec->uid, &shared_seq))
+			return shared_seq;
+	}
+	/* if shared index has any messages that don't exist in private index,
+	   the first of them is the first unseen message */
+	pvt_hdr = mail_index_get_header(box->view_pvt);
+	if (mail_index_lookup_seq_range(box->view,
+					pvt_hdr->next_uid, (uint32_t)-1,
+					&shared_seq, &seq2))
+		return shared_seq;
+	return 0;
+}
+
 void index_storage_get_open_status(struct mailbox *box,
 				   enum mailbox_status_items items,
 				   struct mailbox_status *status_r)
 {
-	const struct mail_index_header *hdr, *hdr_pvt;
+	const struct mail_index_header *hdr;
 
 	memset(status_r, 0, sizeof(struct mailbox_status));
 
 	/* we can get most of the status items without any trouble */
 	hdr = mail_index_get_header(box->view);
-	hdr_pvt = box->view_pvt == NULL ? NULL :
-		mail_index_get_header(box->view_pvt);
 	status_r->messages = hdr->messages_count;
 	if ((items & STATUS_RECENT) != 0) {
 		/* make sure recent count is set, in case syncing hasn't
@@ -63,13 +117,14 @@
 		status_r->recent = index_mailbox_get_recent_count(box);
 		i_assert(status_r->recent <= status_r->messages);
 	}
-	if (hdr_pvt == NULL ||
-	    (mailbox_get_private_flags_mask(box) & MAIL_SEEN) == 0) {
-		status_r->unseen = hdr->messages_count -
-			hdr->seen_messages_count;
-	} else {
-		status_r->unseen = hdr_pvt->messages_count -
-			hdr_pvt->seen_messages_count;
+	if ((items & STATUS_UNSEEN) != 0) {
+		if (box->view_pvt == NULL ||
+		    (mailbox_get_private_flags_mask(box) & MAIL_SEEN) == 0) {
+			status_r->unseen = hdr->messages_count -
+				hdr->seen_messages_count;
+		} else {
+			status_r->unseen = index_storage_count_pvt_unseen(box);
+		}
 	}
 	status_r->uidvalidity = hdr->uid_validity;
 	status_r->uidnext = hdr->next_uid;
@@ -87,13 +142,13 @@
 	}
 
 	if ((items & STATUS_FIRST_UNSEEN_SEQ) != 0) {
-		if (hdr_pvt == NULL ||
+		if (box->view_pvt == NULL ||
 		    (mailbox_get_private_flags_mask(box) & MAIL_SEEN) == 0) {
 			mail_index_lookup_first(box->view, 0, MAIL_SEEN,
 						&status_r->first_unseen_seq);
 		} else {
-			mail_index_lookup_first(box->view_pvt, 0, MAIL_SEEN,
-						&status_r->first_unseen_seq);
+			status_r->first_unseen_seq =
+				index_storage_find_first_pvt_unseen_seq(box);
 		}
 	}
 	if ((items & STATUS_LAST_CACHED_SEQ) != 0)
diff -r 1af9d08e67d7 -r c3a781ef0aeb src/lib-storage/index/index-sync-pvt.c
--- a/src/lib-storage/index/index-sync-pvt.c	Tue Jul 31 02:46:21 2012 +0300
+++ b/src/lib-storage/index/index-sync-pvt.c	Tue Jul 31 19:32:03 2012 +0300
@@ -178,6 +178,7 @@
 		seq_shared = 1;
 	}
 
+	uid = 0;
 	for (; seq_shared <= count_shared; seq_shared++) {
 		mail_index_lookup_uid(view_shared, seq_shared, &uid);
 		mail_index_append(trans_pvt, uid, &seq_pvt);
@@ -189,6 +190,14 @@
 						 seq_old_pvt, seq_pvt);
 		}
 	}
+
+	if (uid < hdr_shared->next_uid) {
+		mail_index_update_header(trans_pvt,
+			offsetof(struct mail_index_header, next_uid),
+			&hdr_shared->next_uid,
+			sizeof(hdr_shared->next_uid), FALSE);
+	}
+
 	if ((ret = mail_index_sync_commit(&sync_ctx)) < 0)
 		mail_storage_set_index_error(box);
 	mail_index_view_close(&view_shared);
diff -r 1af9d08e67d7 -r c3a781ef0aeb src/lib-storage/index/index-sync.c
--- a/src/lib-storage/index/index-sync.c	Tue Jul 31 02:46:21 2012 +0300
+++ b/src/lib-storage/index/index-sync.c	Tue Jul 31 19:32:03 2012 +0300
@@ -189,9 +189,6 @@
 		return &ctx->ctx;
 	}
 
-	/* sync private index if needed */
-	(void)index_storage_mailbox_sync_pvt(box);
-
 	if ((flags & MAILBOX_SYNC_FLAG_NO_EXPUNGES) != 0)
 		sync_flags |= MAIL_INDEX_VIEW_SYNC_FLAG_NOEXPUNGES;
 
@@ -394,6 +391,10 @@
 	if (array_is_created(&ctx->all_flag_update_uids))
 		array_free(&ctx->all_flag_update_uids);
 
+	/* sync private index if needed. do this last to make sure that all
+	   the new messages are added to the private index, so their flags can
+	   be updated. */
+	(void)index_storage_mailbox_sync_pvt(_ctx->box);
 	i_free(ctx);
 	return ret;
 }


More information about the dovecot-cvs mailing list