changeset 19660:7a3a138a4986

doveadm backup: Detect and handle conflicts earlier. This avoids doing a lot of work, only for the next doveadm backup to just delete the entire mailbox and start from the beginning.
author Timo Sirainen <timo.sirainen@dovecot.fi>
date Thu, 28 Jan 2016 16:43:37 +0200
parents c198a998082c
children 166d2d3f57f8
files src/doveadm/dsync/dsync-brain-mails.c src/doveadm/dsync/dsync-mailbox-import.c src/doveadm/dsync/dsync-mailbox-import.h
diffstat 3 files changed, 34 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/src/doveadm/dsync/dsync-brain-mails.c	Thu Jan 28 16:26:53 2016 +0200
+++ b/src/doveadm/dsync/dsync-brain-mails.c	Thu Jan 28 16:43:37 2016 +0200
@@ -117,7 +117,8 @@
 	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
--- a/src/doveadm/dsync/dsync-mailbox-import.c	Thu Jan 28 16:26:53 2016 +0200
+++ b/src/doveadm/dsync/dsync-mailbox-import.c	Thu Jan 28 16:43:37 2016 +0200
@@ -709,6 +709,21 @@
 	}
 }
 
+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 @@
 		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 @@
 			/* 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 @@
 			   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 @@
 	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 @@
 	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 *
--- a/src/doveadm/dsync/dsync-mailbox-import.h	Thu Jan 28 16:26:53 2016 +0200
+++ b/src/doveadm/dsync/dsync-mailbox-import.h	Thu Jan 28 16:43:37 2016 +0200
@@ -37,7 +37,7 @@
 				   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,