static bool
sync_rename_temp_mailboxes(struct dsync_mailbox_tree_sync_ctx *ctx,
struct dsync_mailbox_tree *tree,
- struct dsync_mailbox_node *node)
+ struct dsync_mailbox_node *node, bool *renames_r)
{
const char *reason;
for (; node != NULL; node = node->next) {
- while (sync_rename_temp_mailboxes(ctx, tree, node->first_child)) ;
+ while (sync_rename_temp_mailboxes(ctx, tree, node->first_child, renames_r)) ;
if (!node->sync_temporary_name) {
} else if (dsync_mailbox_node_is_dir(node) &&
sync_rename_delete_node_dirs(ctx, tree, node);
} else {
T_BEGIN {
+ *renames_r = TRUE;
sync_rename_temp_mailbox_node(tree, node, &reason);
if ((ctx->sync_flags & DSYNC_MAILBOX_TREES_SYNC_FLAG_DEBUG) != 0) {
i_debug("brain %c: %s mailbox %s: %s",
}
static int
-dsync_mailbox_tree_handle_renames(struct dsync_mailbox_tree_sync_ctx *ctx)
+dsync_mailbox_tree_handle_renames(struct dsync_mailbox_tree_sync_ctx *ctx,
+ bool *renames_r)
{
unsigned int max_renames, count = 0;
bool changed;
+ *renames_r = FALSE;
+
max_renames = ctx->combined_mailboxes_count * 3;
do {
T_BEGIN {
return -1;
}
- while (sync_rename_temp_mailboxes(ctx, ctx->local_tree, &ctx->local_tree->root)) ;
- while (sync_rename_temp_mailboxes(ctx, ctx->remote_tree, &ctx->remote_tree->root)) ;
+ while (sync_rename_temp_mailboxes(ctx, ctx->local_tree, &ctx->local_tree->root, renames_r)) ;
+ while (sync_rename_temp_mailboxes(ctx, ctx->remote_tree, &ctx->remote_tree->root, renames_r)) ;
return 0;
}
enum dsync_mailbox_trees_sync_flags sync_flags)
{
struct dsync_mailbox_tree_sync_ctx *ctx;
+ unsigned int rename_counter = 0;
+ bool renames;
pool_t pool;
i_assert(hash_table_is_created(local_tree->guid_hash));
ctx->sync_flags = sync_flags;
i_array_init(&ctx->changes, 128);
+again:
+ renames = FALSE;
+ ctx->combined_mailboxes_count = 0;
sync_tree_sort_and_delete_mailboxes(ctx, remote_tree,
sync_type == DSYNC_MAILBOX_TREES_SYNC_TYPE_TWOWAY);
sync_tree_sort_and_delete_mailboxes(ctx, local_tree,
dsync_mailbox_tree_update_child_timestamps(&local_tree->root, 0);
dsync_mailbox_tree_update_child_timestamps(&remote_tree->root, 0);
if ((sync_flags & DSYNC_MAILBOX_TREES_SYNC_FLAG_NO_RENAMES) == 0) {
- if (dsync_mailbox_tree_handle_renames(ctx) < 0) {
+ if (dsync_mailbox_tree_handle_renames(ctx, &renames) < 0) {
ctx->failed = TRUE;
return ctx;
}
sync_create_mailboxes(ctx, remote_tree);
if (sync_type != DSYNC_MAILBOX_TREES_SYNC_TYPE_PRESERVE_REMOTE)
sync_create_mailboxes(ctx, local_tree);
+ if (renames && rename_counter++ <= ctx->combined_mailboxes_count*3) {
+ /* this rename algorithm is just horrible. we're retrying this
+ because the final sync_rename_temp_mailbox_node() calls
+ give different names to local & remote mailbox trees.
+ something's not right here, but this looping is better than
+ a crash in sync_mailbox_dirs() due to trees not matching. */
+ goto again;
+ }
sync_mailbox_dirs(ctx);
return ctx;
}
#endif
}
+static void test_dsync_mailbox_tree_sync_renames22(void)
+{
+ struct dsync_mailbox_tree *tree1, *tree2;
+
+ test_begin("dsync mailbox tree sync renames 22");
+ tree1 = dsync_mailbox_tree_init('/', '_');
+ tree2 = dsync_mailbox_tree_init('/', '_');
+
+ node_create(tree1, 3, "p/a", 0);
+ node_create(tree1, 0, "p/2", 0);
+ node_create(tree1, 5, "p/2/h", 0);
+
+ node_create(tree2, 4, "p/1/z", 0);
+ node_create(tree2, 1, "p/2", 0);
+ node_create(tree2, 2, "p/2/a", 0);
+ node_create(tree2, 5, "p/2/y", 0);
+ node_create(tree2, 3, "p/3", 0);
+
+ test_trees(tree1, tree2);
+ test_end();
+}
+
static void test_dsync_mailbox_tree_sync_random(void)
{
struct dsync_mailbox_tree *tree1, *tree2;
test_dsync_mailbox_tree_sync_renames19,
test_dsync_mailbox_tree_sync_renames20,
test_dsync_mailbox_tree_sync_renames21,
+ test_dsync_mailbox_tree_sync_renames22,
test_dsync_mailbox_tree_sync_random,
NULL
};