001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.master;
019
020import static org.junit.Assert.assertEquals;
021import static org.junit.Assert.assertNotNull;
022import static org.junit.Assert.assertTrue;
023
024import java.util.List;
025import org.apache.hadoop.conf.Configuration;
026import org.apache.hadoop.hbase.ClusterMetrics;
027import org.apache.hadoop.hbase.HBaseClassTestRule;
028import org.apache.hadoop.hbase.HBaseConfiguration;
029import org.apache.hadoop.hbase.HBaseTestingUtility;
030import org.apache.hadoop.hbase.LocalHBaseCluster;
031import org.apache.hadoop.hbase.MiniHBaseCluster;
032import org.apache.hadoop.hbase.client.Admin;
033import org.apache.hadoop.hbase.client.Connection;
034import org.apache.hadoop.hbase.client.ConnectionFactory;
035import org.apache.hadoop.hbase.testclassification.LargeTests;
036import org.apache.hadoop.hbase.testclassification.MasterTests;
037import org.apache.hadoop.hbase.util.JVMClusterUtil.MasterThread;
038import org.junit.ClassRule;
039import org.junit.Test;
040import org.junit.experimental.categories.Category;
041import org.slf4j.Logger;
042import org.slf4j.LoggerFactory;
043
044@Category({MasterTests.class, LargeTests.class})
045public class TestMasterShutdown {
046
047  @ClassRule
048  public static final HBaseClassTestRule CLASS_RULE =
049      HBaseClassTestRule.forClass(TestMasterShutdown.class);
050
051  private static final Logger LOG = LoggerFactory.getLogger(TestMasterShutdown.class);
052
053  /**
054   * Simple test of shutdown.
055   * <p>
056   * Starts with three masters.  Tells the active master to shutdown the cluster.
057   * Verifies that all masters are properly shutdown.
058   */
059  @Test
060  public void testMasterShutdown() throws Exception {
061    final int NUM_MASTERS = 3;
062    final int NUM_RS = 3;
063
064    // Create config to use for this cluster
065    Configuration conf = HBaseConfiguration.create();
066
067    // Start the cluster
068    HBaseTestingUtility htu = new HBaseTestingUtility(conf);
069    htu.startMiniCluster(NUM_MASTERS, NUM_RS);
070    MiniHBaseCluster cluster = htu.getHBaseCluster();
071
072    // get all the master threads
073    List<MasterThread> masterThreads = cluster.getMasterThreads();
074
075    // wait for each to come online
076    for (MasterThread mt : masterThreads) {
077      assertTrue(mt.isAlive());
078    }
079
080    // find the active master
081    HMaster active = null;
082    for (int i = 0; i < masterThreads.size(); i++) {
083      if (masterThreads.get(i).getMaster().isActiveMaster()) {
084        active = masterThreads.get(i).getMaster();
085        break;
086      }
087    }
088    assertNotNull(active);
089    // make sure the other two are backup masters
090    ClusterMetrics status = active.getClusterMetrics();
091    assertEquals(2, status.getBackupMasterNames().size());
092
093    // tell the active master to shutdown the cluster
094    active.shutdown();
095
096    for (int i = NUM_MASTERS - 1; i >= 0 ;--i) {
097      cluster.waitOnMaster(i);
098    }
099    // make sure all the masters properly shutdown
100    assertEquals(0, masterThreads.size());
101
102    htu.shutdownMiniCluster();
103  }
104
105  @Test
106  public void testMasterShutdownBeforeStartingAnyRegionServer() throws Exception {
107    final int NUM_MASTERS = 1;
108    final int NUM_RS = 0;
109
110    // Create config to use for this cluster
111    Configuration conf = HBaseConfiguration.create();
112    conf.setInt("hbase.ipc.client.failed.servers.expiry", 200);
113    conf.setInt(ServerManager.WAIT_ON_REGIONSERVERS_MINTOSTART, 1);
114
115    // Start the cluster
116    final HBaseTestingUtility util = new HBaseTestingUtility(conf);
117    util.startMiniDFSCluster(3);
118    util.startMiniZKCluster();
119    util.createRootDir();
120    final LocalHBaseCluster cluster =
121        new LocalHBaseCluster(conf, NUM_MASTERS, NUM_RS, HMaster.class,
122            MiniHBaseCluster.MiniHBaseClusterRegionServer.class);
123    final int MASTER_INDEX = 0;
124    final MasterThread master = cluster.getMasters().get(MASTER_INDEX);
125    master.start();
126    LOG.info("Called master start on " + master.getName());
127    Thread shutdownThread = new Thread("Shutdown-Thread") {
128      @Override
129      public void run() {
130        LOG.info("Before call to shutdown master");
131        try {
132          try (
133            Connection connection = ConnectionFactory.createConnection(util.getConfiguration())) {
134            try (Admin admin = connection.getAdmin()) {
135              admin.shutdown();
136            }
137          }
138        } catch (Exception e) {
139          LOG.info("Error while calling Admin.shutdown, which is expected: " + e.getMessage());
140        }
141        LOG.info("After call to shutdown master");
142        cluster.waitOnMaster(MASTER_INDEX);
143      }
144    };
145    shutdownThread.start();
146    LOG.info("Called master join on " + master.getName());
147    master.join();
148    shutdownThread.join();
149
150    List<MasterThread> masterThreads = cluster.getMasters();
151    // make sure all the masters properly shutdown
152    assertEquals(0, masterThreads.size());
153
154    util.shutdownMiniZKCluster();
155    util.shutdownMiniDFSCluster();
156    util.cleanupTestDir();
157  }
158}