This is an automated email from the ASF dual-hosted git repository.

nkalmar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/zookeeper.git


The following commit(s) were added to refs/heads/master by this push:
     new b1105cc  ZOOKEEPER-3758: Leader reachability check fails with single 
address
b1105cc is described below

commit b1105ccc47685c64d1cca7ccb0b2bb66c194374a
Author: Mate Szalay-Beko <szalay.beko.m...@gmail.com>
AuthorDate: Thu Mar 19 17:09:38 2020 +0100

    ZOOKEEPER-3758: Leader reachability check fails with single address
    
    Since ZooKeeper 3.6.0 we can specify multiple addresses for each ZooKeeper 
server instance
    (this can increase availability when multiple physical network interfaces 
can be used parallel
    in the cluster). ZooKeeper will perform ICMP ECHO requests or try to 
establish a TCP connection
    on port 7 (Echo) of the destination host in order to find the reachable 
addresses. This should
    happen only if the user provide multiple addresses in the configuration, in 
a single address is
    used then ZooKeeper shouldn’t send any ICMP requests.
    
    This works as we expected for the leader election connections, but in this 
Jira issue we found
    a bug when the reachability check was performed even with a single address 
when the Follower
    tries to connect to the newly elected Leader.
    
    The fix follows the same approach we discussed for the election protocol 
before (see
    ZOOKEEPER-3698). We avoid the reachability check for single addresses. Also 
when we have
    multiple addresses and none of them can be reached, we still start to 
connect to all addresses
    in parallel.
    
    Author: Mate Szalay-Beko <szalay.beko.m...@gmail.com>
    
    Reviewers: Enrico Olivelli <eolive...@apache.org>, Norbert Kalmar 
<nkal...@apache.org>
    
    Closes #1288 from symat/ZOOKEEPER-3758
---
 .../apache/zookeeper/server/quorum/Learner.java    |  4 +++-
 .../zookeeper/server/quorum/MultipleAddresses.java | 18 +++++++++++++++
 .../server/quorum/MultipleAddressesTest.java       | 26 ++++++++++++++++++++++
 3 files changed, 47 insertions(+), 1 deletion(-)

diff --git 
a/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/Learner.java
 
b/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/Learner.java
index 0f8f444..8a0cac1 100644
--- 
a/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/Learner.java
+++ 
b/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/Learner.java
@@ -303,7 +303,9 @@ public class Learner {
         this.leaderAddr = multiAddr;
         Set<InetSocketAddress> addresses;
         if (self.isMultiAddressReachabilityCheckEnabled()) {
-            addresses = multiAddr.getAllReachableAddresses();
+            // even if none of the addresses are reachable, we want to try to 
establish connection
+            // see ZOOKEEPER-3758
+            addresses = multiAddr.getAllReachableAddressesOrAll();
         } else {
             addresses = multiAddr.getAllAddresses();
         }
diff --git 
a/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/MultipleAddresses.java
 
b/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/MultipleAddresses.java
index 3ee63fa..9f15389 100644
--- 
a/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/MultipleAddresses.java
+++ 
b/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/MultipleAddresses.java
@@ -140,6 +140,24 @@ public final class MultipleAddresses {
     }
 
     /**
+     * Returns a set of all reachable addresses. If none is reachable than 
returns all addresses.
+     *
+     * @return all reachable addresses, or all addresses if none is reachable.
+     */
+    public Set<InetSocketAddress> getAllReachableAddressesOrAll() {
+        // if there is only a single address provided then we don't need to do 
any reachability check
+        if (addresses.size() == 1) {
+            return getAllAddresses();
+        }
+
+        Set<InetSocketAddress> allReachable = getAllReachableAddresses();
+        if (allReachable.isEmpty()) {
+            return getAllAddresses();
+        }
+        return allReachable;
+    }
+
+    /**
      * Returns a reachable address or an arbitrary one, if none is reachable. 
It throws an exception
      * if there are no addresses registered. The function is nondeterministic 
in the sense that the
      * result of calling this function twice with the same set of reachable 
addresses might lead
diff --git 
a/zookeeper-server/src/test/java/org/apache/zookeeper/server/quorum/MultipleAddressesTest.java
 
b/zookeeper-server/src/test/java/org/apache/zookeeper/server/quorum/MultipleAddressesTest.java
index e8f08c6..0e1615d 100644
--- 
a/zookeeper-server/src/test/java/org/apache/zookeeper/server/quorum/MultipleAddressesTest.java
+++ 
b/zookeeper-server/src/test/java/org/apache/zookeeper/server/quorum/MultipleAddressesTest.java
@@ -188,6 +188,32 @@ public class MultipleAddressesTest {
     }
 
     @Test
+    public void testGetAllReachableAddressesOrAllWhenSomeReachable() throws 
Exception {
+        InetSocketAddress reachableHost1 = new InetSocketAddress("127.0.0.1", 
1234);
+        InetSocketAddress reachableHost2 = new InetSocketAddress("127.0.0.1", 
2345);
+        InetSocketAddress unreachableHost1 = new 
InetSocketAddress("unreachable1.address.zookeeper.apache.com", 1234);
+        InetSocketAddress unreachableHost2 = new 
InetSocketAddress("unreachable2.address.zookeeper.apache.com", 1234);
+
+        MultipleAddresses multipleAddresses = new MultipleAddresses(
+          Arrays.asList(unreachableHost1, unreachableHost2, reachableHost1, 
reachableHost2));
+
+        Set<InetSocketAddress> reachableHosts = new 
HashSet<>(Arrays.asList(reachableHost1, reachableHost2));
+        Assert.assertEquals(reachableHosts, 
multipleAddresses.getAllReachableAddressesOrAll());
+    }
+
+    @Test
+    public void testGetAllReachableAddressesOrAllWhenNoneReachable() throws 
Exception {
+        InetSocketAddress unreachableHost1 = new 
InetSocketAddress("unreachable1.address.zookeeper.apache.com", 1234);
+        InetSocketAddress unreachableHost2 = new 
InetSocketAddress("unreachable2.address.zookeeper.apache.com", 1234);
+        InetSocketAddress unreachableHost3 = new 
InetSocketAddress("unreachable3.address.zookeeper.apache.com", 1234);
+        List<InetSocketAddress> allUnreachableAddresses = 
Arrays.asList(unreachableHost1, unreachableHost2, unreachableHost3);
+
+        MultipleAddresses multipleAddresses = new 
MultipleAddresses(allUnreachableAddresses);
+
+        Assert.assertEquals(new HashSet<>(allUnreachableAddresses), 
multipleAddresses.getAllReachableAddressesOrAll());
+    }
+
+    @Test
     public void testEquals() {
         List<InetSocketAddress> addresses = getAddressList();
 

Reply via email to