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.assertFalse;
021import static org.junit.Assert.assertTrue;
022
023import java.io.IOException;
024import java.util.List;
025import org.apache.hadoop.hbase.ClusterMetrics;
026import org.apache.hadoop.hbase.HBaseClassTestRule;
027import org.apache.hadoop.hbase.HBaseTestingUtility;
028import org.apache.hadoop.hbase.MasterNotRunningException;
029import org.apache.hadoop.hbase.MiniHBaseCluster;
030import org.apache.hadoop.hbase.StartMiniClusterOption;
031import org.apache.hadoop.hbase.testclassification.LargeTests;
032import org.apache.hadoop.hbase.testclassification.MasterTests;
033import org.apache.hadoop.hbase.util.JVMClusterUtil;
034import org.junit.ClassRule;
035import org.junit.Test;
036import org.junit.experimental.categories.Category;
037
038@Category({MasterTests.class, LargeTests.class})
039public class TestMasterFailoverBalancerPersistence {
040
041  @ClassRule
042  public static final HBaseClassTestRule CLASS_RULE =
043      HBaseClassTestRule.forClass(TestMasterFailoverBalancerPersistence.class);
044
045  /**
046   * Test that if the master fails, the load balancer maintains its
047   * state (running or not) when the next master takes over
048   *
049   * @throws Exception
050   */
051  @Test
052  public void testMasterFailoverBalancerPersistence() throws Exception {
053    // Start the cluster
054    HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
055
056    StartMiniClusterOption option = StartMiniClusterOption.builder()
057        .numMasters(3).build();
058    TEST_UTIL.startMiniCluster(option);
059    MiniHBaseCluster cluster = TEST_UTIL.getHBaseCluster();
060
061    assertTrue(cluster.waitForActiveAndReadyMaster());
062    HMaster active = cluster.getMaster();
063    // check that the balancer is on by default for the active master
064    ClusterMetrics clusterStatus = active.getClusterMetrics();
065    assertTrue(clusterStatus.getBalancerOn());
066
067    active = killActiveAndWaitForNewActive(cluster);
068
069    // ensure the load balancer is still running on new master
070    clusterStatus = active.getClusterMetrics();
071    assertTrue(clusterStatus.getBalancerOn());
072
073    // turn off the load balancer
074    active.balanceSwitch(false);
075
076    // once more, kill active master and wait for new active master to show up
077    active = killActiveAndWaitForNewActive(cluster);
078
079    // ensure the load balancer is not running on the new master
080    clusterStatus = active.getClusterMetrics();
081    assertFalse(clusterStatus.getBalancerOn());
082
083    // Stop the cluster
084    TEST_UTIL.shutdownMiniCluster();
085  }
086
087  /**
088   * Kill the master and wait for a new active master to show up
089   *
090   * @param cluster
091   * @return the new active master
092   * @throws InterruptedException
093   * @throws java.io.IOException
094   */
095  private HMaster killActiveAndWaitForNewActive(MiniHBaseCluster cluster)
096      throws InterruptedException, IOException {
097    int activeIndex = getActiveMasterIndex(cluster);
098    HMaster active = cluster.getMaster();
099    cluster.stopMaster(activeIndex);
100    cluster.waitOnMaster(activeIndex);
101    assertTrue(cluster.waitForActiveAndReadyMaster());
102    // double check this is actually a new master
103    HMaster newActive = cluster.getMaster();
104    assertFalse(active == newActive);
105    return newActive;
106  }
107
108  /**
109   * return the index of the active master in the cluster
110   *
111   * @throws org.apache.hadoop.hbase.MasterNotRunningException
112   *          if no active master found
113   */
114  private int getActiveMasterIndex(MiniHBaseCluster cluster) throws MasterNotRunningException {
115    // get all the master threads
116    List<JVMClusterUtil.MasterThread> masterThreads = cluster.getMasterThreads();
117
118    for (int i = 0; i < masterThreads.size(); i++) {
119      if (masterThreads.get(i).getMaster().isActiveMaster()) {
120        return i;
121      }
122    }
123    throw new MasterNotRunningException();
124  }
125
126}