<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class="">LGTM.<div class="">Sergos</div><div class=""><br class=""><div><br class=""><blockquote type="cite" class=""><div class="">On 12 Oct 2021, at 17:14, Serge Petrenko <<a href="mailto:sergepetrenko@tarantool.org" class="">sergepetrenko@tarantool.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><meta charset="UTF-8" class=""><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">12.10.2021 13:14, sergos пишет:</span><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><blockquote type="cite" style="font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none;" class="">Hi!<br class=""><br class="">Thanks for the patch!<br class=""><br class="">Just request for some addition to the test, otherwise LGTM.<br class=""><br class="">Sergos<br class=""><br class=""><br class=""><blockquote type="cite" class="">On 5 Oct 2021, at 16:18, Serge Petrenko <<a href="mailto:sergepetrenko@tarantool.org" class="">sergepetrenko@tarantool.org</a>> wrote:<br class=""><br class="">Replication reconfiguration used to work as follows: upon receiving a<br class="">new config disconnect from all the existing masters and try to connect<br class="">to all the masters from the new config.<br class=""><br class="">This lead to instances doing extra work when old config and new config<br class="">had the same nodes in them: instead of doing nothing, tarantool<br class="">reinitialized the connection.<br class=""><br class="">There was another problem: when an existing connection is broken, master<br class="">takes some time to notice that. So, when replica resets the connection,<br class="">it may try to reconnect faster than the master is able to notice its<br class="">absence. In this case replica wouldn't be able to reconnect due to<br class="">`duplicate connection with the same replica UUID`. So replication would<br class="">stop for a replication_timeout, which may be quite large (seconds or<br class="">tens of seconds).<br class=""><br class="">Let's prevent tarantool from reconnecting to the same instance, if there<br class="">already is a working connection.<br class=""><br class="">Closes #4669<br class="">---<br class="">.../gh-4669-applier-reconfig-reconnect.md     |  5 ++<br class="">src/box/<a href="http://box.cc" class="">box.cc</a>                                | 31 ++++++---<br class="">src/box/<a href="http://replication.cc" class="">replication.cc</a>                        | 41 ++++++++----<br class="">src/box/replication.h                         |  4 +-<br class="">test/instance_files/base_instance.lua         |  3 +-<br class="">test/instance_files/replica.lua               | 17 +++++<br class="">test/luatest_helpers/server.lua               | 65 +++++++++++++++++++<br class="">.../gh_4669_applier_reconnect_test.lua        | 40 ++++++++++++<br class="">8 files changed, 184 insertions(+), 22 deletions(-)<br class="">create mode 100644 changelogs/unreleased/gh-4669-applier-reconfig-reconnect.md<br class="">create mode 100755 test/instance_files/replica.lua<br class="">create mode 100644 test/replication-luatest/gh_4669_applier_reconnect_test.lua<br class=""><br class="">diff --git a/changelogs/unreleased/gh-4669-applier-reconfig-reconnect.md b/changelogs/unreleased/gh-4669-applier-reconfig-reconnect.md<br class="">new file mode 100644<br class="">index 000000000..2a776872b<br class="">--- /dev/null<br class="">+++ b/changelogs/unreleased/gh-4669-applier-reconfig-reconnect.md<br class="">@@ -0,0 +1,5 @@<br class="">+## bugfix/replication<br class="">+<br class="">+* Fixed replica reconnecting to a living master on any `box.cfg{replication=...}`<br class="">+  change. Such reconnects could lead to replica failing to restore connection<br class="">+  for `replication_timeout` seconds (gh-4669).<br class="">diff --git a/src/box/<a href="http://box.cc" class="">box.cc</a> b/src/box/<a href="http://box.cc" class="">box.cc</a><br class="">index 219ffa38d..cc4ada47e 100644<br class="">--- a/src/box/<a href="http://box.cc" class="">box.cc</a><br class="">+++ b/src/box/<a href="http://box.cc" class="">box.cc</a><br class="">@@ -1249,7 +1249,7 @@ cfg_get_replication(int *p_count)<br class=""> * don't start appliers.<br class=""> */<br class="">static void<br class="">-box_sync_replication(bool connect_quorum)<br class="">+box_sync_replication(bool do_quorum, bool do_reuse)<br class="">{<br class=""><span class="Apple-tab-span" style="white-space: pre;">   </span>int count = 0;<br class=""><span class="Apple-tab-span" style="white-space: pre;">       </span>struct applier **appliers = cfg_get_replication(&count);<br class="">@@ -1260,12 +1260,27 @@ box_sync_replication(bool connect_quorum)<br class=""><span class="Apple-tab-span" style="white-space: pre;">   </span><span class="Apple-tab-span" style="white-space: pre;">  </span>for (int i = 0; i < count; i++)<br class=""><span class="Apple-tab-span" style="white-space: pre;">   </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>applier_delete(appliers[i]); /* doesn't affect diag */<br class=""><span class="Apple-tab-span" style="white-space: pre;">       </span>});<br class="">-<br class="">-<span class="Apple-tab-span" style="white-space: pre;">   </span>replicaset_connect(appliers, count, connect_quorum);<br class="">+<span class="Apple-tab-span" style="white-space: pre;">        </span>replicaset_connect(appliers, count, do_quorum, do_reuse);<br class=""><br class=""><span class="Apple-tab-span" style="white-space: pre;">       </span>guard.is_active = false;<br class="">}<br class=""><br class="">+static inline void<br class="">+box_restart_replication(void)<br class="">+{<br class="">+<span class="Apple-tab-span" style="white-space: pre;">       </span>const bool do_quorum = true;<br class="">+<span class="Apple-tab-span" style="white-space: pre;">        </span>const bool do_reuse = false;<br class="">+<span class="Apple-tab-span" style="white-space: pre;">        </span>box_sync_replication(do_quorum, do_reuse);<br class="">+}<br class="">+<br class="">+static inline void<br class="">+box_update_replication(void)<br class="">+{<br class="">+<span class="Apple-tab-span" style="white-space: pre;">    </span>const bool do_quorum = false;<br class="">+<span class="Apple-tab-span" style="white-space: pre;">       </span>const bool do_reuse = true;<br class="">+<span class="Apple-tab-span" style="white-space: pre;"> </span>box_sync_replication(do_quorum, do_reuse);<br class="">+}<br class="">+<br class="">void<br class="">box_set_replication(void)<br class="">{<br class="">@@ -1284,7 +1299,7 @@ box_set_replication(void)<br class=""><span class="Apple-tab-span" style="white-space: pre;">     </span><span class="Apple-converted-space"> </span>* Stay in orphan mode in case we fail to connect to at least<br class=""><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-converted-space"> </span>* 'replication_connect_quorum' remote instances.<br class=""><span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-converted-space"> </span>*/<br class="">-<span class="Apple-tab-span" style="white-space: pre;">   </span>box_sync_replication(false);<br class="">+<span class="Apple-tab-span" style="white-space: pre;">        </span>box_update_replication();<br class=""><span class="Apple-tab-span" style="white-space: pre;">    </span>/* Follow replica */<br class=""><span class="Apple-tab-span" style="white-space: pre;"> </span>replicaset_follow();<br class=""><span class="Apple-tab-span" style="white-space: pre;"> </span>/* Wait until appliers are in sync */<br class="">@@ -1404,7 +1419,7 @@ box_set_replication_anon(void)<br class=""><span class="Apple-tab-span" style="white-space: pre;">       </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-converted-space"> </span>* them can register and others resend a<br class=""><span class="Apple-tab-span" style="white-space: pre;">       </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-converted-space"> </span>* non-anonymous subscribe.<br class=""><span class="Apple-tab-span" style="white-space: pre;">    </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-converted-space"> </span>*/<br class="">-<span class="Apple-tab-span" style="white-space: pre;">   </span><span class="Apple-tab-span" style="white-space: pre;">  </span>box_sync_replication(true);<br class="">+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;">  </span>box_restart_replication();<br class=""><span class="Apple-tab-span" style="white-space: pre;">   </span><span class="Apple-tab-span" style="white-space: pre;">  </span>/*<br class=""><span class="Apple-tab-span" style="white-space: pre;">   </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-converted-space"> </span>* Wait until the master has registered this<br class=""><span class="Apple-tab-span" style="white-space: pre;">   </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-converted-space"> </span>* instance.<br class="">@@ -3258,7 +3273,7 @@ bootstrap(const struct tt_uuid *instance_uuid,<br class=""><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-converted-space"> </span>* with connecting to 'replication_connect_quorum' masters.<br class=""><span class="Apple-tab-span" style="white-space: pre;">    </span><span class="Apple-converted-space"> </span>* If this also fails, throw an error.<br class=""><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-converted-space"> </span>*/<br class="">-<span class="Apple-tab-span" style="white-space: pre;">   </span>box_sync_replication(true);<br class="">+<span class="Apple-tab-span" style="white-space: pre;"> </span>box_restart_replication();<br class=""><br class=""><span class="Apple-tab-span" style="white-space: pre;">      </span>struct replica *master = replicaset_find_join_master();<br class=""><span class="Apple-tab-span" style="white-space: pre;">      </span>assert(master == NULL || master->applier != NULL);<br class="">@@ -3335,7 +3350,7 @@ local_recovery(const struct tt_uuid *instance_uuid,<br class=""><span class="Apple-tab-span" style="white-space: pre;">  </span>if (wal_dir_lock >= 0) {<br class=""><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>if (box_listen() != 0)<br class=""><span class="Apple-tab-span" style="white-space: pre;">       </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>diag_raise();<br class="">-<span class="Apple-tab-span" style="white-space: pre;">       </span><span class="Apple-tab-span" style="white-space: pre;">  </span>box_sync_replication(false);<br class="">+<span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">  </span>box_update_replication();<br class=""><br class=""><span class="Apple-tab-span" style="white-space: pre;">       </span><span class="Apple-tab-span" style="white-space: pre;">  </span>struct replica *master;<br class=""><span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span>if (replicaset_needs_rejoin(&master)) {<br class="">@@ -3414,7 +3429,7 @@ local_recovery(const struct tt_uuid *instance_uuid,<br class=""><span class="Apple-tab-span" style="white-space: pre;">    </span><span class="Apple-tab-span" style="white-space: pre;">  </span>vclock_copy(&replicaset.vclock, &recovery->vclock);<br class=""><span class="Apple-tab-span" style="white-space: pre;">       </span><span class="Apple-tab-span" style="white-space: pre;">  </span>if (box_listen() != 0)<br class=""><span class="Apple-tab-span" style="white-space: pre;">       </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>diag_raise();<br class="">-<span class="Apple-tab-span" style="white-space: pre;">       </span><span class="Apple-tab-span" style="white-space: pre;">  </span>box_sync_replication(false);<br class="">+<span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">  </span>box_update_replication();<br class=""><span class="Apple-tab-span" style="white-space: pre;">    </span>}<br class=""><span class="Apple-tab-span" style="white-space: pre;">    </span>stream_guard.is_active = false;<br class=""><span class="Apple-tab-span" style="white-space: pre;">      </span>recovery_finalize(recovery);<br class="">diff --git a/src/box/<a href="http://replication.cc" class="">replication.cc</a> b/src/box/<a href="http://replication.cc" class="">replication.cc</a><br class="">index 1288bc9b1..10b4ac915 100644<br class="">--- a/src/box/<a href="http://replication.cc" class="">replication.cc</a><br class="">+++ b/src/box/<a href="http://replication.cc" class="">replication.cc</a><br class="">@@ -507,7 +507,7 @@ replica_on_applier_state_f(struct trigger *trigger, void *event)<br class=""> * upon reconfiguration of box.cfg.replication.<br class=""> */<br class="">static void<br class="">-replicaset_update(struct applier **appliers, int count)<br class="">+replicaset_update(struct applier **appliers, int count, bool keep_connect)<br class="">{<br class=""><span class="Apple-tab-span" style="white-space: pre;">  </span>replica_hash_t uniq;<br class=""><span class="Apple-tab-span" style="white-space: pre;"> </span>memset(&uniq, 0, sizeof(uniq));<br class="">@@ -572,22 +572,39 @@ replicaset_update(struct applier **appliers, int count)<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">  </span>applier_stop(applier);<br class=""><span class="Apple-tab-span" style="white-space: pre;">       </span><span class="Apple-tab-span" style="white-space: pre;">  </span>applier_delete(applier);<br class=""><span class="Apple-tab-span" style="white-space: pre;">     </span>}<br class="">+<br class="">+<span class="Apple-tab-span" style="white-space: pre;">     </span>replicaset.applier.total = count;<br class="">+<span class="Apple-tab-span" style="white-space: pre;">   </span>replicaset.applier.connected = 0;<br class="">+<span class="Apple-tab-span" style="white-space: pre;">   </span>replicaset.applier.loading = 0;<br class="">+<span class="Apple-tab-span" style="white-space: pre;">     </span>replicaset.applier.synced = 0;<br class=""><span class="Apple-tab-span" style="white-space: pre;">       </span>replicaset_foreach(replica) {<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">  </span>if (replica->applier == NULL)<br class=""><span class="Apple-tab-span" style="white-space: pre;">     </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>continue;<br class="">-<span class="Apple-tab-span" style="white-space: pre;">   </span><span class="Apple-tab-span" style="white-space: pre;">  </span>applier = replica->applier;<br class="">-<span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span>replica_clear_applier(replica);<br class="">-<span class="Apple-tab-span" style="white-space: pre;">     </span><span class="Apple-tab-span" style="white-space: pre;">  </span>replica->applier_sync_state = APPLIER_DISCONNECTED;<br class="">+<span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span>struct replica *other = replica_hash_search(&uniq, replica);<br class="">+<span class="Apple-tab-span" style="white-space: pre;">    </span><span class="Apple-tab-span" style="white-space: pre;">  </span>if (keep_connect && other != NULL &&<br class="">+<span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-converted-space"> </span>   (replica->applier->state == APPLIER_FOLLOW ||<br class="">+<span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-converted-space"> </span>    replica->applier->state == APPLIER_SYNC)) {<br class="">+<span class="Apple-tab-span" style="white-space: pre;">    </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>/*<br class="">+<span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-converted-space"> </span>* Try not to interrupt working appliers upon<br class="">+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-converted-space"> </span>* reconfiguration.<br class="">+<span class="Apple-tab-span" style="white-space: pre;">   </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-converted-space"> </span>*/<br class="">+<span class="Apple-tab-span" style="white-space: pre;">   </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>replicaset.applier.connected++;<br class="">+<span class="Apple-tab-span" style="white-space: pre;">     </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>replicaset.applier.synced++;<br class="">+<span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>replica_hash_remove(&uniq, other);<br class="">+<span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>applier = other->applier;<br class="">+<span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>replica_clear_applier(other);<br class="">+<span class="Apple-tab-span" style="white-space: pre;">       </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>replica_delete(other);<br class="">+<span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span>} else {<br class="">+<span class="Apple-tab-span" style="white-space: pre;">    </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>applier = replica->applier;<br class="">+<span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>replica_clear_applier(replica);<br class="">+<span class="Apple-tab-span" style="white-space: pre;">     </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>replica->applier_sync_state = APPLIER_DISCONNECTED;<br class="">+<span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span>}<br class=""><span class="Apple-tab-span" style="white-space: pre;">    </span><span class="Apple-tab-span" style="white-space: pre;">  </span>applier_stop(applier);<br class=""><span class="Apple-tab-span" style="white-space: pre;">       </span><span class="Apple-tab-span" style="white-space: pre;">  </span>applier_delete(applier);<br class=""><span class="Apple-tab-span" style="white-space: pre;">     </span>}<br class=""><br class="">-<span class="Apple-tab-span" style="white-space: pre;">      </span>/* Save new appliers */<br class="">-<span class="Apple-tab-span" style="white-space: pre;">     </span>replicaset.applier.total = count;<br class="">-<span class="Apple-tab-span" style="white-space: pre;">   </span>replicaset.applier.connected = 0;<br class="">-<span class="Apple-tab-span" style="white-space: pre;">   </span>replicaset.applier.loading = 0;<br class="">-<span class="Apple-tab-span" style="white-space: pre;">     </span>replicaset.applier.synced = 0;<br class=""><br class="">+<span class="Apple-tab-span" style="white-space: pre;"> </span>/* Save new appliers */<br class=""><span class="Apple-tab-span" style="white-space: pre;">      </span>replica_hash_foreach_safe(&uniq, replica, next) {<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">  </span>replica_hash_remove(&uniq, replica);<br class=""><br class="">@@ -664,11 +681,11 @@ applier_on_connect_f(struct trigger *trigger, void *event)<br class=""><br class="">void<br class="">replicaset_connect(struct applier **appliers, int count,<br class="">-<span class="Apple-tab-span" style="white-space: pre;">       </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-converted-space"> </span>  bool connect_quorum)<br class="">+<span class="Apple-tab-span" style="white-space: pre;">     </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-converted-space"> </span>  bool connect_quorum, bool keep_connect)<br class="">{<br class=""><span class="Apple-tab-span" style="white-space: pre;">     </span>if (count == 0) {<br class=""><span class="Apple-tab-span" style="white-space: pre;">    </span><span class="Apple-tab-span" style="white-space: pre;">  </span>/* Cleanup the replica set. */<br class="">-<span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span>replicaset_update(appliers, count);<br class="">+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;">  </span>replicaset_update(appliers, 0, false);<br class=""><span class="Apple-tab-span" style="white-space: pre;">       </span><span class="Apple-tab-span" style="white-space: pre;">  </span>return;<br class=""><span class="Apple-tab-span" style="white-space: pre;">      </span>}<br class=""><br class="">@@ -772,7 +789,7 @@ replicaset_connect(struct applier **appliers, int count,<br class=""><br class=""><span class="Apple-tab-span" style="white-space: pre;"> </span>/* Now all the appliers are connected, update the replica set. */<br class=""><span class="Apple-tab-span" style="white-space: pre;">    </span>try {<br class="">-<span class="Apple-tab-span" style="white-space: pre;">       </span><span class="Apple-tab-span" style="white-space: pre;">  </span>replicaset_update(appliers, count);<br class="">+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;">  </span>replicaset_update(appliers, count, keep_connect);<br class=""><span class="Apple-tab-span" style="white-space: pre;">    </span>} catch (Exception *e) {<br class=""><span class="Apple-tab-span" style="white-space: pre;">     </span><span class="Apple-tab-span" style="white-space: pre;">  </span>goto error;<br class=""><span class="Apple-tab-span" style="white-space: pre;">  </span>}<br class="">diff --git a/src/box/replication.h b/src/box/replication.h<br class="">index 4c82cd839..a8fed45e8 100644<br class="">--- a/src/box/replication.h<br class="">+++ b/src/box/replication.h<br class="">@@ -439,10 +439,12 @@ replicaset_add_anon(const struct tt_uuid *replica_uuid);<br class=""> * \param connect_quorum if this flag is set, fail unless at<br class=""> *                       least replication_connect_quorum<br class=""> *                       appliers have successfully connected.<br class="">+ * \param keep_connect   if this flag is set do not force a reconnect if the<br class="">+ *                       old connection to the replica is fine.<br class=""> */<br class="">void<br class="">replicaset_connect(struct applier **appliers, int count,<br class="">-<span class="Apple-tab-span" style="white-space: pre;">    </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-converted-space"> </span>  bool connect_quorum);<br class="">+<span class="Apple-tab-span" style="white-space: pre;">    </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-converted-space"> </span>  bool connect_quorum, bool keep_connect);<br class=""><br class="">/**<br class=""> * Check if the current instance fell too much behind its<br class="">diff --git a/test/instance_files/base_instance.lua b/test/instance_files/base_instance.lua<br class="">index 45bdbc7e8..e579c3843 100755<br class="">--- a/test/instance_files/base_instance.lua<br class="">+++ b/test/instance_files/base_instance.lua<br class="">@@ -5,7 +5,8 @@ local listen = os.getenv('TARANTOOL_LISTEN')<br class="">box.cfg({<br class="">    work_dir = workdir,<br class="">--     listen = 'localhost:3310'<br class="">-    listen = listen<br class="">+    listen = listen,<br class="">+    log = workdir..'/tarantool.log',<br class="">})<br class=""><br class="">box.schema.user.grant('guest', 'read,write,execute,create', 'universe')<br class="">diff --git a/test/instance_files/replica.lua b/test/instance_files/replica.lua<br class="">new file mode 100755<br class="">index 000000000..587345f24<br class="">--- /dev/null<br class="">+++ b/test/instance_files/replica.lua<br class="">@@ -0,0 +1,17 @@<br class="">+#!/usr/bin/env tarantool<br class="">+local workdir = os.getenv('TARANTOOL_WORKDIR')<br class="">+local listen = os.getenv('TARANTOOL_LISTEN')<br class="">+local SOCKET_DIR = os.getenv('VARDIR')<br class="">+local MASTER = arg[1] or "master"<br class="">+<br class="">+local function master_uri()<br class="">+    return SOCKET_DIR..'/'..MASTER..'.sock'<br class="">+end<br class="">+<br class="">+box.cfg({<br class="">+    work_dir = workdir,<br class="">+    listen = listen,<br class="">+    replication = master_uri(),<br class="">+})<br class="">+<br class="">+_G.ready = true<br class="">diff --git a/test/luatest_helpers/server.lua b/test/luatest_helpers/server.lua<br class="">index 018ea4f7d..0306a24ef 100644<br class="">--- a/test/luatest_helpers/server.lua<br class="">+++ b/test/luatest_helpers/server.lua<br class="">@@ -5,6 +5,7 @@ local fiber = require('fiber')<br class="">local fio = require('fio')<br class="">local fun = require('fun')<br class="">local json = require('json')<br class="">+local errno = require('errno')<br class=""><br class="">local checks = require('checks')<br class="">local luatest = require('luatest')<br class="">@@ -59,6 +60,70 @@ function Server:initialize()<br class="">    getmetatable(getmetatable(self)).initialize(self)<br class="">end<br class=""><br class="">+-- A copy of test_run:grep_log.<br class="">+function Server:grep_log(what, bytes, opts)<br class="">+    local opts = opts or {}<br class="">+    local noreset = opts.noreset or false<br class="">+    -- if instance has crashed provide filename to use grep_log<br class="">+    local filename = opts.filename or self:eval('return box.cfg.log')<br class="">+    local file = fio.open(filename, {'O_RDONLY', 'O_NONBLOCK'})<br class="">+<br class="">+    local function fail(msg)<br class="">+        local err = errno.strerror()<br class="">+        if file ~= nil then<br class="">+            file:close()<br class="">+        end<br class="">+        error(string.format("%s: %s: %s", msg, filename, err))<br class="">+    end<br class="">+<br class="">+    if file == nil then<br class="">+        fail("Failed to open log file")<br class="">+    end<br class="">+    io.flush() -- attempt to flush stdout == log fd<br class="">+    local filesize = file:seek(0, 'SEEK_END')<br class="">+    if filesize == nil then<br class="">+        fail("Failed to get log file size")<br class="">+    end<br class="">+    local bytes = bytes or 65536 -- don't read whole log - it can be huge<br class="">+    bytes = bytes > filesize and filesize or bytes<br class="">+    if file:seek(-bytes, 'SEEK_END') == nil then<br class="">+        fail("Failed to seek log file")<br class="">+    end<br class="">+    local found, buf<br class="">+    repeat -- read file in chunks<br class="">+        local s = file:read(2048)<br class="">+        if s == nil then<br class="">+            fail("Failed to read log file")<br class="">+        end<br class="">+        local pos = 1<br class="">+        repeat -- split read string in lines<br class="">+            local endpos = string.find(s, '\n', pos)<br class="">+            endpos = endpos and endpos - 1 -- strip terminating \n<br class="">+            local line = string.sub(s, pos, endpos)<br class="">+            if endpos == nil and s ~= '' then<br class="">+                -- line doesn't end with \n or eof, append it to buffer<br class="">+                -- to be checked on next iteration<br class="">+                buf = buf or {}<br class="">+                table.insert(buf, line)<br class="">+            else<br class="">+                if buf ~= nil then -- prepend line with buffered data<br class="">+                    table.insert(buf, line)<br class="">+                    line = table.concat(buf)<br class="">+                    buf = nil<br class="">+                end<br class="">+                if string.match(line, "Starting instance") and not noreset then<br class="">+                    found = nil -- server was restarted, reset search<br class="">+                else<br class="">+                    found = string.match(line, what) or found<br class="">+                end<br class="">+            end<br class="">+            pos = endpos and endpos + 2 -- jump to char after \n<br class="">+        until pos == nil<br class="">+    until s == ''<br class="">+    file:close()<br class="">+    return found<br class="">+end<br class="">+<br class="">--- Generates environment to run process with.<br class="">-- The result is merged into os.environ().<br class="">-- @return map<br class="">diff --git a/test/replication-luatest/gh_4669_applier_reconnect_test.lua b/test/replication-luatest/gh_4669_applier_reconnect_test.lua<br class="">new file mode 100644<br class="">index 000000000..19e10b136<br class="">--- /dev/null<br class="">+++ b/test/replication-luatest/gh_4669_applier_reconnect_test.lua<br class="">@@ -0,0 +1,40 @@<br class="">+local t = require('luatest')<br class="">+local cluster = require('test.luatest_helpers.cluster')<br class="">+<br class="">+local g = t.group('gh-4669-applier-reconnect')<br class="">+<br class="">+local function check_follow_master(server)<br class="">+    return t.assert_equals(<br class="">+        server:eval('return box.info.replication[1].upstream.status'), 'follow')<br class="">+end<br class="">+<br class="">+g.before_each(function()<br class="">+    g.cluster = cluster:new({})<br class="">+    g.master = g.cluster:build_server(<br class="">+        {}, {alias = 'master'}, 'base_instance.lua')<br class="">+    g.replica = g.cluster:build_server(<br class="">+        {args={'master'}}, {alias = 'replica'}, 'replica.lua')<br class="">+<br class="">+    g.cluster:join_server(g.master)<br class="">+    g.cluster:join_server(g.replica)<br class="">+    g.cluster:start()<br class="">+    check_follow_master(g.replica)<br class="">+end)<br class="">+<br class="">+g.after_each(function()<br class="">+    g.cluster:stop()<br class="">+end)<br class="">+<br class="">+-- Test that appliers aren't recreated upon replication reconfiguration.<br class="">+g.test_applier_connection_on_reconfig = function(g)<br class="">+    g.replica:eval([[<br class="">+        box.cfg{<br class="">+            replication = {<br class="">+                os.getenv("TARANTOOL_LISTEN"),<br class="">+                box.cfg.replication[1],<br class="">+            }<br class="">+        }<br class="">+    ]])<br class=""></blockquote>Should we test this with dynamic add/remove of a 2nd replica?<br class=""></blockquote><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">No problem. Here's the diff:</span><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">============================</span><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">diff --git a/test/replication-luatest/gh_4669_applier_reconnect_test.lua b/test/replication-luatest/gh_4669_applier_reconnect_test.lua</span><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">index 19e10b136..e082515fd 100644</span><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">--- a/test/replication-luatest/gh_4669_applier_reconnect_test.lua</span><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">+++ b/test/replication-luatest/gh_4669_applier_reconnect_test.lua</span><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">@@ -14,9 +14,12 @@ g.before_each(function()</span><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">         {}, {alias = 'master'}, 'base_instance.lua')</span><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">     g.replica = g.cluster:build_server(</span><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">         {args={'master'}}, {alias = 'replica'}, 'replica.lua')</span><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">+    g.replica2 = g.cluster:build_server(</span><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">+        {args={'master'}}, {alias = 'replica2'}, 'replica.lua')</span><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">     g.cluster:join_server(g.master)</span><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">     g.cluster:join_server(g.replica)</span><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">+    g.cluster:join_server(g.replica2)</span><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">     g.cluster:start()</span><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">     check_follow_master(g.replica)</span><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class=""> end)</span><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">@@ -26,12 +29,20 @@ g.after_each(function()</span><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class=""> end)</span><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class=""> -- Test that appliers aren't recreated upon replication reconfiguration.</span><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">+-- Add and then remove two extra replicas to the configuration. The master</span><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">+-- connection should stay intact.</span><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class=""> g.test_applier_connection_on_reconfig = function(g)</span><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">     g.replica:eval([[</span><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">         box.cfg{</span><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">             replication = {</span><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">                 os.getenv("TARANTOOL_LISTEN"),</span><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">                 box.cfg.replication[1],</span><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">+                os.getenv('VARDIR')..'/replica2.sock'</span><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">+            }</span><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">+        }</span><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">+        box.cfg{</span><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">+            replication = {</span><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">+                box.cfg.replication[2]</span><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">             }</span><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">         }</span><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">     ]])</span><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">============================</span><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><blockquote type="cite" style="font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><br class=""><blockquote type="cite" class="">+    check_follow_master(g.replica)<br class="">+    t.assert_equals(g.master:grep_log("exiting the relay loop"), nil)<br class="">+end<br class="">--<span class="Apple-converted-space"> </span><br class="">2.30.1 (Apple Git-130)<br class=""><br class=""></blockquote></blockquote><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">--<span class="Apple-converted-space"> </span></span><br style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">Serge Petrenko</span></div></blockquote></div><br class=""></div></body></html>