Explorar o código

ZOOKEEPER-2847: Cannot bind to client port when reconfig based on old static config

Fixed the issue where clientPortAddress in the static config is not correctly saved in QuorumVerifier. This can cause zookeeper attempting to re-bind to a port already in use during dynamic reconfiguration, failing to recognize that the new port and the current port are identical.

Author: Yisong Yue <yisongyue@fb.com>

Reviewers: hanm@apache.org

Closes #620 from yisong-yue/ZOOKEEPER-2847
Yisong Yue %!s(int64=6) %!d(string=hai) anos
pai
achega
e116d32b63

+ 1 - 0
src/java/main/org/apache/zookeeper/server/quorum/QuorumPeerConfig.java

@@ -712,6 +712,7 @@ public class QuorumPeerConfig {
                         " is different from client address found in dynamic file: " + qs.clientAddr);
         }
         if (qs != null && qs.clientAddr != null) clientPortAddress = qs.clientAddr;
+        if (qs != null && qs.clientAddr == null) qs.clientAddr = clientPortAddress;
     }
 
     private void setupPeerType() {

+ 33 - 0
src/java/test/org/apache/zookeeper/server/quorum/QuorumPeerConfigTest.java

@@ -24,10 +24,12 @@ import static org.junit.Assert.fail;
 
 import java.io.File;
 import java.io.IOException;
+import java.net.InetSocketAddress;
 import java.util.Properties;
 
 import org.apache.zookeeper.common.ZKConfig;
 import org.apache.zookeeper.server.quorum.QuorumPeerConfig.ConfigException;
+import org.apache.zookeeper.server.quorum.QuorumPeer.QuorumServer;
 import org.junit.Test;
 
 public class QuorumPeerConfigTest {
@@ -114,6 +116,37 @@ public class QuorumPeerConfigTest {
         quorumPeerConfig.parseProperties(zkProp);
     }
 
+    /**
+     * Extend the existing QuorumPeerConfig to set the server id.
+     */
+    public static class MockQuorumPeerConfig extends QuorumPeerConfig {
+        public MockQuorumPeerConfig(long serverId) {
+            this.serverId = serverId;
+        }
+    }
+
+    /**
+     * Test case for https://issues.apache.org/jira/browse/ZOOKEEPER-2847
+     */
+    @Test
+    public void testClientAddrFromClientPort()
+            throws IOException, ConfigException {
+        long serverId = 1;
+        QuorumPeerConfig quorumPeerConfig = new MockQuorumPeerConfig(serverId);
+        Properties zkProp = getDefaultZKProperties();
+        int clientPort = 12345;
+        zkProp.setProperty("clientPort", Integer.toString(clientPort));
+        zkProp.setProperty("server.1", "127.0.0.1:2889:3889:participant");
+        quorumPeerConfig.parseProperties(zkProp);
+
+        QuorumServer qs =
+            quorumPeerConfig.getQuorumVerifier().getAllMembers().get(serverId);
+        InetSocketAddress expectedAddress =
+            new InetSocketAddress("0.0.0.0", clientPort);
+        assertEquals(expectedAddress, quorumPeerConfig.getClientPortAddress());
+        assertEquals(quorumPeerConfig.getClientPortAddress(), qs.clientAddr);
+    }
+
     private Properties getDefaultZKProperties() {
         Properties zkProp = new Properties();
         zkProp.setProperty("dataDir", new File("myDataDir").getAbsolutePath());