It was working properly only with mdbox and there wasn't really a need for it.
--HG--
branch : HEAD
case MAIL_TRANSACTION_FLAG_UPDATE:
case MAIL_TRANSACTION_KEYWORD_UPDATE:
case MAIL_TRANSACTION_KEYWORD_RESET:
- case MAIL_TRANSACTION_UID_UPDATE:
/* these changes increase modseq */
return TRUE;
}
case MAIL_TRANSACTION_EXT_ATOMIC_INC:
name = "ext-atomic-inc";
break;
- case MAIL_TRANSACTION_UID_UPDATE:
- name = "uid-update";
- break;
case MAIL_TRANSACTION_MODSEQ_UPDATE:
name = "modseq-update";
break;
printf("\n");
break;
}
- case MAIL_TRANSACTION_UID_UPDATE: {
- const struct mail_transaction_uid_update *rec, *end;
-
- end = CONST_PTR_OFFSET(data, size);
- for (rec = data; rec < end; rec++) {
- printf(" - old uid=%u new uid=%u\n",
- rec->old_uid, rec->new_uid);
- }
- break;
- }
case MAIL_TRANSACTION_MODSEQ_UPDATE: {
const struct mail_transaction_modseq_update *rec, *end;
return TRUE;
}
-static void sync_uid_update(struct mail_index_sync_map_ctx *ctx,
- uint32_t old_uid, uint32_t new_uid)
-{
- struct mail_index_view *view = ctx->view;
- 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 */
- if (sync_update_ignored_change(ctx))
- view->index->sync_commit_result->ignored_uid_changes++;
- return;
- }
-
- if (!mail_index_lookup_seq(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;
-
- /* add the new record */
- dest = sync_append_record(map);
- rec = MAIL_INDEX_MAP_IDX(map, old_seq-1);
- rec->uid = new_uid;
- 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);
-}
-
static int
sync_modseq_update(struct mail_index_sync_map_ctx *ctx,
const struct mail_transaction_modseq_update *u,
ret = mail_index_sync_keywords_reset(ctx, hdr, rec);
break;
}
- case MAIL_TRANSACTION_UID_UPDATE: {
- const struct mail_transaction_uid_update *rec, *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;
- }
case MAIL_TRANSACTION_MODSEQ_UPDATE: {
const struct mail_transaction_modseq_update *rec = data;
return change_mask;
}
-static bool
-mail_index_transaction_export_new_uids(struct mail_index_export_context *ctx,
- struct mail_index_transaction *t)
-{
- const struct mail_index_record *appends;
- const struct mail_transaction_uid_update *updates;
- unsigned int a, u, append_count, update_count;
-
- if (!array_is_created(&t->uid_updates)) {
- /* fast path */
- if (!array_is_created(&t->appends))
- return FALSE;
-
- log_append_buffer(ctx, t->appends.arr.buffer,
- MAIL_TRANSACTION_APPEND);
- return TRUE;
- }
- if (!array_is_created(&t->appends)) {
- log_append_buffer(ctx, t->uid_updates.arr.buffer,
- MAIL_TRANSACTION_UID_UPDATE);
- return TRUE;
- }
-
- /* we'll need to merge so that UIDs are only being appended.
- appends quite a lot of separate records unnecessarily,
- but UID updates are rare.. */
- appends = array_get(&t->appends, &append_count);
- updates = array_get(&t->uid_updates, &update_count);
-
- for (a = u = 0; a < append_count && u < update_count; ) {
- if (appends[a].uid < updates[u].new_uid) {
- mail_transaction_log_append_add(ctx->append_ctx,
- MAIL_TRANSACTION_APPEND,
- &appends[a], sizeof(appends[a]));
- a++;
- } else {
- mail_transaction_log_append_add(ctx->append_ctx,
- MAIL_TRANSACTION_UID_UPDATE,
- &updates[u], sizeof(updates[u]));
- u++;
- }
- }
- if (a < append_count) {
- mail_transaction_log_append_add(ctx->append_ctx,
- MAIL_TRANSACTION_APPEND, &appends[a],
- (append_count - a) * sizeof(appends[a]));
- }
- if (u < update_count) {
- mail_transaction_log_append_add(ctx->append_ctx,
- MAIL_TRANSACTION_UID_UPDATE, &updates[u],
- (update_count - u) * sizeof(updates[u]));
- }
- return TRUE;
-}
-
void mail_index_transaction_export(struct mail_index_transaction *t,
struct mail_transaction_log_append_ctx *append_ctx)
{
log_append_buffer(&ctx, log_get_hdr_update_buffer(t, TRUE),
MAIL_TRANSACTION_HEADER_UPDATE);
}
- if (mail_index_transaction_export_new_uids(&ctx, t))
+ if (array_is_created(&t->appends)) {
change_mask |= MAIL_INDEX_SYNC_TYPE_APPEND;
+ log_append_buffer(&ctx, t->appends.arr.buffer,
+ MAIL_TRANSACTION_APPEND);
+ }
if (array_is_created(&t->updates)) {
change_mask |= MAIL_INDEX_SYNC_TYPE_FLAGS;
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_uids(t, (void *)&t->modseq_updates);
mail_index_convert_to_uid_ranges(t, (void *)&t->updates);
mail_index_convert_to_uid_ranges(t, &t->keyword_resets);
uint32_t min_flagupdate_seq, max_flagupdate_seq;
ARRAY_DEFINE(modseq_updates, struct mail_transaction_modseq_update);
- 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;
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->modseq_updates))
array_free(&t->modseq_updates);
if (array_is_created(&t->expunges))
{
/* 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->modseq_updates) ||
array_is_created(&t->expunges) ||
array_is_created(&t->keyword_resets) ||
}
}
-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;
-
- t->log_updates = TRUE;
-}
-
void mail_index_update_modseq(struct mail_index_transaction *t, uint32_t seq,
uint64_t min_modseq)
{
all of it was written to the same file. */
uoff_t commit_size;
- unsigned int ignored_uid_changes;
unsigned int ignored_modseq_changes;
};
void mail_index_append_finish_uids(struct mail_index_transaction *t,
uint32_t first_uid,
ARRAY_TYPE(seq_range) *uids_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);
case MAIL_TRANSACTION_FLAG_UPDATE:
case MAIL_TRANSACTION_KEYWORD_UPDATE:
case MAIL_TRANSACTION_KEYWORD_RESET:
- case MAIL_TRANSACTION_UID_UPDATE:
/* these changes increase modseq */
*cur_modseq += 1;
break;
MAIL_TRANSACTION_KEYWORD_RESET = 0x00000800,
MAIL_TRANSACTION_EXT_ATOMIC_INC = 0x00001000,
MAIL_TRANSACTION_EXPUNGE_GUID = 0x00002000,
- MAIL_TRANSACTION_UID_UPDATE = 0x00004000,
MAIL_TRANSACTION_MODSEQ_UPDATE = 0x00008000,
MAIL_TRANSACTION_EXT_HDR_UPDATE32 = 0x00010000,
MAIL_TRANSACTION_INDEX_DELETED = 0x00020000,
uint32_t type; /* enum mail_transaction_type */
};
-struct mail_transaction_uid_update {
- uint32_t old_uid, new_uid;
-};
-
struct mail_transaction_modseq_update {
uint32_t uid;
/* don't use uint64_t here. it adds extra 32 bits of paddiong and also
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();
-}
-
static void test_mail_index_transaction_finish_modseq_updates(void)
{
struct mail_index_transaction *t;
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_modseq_updates,
test_mail_index_transaction_finish_expunges,
NULL
test_end();
}
-static void test_mail_index_uid_update(void)
-{
- struct mail_index_transaction *t;
- const struct mail_transaction_uid_update *uid_updates;
- unsigned int count;
-
- test_begin("mail index uid update");
-
- hdr.messages_count = 10;
- t = mail_index_transaction_new();
-
- mail_index_update_uid(t, 4, 7);
- mail_index_update_uid(t, 6, 8);
- mail_index_update_uid(t, 2, 5);
- mail_index_update_uid(t, 4, 9);
-
- uid_updates = array_get(&t->uid_updates, &count);
- test_assert(count == 4);
- test_assert(uid_updates[0].old_uid == 4 && uid_updates[0].new_uid == 7);
- test_assert(uid_updates[1].old_uid == 6 && uid_updates[1].new_uid == 8);
- test_assert(uid_updates[2].old_uid == 2 && uid_updates[2].new_uid == 5);
- test_assert(uid_updates[3].old_uid == 4 && uid_updates[3].new_uid == 9);
- test_end();
-}
-
static void test_mail_index_modseq_update(void)
{
struct mail_index_transaction *t;
test_mail_index_flag_update_appends,
test_mail_index_cancel_flag_updates,
test_mail_index_transaction_get_flag_update_pos,
- test_mail_index_uid_update,
test_mail_index_modseq_update,
test_mail_index_expunge,
NULL
index_mail_update_flags,
index_mail_update_keywords,
index_mail_update_modseq,
- index_mail_update_uid,
NULL,
index_mail_expunge,
index_mail_set_cache_corrupted
mdbox_mail_update_flags,
index_mail_update_keywords,
index_mail_update_modseq,
- index_mail_update_uid,
NULL,
index_mail_expunge,
index_mail_set_cache_corrupted
/* save map UIDs to mailbox index */
if (first_map_uid != 0) {
+ const struct mdbox_mail_index_record *old_rec;
struct mdbox_mail_index_record rec;
const struct dbox_save_mail *mails;
unsigned int i, count;
+ const void *data;
+ bool expunged;
uint32_t next_map_uid = first_map_uid;
mdbox_update_header(mbox, ctx->ctx.trans, NULL);
rec.save_date = ioloop_time;
mails = array_get(&ctx->mails, &count);
for (i = 0; i < count; i++) {
+ mail_index_lookup_ext(_t->view, mails[i].seq,
+ mbox->ext_id, &data, &expunged);
+ old_rec = data;
+ if (old_rec != NULL && old_rec->map_uid != 0) {
+ /* message was copied. keep the existing
+ map uid */
+ continue;
+ }
+
rec.map_uid = next_map_uid++;
mail_index_update_ext(ctx->ctx.trans, mails[i].seq,
mbox->ext_id, &rec, NULL);
index_mail_update_flags,
index_mail_update_keywords,
index_mail_update_modseq,
- index_mail_update_uid,
NULL,
index_mail_expunge,
index_mail_set_cache_corrupted
min_modseq);
}
-void index_mail_update_uid(struct mail *mail, uint32_t new_uid)
-{
- mail_index_update_uid(mail->transaction->itrans, mail->seq, new_uid);
-}
-
void index_mail_expunge(struct mail *mail)
{
const char *value;
void index_mail_update_keywords(struct mail *mail, enum modify_type modify_type,
struct mail_keywords *keywords);
void index_mail_update_modseq(struct mail *mail, uint64_t min_modseq);
-void index_mail_update_uid(struct mail *mail, uint32_t new_uid);
void index_mail_expunge(struct mail *mail);
void index_mail_set_cache_corrupted(struct mail *mail,
enum mail_fetch_field field);
if (ret < 0 && mail_index_is_deleted(box->index))
mailbox_set_deleted(box);
- changes_r->ignored_uid_changes = result.ignored_uid_changes;
changes_r->ignored_modseq_changes = result.ignored_modseq_changes;
return ret;
}
return index_mail_init_stream(mail, hdr_size, body_size, stream_r);
}
-static void maildir_mail_update_uid(struct mail *_mail, uint32_t new_uid)
-{
- maildir_save_add_conflict(_mail->transaction, _mail->uid, new_uid);
- index_mail_update_uid(_mail, new_uid);
-}
-
static void maildir_update_pop3_uidl(struct mail *_mail, const char *uidl)
{
struct maildir_mailbox *mbox = (struct maildir_mailbox *)_mail->box;
index_mail_update_flags,
index_mail_update_keywords,
index_mail_update_modseq,
- maildir_mail_update_uid,
maildir_update_pop3_uidl,
index_mail_expunge,
maildir_mail_set_cache_corrupted
/* unsigned int keywords[]; */
};
-struct maildir_save_conflict {
- uint32_t old_uid, new_uid;
-};
-
struct maildir_save_context {
struct mail_save_context ctx;
pool_t pool;
struct maildir_filename *files, **files_tail, *file_last;
unsigned int files_count;
- ARRAY_DEFINE(conflicts, struct maildir_save_conflict);
-
buffer_t keywords_buffer;
ARRAY_TYPE(keyword_indexes) keywords_array;
(void)maildir_save_finish(_ctx);
}
-void maildir_save_add_conflict(struct mailbox_transaction_context *t,
- uint32_t old_uid, uint32_t new_uid)
-{
- struct maildir_save_context *save_ctx;
- struct maildir_save_conflict *c;
-
- save_ctx = (struct maildir_save_context *)maildir_save_alloc(t);
-
- if (!array_is_created(&save_ctx->conflicts))
- i_array_init(&save_ctx->conflicts, 64);
-
- c = array_append_space(&save_ctx->conflicts);
- c->old_uid = old_uid;
- c->new_uid = new_uid;
-}
-
-static void maildir_sync_conflict(struct maildir_save_context *ctx,
- const struct maildir_save_conflict *conflict)
-{
- const char *filename;
- enum maildir_uidlist_rec_flag flags;
-
- if (maildir_uidlist_lookup(ctx->mbox->uidlist, conflict->old_uid,
- &flags, &filename) <= 0) {
- i_error("maildir %s: uid %u update failed: lost filename",
- ctx->mbox->box.path, conflict->old_uid);
- return;
- }
- maildir_uidlist_sync_remove(ctx->uidlist_sync_ctx, filename);
- if (maildir_uidlist_sync_next_uid(ctx->uidlist_sync_ctx, filename,
- conflict->new_uid, 0) < 0) {
- i_error("maildir %s: uid %u update failed: sync failed",
- ctx->mbox->box.path, conflict->old_uid);
- }
-}
-
-static void maildir_sync_conflicts(struct maildir_save_context *ctx)
-{
- const struct maildir_save_conflict *conflicts;
- unsigned int i, count;
-
- if (!array_is_created(&ctx->conflicts))
- return;
-
- conflicts = array_get(&ctx->conflicts, &count);
- for (i = 0; i < count; i++)
- maildir_sync_conflict(ctx, &conflicts[i]);
-}
-
static void
maildir_save_unlink_files(struct maildir_save_context *ctx)
{
i_assert(_ctx->output == NULL);
i_assert(ctx->last_save_finished);
- if (ctx->files_count == 0 && !array_is_created(&ctx->conflicts))
+ if (ctx->files_count == 0)
return 0;
sync_flags = MAILDIR_UIDLIST_SYNC_PARTIAL |
maildir_transaction_save_rollback(_ctx);
return -1;
}
- maildir_sync_conflicts(ctx);
} else if (ret == 0 &&
(sync_flags & MAILDIR_UIDLIST_SYNC_TRYLOCK) != 0) {
ctx->locked = FALSE;
if (ctx->locked)
maildir_uidlist_unlock(ctx->mbox->uidlist);
- if (array_is_created(&ctx->conflicts))
- array_free(&ctx->conflicts);
pool_unref(&ctx->pool);
}
if (ctx->mail != NULL)
mail_free(&ctx->mail);
- if (array_is_created(&ctx->conflicts))
- array_free(&ctx->conflicts);
pool_unref(&ctx->pool);
}
int maildir_save_finish(struct mail_save_context *ctx);
void maildir_save_cancel(struct mail_save_context *ctx);
-void maildir_save_add_conflict(struct mailbox_transaction_context *t,
- uint32_t old_uid, uint32_t new_uid);
-
void maildir_save_add(struct mail_save_context *_ctx, const char *base_fname,
bool preserve_filename);
const char *maildir_save_file_get_path(struct mailbox_transaction_context *t,
index_mail_update_flags,
index_mail_update_keywords,
index_mail_update_modseq,
- index_mail_update_uid,
NULL,
index_mail_expunge,
index_mail_set_cache_corrupted
index_mail_update_flags,
index_mail_update_keywords,
index_mail_update_modseq,
- index_mail_update_uid,
NULL,
index_mail_expunge,
index_mail_set_cache_corrupted
void (*update_keywords)(struct mail *mail, enum modify_type modify_type,
struct mail_keywords *keywords);
void (*update_modseq)(struct mail *mail, uint64_t min_modseq);
- void (*update_uid)(struct mail *mail, uint32_t new_uid);
void (*update_pop3_uidl)(struct mail *mail, const char *uidl);
void (*expunge)(struct mail *mail);
void (*set_cache_corrupted)(struct mail *mail,
/* UIDs assigned to saved messages. Not necessarily ascending. */
ARRAY_TYPE(seq_range) saved_uids;
- /* number of uid/modseq changes that couldn't be changed as requested */
- unsigned int ignored_uid_changes;
+ /* number of modseq changes that couldn't be changed as requested */
unsigned int ignored_modseq_changes;
};
/* Update message's modseq to be at least min_modseq. */
void mail_update_modseq(struct mail *mail, uint64_t min_modseq);
-/* 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. */
-void mail_update_uid(struct mail *mail, uint32_t new_uid);
/* Update message's POP3 UIDL (if possible). */
void mail_update_pop3_uidl(struct mail *mail, const char *uidl);
/* Expunge this message. Sequence numbers don't change until commit. */
p->v.update_modseq(mail, min_modseq);
}
-void mail_update_uid(struct mail *mail, uint32_t new_uid)
-{
- struct mail_private *p = (struct mail_private *)mail;
-
- p->v.update_uid(mail, new_uid);
-}
-
void mail_update_pop3_uidl(struct mail *mail, const char *uidl)
{
struct mail_private *p = (struct mail_private *)mail;
{
}
-static void test_mail_update_uid(struct mail *mail ATTR_UNUSED,
- uint32_t new_uid ATTR_UNUSED)
-{
-}
-
static void test_mail_expunge(struct mail *mail ATTR_UNUSED)
{
}
test_mail_update_flags,
test_mail_update_keywords,
test_mail_update_modseq,
- test_mail_update_uid,
NULL,
test_mail_expunge,
test_mail_set_cache_corrupted
index_mail_update_flags,
index_mail_update_keywords,
index_mail_update_modseq,
- index_mail_update_uid,
virtual_mail_update_pop3_uidl,
virtual_mail_expunge,
virtual_mail_set_cache_corrupted