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");
}
}