From b6ccf3081ae0b7c093ec763db5ee686b755a4a44 Mon Sep 17 00:00:00 2001 From: Michael Stack Date: Wed, 29 Apr 2009 23:14:57 +0000 Subject: [PATCH] HBASE-1271 Allow multiple tests to run on one machine git-svn-id: https://svn.apache.org/repos/asf/hadoop/hbase/trunk@769989 13f79535-47bb-0310-9956-ffa450edef68 --- CHANGES.txt | 2 ++ conf/hbase-default.xml | 8 ++++++ .../org/apache/hadoop/hbase/HServerInfo.java | 7 +++++ .../hbase/regionserver/HRegionServer.java | 28 ++++++++++++++++--- src/test/hbase-site.xml | 8 ++++++ .../apache/hadoop/hbase/MiniHBaseCluster.java | 17 +++++++++-- .../hadoop/hbase/MiniZooKeeperCluster.java | 27 ++++++++++++------ 7 files changed, 83 insertions(+), 14 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 1a4f1e7a32a..260197143ac 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -178,6 +178,8 @@ Release 0.20.0 - Unreleased split a key range in N chunks (Jon Gray via Stack) HBASE-1350 New method in HTable.java to return start and end keys for regions in a table (Vimal Mathew via Stack) + HBASE-1271 Allow multiple tests to run on one machine + (Evgeny Ryabitskiy via Stack) Release 0.19.0 - 01/21/2009 INCOMPATIBLE CHANGES diff --git a/conf/hbase-default.xml b/conf/hbase-default.xml index cff2afa7a1a..4bf253e5bde 100644 --- a/conf/hbase-default.xml +++ b/conf/hbase-default.xml @@ -107,6 +107,14 @@ Set to -1 if you do not want the info server to run. + + hbase.regionserver.info.port.auto + false + Info server auto port bind. Enables automatic port + search if hbase.regionserver.info.port is already in use. + Useful for testing, turned off by default. + + hbase.regionserver.info.bindAddress 0.0.0.0 diff --git a/src/java/org/apache/hadoop/hbase/HServerInfo.java b/src/java/org/apache/hadoop/hbase/HServerInfo.java index c735f22c4a5..ed625bcb358 100644 --- a/src/java/org/apache/hadoop/hbase/HServerInfo.java +++ b/src/java/org/apache/hadoop/hbase/HServerInfo.java @@ -110,6 +110,13 @@ public class HServerInfo implements WritableComparable { return this.infoPort; } + /** + * @param infoPort - new port of info server + */ + public void setInfoPort(int infoPort) { + this.infoPort = infoPort; + } + /** * @param startCode the startCode to set */ diff --git a/src/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java b/src/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java index c69998e6388..2a688d4ab7e 100644 --- a/src/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java +++ b/src/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java @@ -26,6 +26,7 @@ import java.lang.management.MemoryUsage; import java.lang.management.RuntimeMXBean; import java.lang.reflect.Constructor; import java.lang.reflect.Field; +import java.net.BindException; import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.Arrays; @@ -1056,11 +1057,30 @@ public class HRegionServer implements HConstants, HRegionInterface, this.leases.start(); // Put up info server. int port = this.conf.getInt("hbase.regionserver.info.port", 60030); + // -1 is for disabling info server if (port >= 0) { - String a = this.conf.get("hbase.master.info.bindAddress", "0.0.0.0"); - this.infoServer = new InfoServer("regionserver", a, port, false); - this.infoServer.setAttribute("regionserver", this); - this.infoServer.start(); + String addr = this.conf.get("hbase.master.info.bindAddress", "0.0.0.0"); + // check if auto port bind enabled + boolean auto = this.conf.getBoolean("hbase.regionserver.info.port.auto", + false); + while (true) { + try { + this.infoServer = new InfoServer("regionserver", addr, port, false); + this.infoServer.setAttribute("regionserver", this); + this.infoServer.start(); + break; + } catch (BindException e) { + if (!auto){ + // auto bind disabled throw BindException + throw e; + } + // auto bind enabled, try to use another port + LOG.info("Failed binding http info server to port: " + port); + port++; + // update HRS server info + serverInfo.setInfoPort(port); + } + } } // Set up the safe mode handler if safe mode has been configured. diff --git a/src/test/hbase-site.xml b/src/test/hbase-site.xml index 0158ad58d2f..8482123065a 100644 --- a/src/test/hbase-site.xml +++ b/src/test/hbase-site.xml @@ -81,6 +81,14 @@ Set to -1 if you do not want the info server to run. + + hbase.regionserver.info.port.auto + true + Info server auto port bind. Enables automatic port + search if hbase.regionserver.info.port is already in use. + Enabled for testing to run multiple tests on one machine. + + hbase.master.lease.thread.wakefrequency 3000 diff --git a/src/test/org/apache/hadoop/hbase/MiniHBaseCluster.java b/src/test/org/apache/hadoop/hbase/MiniHBaseCluster.java index 5bd89944d8e..24051922f00 100644 --- a/src/test/org/apache/hadoop/hbase/MiniHBaseCluster.java +++ b/src/test/org/apache/hadoop/hbase/MiniHBaseCluster.java @@ -20,6 +20,7 @@ package org.apache.hadoop.hbase; import java.io.IOException; +import java.net.BindException; import java.util.List; import org.apache.commons.logging.Log; @@ -54,8 +55,20 @@ public class MiniHBaseCluster implements HConstants { private void init(final int nRegionNodes) throws IOException { try { // start up a LocalHBaseCluster - hbaseCluster = new LocalHBaseCluster(conf, nRegionNodes); - hbaseCluster.startup(); + while (true) { + try { + hbaseCluster = new LocalHBaseCluster(conf, nRegionNodes); + hbaseCluster.startup(); + } catch (BindException e) { + //this port is already in use. try to use another (for multiple testing) + int port = conf.getInt("hbase.master.port", DEFAULT_MASTER_PORT); + LOG.info("MiniHBaseCluster: Failed binding Master to port: " + port); + port++; + conf.setInt("hbase.master.port", port); + continue; + } + break; + } } catch(IOException e) { shutdown(); throw e; diff --git a/src/test/org/apache/hadoop/hbase/MiniZooKeeperCluster.java b/src/test/org/apache/hadoop/hbase/MiniZooKeeperCluster.java index 5a7fef300a8..279632ca796 100644 --- a/src/test/org/apache/hadoop/hbase/MiniZooKeeperCluster.java +++ b/src/test/org/apache/hadoop/hbase/MiniZooKeeperCluster.java @@ -25,6 +25,7 @@ import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.Reader; +import java.net.BindException; import java.net.InetSocketAddress; import java.net.Socket; import java.util.HashMap; @@ -48,7 +49,6 @@ public class MiniZooKeeperCluster { private static final Log LOG = LogFactory.getLog(MiniZooKeeperCluster.class); // TODO: make this more configurable? - private static final int CLIENT_PORT_START = 21810; // use non-standard port private static final int LEADER_PORT_START = 31810; // use non-standard port private static final int TICK_TIME = 2000; private static final int INIT_LIMIT = 3; @@ -56,6 +56,7 @@ public class MiniZooKeeperCluster { private static final int CONNECTION_TIMEOUT = 30000; private boolean started; + private int clientPortStart = 21810; // use non-standard port private int numPeers; private File baseDir; private String quorumServers; @@ -119,13 +120,23 @@ public class MiniZooKeeperCluster { recreateDir(dir); ZooKeeperServer server = new ZooKeeperServer(dir, dir, TICK_TIME); - standaloneServerFactory = new NIOServerCnxn.Factory(CLIENT_PORT_START); + while (true) { + try { + standaloneServerFactory = new NIOServerCnxn.Factory(clientPortStart); + } catch (BindException e) { + LOG.info("Faild binding ZK Server to client port: " + clientPortStart); + //this port is already in use. try to use another + clientPortStart++; + continue; + } + break; + } standaloneServerFactory.startup(server); - quorumServers = "localhost:" + CLIENT_PORT_START; + quorumServers = "localhost:" + clientPortStart; ZooKeeperWrapper.setQuorumServers(quorumServers); - if (!waitForServerUp(CLIENT_PORT_START, CONNECTION_TIMEOUT)) { + if (!waitForServerUp(clientPortStart, CONNECTION_TIMEOUT)) { throw new IOException("Waiting for startup of standalone server"); } } @@ -149,7 +160,7 @@ public class MiniZooKeeperCluster { File dir = new File(baseDir, "zookeeper-peer-" + id); recreateDir(dir); - int port = CLIENT_PORT_START + id; + int port = clientPortStart + id; quorumPeers[id - 1] = new QuorumPeer(peers, dir, dir, port, 0, id, TICK_TIME, INIT_LIMIT, SYNC_LIMIT); @@ -169,7 +180,7 @@ public class MiniZooKeeperCluster { // Wait for quorum peers to be up before going on. for (int id = 1; id <= numPeers; ++id) { - int port = CLIENT_PORT_START + id; + int port = clientPortStart + id; if (!waitForServerUp(port, CONNECTION_TIMEOUT)) { throw new IOException("Waiting for startup of peer " + id); } @@ -220,7 +231,7 @@ public class MiniZooKeeperCluster { } for (int id = 1; id <= quorumPeers.length; ++id) { - int port = CLIENT_PORT_START + id; + int port = clientPortStart + id; if (!waitForServerDown(port, CONNECTION_TIMEOUT)) { throw new IOException("Waiting for shutdown of peer " + id); } @@ -229,7 +240,7 @@ public class MiniZooKeeperCluster { private void shutdownStandalone() throws IOException { standaloneServerFactory.shutdown(); - if (!waitForServerDown(CLIENT_PORT_START, CONNECTION_TIMEOUT)) { + if (!waitForServerDown(clientPortStart, CONNECTION_TIMEOUT)) { throw new IOException("Waiting for shutdown of standalone server"); } }