From 36ff3c89d02d897b980a8498c68d696c2193c326 Mon Sep 17 00:00:00 2001
From: Ilya Kosarev <i.kosarev@tarantool.org>
Date: Mon, 25 Nov 2019 14:24:25 +0300
Subject: [PATCH] replication: fix appliers pruning

During pruning of appliers some anon replicas might connect
from replicaset_follow called in another fiber. Therefore we need to
prune appliers of anon replicas first and, moreover, prune them one by
one instead of iterating them, as far as any of them might connect
while we are stopping the other one and it will break iteration.

Part of #4586
Closes #4643
---
 src/box/replication.cc | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/src/box/replication.cc b/src/box/replication.cc
index 509187cd3c..f15e51f4da 100644
--- a/src/box/replication.cc
+++ b/src/box/replication.cc
@@ -516,23 +516,25 @@ replicaset_update(struct applier **appliers, int count)
 	 */
 
 	/* Prune old appliers */
-	replicaset_foreach(replica) {
-		if (replica->applier == NULL)
-			continue;
+	while (!rlist_empty(&replicaset.anon)) {
+		replica = rlist_first_entry(&replicaset.anon,
+					    typeof(*replica), in_anon);
 		applier = replica->applier;
 		replica_clear_applier(replica);
-		replica->applier_sync_state = APPLIER_DISCONNECTED;
+		rlist_del_entry(replica, in_anon);
+		replica_delete(replica);
 		applier_stop(applier);
 		applier_delete(applier);
 	}
-	rlist_foreach_entry_safe(replica, &replicaset.anon, in_anon, next) {
+	replicaset_foreach(replica) {
+		if (replica->applier == NULL)
+			continue;
 		applier = replica->applier;
 		replica_clear_applier(replica);
-		replica_delete(replica);
+		replica->applier_sync_state = APPLIER_DISCONNECTED;
 		applier_stop(applier);
 		applier_delete(applier);
 	}
-	rlist_create(&replicaset.anon);
 
 	/* Save new appliers */
 	replicaset.applier.total = count;
-- 
GitLab