java: add a fake DNS resolver to avoid reverse DNS hangs On my system, I found that reverse DNS lookups for IPs like 127.3.4.5 were causing 5-second hangs. This wasn't a problem previously because we don't ourselves do any reverse DNS, but it turns out that the GSSAPI implementation in Java always does reverse DNS with no way to disable it.
This adds a wrapper which can be installed into the InetAddress.nameServices list which short-circuits the reverse lookups for such IP addresses. This fixed the 5-second negotiation hangs that I saw on my system. Change-Id: Ife71d7a815c7ef2028e569476fba060481b00f97 Reviewed-on: http://gerrit.cloudera.org:8080/6076 Tested-by: Kudu Jenkins Reviewed-by: Dan Burkert <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/kudu/repo Commit: http://git-wip-us.apache.org/repos/asf/kudu/commit/66e57564 Tree: http://git-wip-us.apache.org/repos/asf/kudu/tree/66e57564 Diff: http://git-wip-us.apache.org/repos/asf/kudu/diff/66e57564 Branch: refs/heads/master Commit: 66e57564be49f1bfb701b51655a1fe3a1a8178d7 Parents: 77e8849 Author: Todd Lipcon <[email protected]> Authored: Sat Feb 18 18:19:49 2017 -0800 Committer: Todd Lipcon <[email protected]> Committed: Wed Feb 22 04:49:23 2017 +0000 ---------------------------------------------------------------------- .../org/apache/kudu/client/BaseKuduTest.java | 2 + .../java/org/apache/kudu/client/FakeDNS.java | 91 ++++++++++++++++++++ 2 files changed, 93 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/kudu/blob/66e57564/java/kudu-client/src/test/java/org/apache/kudu/client/BaseKuduTest.java ---------------------------------------------------------------------- diff --git a/java/kudu-client/src/test/java/org/apache/kudu/client/BaseKuduTest.java b/java/kudu-client/src/test/java/org/apache/kudu/client/BaseKuduTest.java index a25e74a..c87b706 100644 --- a/java/kudu-client/src/test/java/org/apache/kudu/client/BaseKuduTest.java +++ b/java/kudu-client/src/test/java/org/apache/kudu/client/BaseKuduTest.java @@ -79,6 +79,8 @@ public class BaseKuduTest { @BeforeClass public static void setUpBeforeClass() throws Exception { + FakeDNS.getInstance().install(); + LOG.info("Setting up before class..."); miniCluster = miniClusterBuilder http://git-wip-us.apache.org/repos/asf/kudu/blob/66e57564/java/kudu-client/src/test/java/org/apache/kudu/client/FakeDNS.java ---------------------------------------------------------------------- diff --git a/java/kudu-client/src/test/java/org/apache/kudu/client/FakeDNS.java b/java/kudu-client/src/test/java/org/apache/kudu/client/FakeDNS.java new file mode 100644 index 0000000..6ac8939 --- /dev/null +++ b/java/kudu-client/src/test/java/org/apache/kudu/client/FakeDNS.java @@ -0,0 +1,91 @@ +// 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.kudu.client; + +import java.lang.reflect.Field; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.List; + +import javax.annotation.concurrent.GuardedBy; + +import com.google.common.base.Throwables; +import com.google.common.net.InetAddresses; + +import sun.net.spi.nameservice.NameService; + +/** + * Fake DNS resolver which allows our tests to work well even though we use + * strange loopback IP addresses (127.x.y.z) with no corresponding reverse + * DNS. + * + * This overrides the reverse lookups for such IPs to return the same address + * in String form. + * + * Without this class, reverse DNS lookups for such addresses often take + * 5 seconds to return, causing timeouts and overall test slowness. + * + * In the future this class might also be extended to test more interesting + * DNS-related scenarios. + */ +public class FakeDNS { + static FakeDNS instance = new FakeDNS(); + + /** whether the fake resolver has been installed */ + @GuardedBy("this") + private boolean installed = false; + + private FakeDNS() {} + public static FakeDNS getInstance() { + return instance; + } + + /** + * Install the fake DNS resolver into the Java runtime. + */ + public synchronized void install() { + if (installed) return; + try { + Field field = InetAddress.class.getDeclaredField("nameServices"); + field.setAccessible(true); + @SuppressWarnings("unchecked") + List<NameService> nameServices = (List<NameService>) field.get(null); + nameServices.add(0, new NSImpl()); + } catch (Exception e) { + throw Throwables.propagate(e); + } + installed = true; + } + + private class NSImpl implements NameService { + @Override + public InetAddress[] lookupAllHostAddr(String host) + throws UnknownHostException { + // JDK chains to the next provider automatically. + throw new UnknownHostException(); + } + + @Override + public String getHostByAddr(byte[] addr) throws UnknownHostException { + if (addr[0] == 127) { + return InetAddresses.toAddrString(InetAddress.getByAddress(addr)); + } + throw new UnknownHostException(); + } + } +}
