dovecot-2.2: dsync: Added more debug output for mailbox renaming.
dovecot at dovecot.org
dovecot at dovecot.org
Fri Feb 20 10:57:09 UTC 2015
details: http://hg.dovecot.org/dovecot-2.2/rev/52016e4cb3db
changeset: 18270:52016e4cb3db
user: Timo Sirainen <tss at iki.fi>
date: Fri Feb 20 12:56:43 2015 +0200
description:
dsync: Added more debug output for mailbox renaming.
diffstat:
src/doveadm/dsync/dsync-mailbox-tree-sync.c | 152 +++++++++++++++++++++------
1 files changed, 119 insertions(+), 33 deletions(-)
diffs (truncated from 377 to 300 lines):
diff -r 4f3db8aec0a1 -r 52016e4cb3db src/doveadm/dsync/dsync-mailbox-tree-sync.c
--- a/src/doveadm/dsync/dsync-mailbox-tree-sync.c Thu Feb 19 19:31:49 2015 +0200
+++ b/src/doveadm/dsync/dsync-mailbox-tree-sync.c Fri Feb 20 12:56:43 2015 +0200
@@ -377,7 +377,8 @@
sync_rename_node_to_temp(struct dsync_mailbox_tree_sync_ctx *ctx,
struct dsync_mailbox_tree *tree,
struct dsync_mailbox_node *node,
- struct dsync_mailbox_node *new_parent)
+ struct dsync_mailbox_node *new_parent,
+ const char **reason_r)
{
struct dsync_mailbox_tree_sync_change *change;
const char *old_name, *new_name, *p;
@@ -411,6 +412,7 @@
old_name = tree != ctx->local_tree ? NULL :
dsync_mailbox_node_get_full_name(tree, node);
+ *reason_r = t_strdup_printf("Renamed '%s' to '%s'", node->name, str_c(&buf));
node->name = p_strdup(tree->pool, str_c(&buf));
node->sync_temporary_name = TRUE;
node->last_renamed_or_created = 0;
@@ -445,7 +447,8 @@
struct dsync_mailbox_tree *tree,
struct dsync_mailbox_node *temp_node,
struct dsync_mailbox_node *node,
- const struct dsync_mailbox_node *other_node)
+ const struct dsync_mailbox_node *other_node,
+ const char **reason_r)
{
struct dsync_mailbox_tree_sync_change *change;
struct dsync_mailbox_tree *other_tree;
@@ -467,15 +470,18 @@
if (node_has_parent(parent, node)) {
/* don't introduce a loop. temporarily rename node
under root. */
- sync_rename_node_to_temp(ctx, tree, node, &tree->root);
+ sync_rename_node_to_temp(ctx, tree, node, &tree->root, reason_r);
+ *reason_r = t_strconcat(*reason_r, " (Don't introduce loop)", NULL);
return;
}
- sync_rename_node_to_temp(ctx, tree, temp_node, temp_node->parent);
+ sync_rename_node_to_temp(ctx, tree, temp_node, temp_node->parent, reason_r);
/* get the old name before it's modified */
name = dsync_mailbox_node_get_full_name(tree, node);
/* set the new name */
+ *reason_r = t_strdup_printf("%s + Renamed '%s' to '%s'",
+ *reason_r, node->name, other_node->name);
node->name = p_strdup(tree->pool, other_node->name);
node->sync_temporary_name = other_node->sync_temporary_name;
node->last_renamed_or_created = other_node->last_renamed_or_created;
@@ -584,7 +590,8 @@
struct dsync_mailbox_node *local_node1,
struct dsync_mailbox_node *remote_node1,
struct dsync_mailbox_node *local_node2,
- struct dsync_mailbox_node *remote_node2)
+ struct dsync_mailbox_node *remote_node2,
+ const char **reason_r)
{
time_t local_ts, remote_ts;
@@ -627,11 +634,13 @@
/* local : 1A
remote: 1B, 2A -> 2A-temp, 1A */
sync_rename_node(ctx, ctx->remote_tree, remote_node2,
- remote_node1, local_node1);
+ remote_node1, local_node1, reason_r);
+ *reason_r = t_strconcat(*reason_r, "(local: local_node2=NULL)", NULL);
return TRUE;
} else if (remote_node1 == remote_node2) {
/* FIXME: this fixes an infinite loop when in
rename2 test, think it through why :) */
+ *reason_r = "local: remote_node1=remote_node2";
} else if (remote_node1 != NULL) {
/* a) local_node1->parent == local_node2->parent
@@ -651,52 +660,65 @@
always renaming 2 to a temporary name and handling
it when we reach B handling. */
sync_rename_node(ctx, ctx->remote_tree, remote_node2,
- remote_node1, local_node1);
+ remote_node1, local_node1, reason_r);
+ *reason_r = t_strconcat(*reason_r, "(local: remote_node1=NULL)", NULL);
return TRUE;
} else if (node_has_parent(local_node1, local_node2)) {
/* node2 is a parent of node1, but it should be
vice versa */
sync_rename_node_to_temp(ctx, ctx->local_tree,
- local_node1, local_node2->parent);
+ local_node1, local_node2->parent, reason_r);
+ *reason_r = t_strconcat(*reason_r, "(local: node2 parent of node1)", NULL);
return TRUE;
} else if (node_has_parent(local_node2, local_node1)) {
/* node1 is a parent of node2, but it should be
vice versa */
sync_rename_node_to_temp(ctx, ctx->local_tree,
- local_node2, local_node1->parent);
+ local_node2, local_node1->parent, reason_r);
+ *reason_r = t_strconcat(*reason_r, "(local: node1 parent of node2)", NULL);
return TRUE;
} else if (local_node1->existence == DSYNC_MAILBOX_NODE_EXISTS) {
sync_rename_node_to_temp(ctx, ctx->remote_tree,
- remote_node2, remote_node2->parent);
+ remote_node2, remote_node2->parent, reason_r);
+ *reason_r = t_strconcat(*reason_r, "(local: local_node1 exists)", NULL);
return TRUE;
} else {
/* local : 1A, 2B
remote: 2A -> (2B)
remote: 2A, 3B -> (3B-temp, 2B) */
+ *reason_r = "local: unchanged";
}
} else {
/* remote nodes have a higher timestamp */
if (remote_node1 == NULL) {
sync_rename_node(ctx, ctx->local_tree, local_node1,
- local_node2, remote_node2);
+ local_node2, remote_node2, reason_r);
+ *reason_r = t_strconcat(*reason_r, "(remote: remote_node1=NULL)", NULL);
return TRUE;
} else if (local_node2 == local_node1) {
+ *reason_r = "remote: remote_node2=remote_node1";
} else if (local_node2 != NULL) {
sync_rename_node(ctx, ctx->local_tree, local_node1,
- local_node2, remote_node2);
+ local_node2, remote_node2, reason_r);
+ *reason_r = t_strconcat(*reason_r, "(remote: local_node2=NULL)", NULL);
return TRUE;
} else if (node_has_parent(remote_node1, remote_node2)) {
sync_rename_node_to_temp(ctx, ctx->remote_tree,
- remote_node1, remote_node2->parent);
+ remote_node1, remote_node2->parent, reason_r);
+ *reason_r = t_strconcat(*reason_r, "(remote: node2 parent of node1)", NULL);
return TRUE;
} else if (node_has_parent(remote_node2, remote_node1)) {
sync_rename_node_to_temp(ctx, ctx->remote_tree,
- remote_node2, remote_node1->parent);
+ remote_node2, remote_node1->parent, reason_r);
+ *reason_r = t_strconcat(*reason_r, "(remote: node1 parent of node2)", NULL);
return TRUE;
} else if (remote_node2->existence == DSYNC_MAILBOX_NODE_EXISTS) {
sync_rename_node_to_temp(ctx, ctx->local_tree,
- local_node1, local_node1->parent);
+ local_node1, local_node1->parent, reason_r);
+ *reason_r = t_strconcat(*reason_r, "(remote: remote_node2 exists)", NULL);
return TRUE;
+ } else {
+ *reason_r = "remote: unchanged";
}
}
return FALSE;
@@ -704,10 +726,12 @@
static bool sync_rename_conflict(struct dsync_mailbox_tree_sync_ctx *ctx,
struct dsync_mailbox_node *local_node1,
- struct dsync_mailbox_node *remote_node2)
+ struct dsync_mailbox_node *remote_node2,
+ const char **reason_r)
{
struct dsync_mailbox_node *local_node2, *remote_node1;
const uint8_t *guid_p;
+ bool ret;
guid_p = local_node1->mailbox_guid;
remote_node1 = hash_table_lookup(ctx->remote_tree->guid_hash, guid_p);
@@ -717,13 +741,16 @@
if ((remote_node1 != NULL && remote_node1->existence == DSYNC_MAILBOX_NODE_EXISTS) ||
(local_node2 != NULL && local_node2->existence == DSYNC_MAILBOX_NODE_EXISTS)) {
/* conflicting name, rename the one with lower timestamp */
- return sync_rename_lower_ts(ctx, local_node1, remote_node1,
- local_node2, remote_node2);
+ ret = sync_rename_lower_ts(ctx, local_node1, remote_node1,
+ local_node2, remote_node2, reason_r);
+ *reason_r = t_strconcat("conflicting name: ", *reason_r, NULL);
+ return ret;
} else if (dsync_mailbox_node_is_dir(local_node1) ||
dsync_mailbox_node_is_dir(remote_node2)) {
/* one of the nodes is a directory, and the other is a mailbox
that doesn't exist on the other side. there is no conflict,
we'll just need to create the mailbox later. */
+ *reason_r = "mailbox not selectable yet";
return FALSE;
} else {
/* both nodes are mailboxes that don't exist on the other side.
@@ -731,6 +758,7 @@
GUIDs and UIDVALIDITYs to be the same */
local_node1->sync_delayed_guid_change = TRUE;
remote_node2->sync_delayed_guid_change = TRUE;
+ *reason_r = "GUIDs conflict - will be merged later";
return FALSE;
}
}
@@ -769,7 +797,8 @@
static bool sync_rename_directory(struct dsync_mailbox_tree_sync_ctx *ctx,
struct dsync_mailbox_node *local_node1,
- struct dsync_mailbox_node *remote_node2)
+ struct dsync_mailbox_node *remote_node2,
+ const char **reason_r)
{
struct dsync_mailbox_node *remote_node1, *local_node2;
@@ -780,16 +809,24 @@
ctx->remote_tree, local_node1);
local_node2 = sync_find_branch(ctx->remote_tree, ctx->local_tree,
remote_node2);
- if (remote_node1 == NULL || local_node2 == NULL ||
- node_names_equal(remote_node1, local_node2) ||
- sync_node_is_namespace_root(ctx->remote_tree, remote_node1) ||
+ if (remote_node1 == NULL || local_node2 == NULL) {
+ *reason_r = "Directory rename branch not found";
+ return FALSE;
+ }
+ if (node_names_equal(remote_node1, local_node2)) {
+ *reason_r = "Directory name paths are equal";
+ return FALSE;
+ }
+ if (sync_node_is_namespace_root(ctx->remote_tree, remote_node1) ||
sync_node_is_namespace_root(ctx->remote_tree, remote_node2) ||
sync_node_is_namespace_root(ctx->local_tree, local_node1) ||
- sync_node_is_namespace_root(ctx->local_tree, local_node2))
+ sync_node_is_namespace_root(ctx->local_tree, local_node2)) {
+ *reason_r = "Directory is part of namespace prefix";
return FALSE;
+ }
return sync_rename_lower_ts(ctx, local_node1, remote_node1,
- local_node2, remote_node2);
+ local_node2, remote_node2, reason_r);
}
static bool sync_rename_mailboxes(struct dsync_mailbox_tree_sync_ctx *ctx,
@@ -799,8 +836,13 @@
struct dsync_mailbox_node **local_nodep = &local_parent->first_child;
struct dsync_mailbox_node **remote_nodep = &remote_parent->first_child;
struct dsync_mailbox_node *local_node, *remote_node;
+ const char *reason;
+ string_t *debug = NULL;
bool changed;
+ if ((ctx->sync_flags & DSYNC_MAILBOX_TREES_SYNC_FLAG_DEBUG) != 0)
+ debug = t_str_new(128);
+
/* the nodes are sorted by their names. */
while (*local_nodep != NULL || *remote_nodep != NULL) {
local_node = *local_nodep;
@@ -820,28 +862,44 @@
remote_parent, local_node);
}
i_assert(strcmp(local_node->name, remote_node->name) == 0);
+ if (debug != NULL) {
+ str_truncate(debug, 0);
+ str_printfa(debug, "Mailbox %s: local=%s/%ld/%d, remote=%s/%ld/%d",
+ local_node->name,
+ guid_128_to_string(local_node->mailbox_guid),
+ (long)local_node->last_renamed_or_created,
+ local_node->existence,
+ guid_128_to_string(remote_node->mailbox_guid),
+ (long)remote_node->last_renamed_or_created,
+ remote_node->existence);
+ }
if (dsync_mailbox_node_is_dir(local_node) &&
dsync_mailbox_node_is_dir(remote_node)) {
/* both nodes are directories (or other side is
nonexistent). see if we can match them by their
child mailboxes */
- if (sync_rename_directory(ctx, local_node, remote_node))
- return TRUE;
+ changed = sync_rename_directory(ctx, local_node, remote_node, &reason);
} else if (dsync_mailbox_node_guids_equal(local_node,
remote_node)) {
/* mailboxes are equal, no need to rename */
+ reason = "Mailboxes are equal";
+ changed = FALSE;
} else {
/* mailbox naming conflict */
T_BEGIN {
changed = sync_rename_conflict(ctx, local_node,
- remote_node);
+ remote_node, &reason);
} T_END;
- if (changed)
- return TRUE;
}
/* handle children, if there are any */
- T_BEGIN {
+ if (debug != NULL) {
+ i_debug("brain %c: %s: %s",
+ (ctx->sync_flags & DSYNC_MAILBOX_TREES_SYNC_FLAG_MASTER_BRAIN) != 0 ? 'M' : 'S',
+ str_c(debug), reason);
+ }
+
+ if (!changed) T_BEGIN {
changed = sync_rename_mailboxes(ctx, local_node,
remote_node);
} T_END;
@@ -911,7 +969,8 @@
More information about the dovecot-cvs
mailing list