dovecot-2.2: dsync: Change duplicate local mailbox GUIDs if they...

dovecot at dovecot.org dovecot at dovecot.org
Wed Feb 27 11:22:08 EET 2013


details:   http://hg.dovecot.org/dovecot-2.2/rev/6bebab0d5c02
changeset: 15982:6bebab0d5c02
user:      Timo Sirainen <tss at iki.fi>
date:      Wed Feb 27 11:21:48 2013 +0200
description:
dsync: Change duplicate local mailbox GUIDs if they're found.

diffstat:

 src/doveadm/dsync/dsync-brain-mailbox-tree.c     |  27 ++++++++----
 src/doveadm/dsync/dsync-mailbox-tree-fill.c      |  49 +++++++++++++++++++++--
 src/doveadm/dsync/dsync-mailbox-tree.c           |  24 +++++-----
 src/doveadm/dsync/dsync-mailbox-tree.h           |  11 +++-
 src/doveadm/dsync/test-dsync-mailbox-tree-sync.c |   9 ++-
 5 files changed, 87 insertions(+), 33 deletions(-)

diffs (247 lines):

diff -r 323b76127e3a -r 6bebab0d5c02 src/doveadm/dsync/dsync-brain-mailbox-tree.c
--- a/src/doveadm/dsync/dsync-brain-mailbox-tree.c	Wed Feb 27 11:04:14 2013 +0200
+++ b/src/doveadm/dsync/dsync-brain-mailbox-tree.c	Wed Feb 27 11:21:48 2013 +0200
@@ -315,7 +315,7 @@
 bool dsync_brain_recv_mailbox_tree(struct dsync_brain *brain)
 {
 	const struct dsync_mailbox_node *remote_node;
-	struct dsync_mailbox_node *node;
+	struct dsync_mailbox_node *node, *dup_node1, *dup_node2;
 	const char *const *parts, *name;
 	struct mail_namespace *ns;
 	enum dsync_ibc_recv_ret ret;
@@ -335,14 +335,22 @@
 		node->ns = ns;
 		dsync_mailbox_node_copy_data(node, remote_node);
 	}
-	if (ret == DSYNC_IBC_RECV_RET_FINISHED) {
-		if (dsync_mailbox_tree_build_guid_hash(brain->remote_mailbox_tree) < 0)
-			brain->failed = TRUE;
+	if (ret != DSYNC_IBC_RECV_RET_FINISHED)
+		return changed;
 
-		brain->state = DSYNC_STATE_RECV_MAILBOX_TREE_DELETES;
-		changed = TRUE;
+	if (dsync_mailbox_tree_build_guid_hash(brain->remote_mailbox_tree,
+					       &dup_node1, &dup_node2) < 0) {
+		i_error("Remote sent duplicate mailbox GUID %s for mailboxes %s and %s",
+			guid_128_to_string(dup_node1->mailbox_guid),
+			dsync_mailbox_node_get_full_name(brain->remote_mailbox_tree,
+							 dup_node1),
+			dsync_mailbox_node_get_full_name(brain->remote_mailbox_tree,
+							 dup_node2));
+		brain->failed = TRUE;
 	}
-	return changed;
+
+	brain->state = DSYNC_STATE_RECV_MAILBOX_TREE_DELETES;
+	return TRUE;
 }
 
 static void
@@ -351,7 +359,7 @@
 				    const struct dsync_mailbox_delete *other_del)
 {
 	const struct dsync_mailbox_node *node;
-	struct dsync_mailbox_node *other_node;
+	struct dsync_mailbox_node *other_node, *old_node;
 	const char *name;
 
 	/* see if we can find the deletion based on mailbox tree that should
@@ -388,7 +396,8 @@
 	other_node->ns = node->ns;
 	other_node->existence = DSYNC_MAILBOX_NODE_DELETED;
 
-	if (dsync_mailbox_tree_guid_hash_add(other_tree, other_node) < 0)
+	if (dsync_mailbox_tree_guid_hash_add(other_tree, other_node,
+					     &old_node) < 0)
 		i_unreached();
 }
 
diff -r 323b76127e3a -r 6bebab0d5c02 src/doveadm/dsync/dsync-mailbox-tree-fill.c
--- a/src/doveadm/dsync/dsync-mailbox-tree-fill.c	Wed Feb 27 11:04:14 2013 +0200
+++ b/src/doveadm/dsync/dsync-mailbox-tree-fill.c	Wed Feb 27 11:21:48 2013 +0200
@@ -191,6 +191,40 @@
 	return 0;
 }
 
+static int
+dsync_mailbox_tree_fix_guid_duplicate(struct dsync_mailbox_tree *tree,
+				      struct dsync_mailbox_node *node1,
+				      struct dsync_mailbox_node *node2)
+{
+	struct mailbox *box;
+	struct mailbox_update update;
+	const char *node2_name;
+	int ret = 0;
+
+	memset(&update, 0, sizeof(update));
+	guid_128_generate(update.mailbox_guid);
+
+	node2_name = dsync_mailbox_node_get_full_name(tree, node2);
+	i_error("Duplicate mailbox GUID %s for mailboxes %s and %s - "
+		"giving a new GUID %s to %s",
+		guid_128_to_string(node1->mailbox_guid),
+		dsync_mailbox_node_get_full_name(tree, node1), node2_name,
+		guid_128_to_string(update.mailbox_guid), node2_name);
+
+	i_assert(node2->ns != NULL);
+	box = mailbox_alloc(node2->ns->list, node2->name, 0);
+	if (mailbox_update(box, &update) < 0) {
+		i_error("Couldn't update mailbox %s GUID: %s",
+			node2->name, mailbox_get_last_error(box, NULL));
+		ret = -1;
+	} else {
+		memcpy(node2->mailbox_guid, update.mailbox_guid,
+		       sizeof(node2->mailbox_guid));
+	}
+	mailbox_free(&box);
+	return ret;
+}
+
 int dsync_mailbox_tree_fill(struct dsync_mailbox_tree *tree,
 			    struct mail_namespace *ns, const char *box_name)
 {
@@ -205,7 +239,7 @@
 		MAILBOX_LIST_ITER_SELECT_SUBSCRIBED |
 		MAILBOX_LIST_ITER_RETURN_NO_FLAGS;
 	struct mailbox_list_iterate_context *iter;
-	struct dsync_mailbox_node *node;
+	struct dsync_mailbox_node *node, *dup_node1, *dup_node2;
 	const struct mailbox_info *info;
 	const char *list_pattern = box_name != NULL ? box_name : "*";
 	int ret = 0;
@@ -244,12 +278,17 @@
 		i_error("Mailbox listing for namespace '%s' failed", ns->prefix);
 		ret = -1;
 	}
+	if (ret < 0)
+		return -1;
 
-	if (dsync_mailbox_tree_build_guid_hash(tree) < 0)
-		ret = -1;
+	while (dsync_mailbox_tree_build_guid_hash(tree, &dup_node1,
+						  &dup_node2) < 0) {
+		if (dsync_mailbox_tree_fix_guid_duplicate(tree, dup_node1, dup_node2) < 0)
+			return -1;
+	}
 
 	/* add timestamps */
 	if (dsync_mailbox_tree_add_change_timestamps(tree, ns) < 0)
-		ret = -1;
-	return ret;
+		return -1;
+	return 0;
 }
diff -r 323b76127e3a -r 6bebab0d5c02 src/doveadm/dsync/dsync-mailbox-tree.c
--- a/src/doveadm/dsync/dsync-mailbox-tree.c	Wed Feb 27 11:04:14 2013 +0200
+++ b/src/doveadm/dsync/dsync-mailbox-tree.c	Wed Feb 27 11:21:48 2013 +0200
@@ -292,7 +292,8 @@
 }
 
 int dsync_mailbox_tree_guid_hash_add(struct dsync_mailbox_tree *tree,
-				     struct dsync_mailbox_node *node)
+				     struct dsync_mailbox_node *node,
+				     struct dsync_mailbox_node **old_node_r)
 {
 	struct dsync_mailbox_node *old_node;
 	uint8_t *guid = node->mailbox_guid;
@@ -300,24 +301,20 @@
 	if (guid_128_is_empty(node->mailbox_guid))
 		return 0;
 
-	old_node = hash_table_lookup(tree->guid_hash, guid);
+	*old_node_r = old_node = hash_table_lookup(tree->guid_hash, guid);
 	if (old_node == NULL)
 		hash_table_insert(tree->guid_hash, guid, node);
-	else if (old_node != node) {
-		i_error("Duplicate mailbox GUID %s "
-			"for mailboxes %s and %s",
-			guid_128_to_string(node->mailbox_guid),
-			dsync_mailbox_node_get_full_name(tree, old_node),
-			dsync_mailbox_node_get_full_name(tree, node));
+	else if (old_node != node)
 		return -1;
-	}
 	return 0;
 }
 
-int dsync_mailbox_tree_build_guid_hash(struct dsync_mailbox_tree *tree)
+int dsync_mailbox_tree_build_guid_hash(struct dsync_mailbox_tree *tree,
+				       struct dsync_mailbox_node **dup_node1_r,
+				       struct dsync_mailbox_node **dup_node2_r)
 {
 	struct dsync_mailbox_tree_iter *iter;
-	struct dsync_mailbox_node *node;
+	struct dsync_mailbox_node *node, *old_node;
 	const char *name;
 	int ret = 0;
 
@@ -327,8 +324,11 @@
 	}
 	iter = dsync_mailbox_tree_iter_init(tree);
 	while (dsync_mailbox_tree_iter_next(iter, &name, &node)) {
-		if (dsync_mailbox_tree_guid_hash_add(tree, node) < 0)
+		if (dsync_mailbox_tree_guid_hash_add(tree, node, &old_node) < 0) {
+			*dup_node1_r = node;
+			*dup_node2_r = old_node;
 			ret = -1;
+		}
 	}
 	dsync_mailbox_tree_iter_deinit(&iter);
 	return ret;
diff -r 323b76127e3a -r 6bebab0d5c02 src/doveadm/dsync/dsync-mailbox-tree.h
--- a/src/doveadm/dsync/dsync-mailbox-tree.h	Wed Feb 27 11:04:14 2013 +0200
+++ b/src/doveadm/dsync/dsync-mailbox-tree.h	Wed Feb 27 11:21:48 2013 +0200
@@ -137,11 +137,16 @@
 struct dsync_mailbox_node *
 dsync_mailbox_tree_find_delete(struct dsync_mailbox_tree *tree,
 			       const struct dsync_mailbox_delete *del);
-/* Build GUID lookup hash, if it's not already built. */
-int dsync_mailbox_tree_build_guid_hash(struct dsync_mailbox_tree *tree);
+/* Build GUID lookup hash, if it's not already built. Returns 0 if ok, -1 if
+   there are duplicate GUIDs. The nodes with the duplicate GUIDs are
+   returned. */
+int dsync_mailbox_tree_build_guid_hash(struct dsync_mailbox_tree *tree,
+				       struct dsync_mailbox_node **dup_node1_r,
+				       struct dsync_mailbox_node **dup_node2_r);
 /* Manually add a new node to hash. */
 int dsync_mailbox_tree_guid_hash_add(struct dsync_mailbox_tree *tree,
-				     struct dsync_mailbox_node *node);
+				     struct dsync_mailbox_node *node,
+				     struct dsync_mailbox_node **old_node_r);
 /* Set remote separator used for directory deletions in
    dsync_mailbox_tree_find_delete() */
 void dsync_mailbox_tree_set_remote_sep(struct dsync_mailbox_tree *tree,
diff -r 323b76127e3a -r 6bebab0d5c02 src/doveadm/dsync/test-dsync-mailbox-tree-sync.c
--- a/src/doveadm/dsync/test-dsync-mailbox-tree-sync.c	Wed Feb 27 11:04:14 2013 +0200
+++ b/src/doveadm/dsync/test-dsync-mailbox-tree-sync.c	Wed Feb 27 11:21:48 2013 +0200
@@ -159,14 +159,15 @@
 {
 	struct dsync_mailbox_tree *orig_tree1, *orig_tree2;
 	struct dsync_mailbox_tree_sync_ctx *ctx;
+	struct dsync_mailbox_node *dup_node1, *dup_node2;
 	const struct dsync_mailbox_tree_sync_change *change;
 
 	orig_tree1 = dsync_mailbox_tree_dup(tree1);
 	orig_tree2 = dsync_mailbox_tree_dup(tree2);
 
 	/* test tree1 -> tree2 */
-	dsync_mailbox_tree_build_guid_hash(tree1);
-	dsync_mailbox_tree_build_guid_hash(tree2);
+	dsync_mailbox_tree_build_guid_hash(tree1, &dup_node1, &dup_node2);
+	dsync_mailbox_tree_build_guid_hash(tree2, &dup_node1, &dup_node2);
 	ctx = dsync_mailbox_trees_sync_init(tree1, tree2,
 					    DSYNC_MAILBOX_TREES_SYNC_TYPE_TWOWAY);
 	while ((change = dsync_mailbox_trees_sync_next(ctx)) != NULL) {
@@ -180,8 +181,8 @@
 	}
 
 	/* test tree2 -> tree1 */
-	dsync_mailbox_tree_build_guid_hash(orig_tree1);
-	dsync_mailbox_tree_build_guid_hash(orig_tree2);
+	dsync_mailbox_tree_build_guid_hash(orig_tree1, &dup_node1, &dup_node2);
+	dsync_mailbox_tree_build_guid_hash(orig_tree2, &dup_node1, &dup_node2);
 	ctx = dsync_mailbox_trees_sync_init(orig_tree2, orig_tree1,
 					    DSYNC_MAILBOX_TREES_SYNC_TYPE_TWOWAY);
 	while ((change = dsync_mailbox_trees_sync_next(ctx)) != NULL) {


More information about the dovecot-cvs mailing list