dovecot-2.2: dsync: Fixes to handling local changes during dsync.
dovecot at dovecot.org
dovecot at dovecot.org
Sun Feb 17 11:48:27 EET 2013
details: http://hg.dovecot.org/dovecot-2.2/rev/953594b35bb3
changeset: 15824:953594b35bb3
user: Timo Sirainen <tss at iki.fi>
date: Sun Feb 17 11:48:16 2013 +0200
description:
dsync: Fixes to handling local changes during dsync.
diffstat:
src/doveadm/dsync/dsync-mailbox-import.c | 123 ++++++++++++++++--------------
1 files changed, 64 insertions(+), 59 deletions(-)
diffs (217 lines):
diff -r 945ea8abe713 -r 953594b35bb3 src/doveadm/dsync/dsync-mailbox-import.c
--- a/src/doveadm/dsync/dsync-mailbox-import.c Sun Feb 17 11:47:32 2013 +0200
+++ b/src/doveadm/dsync/dsync-mailbox-import.c Sun Feb 17 11:48:16 2013 +0200
@@ -77,6 +77,7 @@
ARRAY(struct importer_new_mail *) newmails;
ARRAY_TYPE(uint32_t) wanted_uids;
+ uint32_t highest_wanted_uid;
ARRAY(struct dsync_mail_request) mail_requests;
unsigned int mail_request_idx;
@@ -1279,6 +1280,15 @@
return 1;
}
+static void
+dsync_mailbox_import_want_uid(struct dsync_mailbox_importer *importer,
+ uint32_t uid)
+{
+ if (importer->highest_wanted_uid < uid)
+ importer->highest_wanted_uid = uid;
+ array_append(&importer->wanted_uids, &uid, 1);
+}
+
static bool
dsync_msg_change_uid(struct dsync_mailbox_importer *importer,
uint32_t old_uid, uint32_t new_uid)
@@ -1295,7 +1305,7 @@
mailbox_save_set_uid(save_ctx, new_uid);
if (mailbox_move(&save_ctx, importer->mail) < 0)
return FALSE;
- array_append(&importer->wanted_uids, &new_uid, 1);
+ dsync_mailbox_import_want_uid(importer, new_uid);
return TRUE;
}
@@ -1643,7 +1653,7 @@
}
if (ret > 0) {
i_assert(save_ctx == NULL);
- array_append(&importer->wanted_uids, &newmail->final_uid, 1);
+ dsync_mailbox_import_want_uid(importer, newmail->final_uid);
return;
}
/* fallback to saving from remote stream */
@@ -1691,8 +1701,8 @@
mailbox_get_last_error(importer->box, NULL));
importer->failed = TRUE;
} else {
- array_append(&importer->wanted_uids,
- &newmail->final_uid, 1);
+ dsync_mailbox_import_want_uid(importer,
+ newmail->final_uid);
}
}
}
@@ -1742,23 +1752,34 @@
}
static int
-reassign_uids_in_seq_range(struct mailbox *box, uint32_t seq1, uint32_t seq2)
+reassign_uids_in_seq_range(struct mailbox *box,
+ const ARRAY_TYPE(seq_range) *unwanted_uids)
{
const enum mailbox_transaction_flags trans_flags =
MAILBOX_TRANSACTION_FLAG_EXTERNAL |
MAILBOX_TRANSACTION_FLAG_ASSIGN_UIDS;
struct mailbox_transaction_context *trans;
+ struct mail_search_args *search_args;
+ struct mail_search_arg *arg;
+ struct mail_search_context *search_ctx;
struct mail_save_context *save_ctx;
struct mail *mail;
- uint32_t seq;
- int ret = 0;
+ int ret = 1;
+
+ if (array_count(unwanted_uids) == 0)
+ return 1;
+
+ search_args = mail_search_build_init();
+ arg = mail_search_build_add(search_args, SEARCH_UIDSET);
+ p_array_init(&arg->value.seqset, search_args->pool,
+ array_count(unwanted_uids));
+ array_append_array(&arg->value.seqset, unwanted_uids);
trans = mailbox_transaction_begin(box, trans_flags);
- mail = mail_alloc(trans, 0, NULL);
+ search_ctx = mailbox_search_init(trans, search_args, NULL, 0, NULL);
+ mail_search_args_unref(&search_args);
- for (seq = seq1; seq <= seq2; seq++) {
- mail_set_seq(mail, seq);
-
+ while (mailbox_search_next(search_ctx, &mail)) {
save_ctx = mailbox_save_alloc(trans);
mailbox_save_copy_flags(save_ctx, mail);
if (mailbox_move(&save_ctx, mail) < 0) {
@@ -1766,9 +1787,16 @@
mailbox_get_vname(box),
mailbox_get_last_error(box, NULL));
ret = -1;
+ } else if (ret > 0) {
+ ret = 0;
}
}
- mail_free(&mail);
+ if (mailbox_search_deinit(&search_ctx) < 0) {
+ i_error("Mailbox %s: mail search failed: %s",
+ mailbox_get_vname(box),
+ mailbox_get_last_error(box, NULL));
+ ret = -1;
+ }
if (mailbox_transaction_commit(&trans) < 0) {
i_error("Mailbox %s: UID reassign commit failed: %s",
@@ -1784,14 +1812,18 @@
const struct mail_transaction_commit_changes *changes,
bool *changes_during_sync_r)
{
+ ARRAY_TYPE(seq_range) unwanted_uids;
struct seq_range_iter iter;
const uint32_t *wanted_uids;
- uint32_t saved_uid, highest_wanted_uid = 0;
- uint32_t seq1, seq2, lowest_saved_uid = (uint32_t)-1;
- uint32_t lowest_unwanted_uid = (uint32_t)-1;
+ uint32_t saved_uid, highest_seen_uid;
unsigned int i, n, wanted_count;
int ret = 0;
+ wanted_uids = array_get(&importer->wanted_uids, &wanted_count);
+ if (wanted_count == 0) {
+ i_assert(array_count(&changes->saved_uids) == 0);
+ return 0;
+ }
/* wanted_uids contains the UIDs we tried to save mails with.
if nothing changed during dsync, we should have the expected UIDs
(changes->saved_uids) and all is well.
@@ -1804,61 +1836,34 @@
locally added new uid=5 ->
saved_uids = 10,7,9
- we'll now need to reassign UIDs 5 and 10. or more generally, we
- need to reassign UIDs [original local uidnext .. lowest saved_uid-1]
- and [lowest unwanted uid .. remote uidnext-1] */
+ we'll now need to reassign UIDs 5 and 10. to be fully future-proof
+ we'll reassign all UIDs between [original local uidnext .. highest
+ UID we think we know] that aren't in saved_uids. */
- /* find the highest wanted UID that doesn't match what we got */
- wanted_uids = array_get(&importer->wanted_uids, &wanted_count);
+ /* create uidset for the list of UIDs we don't want to exist */
+ t_array_init(&unwanted_uids, 8);
+ highest_seen_uid = I_MAX(importer->remote_uid_next-1,
+ importer->highest_wanted_uid);
+ i_assert(importer->local_uid_next <= highest_seen_uid);
+ seq_range_array_add_range(&unwanted_uids,
+ importer->local_uid_next, highest_seen_uid);
seq_range_array_iter_init(&iter, &changes->saved_uids); i = n = 0;
while (seq_range_array_iter_nth(&iter, n++, &saved_uid)) {
i_assert(i < wanted_count);
- if (lowest_saved_uid > saved_uid)
- lowest_saved_uid = saved_uid;
- if (saved_uid == wanted_uids[i]) {
- if (highest_wanted_uid < saved_uid)
- highest_wanted_uid = saved_uid;
- } else {
- IMPORTER_DEBUG_CHANGE(importer);
- if (lowest_unwanted_uid > saved_uid)
- lowest_unwanted_uid = saved_uid;
- }
+ if (saved_uid == wanted_uids[i])
+ seq_range_array_remove(&unwanted_uids, saved_uid);
i++;
}
- i_assert(lowest_unwanted_uid == (uint32_t)-1 ||
- lowest_unwanted_uid == highest_wanted_uid+1 ||
- highest_wanted_uid == 0);
+ i_assert(i == wanted_count);
- if (importer->local_uid_next != lowest_saved_uid &&
- lowest_saved_uid != (uint32_t)-1) {
- /* [original local uidnext .. lowest saved_uid-1] */
- mailbox_get_seq_range(importer->box, importer->local_uid_next,
- lowest_saved_uid-1, &seq1, &seq2);
- if (seq1 > 0) {
- if (reassign_uids_in_seq_range(importer->box,
- seq1, seq2) < 0)
- ret = -1;
- *changes_during_sync_r = TRUE;
- }
- }
-
- if (lowest_unwanted_uid < importer->remote_uid_next) {
- /* [highest wanted_uid+1 .. remote uidnext-1] */
- mailbox_get_seq_range(importer->box, lowest_unwanted_uid,
- importer->remote_uid_next-1, &seq1, &seq2);
- if (seq1 > 0) {
- if (reassign_uids_in_seq_range(importer->box,
- seq1, seq2) < 0)
- ret = -1;
- *changes_during_sync_r = TRUE;
- }
- }
- if (*changes_during_sync_r) {
+ ret = reassign_uids_in_seq_range(importer->box, &unwanted_uids);
+ if (ret == 0) {
+ *changes_during_sync_r = TRUE;
/* conflicting changes during sync, revert our last-common-uid
back to a safe value. */
importer->last_common_uid = importer->local_uid_next - 1;
}
- return ret;
+ return ret < 0 ? -1 : 0;
}
static int dsync_mailbox_import_commit(struct dsync_mailbox_importer *importer,
More information about the dovecot-cvs
mailing list