dovecot-2.0: Added ability to change existing messages' UIDs wit...

dovecot at dovecot.org dovecot at dovecot.org
Tue Jul 28 02:04:45 EEST 2009


details:   http://hg.dovecot.org/dovecot-2.0/rev/cf187692fcfe
changeset: 9681:cf187692fcfe
user:      Timo Sirainen <tss at iki.fi>
date:      Mon Jul 27 18:47:16 2009 -0400
description:
Added ability to change existing messages' UIDs with mail_[index_]update_uid().

diffstat:

22 files changed, 196 insertions(+), 13 deletions(-)
src/lib-index/mail-index-sync-update.c             |   61 +++++++++++++++++---
src/lib-index/mail-index-transaction-export.c      |    6 +
src/lib-index/mail-index-transaction-finish.c      |    1 
src/lib-index/mail-index-transaction-private.h     |    1 
src/lib-index/mail-index-transaction-update.c      |   16 +++++
src/lib-index/mail-index.h                         |    6 +
src/lib-index/mail-transaction-log.h               |    5 +
src/lib-index/test-mail-index-transaction-finish.c |   52 +++++++++++++++--
src/lib-index/test-mail-index-transaction-update.c |   26 ++++++++
src/lib-storage/index/cydir/cydir-mail.c           |    1 
src/lib-storage/index/dbox/dbox-mail.c             |    1 
src/lib-storage/index/index-mail.c                 |    7 ++
src/lib-storage/index/index-mail.h                 |    1 
src/lib-storage/index/index-transaction.c          |    1 
src/lib-storage/index/maildir/maildir-mail.c       |    1 
src/lib-storage/index/mbox/mbox-mail.c             |    1 
src/lib-storage/index/raw/raw-mail.c               |    1 
src/lib-storage/mail-storage-private.h             |    1 
src/lib-storage/mail-storage.h                     |    6 +
src/lib-storage/mail.c                             |    7 ++
src/lib-storage/test-mail.c                        |    6 +
src/plugins/virtual/virtual-mail.c                 |    1 

diffs (truncated from 520 to 300 lines):

diff -r 77e629913bfc -r cf187692fcfe src/lib-index/mail-index-sync-update.c
--- a/src/lib-index/mail-index-sync-update.c	Mon Jul 27 15:55:10 2009 -0400
+++ b/src/lib-index/mail-index-sync-update.c	Mon Jul 27 18:47:16 2009 -0400
@@ -268,6 +268,51 @@ sync_expunge(struct mail_index_sync_map_
 	mail_index_modseq_expunge(ctx->modseq_ctx, seq1, seq2);
 }
 
+static void *sync_append_record(struct mail_index_map *map)
+{
+	size_t append_pos;
+	void *ret;
+
+	append_pos = map->rec_map->records_count * map->hdr.record_size;
+	ret = buffer_get_space_unsafe(map->rec_map->buffer, append_pos,
+				      map->hdr.record_size);
+	map->rec_map->records =
+		buffer_get_modifiable_data(map->rec_map->buffer, NULL);
+	return ret;
+}
+
+static void sync_uid_update(struct mail_index_sync_map_ctx *ctx,
+			    uint32_t old_uid, uint32_t new_uid)
+{
+	struct mail_index_map *map;
+	struct mail_index_record *rec;
+	uint32_t old_seq;
+	void *dest;
+
+	if (new_uid < ctx->view->map->hdr.next_uid) {
+		/* uid update is no longer possible */
+		return;
+	}
+
+	if (!mail_index_lookup_seq(ctx->view, old_uid, &old_seq))
+		return;
+
+	map = mail_index_sync_get_atomic_map(ctx);
+	map->hdr.next_uid = new_uid+1;
+	map->rec_map->last_appended_uid = new_uid;
+
+	rec = MAIL_INDEX_MAP_IDX(map, old_seq-1);
+
+	/* add the new record */
+	dest = sync_append_record(map);
+	memcpy(dest, rec, map->hdr.record_size);
+
+	/* @UNSAFE: remove the old record */
+	memmove(rec, PTR_OFFSET(rec, map->hdr.record_size),
+		(map->rec_map->records_count + 1 - old_seq) *
+		map->hdr.record_size);
+}
+
 void mail_index_sync_write_seq_update(struct mail_index_sync_map_ctx *ctx,
 				      uint32_t seq1, uint32_t seq2)
 {
@@ -288,7 +333,6 @@ static int sync_append(const struct mail
 	const struct mail_index_record *old_rec;
 	enum mail_flags new_flags;
 	void *dest;
-	size_t append_pos;
 
 	if (rec->uid < map->hdr.next_uid) {
 		mail_index_sync_set_corrupted(ctx,
@@ -314,12 +358,7 @@ static int sync_append(const struct mail
 	} else {
 		/* don't rely on buffer->used being at the correct position.
 		   at least expunges can move it */
-		append_pos = map->rec_map->records_count * map->hdr.record_size;
-		dest = buffer_get_space_unsafe(map->rec_map->buffer, append_pos,
-					       map->hdr.record_size);
-		map->rec_map->records =
-			buffer_get_modifiable_data(map->rec_map->buffer, NULL);
-
+		dest = sync_append_record(map);
 		memcpy(dest, rec, sizeof(*rec));
 		memset(PTR_OFFSET(dest, sizeof(*rec)), 0,
 		       map->hdr.record_size - sizeof(*rec));
@@ -671,6 +710,14 @@ int mail_index_sync_record(struct mail_i
 		const struct mail_transaction_keyword_reset *rec = data;
 
 		ret = mail_index_sync_keywords_reset(ctx, hdr, rec);
+		break;
+	}
+	case MAIL_TRANSACTION_UID_UPDATE: {
+		const struct mail_transaction_uid_update *rec = data, *end;
+
+		end = CONST_PTR_OFFSET(data, hdr->size);
+		for (rec = data; rec < end; rec++)
+			sync_uid_update(ctx, rec->old_uid, rec->new_uid);
 		break;
 	}
 	default:
diff -r 77e629913bfc -r cf187692fcfe src/lib-index/mail-index-transaction-export.c
--- a/src/lib-index/mail-index-transaction-export.c	Mon Jul 27 15:55:10 2009 -0400
+++ b/src/lib-index/mail-index-transaction-export.c	Mon Jul 27 18:47:16 2009 -0400
@@ -382,6 +382,12 @@ void mail_index_transaction_export(struc
 		log_append_buffer(&ctx, t->expunges.arr.buffer,
 				  MAIL_TRANSACTION_EXPUNGE_GUID);
 	}
+	/* keep uid updates last. if there are other updates to the message,
+	   they're referring to the old uid. */
+	if (array_is_created(&t->uid_updates)) {
+		log_append_buffer(&ctx, t->uid_updates.arr.buffer,
+				  MAIL_TRANSACTION_UID_UPDATE);
+	}
 
 	if (t->post_hdr_changed) {
 		log_append_buffer(&ctx, log_get_hdr_update_buffer(t, FALSE),
diff -r 77e629913bfc -r cf187692fcfe src/lib-index/mail-index-transaction-finish.c
--- a/src/lib-index/mail-index-transaction-finish.c	Mon Jul 27 15:55:10 2009 -0400
+++ b/src/lib-index/mail-index-transaction-finish.c	Mon Jul 27 18:47:16 2009 -0400
@@ -316,6 +316,7 @@ mail_index_transaction_convert_to_uids(s
 
         keyword_updates_convert_to_uids(t);
 	expunges_convert_to_uids(t);
+	mail_index_convert_to_uids(t, (void *)&t->uid_updates);
 	mail_index_convert_to_uid_ranges(t, (void *)&t->updates);
 	mail_index_convert_to_uid_ranges(t, &t->keyword_resets);
 }
diff -r 77e629913bfc -r cf187692fcfe src/lib-index/mail-index-transaction-private.h
--- a/src/lib-index/mail-index-transaction-private.h	Mon Jul 27 15:55:10 2009 -0400
+++ b/src/lib-index/mail-index-transaction-private.h	Mon Jul 27 18:47:16 2009 -0400
@@ -44,6 +44,7 @@ struct mail_index_transaction {
 	/* lowest/highest sequence that updates flags/keywords */
 	uint32_t min_flagupdate_seq, max_flagupdate_seq;
 
+	ARRAY_DEFINE(uid_updates, struct mail_transaction_uid_update);
 	ARRAY_DEFINE(expunges, struct mail_transaction_expunge_guid);
 	ARRAY_DEFINE(updates, struct mail_transaction_flag_update);
 	size_t last_update_idx;
diff -r 77e629913bfc -r cf187692fcfe src/lib-index/mail-index-transaction-update.c
--- a/src/lib-index/mail-index-transaction-update.c	Mon Jul 27 15:55:10 2009 -0400
+++ b/src/lib-index/mail-index-transaction-update.c	Mon Jul 27 18:47:16 2009 -0400
@@ -69,6 +69,8 @@ void mail_index_transaction_reset_v(stru
 
 	if (array_is_created(&t->appends))
 		array_free(&t->appends);
+	if (array_is_created(&t->uid_updates))
+		array_free(&t->uid_updates);
 	if (array_is_created(&t->expunges))
 		array_free(&t->expunges);
 	if (array_is_created(&t->updates))
@@ -105,6 +107,7 @@ void mail_index_transaction_set_log_upda
 {
 	/* flag updates aren't included in log_updates */
 	t->log_updates = array_is_created(&t->appends) ||
+		array_is_created(&t->uid_updates) ||
 		array_is_created(&t->expunges) ||
 		array_is_created(&t->keyword_resets) ||
 		array_is_created(&t->keyword_updates) ||
@@ -211,6 +214,19 @@ void mail_index_append_assign_uids(struc
 	}
 
 	*next_uid_r = first_uid;
+}
+
+void mail_index_update_uid(struct mail_index_transaction *t, uint32_t seq,
+			   uint32_t new_uid)
+{
+	struct mail_transaction_uid_update *u;
+
+	if (!array_is_created(&t->uid_updates))
+		i_array_init(&t->uid_updates, 32);
+
+	u = array_append_space(&t->uid_updates);
+	u->old_uid = seq;
+	u->new_uid = new_uid;
 }
 
 static void
diff -r 77e629913bfc -r cf187692fcfe src/lib-index/mail-index.h
--- a/src/lib-index/mail-index.h	Mon Jul 27 15:55:10 2009 -0400
+++ b/src/lib-index/mail-index.h	Mon Jul 27 18:47:16 2009 -0400
@@ -400,6 +400,12 @@ void mail_index_append(struct mail_index
    for mail_index_append(). Returns the next unused UID. */
 void mail_index_append_assign_uids(struct mail_index_transaction *t,
 				   uint32_t first_uid, uint32_t *next_uid_r);
+/* Update message's UID. The new UID must not be lower than next_uid at the
+   commit time, otherwise the UID update fails and is just ignored.
+   If there are appends in the same transaction, the updated UIDs must be
+   higher than the append UIDs. */
+void mail_index_update_uid(struct mail_index_transaction *t, uint32_t seq,
+			   uint32_t new_uid);
 /* Expunge record from index. Note that this doesn't affect sequence numbers
    until transaction is committed and mailbox is synced. */
 void mail_index_expunge(struct mail_index_transaction *t, uint32_t seq);
diff -r 77e629913bfc -r cf187692fcfe src/lib-index/mail-transaction-log.h
--- a/src/lib-index/mail-transaction-log.h	Mon Jul 27 15:55:10 2009 -0400
+++ b/src/lib-index/mail-transaction-log.h	Mon Jul 27 18:47:16 2009 -0400
@@ -39,6 +39,7 @@ enum mail_transaction_type {
 	MAIL_TRANSACTION_KEYWORD_RESET		= 0x00000800,
 	MAIL_TRANSACTION_EXT_ATOMIC_INC		= 0x00001000,
 	MAIL_TRANSACTION_EXPUNGE_GUID		= 0x00002000,
+	MAIL_TRANSACTION_UID_UPDATE		= 0x00004000,
 
 	MAIL_TRANSACTION_TYPE_MASK		= 0x0000ffff,
 
@@ -60,6 +61,10 @@ struct mail_transaction_header {
 struct mail_transaction_header {
 	uint32_t size;
 	uint32_t type; /* enum mail_transaction_type */
+};
+
+struct mail_transaction_uid_update {
+	uint32_t old_uid, new_uid;
 };
 
 struct mail_transaction_expunge {
diff -r 77e629913bfc -r cf187692fcfe src/lib-index/test-mail-index-transaction-finish.c
--- a/src/lib-index/test-mail-index-transaction-finish.c	Mon Jul 27 15:55:10 2009 -0400
+++ b/src/lib-index/test-mail-index-transaction-finish.c	Mon Jul 27 18:47:16 2009 -0400
@@ -79,11 +79,18 @@ static void test_mail_index_transaction_
 	mail_index_transaction_finish(t);
 
 	updates = array_get(&t->updates, &count);
-	test_assert(count == 2);
-	test_assert(updates[0].uid1 == 1 && updates[0].uid2 == 2);
-	test_assert(updates[1].uid1 == 4 && updates[1].uid2 == 5);
+	test_assert(count == 4);
+	test_assert(updates[0].uid1 == 1*2 && updates[0].uid2 == 1*2);
+	test_assert(updates[1].uid1 == 2*2 && updates[1].uid2 == 2*2);
+	test_assert(updates[2].uid1 == 4*2 && updates[2].uid2 == 4*2);
+	test_assert(updates[3].uid1 == 5*2 && updates[3].uid2 == 5*2);
 
 	/* nothing changed */
+	t_array_init(&t->updates, 10);
+	u.uid1 = 1; u.uid2 = 2;
+	array_append(&t->updates, &u, 1);
+	u.uid1 = 4; u.uid2 = 5;
+	array_append(&t->updates, &u, 1);
 	recs[1].flags = MAIL_SEEN;
 	recs[2].flags = MAIL_SEEN;
 	recs[4].flags = MAIL_SEEN;
@@ -101,8 +108,8 @@ static void test_mail_index_transaction_
 
 	updates = array_get(&t->updates, &count);
 	test_assert(count == 2);
-	test_assert(updates[0].uid1 == 3 && updates[0].uid2 == 3);
-	test_assert(updates[1].uid1 == 6 && updates[1].uid2 == 6);
+	test_assert(updates[0].uid1 == 3*2 && updates[0].uid2 == 3*2);
+	test_assert(updates[1].uid1 == 6*2 && updates[1].uid2 == 6*2);
 
 	test_end();
 }
@@ -142,6 +149,38 @@ static void test_mail_index_transaction_
 	test_assert(conflicts[0].seq1 == 6 && conflicts[0].seq2 == 6);
 	test_assert(conflicts[1].seq1 == 8 && conflicts[1].seq2 == 8);
 
+	test_end();
+}
+
+static void test_mail_index_transaction_finish_uid_updates(void)
+{
+	struct mail_index_transaction *t;
+	const struct mail_transaction_uid_update *uid_updates;
+	struct mail_transaction_uid_update *u;
+	unsigned int count;
+
+	t = t_new(struct mail_index_transaction, 1);
+
+	test_begin("mail index transaction finish uid updates");
+
+	t_array_init(&t->uid_updates, 10);
+	u = array_append_space(&t->uid_updates);
+	u->old_uid = 1; u->new_uid = 15;
+	u = array_append_space(&t->uid_updates);
+	u->old_uid = 2; u->new_uid = 16;
+	u = array_append_space(&t->uid_updates);
+	u->old_uid = 5; u->new_uid = 17;
+	u = array_append_space(&t->uid_updates);
+	u->old_uid = 2; u->new_uid = 18;
+
+	mail_index_transaction_finish(t);
+
+	uid_updates = array_get(&t->uid_updates, &count);
+	test_assert(count == 4);
+	test_assert(uid_updates[0].old_uid == 1*2 && uid_updates[0].new_uid == 15);
+	test_assert(uid_updates[1].old_uid == 2*2 && uid_updates[1].new_uid == 16);
+	test_assert(uid_updates[2].old_uid == 5*2 && uid_updates[2].new_uid == 17);
+	test_assert(uid_updates[3].old_uid == 2*2 && uid_updates[3].new_uid == 18);
 	test_end();
 }
 
@@ -202,12 +241,13 @@ int main(void)
 	static void (*test_functions[])(void) = {
 		test_mail_index_transaction_finish_flag_updates,
 		test_mail_index_transaction_finish_check_conflicts,
+		test_mail_index_transaction_finish_uid_updates,
 		test_mail_index_transaction_finish_expunges,
 		NULL
 	};
 	unsigned int i;
 
 	for (i = 1; i < N_ELEMENTS(recs); i++)
-		recs[i].uid = i;
+		recs[i].uid = i*2;
 	return test_run(test_functions);
 }
diff -r 77e629913bfc -r cf187692fcfe src/lib-index/test-mail-index-transaction-update.c
--- a/src/lib-index/test-mail-index-transaction-update.c	Mon Jul 27 15:55:10 2009 -0400


More information about the dovecot-cvs mailing list