Przeglądaj źródła

ZOOKEEPER-3540: Avoid client port unavailable by skip binding the same client port during reconfig

Author: Fangmin Lyu <fangmin@apache.org>

Reviewers: Enrico Olivelli <eolivelli@apache.org>

Closes #1083 from lvfangmin/ZOOKEEPER-3540
Fangmin Lyu 5 lat temu
rodzic
commit
8460f4ed48

+ 14 - 1
zookeeper-server/src/main/java/org/apache/zookeeper/server/NettyServerCnxnFactory.java

@@ -622,9 +622,18 @@ public class NettyServerCnxnFactory extends ServerCnxnFactory {
     }
 
     public void reconfigure(InetSocketAddress addr) {
+        LOG.info("binding to port {}, {}", addr, localAddress);
+        if (addr != null && localAddress != null) {
+            if (addr.equals(localAddress) || (addr.getAddress().isAnyLocalAddress()
+                    && localAddress.getAddress().isAnyLocalAddress()
+                    && addr.getPort() == localAddress.getPort())) {
+                 LOG.info("address is the same, skip rebinding");
+                 return;
+            }
+        }
+
         Channel oldChannel = parentChannel;
         try {
-            LOG.info("binding to port {}", addr);
             parentChannel = bootstrap.bind(addr).syncUninterruptibly().channel();
             // Port changes after bind() if the original port was 0, update
             // localAddress to get the real port.
@@ -734,4 +743,8 @@ public class NettyServerCnxnFactory extends ServerCnxnFactory {
         this.secure = secure;
     }
 
+    // VisibleForTest
+    public Channel getParentChannel() {
+        return parentChannel;
+    }
 }

+ 61 - 0
zookeeper-server/src/test/java/org/apache/zookeeper/server/NettyServerCnxnFactoryTest.java

@@ -0,0 +1,61 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zookeeper.server;
+
+import java.net.InetSocketAddress;
+import org.apache.zookeeper.PortAssignment;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class NettyServerCnxnFactoryTest {
+
+    @Test
+    public void testRebind() throws Exception {
+        InetSocketAddress addr = new InetSocketAddress(PortAssignment.unique());
+        NettyServerCnxnFactory factory = new NettyServerCnxnFactory();
+        factory.configure(addr, 100, -1, false);
+        factory.start();
+        Assert.assertTrue(factory.getParentChannel().isActive());
+
+        factory.reconfigure(addr);
+
+        // wait the state change
+        Thread.sleep(100);
+
+        Assert.assertTrue(factory.getParentChannel().isActive());
+    }
+
+    @Test
+    public void testRebindIPv4IPv6() throws Exception {
+        int randomPort = PortAssignment.unique();
+        InetSocketAddress addr = new InetSocketAddress("0.0.0.0", randomPort);
+        NettyServerCnxnFactory factory = new NettyServerCnxnFactory();
+        factory.configure(addr, 100, -1, false);
+        factory.start();
+        Assert.assertTrue(factory.getParentChannel().isActive());
+
+        factory.reconfigure(new InetSocketAddress("[0:0:0:0:0:0:0:0]", randomPort));
+
+        // wait the state change
+        Thread.sleep(100);
+
+        Assert.assertTrue(factory.getParentChannel().isActive());
+    }
+
+}