diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/RackManager.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/RackManager.java index 498b95c..3faafca 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/RackManager.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/RackManager.java @@ -20,13 +20,20 @@ package org.apache.hadoop.hbase.master; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.hbase.classification.InterfaceAudience; import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.hbase.DaemonThreadFactory; import org.apache.hadoop.hbase.ServerName; import org.apache.hadoop.hbase.util.ReflectionUtils; +import org.apache.hadoop.net.CachedDNSToSwitchMapping; import org.apache.hadoop.net.DNSToSwitchMapping; import org.apache.hadoop.net.ScriptBasedMapping; /** @@ -40,6 +47,13 @@ public class RackManager { public static final String UNKNOWN_RACK = "Unknown Rack"; private DNSToSwitchMapping switchMapping; + private final int numThreads = 3; + // the amount of time, in milliseconds, we give IP to rack determiner to resolve rack + private int timeout; + private final ExecutorService executorService = + Executors.newFixedThreadPool(numThreads, new DaemonThreadFactory("rackmanager")); + public final static String IP_TO_RACK_DETEMINDER_TIMEOUT = "hbase.ip.to.rack.determiner.timeout"; + private final static int DEFAULT_IP_TO_RACK_DETEMINDER_TIMEOUT = 60000; public RackManager() { } @@ -47,8 +61,9 @@ public class RackManager { public RackManager(Configuration conf) { switchMapping = ReflectionUtils.instantiateWithCustomCtor( conf.getClass("hbase.util.ip.to.rack.determiner", ScriptBasedMapping.class, - DNSToSwitchMapping.class).getName(), new Class[]{Configuration.class}, + CachedDNSToSwitchMapping.class).getName(), new Class[]{Configuration.class}, new Object[]{conf}); + timeout = conf.getInt(IP_TO_RACK_DETEMINDER_TIMEOUT, DEFAULT_IP_TO_RACK_DETEMINDER_TIMEOUT); } /** @@ -57,15 +72,31 @@ public class RackManager { * @param server the server for which to get the rack name * @return the rack name of the server */ - public String getRack(ServerName server) { + public String getRack(final ServerName server) { if (server == null) { return UNKNOWN_RACK; } - // just a note - switchMapping caches results (at least the implementation should unless the - // resolution is really a lightweight process) - List racks = switchMapping.resolve(Arrays.asList(server.getHostname())); - if (racks != null && !racks.isEmpty()) { - return racks.get(0); + final List racks = new ArrayList(); + final String hostname = server.getHostname(); + Future f = (Future)executorService.submit(new Runnable() { + + @Override + public void run() { + // just a note - switchMapping caches results (at least the implementation should unless the + // resolution is really a lightweight process) + racks.addAll(switchMapping.resolve(Arrays.asList(hostname))); + } + }); + try { + f.get(timeout, TimeUnit.MILLISECONDS); + if (racks != null && !racks.isEmpty()) { + return racks.get(0); + } + } catch (TimeoutException e) { + f.cancel(true); + LOG.warn("Timeout retrieving rack for " + hostname); + } catch (Exception e) { + LOG.warn("Got exception retrieving rack for " + hostname, e); } return UNKNOWN_RACK; diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/TestBaseLoadBalancer.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/TestBaseLoadBalancer.java index 11ca6c7..79ccb99 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/TestBaseLoadBalancer.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/TestBaseLoadBalancer.java @@ -77,6 +77,7 @@ public class TestBaseLoadBalancer extends BalancerTestBase { @BeforeClass public static void beforeAllTests() throws Exception { Configuration conf = HBaseConfiguration.create(); + conf.setInt(RackManager.IP_TO_RACK_DETEMINDER_TIMEOUT, 10); loadBalancer = new MockBalancer(); loadBalancer.setConf(conf); MasterServices st = Mockito.mock(MasterServices.class);