]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
doveadm backup: Detect and handle conflicts earlier.
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Thu, 28 Jan 2016 14:43:37 +0000 (16:43 +0200)
committerTimo Sirainen <timo.sirainen@dovecot.fi>
Thu, 28 Jan 2016 14:43:37 +0000 (16:43 +0200)
This avoids doing a lot of work, only for the next doveadm backup to just
delete the entire mailbox and start from the beginning.

src/doveadm/dsync/dsync-brain-mails.c
src/doveadm/dsync/dsync-mailbox-import.c
src/doveadm/dsync/dsync-mailbox-import.h

index 72b694afd649439494a573b437aaa3fde30e0ee2..2def387e644a73eec897019c7ed658af9a39cf03 100644 (file)
@@ -117,7 +117,8 @@ static bool dsync_brain_recv_mail_change(struct dsync_brain *brain)
        if ((ret = dsync_ibc_recv_change(brain->ibc, &change)) == 0)
                return FALSE;
        if (ret == DSYNC_IBC_RECV_RET_FINISHED) {
-               dsync_mailbox_import_changes_finish(brain->box_importer);
+               if (dsync_mailbox_import_changes_finish(brain->box_importer) < 0)
+                       brain->failed = TRUE;
                if (brain->mail_requests && brain->box_exporter != NULL)
                        brain->box_recv_state = DSYNC_BOX_STATE_MAIL_REQUESTS;
                else
index 98de1356d4d318a128632abd88290f22dbafc5a2..aebf02e9eb83e864846f5cb0f50c23fef90d2365 100644 (file)
@@ -709,6 +709,21 @@ static void newmail_link(struct dsync_mailbox_importer *importer,
        }
 }
 
+static void
+dsync_mailbox_revert_existing_uid(struct dsync_mailbox_importer *importer,
+                                 uint32_t uid, const char *reason)
+{
+       i_assert(importer->revert_local_changes);
+
+       /* UID either already exists or UIDNEXT is too high. we can't set the
+          wanted UID, so we'll need to delete the whole mailbox and resync */
+       i_warning("Deleting mailbox '%s': UID=%u already exists locally for a different mail: %s",
+                 mailbox_get_vname(importer->box), uid, reason);
+       importer->delete_mailbox = TRUE;
+       importer->mail_error = MAIL_ERROR_TEMP;
+       importer->failed = TRUE;
+}
+
 static bool dsync_mailbox_try_save_cur(struct dsync_mailbox_importer *importer,
                                       struct dsync_mail_change *save_change)
 {
@@ -758,6 +773,11 @@ static bool dsync_mailbox_try_save_cur(struct dsync_mailbox_importer *importer,
                newmail->uid_in_local = FALSE;
                newmail->uid_is_usable =
                        newmail->final_uid >= importer->local_uid_next;
+               if (!newmail->uid_is_usable && importer->revert_local_changes) {
+                       dsync_mailbox_revert_existing_uid(importer, newmail->final_uid,
+                               t_strdup_printf("UID >= local UIDNEXT=%u", importer->local_uid_next));
+                       return TRUE;
+               }
                remote_saved = TRUE;
        } else {
                /* identical */
@@ -1619,11 +1639,15 @@ dsync_mailbox_find_common_uid(struct dsync_mailbox_importer *importer,
                        /* unknown */
                        return;
                }
-               if (ret == 0) {
+               if (ret > 0) {
+                       importer->last_common_uid = change->uid;
+               } else if (!importer->revert_local_changes) {
                        /* mismatch - found the first non-common UID */
                        dsync_mailbox_common_uid_found(importer);
                } else {
-                       importer->last_common_uid = change->uid;
+                       /* mismatch and we want to revert local changes -
+                          need to delete the mailbox. */
+                       dsync_mailbox_revert_existing_uid(importer, change->uid, *result_r);
                }
                return;
        }
@@ -1746,6 +1770,7 @@ dsync_mailbox_import_assign_new_uids(struct dsync_mailbox_importer *importer)
                           this mail */
                        new_uid = newmail->link->final_uid;
                } else {
+                       i_assert(!importer->revert_local_changes);
                        new_uid = common_uid_next++;
                        imp_debug(importer, "UID %u isn't usable, assigning new UID %u",
                                  newmail->final_uid, new_uid);
@@ -2088,7 +2113,7 @@ dsync_mailbox_import_handle_local_mails(struct dsync_mailbox_importer *importer)
        hash_table_iterate_deinit(&iter);
 }
 
-void dsync_mailbox_import_changes_finish(struct dsync_mailbox_importer *importer)
+int dsync_mailbox_import_changes_finish(struct dsync_mailbox_importer *importer)
 {
        i_assert(!importer->new_uids_assigned);
 
@@ -2117,7 +2142,9 @@ void dsync_mailbox_import_changes_finish(struct dsync_mailbox_importer *importer
        dsync_mailbox_import_assign_new_uids(importer);
        /* save mails from local sources where possible,
           request the rest from remote */
-       dsync_mailbox_import_handle_local_mails(importer);
+       if (!importer->failed)
+               dsync_mailbox_import_handle_local_mails(importer);
+       return importer->failed ? -1 : 0;
 }
 
 const struct dsync_mail_request *
index aaa302bdfc4a26d3aeb89286c5a90173e34231f9..2985a117c282f1ea0ff76a32eaebb391b6192db9 100644 (file)
@@ -37,7 +37,7 @@ int dsync_mailbox_import_attribute(struct dsync_mailbox_importer *importer,
                                   const struct dsync_mailbox_attribute *attr);
 int dsync_mailbox_import_change(struct dsync_mailbox_importer *importer,
                                const struct dsync_mail_change *change);
-void dsync_mailbox_import_changes_finish(struct dsync_mailbox_importer *importer);
+int dsync_mailbox_import_changes_finish(struct dsync_mailbox_importer *importer);
 const struct dsync_mail_request *
 dsync_mailbox_import_next_request(struct dsync_mailbox_importer *importer);
 void dsync_mailbox_import_mail(struct dsync_mailbox_importer *importer,