changeset 8549:7b16388a3bb0 HEAD

mail_get_flags/keywords() now returns updated values if they've been changed within transaction.
author Timo Sirainen <tss@iki.fi>
date Sun, 14 Dec 2008 07:19:48 +0200
parents 6a6a3bfea547
children 613151990b79
files src/lib-index/mail-index-dummy-view.c src/lib-index/mail-index-transaction-private.h src/lib-index/mail-index-transaction-view.c src/lib-index/mail-index-transaction.c src/lib-index/mail-index-view-private.h src/lib-index/mail-index-view.c src/lib-storage/index/index-mail.c src/lib-storage/index/index-mail.h src/plugins/virtual/virtual-mail.c
diffstat 9 files changed, 210 insertions(+), 74 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-index/mail-index-dummy-view.c	Sun Dec 14 06:51:04 2008 +0200
+++ b/src/lib-index/mail-index-dummy-view.c	Sun Dec 14 07:19:48 2008 +0200
@@ -29,6 +29,7 @@
 	NULL,
 	NULL,
 	NULL,
+	NULL,
 	NULL
 };
 
--- a/src/lib-index/mail-index-transaction-private.h	Sun Dec 14 06:51:04 2008 +0200
+++ b/src/lib-index/mail-index-transaction-private.h	Sun Dec 14 07:19:48 2008 +0200
@@ -100,6 +100,12 @@
 void mail_index_transaction_convert_to_uids(struct mail_index_transaction *t);
 void mail_index_transaction_check_conflicts(struct mail_index_transaction *t);
 
+unsigned int
+mail_index_transaction_get_flag_update_pos(struct mail_index_transaction *t,
+					   unsigned int left_idx,
+					   unsigned int right_idx,
+					   uint32_t seq);
+
 bool mail_index_seq_array_lookup(const ARRAY_TYPE(seq_array) *array,
 				 uint32_t seq, unsigned int *idx_r);
 
--- a/src/lib-index/mail-index-transaction-view.c	Sun Dec 14 06:51:04 2008 +0200
+++ b/src/lib-index/mail-index-transaction-view.c	Sun Dec 14 07:19:48 2008 +0200
@@ -15,8 +15,12 @@
 
 	struct mail_index_map *lookup_map;
 	struct mail_index_header hdr;
+
 	buffer_t *lookup_return_data;
 	uint32_t lookup_prev_seq;
+
+	unsigned int recs_count;
+	struct mail_index_record *recs;
 };
 
 static void tview_close(struct mail_index_view *view)
@@ -29,6 +33,7 @@
 		mail_index_unmap(&tview->lookup_map);
 	if (tview->lookup_return_data != NULL)
 		buffer_free(&tview->lookup_return_data);
+	i_free(tview->recs);
 
 	tview->super->close(view);
 	mail_index_transaction_unref(&t);
@@ -65,6 +70,42 @@
 }
 
 static const struct mail_index_record *
+tview_apply_flag_updates(struct mail_index_view_transaction *tview,
+			 const struct mail_index_record *rec, uint32_t seq)
+{
+	struct mail_index_transaction *t = tview->t;
+	const struct mail_transaction_flag_update *updates;
+	unsigned int idx, count;
+
+	/* see if there are any flag updates */
+	if (seq < t->min_flagupdate_seq || seq > t->max_flagupdate_seq ||
+	    !array_is_created(&t->updates))
+		return rec;
+
+	updates = array_get(&t->updates, &count);
+	idx = mail_index_transaction_get_flag_update_pos(t, 0, count, seq);
+	if (seq < updates[idx].uid1 || seq > updates[idx].uid2)
+		return rec;
+
+	/* yes, we have flag updates. since we can't modify rec directly and
+	   we want to be able to handle multiple mail_index_lookup() calls
+	   without the second one overriding the first one's data, we'll
+	   create a records array and return data from there */
+	if (tview->recs == NULL) {
+		tview->recs_count = t->first_new_seq;
+		tview->recs = i_new(struct mail_index_record,
+				    tview->recs_count);
+	}
+	i_assert(tview->recs_count == t->first_new_seq);
+	i_assert(seq > 0 && seq <= tview->recs_count);
+
+	tview->recs[seq-1] = *rec;
+	tview->recs[seq-1].flags |= updates[idx].add_flags;
+	tview->recs[seq-1].flags &= ~updates[idx].remove_flags;
+	return &tview->recs[seq-1];
+}
+
+static const struct mail_index_record *
 tview_lookup_full(struct mail_index_view *view, uint32_t seq,
 		  struct mail_index_map **map_r, bool *expunged_r)
 {
@@ -81,8 +122,8 @@
 	}
 
 	rec = tview->super->lookup_full(view, seq, map_r, expunged_r);
+	rec = tview_apply_flag_updates(tview, rec, seq);
 
-	/* if we're expunged within this transaction, return 0 */
 	if (array_is_created(&tview->t->expunges) &&
 	    seq_range_exists(&tview->t->expunges, seq))
 		*expunged_r = TRUE;
@@ -190,6 +231,73 @@
 	}
 }
 
+static void keyword_index_add(ARRAY_TYPE(keyword_indexes) *keywords,
+			      unsigned int idx)
+{
+	const unsigned int *indexes;
+	unsigned int i, count;
+
+	indexes = array_get(keywords, &count);
+	for (i = 0; i < count; i++) {
+		if (indexes[i] == idx)
+			return;
+	}
+	array_append(keywords, &idx, 1);
+}
+
+static void keyword_index_remove(ARRAY_TYPE(keyword_indexes) *keywords,
+				 unsigned int idx)
+{
+	const unsigned int *indexes;
+	unsigned int i, count;
+
+	indexes = array_get(keywords, &count);
+	for (i = 0; i < count; i++) {
+		if (indexes[i] == idx) {
+			array_delete(keywords, i, 1);
+			break;
+		}
+	}
+}
+
+static void tview_lookup_keywords(struct mail_index_view *view, uint32_t seq,
+				  ARRAY_TYPE(keyword_indexes) *keyword_idx)
+{
+	struct mail_index_view_transaction *tview =
+		(struct mail_index_view_transaction *)view;
+	struct mail_index_transaction *t = tview->t;
+	const struct mail_index_transaction_keyword_update *updates;
+	unsigned int i, count;
+
+	tview->super->lookup_keywords(view, seq, keyword_idx);
+
+	if (seq < t->min_flagupdate_seq || seq > t->max_flagupdate_seq) {
+		/* no keyword updates for this sequence */
+		return;
+	}
+
+	/* apply any keyword updates in this transaction */
+	if (array_is_created(&t->keyword_resets)) {
+		if (seq_range_exists(&t->keyword_resets, seq))
+			array_clear(keyword_idx);
+	}
+
+	if (array_is_created(&t->keyword_updates))
+		updates = array_get(&t->keyword_updates, &count);
+	else {
+		updates = NULL;
+		count = 0;
+	}
+	for (i = 0; i < count; i++) {
+		if (array_is_created(&updates[i].add_seq) &&
+		    seq_range_exists(&updates[i].add_seq, seq))
+			keyword_index_add(keyword_idx, i);
+		else if (array_is_created(&updates[i].remove_seq) &&
+			 seq_range_exists(&updates[i].remove_seq, seq))
+			keyword_index_remove(keyword_idx, i);
+	}
+}
+
 static struct mail_index_map *
 tview_get_lookup_map(struct mail_index_view_transaction *tview)
 {
@@ -336,6 +444,7 @@
 	tview_lookup_uid,
 	tview_lookup_seq_range,
 	tview_lookup_first,
+	tview_lookup_keywords,
 	tview_lookup_ext_full,
 	tview_get_header_ext,
 	tview_ext_get_reset_id
--- a/src/lib-index/mail-index-transaction.c	Sun Dec 14 06:51:04 2008 +0200
+++ b/src/lib-index/mail-index-transaction.c	Sun Dec 14 07:19:48 2008 +0200
@@ -805,10 +805,11 @@
 	return FALSE;
 }
 
-static uint32_t
-mail_index_find_update_insert_pos(struct mail_index_transaction *t,
-				  unsigned int left_idx, unsigned int right_idx,
-				  uint32_t seq)
+unsigned int
+mail_index_transaction_get_flag_update_pos(struct mail_index_transaction *t,
+					   unsigned int left_idx,
+					   unsigned int right_idx,
+					   uint32_t seq)
 {
 	const struct mail_transaction_flag_update *updates;
 	unsigned int idx, count;
@@ -1038,8 +1039,8 @@
 			first_idx = 0;
 			count = t->last_update_idx + 1;
 		}
-		idx = mail_index_find_update_insert_pos(t, first_idx, count,
-							u.uid1);
+		idx = mail_index_transaction_get_flag_update_pos(t, first_idx,
+								 count, u.uid1);
 		mail_index_insert_flag_update(t, u, idx);
 	}
 }
@@ -1567,7 +1568,7 @@
 		return ret;
 
 	updates = array_get_modifiable(&t->updates, &count);
-	i = mail_index_find_update_insert_pos(t, 0, count, seq);
+	i = mail_index_transaction_get_flag_update_pos(t, 0, count, seq);
 	if (i < count && updates[i].uid1 <= seq && updates[i].uid2 >= seq) {
 		/* exists */
 		ret = TRUE;
--- a/src/lib-index/mail-index-view-private.h	Sun Dec 14 06:51:04 2008 +0200
+++ b/src/lib-index/mail-index-view-private.h	Sun Dec 14 07:19:48 2008 +0200
@@ -26,6 +26,8 @@
 	void (*lookup_first)(struct mail_index_view *view,
 			     enum mail_flags flags, uint8_t flags_mask,
 			     uint32_t *seq_r);
+	void (*lookup_keywords)(struct mail_index_view *view, uint32_t seq,
+				ARRAY_TYPE(keyword_indexes) *keyword_idx);
 	void (*lookup_ext_full)(struct mail_index_view *view, uint32_t seq,
 				uint32_t ext_id, struct mail_index_map **map_r,
 				const void **data_r, bool *expunged_r);
--- a/src/lib-index/mail-index-view.c	Sun Dec 14 06:51:04 2008 +0200
+++ b/src/lib-index/mail-index-view.c	Sun Dec 14 07:19:48 2008 +0200
@@ -333,6 +333,62 @@
 }
 
 static void
+mail_index_data_lookup_keywords(struct mail_index_map *map,
+				const unsigned char *data,
+				ARRAY_TYPE(keyword_indexes) *keyword_idx)
+{
+	const unsigned int *keyword_idx_map;
+	unsigned int i, j, keyword_count, index_idx;
+	uint32_t idx;
+	uint16_t record_size;
+
+	array_clear(keyword_idx);
+	if (data == NULL) {
+		/* no keywords at all in index */
+		return;
+	}
+	(void)mail_index_ext_get_size(NULL, map->index->keywords_ext_id,
+				      map, NULL, &record_size, NULL);
+
+	/* keyword_idx_map[] contains file => index keyword mapping */
+	if (!array_is_created(&map->keyword_idx_map))
+		return;
+
+	keyword_idx_map = array_get(&map->keyword_idx_map, &keyword_count);
+	for (i = 0, idx = 0; i < record_size; i++) {
+		/* first do the quick check to see if there's keywords at all */
+		if (data[i] == 0)
+			continue;
+
+		idx = i * CHAR_BIT;
+		for (j = 0; j < CHAR_BIT; j++, idx++) {
+			if ((data[i] & (1 << j)) == 0)
+				continue;
+
+			if (idx >= keyword_count) {
+				/* extra bits set in keyword bytes.
+				   shouldn't happen, but just ignore. */
+				break;
+			}
+
+			index_idx = keyword_idx_map[idx];
+			array_append(keyword_idx, &index_idx, 1);
+		}
+	}
+}
+
+static void view_lookup_keywords(struct mail_index_view *view, uint32_t seq,
+				 ARRAY_TYPE(keyword_indexes) *keyword_idx)
+{
+	struct mail_index_map *map;
+	const void *data;
+
+	mail_index_lookup_ext_full(view, seq, view->index->keywords_ext_id,
+				   &map, &data, NULL);
+	mail_index_data_lookup_keywords(map, data, keyword_idx);
+}
+
+static void
 view_lookup_ext_full(struct mail_index_view *view, uint32_t seq,
 		     uint32_t ext_id, struct mail_index_map **map_r,
 		     const void **data_r, bool *expunged_r)
@@ -442,51 +498,6 @@
 	return expunged;
 }
 
-static void
-mail_index_data_lookup_keywords(struct mail_index_map *map,
-				const unsigned char *data,
-				ARRAY_TYPE(keyword_indexes) *keyword_idx)
-{
-	const unsigned int *keyword_idx_map;
-	unsigned int i, j, keyword_count, index_idx;
-	uint32_t idx;
-	uint16_t record_size;
-
-	array_clear(keyword_idx);
-	if (data == NULL) {
-		/* no keywords at all in index */
-		return;
-	}
-	(void)mail_index_ext_get_size(NULL, map->index->keywords_ext_id,
-				      map, NULL, &record_size, NULL);
-
-	/* keyword_idx_map[] contains file => index keyword mapping */
-	if (!array_is_created(&map->keyword_idx_map))
-		return;
-
-	keyword_idx_map = array_get(&map->keyword_idx_map, &keyword_count);
-	for (i = 0, idx = 0; i < record_size; i++) {
-		/* first do the quick check to see if there's keywords at all */
-		if (data[i] == 0)
-			continue;
-
-		idx = i * CHAR_BIT;
-		for (j = 0; j < CHAR_BIT; j++, idx++) {
-			if ((data[i] & (1 << j)) == 0)
-				continue;
-
-			if (idx >= keyword_count) {
-				/* extra bits set in keyword bytes.
-				   shouldn't happen, but just ignore. */
-				break;
-			}
-
-			index_idx = keyword_idx_map[idx];
-			array_append(keyword_idx, &index_idx, 1);
-		}
-	}
-}
-
 void mail_index_map_lookup_keywords(struct mail_index_map *map, uint32_t seq,
 				    ARRAY_TYPE(keyword_indexes) *keyword_idx)
 {
@@ -509,12 +520,7 @@
 void mail_index_lookup_keywords(struct mail_index_view *view, uint32_t seq,
 				ARRAY_TYPE(keyword_indexes) *keyword_idx)
 {
-	struct mail_index_map *map;
-	const void *data;
-
-	mail_index_lookup_ext_full(view, seq, view->index->keywords_ext_id,
-				   &map, &data, NULL);
-	mail_index_data_lookup_keywords(map, data, keyword_idx);
+	view->v.lookup_keywords(view, seq, keyword_idx);
 }
 
 void mail_index_lookup_uid(struct mail_index_view *view, uint32_t seq,
@@ -625,6 +631,7 @@
 	view_lookup_uid,
 	view_lookup_seq_range,
 	view_lookup_first,
+	view_lookup_keywords,
 	view_lookup_ext_full,
 	view_get_header_ext,
 	view_ext_get_reset_id
--- a/src/lib-storage/index/index-mail.c	Sun Dec 14 06:51:04 2008 +0200
+++ b/src/lib-storage/index/index-mail.c	Sun Dec 14 07:19:48 2008 +0200
@@ -122,12 +122,17 @@
 enum mail_flags index_mail_get_flags(struct mail *_mail)
 {
 	struct index_mail *mail = (struct index_mail *)_mail;
-	struct index_mail_data *data = &mail->data;
+	const struct mail_index_record *rec;
+	enum mail_flags flags;
+
+	rec = mail_index_lookup(mail->trans->trans_view, _mail->seq);
+	flags = rec->flags & (MAIL_FLAGS_NONRECENT |
+			      MAIL_INDEX_MAIL_FLAG_BACKEND);
 
 	if (index_mailbox_is_recent(mail->ibox, _mail->uid))
-		data->flags |= MAIL_RECENT;
+		flags |= MAIL_RECENT;
 
-	return data->flags;
+	return flags;
 }
 
 uint64_t index_mail_get_modseq(struct mail *_mail)
@@ -180,7 +185,8 @@
 
 	if (!array_is_created(&data->keyword_indexes)) {
 		p_array_init(&data->keyword_indexes, mail->data_pool, 32);
-		mail_index_lookup_keywords(mail->ibox->view, mail->data.seq,
+		mail_index_lookup_keywords(mail->trans->trans_view,
+					   mail->data.seq,
 					   &data->keyword_indexes);
 	}
 	return &data->keyword_indexes;
@@ -1176,7 +1182,6 @@
 	struct index_mail_data *data = &mail->data;
 	struct mail_cache_field *cache_fields = mail->ibox->cache_fields;
         struct mail_cache_view *cache_view = mail->trans->cache_view;
-	const struct mail_index_record *rec;
 	struct istream *input;
 
 	if (data->seq == seq)
@@ -1184,13 +1189,11 @@
 
 	index_mail_reset(mail);
 
-	rec = mail_index_lookup(mail->trans->trans_view, seq);
 	data->seq = seq;
-	data->flags = rec->flags & (MAIL_FLAGS_NONRECENT |
-				    MAIL_INDEX_MAIL_FLAG_BACKEND);
 
 	mail->mail.mail.seq = seq;
-	mail->mail.mail.uid = rec->uid;
+	mail_index_lookup_uid(mail->trans->trans_view, seq,
+			      &mail->mail.mail.uid);
 
 	if (mail_index_view_is_inconsistent(mail->trans->trans_view)) {
 		mail_set_expunged(&mail->mail.mail);
@@ -1395,6 +1398,18 @@
 {
 	struct index_mail *imail = (struct index_mail *)mail;
 
+	if (array_is_created(&imail->data.keyword_indexes))
+		array_free(&imail->data.keyword_indexes);
+	if (array_is_created(&imail->data.keywords)) {
+		/* clear the keywords array so the next mail_get_keywords()
+		   returns the updated keywords. don't free the array, because
+		   then any existing mail_get_keywords() return values would
+		   point to broken data. this won't leak memory because the
+		   array is allocated from mail's memory pool. */
+		memset(&imail->data.keywords, 0,
+		       sizeof(imail->data.keywords));
+	}
+
 	mail_index_update_keywords(imail->trans->trans, mail->seq, modify_type,
 				   keywords);
 }
--- a/src/lib-storage/index/index-mail.h	Sun Dec 14 06:51:04 2008 +0200
+++ b/src/lib-storage/index/index-mail.h	Sun Dec 14 07:19:48 2008 +0200
@@ -69,7 +69,6 @@
 struct message_header_line;
 
 struct index_mail_data {
-	enum mail_flags flags;
 	time_t date, received_date, save_date;
 	uoff_t virtual_size, physical_size;
 
--- a/src/plugins/virtual/virtual-mail.c	Sun Dec 14 06:51:04 2008 +0200
+++ b/src/plugins/virtual/virtual-mail.c	Sun Dec 14 07:19:48 2008 +0200
@@ -83,7 +83,6 @@
 	struct mailbox_transaction_context *backend_trans;
 	struct mailbox_header_lookup_ctx *backend_headers;
 	const struct virtual_mail_index_record *vrec;
-	const struct mail_index_record *rec;
 	const void *data;
 	bool expunged;
 
@@ -112,12 +111,9 @@
 	memset(&vmail->imail.data, 0, sizeof(vmail->imail.data));
 	p_clear(vmail->imail.data_pool);
 
-	rec = mail_index_lookup(mbox->ibox.view, seq);
 	vmail->imail.data.seq = seq;
-	vmail->imail.data.flags = rec->flags & MAIL_FLAGS_NONRECENT;
-
 	mail->seq = seq;
-	mail->uid = rec->uid;
+	mail_index_lookup_uid(mbox->ibox.view, seq, &mail->uid);
 
 	mail->expunged = vmail->backend_mail->expunged;
 	mail->has_nuls = vmail->backend_mail->has_nuls;