From 0f12367f9040c72cb1b6d63e0183d68139e34ca2 Mon Sep 17 00:00:00 2001
From: Vladimir Davydov <vdavydov@tarantool.org>
Date: Wed, 19 Apr 2023 13:57:47 +0300
Subject: [PATCH] replication: pass uris instead of appliers to
 replicaset_connect

Historically, we create appliers in box.cc and then pass them to
replicaset_connect. Now, that we have struct uri_set, it's better
to pass URIs instead of appliers and let replicaset_connect create
appliers. It looks better because replicaset_connect may actually
delete some of the passed appliers on success, which makes the
function protocol difficult for understanding. Another reason to
pass URIs instead of appliers is that we need to store the configured
URIs in replication.cc so that we can detect the case when box.cfg
doesn't change box.cfg.replication (required for SSL certificate
update).

While we are at it,
 - Make replica_set_applier and replica_clear_applier static.
 - Mark the URI argument of applier_new as const and copy it instead
   of moving. This isn't a hot path and with copying it's easier to
   make assumptions about object lifetime.
 - Remove the error label from replicaset_connect. Use a guard instead.

Needed for tarantool/tarantool-ee#432

NO_DOC=refactoring
NO_TEST=refactoring
NO_CHANGELOG=refactoring
---
 src/box/applier.cc     |  4 ++--
 src/box/applier.h      |  2 +-
 src/box/box.cc         | 16 +--------------
 src/box/replication.cc | 45 ++++++++++++++++++++++--------------------
 src/box/replication.h  | 13 +++---------
 5 files changed, 31 insertions(+), 49 deletions(-)

diff --git a/src/box/applier.cc b/src/box/applier.cc
index dec0c355c0..a44347fe0b 100644
--- a/src/box/applier.cc
+++ b/src/box/applier.cc
@@ -2659,7 +2659,7 @@ applier_stop(struct applier *applier)
 }
 
 struct applier *
-applier_new(struct uri *uri)
+applier_new(const struct uri *uri)
 {
 	struct applier *applier = (struct applier *)
 		xcalloc(1, sizeof(struct applier));
@@ -2670,7 +2670,7 @@ applier_new(struct uri *uri)
 	iostream_clear(&applier->io);
 	ibuf_create(&applier->ibuf, &cord()->slabc, 1024);
 
-	uri_move(&applier->uri, uri);
+	uri_copy(&applier->uri, uri);
 	applier->last_row_time = ev_monotonic_now(loop());
 	rlist_create(&applier->on_state);
 	rlist_create(&applier->on_ballot_update);
diff --git a/src/box/applier.h b/src/box/applier.h
index 9930138972..15c41ffe71 100644
--- a/src/box/applier.h
+++ b/src/box/applier.h
@@ -308,7 +308,7 @@ applier_stop(struct applier *applier);
  * @error   throws exception
  */
 struct applier *
-applier_new(struct uri *uri);
+applier_new(const struct uri *uri);
 
 /**
  * Destroy and delete a applier.
diff --git a/src/box/box.cc b/src/box/box.cc
index 7bb2971007..4c125704cd 100644
--- a/src/box/box.cc
+++ b/src/box/box.cc
@@ -1728,21 +1728,7 @@ box_sync_replication(bool do_quorum, bool do_reuse)
 	auto uri_set_guard = make_scoped_guard([&]{
 		uri_set_destroy(&uri_set);
 	});
-	if (uri_set.uri_count >= VCLOCK_MAX) {
-		tnt_raise(ClientError, ER_CFG, "replication",
-			  "too many replicas");
-	}
-	int count = 0;
-	struct applier *appliers[VCLOCK_MAX] = {};
-	auto appliers_guard = make_scoped_guard([&]{
-		for (int i = 0; i < count; i++)
-			applier_delete(appliers[i]); /* doesn't affect diag */
-	});
-	for (; count < uri_set.uri_count; count++) {
-		appliers[count] = applier_new(&uri_set.uris[count]);
-	}
-	replicaset_connect(appliers, count, do_quorum, do_reuse);
-	appliers_guard.is_active = false;
+	replicaset_connect(&uri_set, do_quorum, do_reuse);
 }
 
 static inline void
diff --git a/src/box/replication.cc b/src/box/replication.cc
index 074fc42f45..27aa447f4d 100644
--- a/src/box/replication.cc
+++ b/src/box/replication.cc
@@ -450,7 +450,7 @@ replicaset_on_health_change(void)
 		trigger_run(&replicaset_on_quorum_loss, NULL);
 }
 
-void
+static void
 replica_set_applier(struct replica *replica, struct applier *applier)
 {
 	assert(replica->applier == NULL);
@@ -482,7 +482,7 @@ replica_update_applier_health(struct replica *replica)
 	replicaset_on_health_change();
 }
 
-void
+static void
 replica_clear_applier(struct replica *replica)
 {
 	assert(replica->applier != NULL);
@@ -973,14 +973,29 @@ replicaset_is_connected(struct replicaset_connect_state *state,
 }
 
 void
-replicaset_connect(struct applier **appliers, int count,
+replicaset_connect(const struct uri_set *uris,
 		   bool connect_quorum, bool keep_connect)
 {
-	if (count == 0) {
+	if (uris->uri_count == 0) {
 		/* Cleanup the replica set. */
-		replicaset_update(appliers, 0, false);
+		replicaset_update(NULL, 0, false);
 		return;
 	}
+	if (uris->uri_count >= VCLOCK_MAX) {
+		tnt_raise(ClientError, ER_CFG, "replication",
+			  "too many replicas");
+	}
+	int count = 0;
+	struct applier *appliers[VCLOCK_MAX] = {};
+	auto appliers_guard = make_scoped_guard([&]{
+		for (int i = 0; i < count; i++) {
+			struct applier *applier = appliers[i];
+			applier_stop(applier);
+			applier_delete(applier);
+		}
+	});
+	for (; count < uris->uri_count; count++)
+		appliers[count] = applier_new(&uris->uris[count]);
 
 	say_info("connecting to %d replicas", count);
 
@@ -1045,9 +1060,8 @@ replicaset_connect(struct applier **appliers, int count,
 		/* Timeout or connection failure. */
 		if (state.connected < replicaset_connect_quorum(count) &&
 		    connect_quorum) {
-			diag_set(ClientError, ER_CFG, "replication",
-				 "failed to connect to one or more replicas");
-			goto error;
+			tnt_raise(ClientError, ER_CFG, "replication",
+				  "failed to connect to one or more replicas");
 		}
 	} else {
 		say_info("connected to %d replicas", state.connected);
@@ -1067,19 +1081,8 @@ replicaset_connect(struct applier **appliers, int count,
 	}
 
 	/* Now all the appliers are connected, update the replica set. */
-	try {
-		replicaset_update(appliers, count, keep_connect);
-	} catch (Exception *e) {
-		goto error;
-	}
-	return;
-error:
-	/* Destroy appliers */
-	for (int i = 0; i < count; i++) {
-		trigger_clear(&triggers[i].base);
-		applier_stop(appliers[i]);
-	}
-	diag_raise();
+	replicaset_update(appliers, count, keep_connect);
+	appliers_guard.is_active = false;
 }
 
 bool
diff --git a/src/box/replication.h b/src/box/replication.h
index 059fa9685a..00bb2da13c 100644
--- a/src/box/replication.h
+++ b/src/box/replication.h
@@ -457,12 +457,6 @@ replica_set_id(struct replica *replica, uint32_t id);
 void
 replica_clear_id(struct replica *replica);
 
-void
-replica_clear_applier(struct replica *replica);
-
-void
-replica_set_applier(struct replica * replica, struct applier * applier);
-
 /**
  * Check if there are enough "healthy" connections, and fire the appropriate
  * triggers. A replica connection is considered "healthy", when:
@@ -574,9 +568,8 @@ replicaset_add_anon(const struct tt_uuid *replica_uuid);
  * \post appliers are connected to remote hosts and paused.
  * Use replicaset_follow() to resume appliers.
  *
- * \param appliers the array of appliers
- * \param count size of appliers array
- * \param timeout connection timeout
+ * \param uris           remote peer URIs
+ * \param timeout        connection timeout
  * \param connect_quorum if this flag is set, fail unless at
  *                       least replication_connect_quorum
  *                       appliers have successfully connected.
@@ -584,7 +577,7 @@ replicaset_add_anon(const struct tt_uuid *replica_uuid);
  *                       old connection to the replica is fine.
  */
 void
-replicaset_connect(struct applier **appliers, int count,
+replicaset_connect(const struct uri_set *uris,
 		   bool connect_quorum, bool keep_connect);
 
 /**
-- 
GitLab