View Javadoc

1   /**
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  package org.apache.hadoop.hbase.master;
20  
21  import static org.junit.Assert.assertEquals;
22  import static org.junit.Assert.assertFalse;
23  import static org.junit.Assert.assertTrue;
24  
25  import org.apache.hadoop.hbase.ClusterStatus;
26  import org.apache.hadoop.hbase.HBaseTestingUtility;
27  
28  import org.apache.hadoop.hbase.HRegionInfo;
29  import org.apache.hadoop.hbase.HRegionLocation;
30  import org.apache.hadoop.hbase.HTableDescriptor;
31  import org.apache.hadoop.hbase.ServerName;
32  import org.apache.hadoop.hbase.TableName;
33  import org.apache.hadoop.hbase.client.RegionLocator;
34  import org.apache.hadoop.hbase.client.Table;
35  import org.apache.hadoop.hbase.testclassification.LargeTests;
36  import org.apache.hadoop.hbase.util.Bytes;
37  import org.apache.hadoop.hbase.MasterNotRunningException;
38  import org.apache.hadoop.hbase.MiniHBaseCluster;
39  import org.apache.hadoop.hbase.util.JVMClusterUtil;
40  import org.junit.AfterClass;
41  import org.junit.BeforeClass;
42  import org.junit.Test;
43  import org.junit.experimental.categories.Category;
44  
45  import java.io.IOException;
46  import java.util.ArrayList;
47  import java.util.Collection;
48  import java.util.List;
49  import java.util.Map;
50  
51  @Category(LargeTests.class)
52  public class TestMasterFailoverBalancerPersistence {
53    // Start the cluster
54    private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
55    private static MiniHBaseCluster cluster;
56  
57  
58    @BeforeClass
59    public static void setUpBeforeClass() throws Exception {
60      TEST_UTIL.startMiniCluster(4, 1);
61      cluster = TEST_UTIL.getHBaseCluster();
62    }
63  
64    @AfterClass
65    public static void tearDownAfterClass() throws Exception {
66      TEST_UTIL.shutdownMiniCluster();
67    }
68  
69  
70    /**
71     * Test that if the master fails, the load balancer maintains its
72     * state (running or not) when the next master takes over
73     *
74     * @throws Exception on failure
75     */
76    @Test(timeout = 240000)
77    public void testMasterFailoverBalancerPersistence() throws Exception {
78  
79      assertTrue(cluster.waitForActiveAndReadyMaster());
80      HMaster active = cluster.getMaster();
81      // check that the balancer is on by default for the active master
82      ClusterStatus clusterStatus = active.getClusterStatus();
83      assertTrue(clusterStatus.isBalancerOn());
84  
85      active = killActiveAndWaitForNewActive(cluster);
86  
87      // ensure the load balancer is still running on new master
88      clusterStatus = active.getClusterStatus();
89      assertTrue(clusterStatus.isBalancerOn());
90  
91      // turn off the load balancer
92      active.balanceSwitch(false);
93  
94      // once more, kill active master and wait for new active master to show up
95      active = killActiveAndWaitForNewActive(cluster);
96  
97      // ensure the load balancer is not running on the new master
98      clusterStatus = active.getClusterStatus();
99      assertFalse(clusterStatus.isBalancerOn());
100   }
101 
102   /**
103    * Test that if the master fails, the ReplicaMapping is rebuilt
104    * by the new master.
105    *
106    * @throws Exception on failure
107    */
108   @Test(timeout = 100000)
109   public void testReadReplicaMappingAfterMasterFailover() throws Exception {
110     final byte [] FAMILY = Bytes.toBytes("testFamily");
111 
112     assertTrue(cluster.waitForActiveAndReadyMaster());
113     HMaster active = cluster.getMaster();
114 
115     final TableName tableName = TableName.valueOf("testReadReplicaMappingAfterMasterFailover");
116     HTableDescriptor hdt = TEST_UTIL.createTableDescriptor(tableName.getNameAsString());
117     hdt.setRegionReplication(2);
118     Table ht = null;
119     try {
120       ht = TEST_UTIL.createTable(hdt, new byte[][] { FAMILY }, TEST_UTIL.getConfiguration());
121 
122       RegionLocator locator = TEST_UTIL.getConnection().getRegionLocator(tableName);
123       List<HRegionLocation> allRegionLocations = locator.getAllRegionLocations();
124 
125       // There are two regions, one for primary, one for the replica.
126       assertTrue(allRegionLocations.size() == 2);
127 
128       List<HRegionInfo> parentRegion = new ArrayList<>();
129       parentRegion.add(allRegionLocations.get(0).getRegionInfo());
130       Map<ServerName, List<HRegionInfo>> currentAssign =
131           active.getAssignmentManager().getRegionStates().getRegionAssignments(parentRegion);
132       Collection<List<HRegionInfo>> c = currentAssign.values();
133       int count = 0;
134       for (List<HRegionInfo> l : c) {
135         count += l.size();
136       }
137 
138       // Make sure that there are regions in the ReplicaMapping
139       assertEquals(2, count);
140 
141       active = killActiveAndWaitForNewActive(cluster);
142 
143       Map<ServerName, List<HRegionInfo>> currentAssignNew =
144           active.getAssignmentManager().getRegionStates().getRegionAssignments(parentRegion);
145       Collection<List<HRegionInfo>> cNew = currentAssignNew.values();
146       count = 0;
147       for (List<HRegionInfo> l : cNew) {
148         count += l.size();
149       }
150 
151       // Make sure that there are regions in the ReplicaMapping when the new master takes over.
152       assertEquals(2, count);
153     } finally {
154       if (ht != null) {
155         TEST_UTIL.deleteTable(tableName.getName());
156       }
157     }
158   }
159 
160   /**
161    * Kill the master and wait for a new active master to show up
162    *
163    * @param cluster
164    * @return the new active master
165    * @throws InterruptedException
166    * @throws java.io.IOException
167    */
168   private HMaster killActiveAndWaitForNewActive(MiniHBaseCluster cluster)
169       throws InterruptedException, IOException {
170     int activeIndex = getActiveMasterIndex(cluster);
171     HMaster active = cluster.getMaster();
172     cluster.stopMaster(activeIndex);
173     cluster.waitOnMaster(activeIndex);
174     assertTrue(cluster.waitForActiveAndReadyMaster());
175     // double check this is actually a new master
176     HMaster newActive = cluster.getMaster();
177     assertFalse(active == newActive);
178     return newActive;
179   }
180 
181   /**
182    * return the index of the active master in the cluster
183    *
184    * @throws org.apache.hadoop.hbase.MasterNotRunningException
185    *          if no active master found
186    */
187   private int getActiveMasterIndex(MiniHBaseCluster cluster) throws MasterNotRunningException {
188     // get all the master threads
189     List<JVMClusterUtil.MasterThread> masterThreads = cluster.getMasterThreads();
190 
191     for (int i = 0; i < masterThreads.size(); i++) {
192       if (masterThreads.get(i).getMaster().isActiveMaster()) {
193         return i;
194       }
195     }
196     throw new MasterNotRunningException();
197   }
198 
199 }