blob: 843dafc16fe16633f4d2128392f362feb833c276 [file] [log] [blame]
/**
* Copyright 2010 The Apache Software Foundation
*
* 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.hadoop.hbase.util;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.master.HMaster;
import org.apache.hadoop.hbase.regionserver.HRegionServer;
/**
* Utility used running a cluster all in the one JVM.
*/
public class JVMClusterUtil {
private static final Log LOG = LogFactory.getLog(JVMClusterUtil.class);
/**
* Datastructure to hold RegionServer Thread and RegionServer instance
*/
public static class RegionServerThread extends Thread {
private final HRegionServer regionServer;
public RegionServerThread(final HRegionServer r, final int index) {
super(r, "RegionServer:" + index);
this.regionServer = r;
}
/** @return the region server */
public HRegionServer getRegionServer() {
return this.regionServer;
}
/**
* Block until the region server has come online, indicating it is ready
* to be used.
*/
public void waitForServerOnline() {
// The server is marked online after the init method completes inside of
// the HRS#run method. HRS#init can fail for whatever region. In those
// cases, we'll jump out of the run without setting online flag. Check
// stopRequested so we don't wait here a flag that will never be flipped.
while (!this.regionServer.isOnline() &&
!this.regionServer.isStopRequested()) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// continue waiting
}
}
}
}
/**
* Creates a {@link RegionServerThread}.
* Call 'start' on the returned thread to make it run.
* @param c Configuration to use.
* @param hrsc Class to create.
* @param index Used distinguishing the object returned.
* @throws IOException
* @return Region server added.
*/
public static JVMClusterUtil.RegionServerThread createRegionServerThread(
final Configuration c, final Class<? extends HRegionServer> hrsc,
final int index)
throws IOException {
HRegionServer server;
try {
server = hrsc.getConstructor(Configuration.class).newInstance(c);
} catch (Exception e) {
IOException ioe = new IOException();
ioe.initCause(e);
throw ioe;
}
return new JVMClusterUtil.RegionServerThread(server, index);
}
/**
* Datastructure to hold Master Thread and Master instance
*/
public static class MasterThread extends Thread {
private final HMaster master;
public MasterThread(final HMaster m, final int index) {
super(m, "Master:" + index);
this.master = m;
}
/** @return the master */
public HMaster getMaster() {
return this.master;
}
/**
* Block until the master has come online, indicating it is ready
* to be used.
*/
public void waitForServerOnline() {
// The server is marked online after init begins but before race to become
// the active master.
while (!this.master.isMasterRunning() &&
!this.master.getShutdownRequested().get()) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// continue waiting
}
}
}
}
/**
* Creates a {@link MasterThread}.
* Call 'start' on the returned thread to make it run.
* @param c Configuration to use.
* @param hmc Class to create.
* @param index Used distinguishing the object returned.
* @throws IOException
* @return Master added.
*/
public static JVMClusterUtil.MasterThread createMasterThread(
final Configuration c, final Class<? extends HMaster> hmc,
final int index)
throws IOException {
HMaster server;
try {
server = hmc.getConstructor(Configuration.class).newInstance(c);
} catch (InvocationTargetException ite) {
Throwable target = ite.getTargetException();
throw new RuntimeException("Failed construction of Master: " +
hmc.toString() + ((target.getCause() != null)?
target.getCause().getMessage(): ""), target);
} catch (Exception e) {
IOException ioe = new IOException();
ioe.initCause(e);
throw ioe;
}
return new JVMClusterUtil.MasterThread(server, index);
}
/**
* Start the cluster.
* @param m
* @param regionServers
* @return Address to use contacting master.
*/
public static String startup(final List<JVMClusterUtil.MasterThread> masters,
final List<JVMClusterUtil.RegionServerThread> regionservers) throws IOException {
if (masters != null) {
for (JVMClusterUtil.MasterThread t : masters) {
t.start();
}
}
if (regionservers != null) {
for (JVMClusterUtil.RegionServerThread t: regionservers) {
t.start();
}
}
if (masters == null || masters.isEmpty()) {
return null;
}
// Wait for an active master
while (true) {
for (JVMClusterUtil.MasterThread t : masters) {
if (t.master.isActiveMaster()) {
return t.master.getServerName().toString();
}
}
try {
Thread.sleep(1000);
} catch(InterruptedException e) {
// Keep waiting
}
}
}
/**
* @param master
* @param regionservers
*/
public static void shutdown(final List<MasterThread> masters,
final List<RegionServerThread> regionservers) {
LOG.debug("Shutting down HBase Cluster");
if (masters != null) {
for (JVMClusterUtil.MasterThread t : masters) {
if (t.master.isActiveMaster()) {
t.master.shutdown();
} else {
t.master.stopMaster();
}
}
}
boolean interrupted = false;
try {
// regionServerThreads can never be null because they are initialized when
// the class is constructed.
for (Thread t : regionservers) {
if (t.isAlive()) {
try {
t.join();
} catch (InterruptedException e) {
interrupted = true;
}
}
}
if (masters != null) {
for (JVMClusterUtil.MasterThread t : masters) {
while (t.isAlive()) {
try {
t.join();
} catch (InterruptedException e) {
interrupted = true;
}
}
}
}
} finally {
if (interrupted) {
Thread.currentThread().interrupt();
}
}
LOG.info("Shutdown of " +
((masters != null) ? masters.size() : "0") + " master(s) and " +
((regionservers != null) ? regionservers.size() : "0") +
" regionserver(s) complete");
}
}