Java tutorial
/** * 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 com.alibaba.wasp; import com.alibaba.wasp.client.ClientProtocol; import com.alibaba.wasp.client.FConnectionManager; import com.alibaba.wasp.conf.WaspConfiguration; import com.alibaba.wasp.fserver.AdminProtocol; import com.alibaba.wasp.fserver.EntityGroup; import com.alibaba.wasp.fserver.FServer; import com.alibaba.wasp.master.FMaster; import com.alibaba.wasp.master.FMasterAdminProtocol; import com.alibaba.wasp.master.FMasterMonitorProtocol; import com.alibaba.wasp.protobuf.generated.FServerStatusProtos.FServerStartupResponse; import com.alibaba.wasp.util.JVMClusterUtil; import junit.framework.TestCase; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.Threads; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.List; /** * MiniWaspCluster for test unit. This class creates a single process Wasp * cluster. each server. The master uses the 'default' HBase. The FServers, if * we are running on HBase, create a HBase instance each and will close down * their instance on the way out. */ public class MiniWaspCluster extends WaspCluster { static final Log LOG = LogFactory.getLog(MiniWaspCluster.class.getName()); public LocalWaspCluster waspCluster; /** * Start a MiniWaspCluster. * * @param conf * Configuration to be used for cluster * @param numFServers * initial number of fservers to start. * @throws java.io.IOException */ public MiniWaspCluster(Configuration conf, int numFServers) throws IOException, InterruptedException { this(conf, 1, numFServers); } /** * Start a MiniWaspCluster. * * @param conf * Configuration to be used for cluster * @param numMasters * initial number of masters to start. * @param numFServers * initial number of entityGroup servers to start. * @throws java.io.IOException */ public MiniWaspCluster(Configuration conf, int numMasters, int numFServers) throws IOException, InterruptedException { this(conf, numMasters, numFServers, null, null); } public MiniWaspCluster(Configuration conf, int numMasters, int numFServers, Class<? extends FMaster> masterClass, Class<? extends MiniWaspClusterFServer> fserverClass) throws IOException, InterruptedException { super(conf); conf.set(FConstants.MASTER_PORT, "0"); init(numMasters, numFServers, masterClass, fserverClass); this.initialClusterStatus = getClusterStatus(); } public Configuration getConfiguration() { return this.conf; } /** * Subclass so can get at protected methods (none at moment). */ public static class MiniWaspClusterFServer extends FServer { public static boolean TEST_SKIP_CLOSE = false; public MiniWaspClusterFServer(Configuration conf) throws IOException, InterruptedException { super(conf); } /* * @param c * * @param currentfs We return this if we did not make a new one. * * @param uniqueName Same name used to help identify the created fs. * * @return A new fs instance if we are up on DistributeFileSystem. * * @throws IOException */ @Override protected void handleReportForDutyResponse(final FServerStartupResponse c) throws IOException { super.handleReportForDutyResponse(c); } @Override public void run() { try { runFServer(); } catch (Throwable t) { LOG.error("Exception in run", t); } } private void runFServer() { super.run(); } @Override public void kill() { super.kill(); } public void abort(final String reason, final Throwable cause) { abortFServer(reason, cause); } private void abortFServer(String reason, Throwable cause) { super.abort(reason, cause); } } private void init(final int nMasterNodes, final int nEntityGroupNodes, Class<? extends FMaster> masterClass, Class<? extends MiniWaspClusterFServer> fserverClass) throws IOException, InterruptedException { try { if (masterClass == null) { masterClass = FMaster.class; } if (fserverClass == null) { fserverClass = MiniWaspCluster.MiniWaspClusterFServer.class; } // start up a LocalWaspCluster waspCluster = new LocalWaspCluster(conf, nMasterNodes, 0, masterClass, fserverClass); // manually add the fservers as other users for (int i = 0; i < nEntityGroupNodes; i++) { Configuration rsConf = WaspConfiguration.create(conf); waspCluster.addFServer(rsConf, i); } waspCluster.startup(); } catch (IOException e) { shutdown(); throw e; } catch (Throwable t) { LOG.error("Error starting cluster", t); shutdown(); throw new IOException("Shutting down", t); } } @Override public void startFServer(String hostname) throws IOException { this.startFServer(); } @Override public void killFServer(ServerName serverName) throws IOException { FServer server = getFServer(getFServerIndex(serverName)); if (server instanceof MiniWaspClusterFServer) { LOG.info("Killing " + server.toString()); ((MiniWaspClusterFServer) server).kill(); } else { abortFServer(getFServerIndex(serverName)); } } @Override public void stopFServer(ServerName serverName) throws IOException { stopFServer(getFServerIndex(serverName)); } @Override public void waitForFServerToStop(ServerName serverName, long timeout) throws IOException { // ignore timeout for now waitOnEntityGroupServer(getFServerIndex(serverName)); } @Override public void startMaster(String hostname) throws IOException { this.startMaster(); } @Override public void killMaster(ServerName serverName) throws IOException { abortMaster(getMasterIndex(serverName)); } @Override public void stopMaster(ServerName serverName) throws IOException { stopMaster(getMasterIndex(serverName)); } @Override public void waitForMasterToStop(ServerName serverName, long timeout) throws IOException { // ignore timeout for now waitOnMaster(getMasterIndex(serverName)); } /** * Starts a entityGroup server thread running * * @throws java.io.IOException * @return New FServerThread */ public JVMClusterUtil.FServerThread startFServer() throws IOException { final Configuration newConf = WaspConfiguration.create(conf); JVMClusterUtil.FServerThread t = null; t = waspCluster.addFServer(newConf, waspCluster.getFServers().size()); t.start(); t.waitForServerOnline(); return t; } /** * Cause a entityGroup server to exit doing basic clean up only on its way * out. * * @param serverNumber * Used as index into a list. */ public String abortFServer(int serverNumber) { FServer server = getFServer(serverNumber); LOG.info("Aborting " + server.toString()); server.abort("Aborting for tests", new Exception("Trace info")); return server.toString(); } /** * Shut down the specified entityGroup server cleanly * * @param serverNumber * Used as index into a list. * @return the entityGroups server that was stopped */ public JVMClusterUtil.FServerThread stopFServer(int serverNumber) { JVMClusterUtil.FServerThread server = waspCluster.getFServers().get(serverNumber); LOG.info("Stopping " + server.toString()); server.getFServer().stop("Stopping rs " + serverNumber); return server; } /** * Wait for the specified entityGroup server to stop. Removes this thread from * list of running threads. * * @param serverNumber * @return Name of entityGroup server that just went down. */ public String waitOnEntityGroupServer(final int serverNumber) { return this.waspCluster.waitOnFServer(serverNumber); } /** * Starts a master thread running * * @throws java.io.IOException * @return New FServerThread */ public JVMClusterUtil.MasterThread startMaster() throws IOException { Configuration c = WaspConfiguration.create(conf); JVMClusterUtil.MasterThread t = null; t = waspCluster.addMaster(c, waspCluster.getMasters().size()); t.start(); return t; } @Override public FMasterAdminProtocol getMasterAdmin() { return this.waspCluster.getActiveMaster(); } @Override public FMasterMonitorProtocol getMasterMonitor() { return this.waspCluster.getActiveMaster(); } /** * Returns the current active master, if available. * * @return the active HMaster, null if none is active. */ public FMaster getMaster() { return this.waspCluster.getActiveMaster(); } /** * Returns the master at the specified index, if available. * * @return the active HMaster, null if none is active. */ public FMaster getMaster(final int serverNumber) { return this.waspCluster.getMaster(serverNumber); } /** * Cause a master to exit without shutting down entire cluster. * * @param serverNumber * Used as index into a list. */ public String abortMaster(int serverNumber) { FMaster server = getMaster(serverNumber); LOG.info("Aborting " + server.toString()); server.abort("Aborting for tests", new Exception("Trace info")); return server.toString(); } /** * Shut down the specified master cleanly * * @param serverNumber * Used as index into a list. * @return the entityGroup server that was stopped */ public JVMClusterUtil.MasterThread stopMaster(int serverNumber) { return stopMaster(serverNumber, true); } /** * Shut down the specified master cleanly * * @param serverNumber * Used as index into a list. * @param shutdownFS * True is we are to shutdown the filesystem as part of this master's * shutdown. Usually we do but you do not want to do this if you are * running multiple master in a test and you shut down one before end * of the test. * @return the master that was stopped */ public JVMClusterUtil.MasterThread stopMaster(int serverNumber, final boolean shutdownFS) { JVMClusterUtil.MasterThread server = waspCluster.getMasters().get(serverNumber); LOG.info("Stopping " + server.toString()); server.getMaster().stop("Stopping master " + serverNumber); return server; } /** * Wait for the specified master to stop. Removes this thread from list of * running threads. * * @param serverNumber * @return Name of master that just went down. */ public String waitOnMaster(final int serverNumber) { return this.waspCluster.waitOnMaster(serverNumber); } /** * Blocks until there is an active master and that master has completed * initialization. * * @return true if an active master becomes available. false if there are no * masters left. * @throws InterruptedException */ public boolean waitForActiveAndReadyMaster(long timeout) throws IOException { List<JVMClusterUtil.MasterThread> mts; long start = System.currentTimeMillis(); while (!(mts = getMasterThreads()).isEmpty() && (System.currentTimeMillis() - start) < timeout) { for (JVMClusterUtil.MasterThread mt : mts) { if (mt.getMaster().isActiveMaster() && mt.getMaster().isInitialized()) { return true; } } Threads.sleep(100); } return false; } /** * @return List of master threads. */ public List<JVMClusterUtil.MasterThread> getMasterThreads() { return this.waspCluster.getMasters(); } /** * @return List of live master threads (skips the aborted and the killed) */ public List<JVMClusterUtil.MasterThread> getLiveMasterThreads() { return this.waspCluster.getLiveMasters(); } /** * Wait for Mini HBase Cluster to shut down. */ public void join() { this.waspCluster.join(); } /** * Shut down the mini HBase cluster * * @throws java.io.IOException */ public void shutdown() throws IOException { if (this.waspCluster != null) { this.waspCluster.shutdown(); } FConnectionManager.deleteAllConnections(false); } @Override public void close() throws IOException { } @Override public ClusterStatus getClusterStatus() throws IOException { FMaster master = getMaster(); return master == null ? null : master.getClusterStatus(); } /** * @return List of entityGroup server threads. */ public List<JVMClusterUtil.FServerThread> getFServerThreads() { return this.waspCluster.getFServers(); } /** * @return List of live entityGroup server threads (skips the aborted and the * killed) */ public List<JVMClusterUtil.FServerThread> getLiveFServerThreads() { return this.waspCluster.getLiveFServers(); } /** * Grab a numbered entityGroup server of your choice. * * @param serverNumber * @return entityGroup server */ public FServer getFServer(int serverNumber) { return waspCluster.getFServer(serverNumber); } public List<EntityGroup> getEntityGroups(byte[] tableName) { List<EntityGroup> ret = new ArrayList<EntityGroup>(); for (JVMClusterUtil.FServerThread rst : getFServerThreads()) { FServer fs = rst.getFServer(); Collection<EntityGroup> egs = fs.getOnlineEntityGroupsLocalContext(); for (EntityGroup entityGroup : egs) { TestCase.assertNotNull(entityGroup); TestCase.assertNotNull(entityGroup.getTableDesc()); TestCase.assertNotNull(entityGroup.getTableDesc().getTableName()); TestCase.assertNotNull(tableName); if (Bytes.equals(Bytes.toBytes(entityGroup.getTableDesc().getTableName()), tableName)) { ret.add(entityGroup); } } } return ret; } /** * Get the location of the specified entityGroup * * @param entityGroupName * Name of the entityGroup in bytes * @return Index into List of {@link MiniWaspCluster#getFServerThreads()} of * HRS carrying .META.. Returns -1 if none found. */ public int getServerWith(byte[] entityGroupName) { int index = -1; int count = 0; for (JVMClusterUtil.FServerThread rst : getFServerThreads()) { FServer hrs = rst.getFServer(); EntityGroup entityGroup = hrs.getOnlineEntityGroup(entityGroupName); if (entityGroup != null) { index = count; break; } count++; } return index; } @Override public ServerName getServerHoldingEntityGroup(byte[] entityGroupName) throws IOException { int index = getServerWith(entityGroupName); if (index < 0) { return null; } return getFServer(index).getServerName(); } /** * Counts the total numbers of entityGroups being served by the currently * online entityGroup servers by asking each how many entityGroups they have. * Does not look at META at all. Count includes catalog tables. * * @return number of entityGroups being served by all entityGroup servers */ public long countServedEntityGroups() { long count = 0; for (JVMClusterUtil.FServerThread rst : getLiveFServerThreads()) { count += rst.getFServer().getNumberOfOnlineEntityGroups(); } return count; } /** * Do a simulated kill all masters and entityGroups servers. Useful when it is * impossible to bring the mini-cluster back for clean shutdown. */ public void killAll() { for (JVMClusterUtil.FServerThread rst : getFServerThreads()) { rst.getFServer().abort("killAll"); } for (JVMClusterUtil.MasterThread masterThread : getMasterThreads()) { masterThread.getMaster().abort("killAll", new Throwable()); } } @Override public void waitUntilShutDown() { this.waspCluster.join(); } protected int getFServerIndex(ServerName serverName) { // we have a small number of entityGroup servers, this should be fine for // now. List<JVMClusterUtil.FServerThread> servers = getFServerThreads(); for (int i = 0; i < servers.size(); i++) { if (servers.get(i).getFServer().getServerName().equals(serverName)) { return i; } } return -1; } protected int getMasterIndex(ServerName serverName) { List<JVMClusterUtil.MasterThread> masters = getMasterThreads(); for (int i = 0; i < masters.size(); i++) { if (masters.get(i).getMaster().getServerName().equals(serverName)) { return i; } } return -1; } @Override public AdminProtocol getAdminProtocol(ServerName serverName) throws IOException { return getFServer(getFServerIndex(serverName)); } @Override public ClientProtocol getClientProtocol(ServerName serverName) throws IOException { return getFServer(getFServerIndex(serverName)); } }