You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kyuubi.apache.org by ch...@apache.org on 2023/05/15 17:53:49 UTC

[kyuubi-shaded] branch master updated: [KYUUBI-SHADED #4] Copy StaticHostProvider from Zookeeper 3.4.14

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

chengpan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/kyuubi-shaded.git


The following commit(s) were added to refs/heads/master by this push:
     new 678c7ef  [KYUUBI-SHADED #4] Copy StaticHostProvider from Zookeeper 3.4.14
678c7ef is described below

commit 678c7ef2b7f1f0fbbbc896808f1d43c55e7f62a3
Author: Cheng Pan <ch...@apache.org>
AuthorDate: Tue May 16 01:53:39 2023 +0800

    [KYUUBI-SHADED #4] Copy StaticHostProvider from Zookeeper 3.4.14
    
    ### _Why are the changes needed?_
    
    Simply copy `StaticHostProvider` from Zookeeper 3.4.14, to pave the way for fixing ZOOKEEPER-3779
    
    ### _How was this patch tested?_
    - [ ] Add some test cases that check the changes thoroughly including negative and positive cases if possible
    
    - [ ] Add screenshots for manual tests if appropriate
    
    - [ ] [Run test](https://kyuubi.readthedocs.io/en/master/develop_tools/testing.html#running-tests) locally before make a pull request
    
    Closes #4 from pan3793/zk-34.
    
    6c588c9 [Cheng Pan] Copy StaticHostProvider from Zookeeper 3.4.14
    
    Authored-by: Cheng Pan <ch...@apache.org>
    Signed-off-by: Cheng Pan <ch...@apache.org>
---
 .../kyuubi-shaded-zookeeper-34/pom.xml             |  14 ++
 .../zookeeper/client/StaticHostProvider.java       | 170 +++++++++++++++++++++
 2 files changed, 184 insertions(+)

diff --git a/kyuubi-shaded-zookeeper-parent/kyuubi-shaded-zookeeper-34/pom.xml b/kyuubi-shaded-zookeeper-parent/kyuubi-shaded-zookeeper-34/pom.xml
index 3faf27d..c6b8e1d 100644
--- a/kyuubi-shaded-zookeeper-parent/kyuubi-shaded-zookeeper-34/pom.xml
+++ b/kyuubi-shaded-zookeeper-parent/kyuubi-shaded-zookeeper-34/pom.xml
@@ -33,6 +33,8 @@ under the License.
     <properties>
         <zookeeper.version>3.4.14</zookeeper.version>
         <curator.version>4.2.0</curator.version>
+        <slf4j.version>1.7.25</slf4j.version>
+        <yetus.version>0.5.0</yetus.version>
     </properties>
 
     <dependencyManagement>
@@ -46,6 +48,18 @@ under the License.
     </dependencyManagement>
 
     <dependencies>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+            <version>${slf4j.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.yetus</groupId>
+            <artifactId>audience-annotations</artifactId>
+            <version>${yetus.version}</version>
+            <scope>provided</scope>
+        </dependency>
         <dependency>
             <groupId>org.apache.zookeeper</groupId>
             <artifactId>zookeeper</artifactId>
diff --git a/kyuubi-shaded-zookeeper-parent/kyuubi-shaded-zookeeper-34/src/main/java/org/apache/zookeeper/client/StaticHostProvider.java b/kyuubi-shaded-zookeeper-parent/kyuubi-shaded-zookeeper-34/src/main/java/org/apache/zookeeper/client/StaticHostProvider.java
new file mode 100644
index 0000000..8a24783
--- /dev/null
+++ b/kyuubi-shaded-zookeeper-parent/kyuubi-shaded-zookeeper-34/src/main/java/org/apache/zookeeper/client/StaticHostProvider.java
@@ -0,0 +1,170 @@
+/**
+ * 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
+ *
+ * <p>http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * <p>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.client;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import org.apache.yetus.audience.InterfaceAudience;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Most simple HostProvider, resolves on every next() call.
+ *
+ * <p>Please be aware that although this class doesn't do any DNS caching, there're multiple levels
+ * of caching already present across the stack like in JVM, OS level, hardware, etc. The best we
+ * could do here is to get the most recent address from the underlying system which is considered
+ * up-to-date.
+ */
+@InterfaceAudience.Public
+public final class StaticHostProvider implements HostProvider {
+  public interface Resolver {
+    InetAddress[] getAllByName(String name) throws UnknownHostException;
+  }
+
+  private static final Logger LOG = LoggerFactory.getLogger(StaticHostProvider.class);
+
+  private final List<InetSocketAddress> serverAddresses = new ArrayList<InetSocketAddress>(5);
+
+  private int lastIndex = -1;
+
+  private int currentIndex = -1;
+
+  private Resolver resolver;
+
+  /**
+   * Constructs a SimpleHostSet.
+   *
+   * @param serverAddresses possibly unresolved ZooKeeper server addresses
+   * @throws IllegalArgumentException if serverAddresses is empty or resolves to an empty list
+   */
+  public StaticHostProvider(Collection<InetSocketAddress> serverAddresses) {
+    this.resolver =
+        new Resolver() {
+          @Override
+          public InetAddress[] getAllByName(String name) throws UnknownHostException {
+            return InetAddress.getAllByName(name);
+          }
+        };
+    init(serverAddresses);
+  }
+
+  /**
+   * Introduced for testing purposes. getAllByName() is a static method of InetAddress, therefore
+   * cannot be easily mocked. By abstraction of Resolver interface we can easily inject a mocked
+   * implementation in tests.
+   *
+   * @param serverAddresses possibly unresolved ZooKeeper server addresses
+   * @param resolver custom resolver implementation
+   * @throws IllegalArgumentException if serverAddresses is empty or resolves to an empty list
+   */
+  public StaticHostProvider(Collection<InetSocketAddress> serverAddresses, Resolver resolver) {
+    this.resolver = resolver;
+    init(serverAddresses);
+  }
+
+  /**
+   * Common init method for all constructors. Resolve all unresolved server addresses, put them in a
+   * list and shuffle.
+   */
+  private void init(Collection<InetSocketAddress> serverAddresses) {
+    if (serverAddresses.isEmpty()) {
+      throw new IllegalArgumentException("A HostProvider may not be empty!");
+    }
+
+    this.serverAddresses.addAll(serverAddresses);
+    Collections.shuffle(this.serverAddresses);
+  }
+
+  /**
+   * Evaluate to a hostname if one is available and otherwise it returns the string representation
+   * of the IP address.
+   *
+   * <p>In Java 7, we have a method getHostString, but earlier versions do not support it. This
+   * method is to provide a replacement for InetSocketAddress.getHostString().
+   *
+   * @param addr
+   * @return Hostname string of address parameter
+   */
+  private String getHostString(InetSocketAddress addr) {
+    String hostString = "";
+
+    if (addr == null) {
+      return hostString;
+    }
+    if (!addr.isUnresolved()) {
+      InetAddress ia = addr.getAddress();
+
+      // If the string starts with '/', then it has no hostname
+      // and we want to avoid the reverse lookup, so we return
+      // the string representation of the address.
+      if (ia.toString().startsWith("/")) {
+        hostString = ia.getHostAddress();
+      } else {
+        hostString = addr.getHostName();
+      }
+    } else {
+      // According to the Java 6 documentation, if the hostname is
+      // unresolved, then the string before the colon is the hostname.
+      String addrString = addr.toString();
+      hostString = addrString.substring(0, addrString.lastIndexOf(':'));
+    }
+
+    return hostString;
+  }
+
+  public int size() {
+    return serverAddresses.size();
+  }
+
+  public InetSocketAddress next(long spinDelay) {
+    currentIndex = ++currentIndex % serverAddresses.size();
+    if (currentIndex == lastIndex && spinDelay > 0) {
+      try {
+        Thread.sleep(spinDelay);
+      } catch (InterruptedException e) {
+        LOG.warn("Unexpected exception", e);
+      }
+    } else if (lastIndex == -1) {
+      // We don't want to sleep on the first ever connect attempt.
+      lastIndex = 0;
+    }
+
+    InetSocketAddress curAddr = serverAddresses.get(currentIndex);
+    try {
+      String curHostString = getHostString(curAddr);
+      List<InetAddress> resolvedAddresses =
+          new ArrayList<InetAddress>(Arrays.asList(this.resolver.getAllByName(curHostString)));
+      if (resolvedAddresses.isEmpty()) {
+        return curAddr;
+      }
+      Collections.shuffle(resolvedAddresses);
+      return new InetSocketAddress(resolvedAddresses.get(0), curAddr.getPort());
+    } catch (UnknownHostException e) {
+      return curAddr;
+    }
+  }
+
+  @Override
+  public void onConnected() {
+    lastIndex = currentIndex;
+  }
+}