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