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.assertArrayEquals;
22  import static org.junit.Assert.assertEquals;
23  import static org.junit.Assert.assertTrue;
24  import static org.junit.Assert.fail;
25  
26  import java.io.IOException;
27  import java.util.List;
28  
29  import org.apache.commons.logging.Log;
30  import org.apache.commons.logging.LogFactory;
31  import org.apache.hadoop.hbase.HBaseIOException;
32  import org.apache.hadoop.hbase.HBaseTestingUtility;
33  import org.apache.hadoop.hbase.HColumnDescriptor;
34  import org.apache.hadoop.hbase.HConstants;
35  import org.apache.hadoop.hbase.HRegionInfo;
36  import org.apache.hadoop.hbase.HTableDescriptor;
37  import org.apache.hadoop.hbase.testclassification.MediumTests;
38  import org.apache.hadoop.hbase.MetaTableAccessor;
39  import org.apache.hadoop.hbase.MiniHBaseCluster;
40  import org.apache.hadoop.hbase.PleaseHoldException;
41  import org.apache.hadoop.hbase.ServerName;
42  import org.apache.hadoop.hbase.TableName;
43  import org.apache.hadoop.hbase.UnknownRegionException;
44  import org.apache.hadoop.hbase.client.Admin;
45  import org.apache.hadoop.hbase.client.HTable;
46  import org.apache.hadoop.hbase.protobuf.generated.ZooKeeperProtos;
47  import org.apache.hadoop.hbase.util.Bytes;
48  import org.apache.hadoop.hbase.util.Pair;
49  import org.apache.hadoop.util.StringUtils;
50  import org.apache.zookeeper.KeeperException;
51  import org.junit.AfterClass;
52  import org.junit.Assert;
53  import org.junit.BeforeClass;
54  import org.junit.Test;
55  import org.junit.experimental.categories.Category;
56  
57  import com.google.common.base.Joiner;
58  
59  @Category(MediumTests.class)
60  public class TestMaster {
61    private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
62    private static final Log LOG = LogFactory.getLog(TestMaster.class);
63    private static final TableName TABLENAME =
64        TableName.valueOf("TestMaster");
65    private static final byte[] FAMILYNAME = Bytes.toBytes("fam");
66    private static Admin admin;
67  
68    @BeforeClass
69    public static void beforeAllTests() throws Exception {
70      // we will retry operations when PleaseHoldException is thrown
71      TEST_UTIL.getConfiguration().setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, 3);
72      // Here just set 1 ms for testing.
73      TEST_UTIL.getConfiguration().
74        setLong(HConstants.HBASE_MASTER_WAITING_META_ASSIGNMENT_TIMEOUT, 1);
75      // Set hbase.min.version.move.system.tables as version 0 so that
76      // testMoveRegionWhenNotInitialized never fails even if hbase-default has valid default
77      // value present for production use-case.
78      // See HBASE-22923 for details.
79      TEST_UTIL.getConfiguration().set("hbase.min.version.move.system.tables", "0.0.0");
80      // Start a cluster of two regionservers.
81      TEST_UTIL.startMiniCluster(2);
82      admin = TEST_UTIL.getHBaseAdmin();
83      TEST_UTIL.getHBaseCluster().getMaster().assignmentManager.initializeHandlerTrackers();
84    }
85  
86    @AfterClass
87    public static void afterAllTests() throws Exception {
88      TEST_UTIL.shutdownMiniCluster();
89    }
90  
91    @Test
92    public void testMasterOpsWhileSplitting() throws Exception {
93      MiniHBaseCluster cluster = TEST_UTIL.getHBaseCluster();
94      HMaster m = cluster.getMaster();
95  
96      try (HTable ht = TEST_UTIL.createTable(TABLENAME, FAMILYNAME)) {
97        assertTrue(m.assignmentManager.getTableStateManager().isTableState(TABLENAME,
98          ZooKeeperProtos.Table.State.ENABLED));
99        TEST_UTIL.loadTable(ht, FAMILYNAME, false);
100     }
101 
102     List<Pair<HRegionInfo, ServerName>> tableRegions = MetaTableAccessor.getTableRegionsAndLocations(
103         m.getZooKeeper(),
104         m.getConnection(), TABLENAME);
105     LOG.info("Regions after load: " + Joiner.on(',').join(tableRegions));
106     assertEquals(1, tableRegions.size());
107     assertArrayEquals(HConstants.EMPTY_START_ROW,
108         tableRegions.get(0).getFirst().getStartKey());
109     assertArrayEquals(HConstants.EMPTY_END_ROW,
110         tableRegions.get(0).getFirst().getEndKey());
111 
112     // Now trigger a split and stop when the split is in progress
113     LOG.info("Splitting table");
114     TEST_UTIL.getHBaseAdmin().split(TABLENAME);
115     LOG.info("Waiting for split result to be about to open");
116     RegionStates regionStates = m.assignmentManager.getRegionStates();
117     while (regionStates.getRegionsOfTable(TABLENAME).size() <= 1) {
118       Thread.sleep(100);
119     }
120     LOG.info("Making sure we can call getTableRegions while opening");
121     tableRegions = MetaTableAccessor.getTableRegionsAndLocations(m.getZooKeeper(),
122       m.getConnection(),
123       TABLENAME, false);
124 
125     LOG.info("Regions: " + Joiner.on(',').join(tableRegions));
126     // We have three regions because one is split-in-progress
127     assertEquals(3, tableRegions.size());
128     LOG.info("Making sure we can call getTableRegionClosest while opening");
129     Pair<HRegionInfo, ServerName> pair =
130         m.getTableRegionForRow(TABLENAME, Bytes.toBytes("cde"));
131     LOG.info("Result is: " + pair);
132     Pair<HRegionInfo, ServerName> tableRegionFromName =
133         MetaTableAccessor.getRegion(m.getConnection(),
134           pair.getFirst().getRegionName());
135     assertEquals(tableRegionFromName.getFirst(), pair.getFirst());
136   }
137 
138   @Test
139   public void testMoveRegionWhenNotInitialized() {
140     MiniHBaseCluster cluster = TEST_UTIL.getHBaseCluster();
141     HMaster m = cluster.getMaster();
142     try {
143       m.setInitialized(false); // fake it, set back later
144       HRegionInfo meta = HRegionInfo.FIRST_META_REGIONINFO;
145       m.move(meta.getEncodedNameAsBytes(), null);
146       fail("Region should not be moved since master is not initialized");
147     } catch (IOException ioe) {
148       assertTrue(ioe instanceof PleaseHoldException);
149     } finally {
150       m.setInitialized(true);
151     }
152   }
153 
154   @Test
155   public void testMoveThrowsUnknownRegionException() throws IOException {
156     TableName tableName =
157         TableName.valueOf("testMoveThrowsUnknownRegionException");
158     HTableDescriptor htd = new HTableDescriptor(tableName);
159     HColumnDescriptor hcd = new HColumnDescriptor("value");
160     htd.addFamily(hcd);
161 
162     admin.createTable(htd, null);
163     try {
164       HRegionInfo hri = new HRegionInfo(
165         tableName, Bytes.toBytes("A"), Bytes.toBytes("Z"));
166       admin.move(hri.getEncodedNameAsBytes(), null);
167       fail("Region should not be moved since it is fake");
168     } catch (IOException ioe) {
169       assertTrue(ioe instanceof UnknownRegionException);
170     } finally {
171       TEST_UTIL.deleteTable(tableName);
172     }
173   }
174 
175   @Test
176   public void testMoveThrowsPleaseHoldException() throws IOException {
177     TableName tableName = TableName.valueOf("testMoveThrowsPleaseHoldException");
178     HMaster master = TEST_UTIL.getMiniHBaseCluster().getMaster();
179     HTableDescriptor htd = new HTableDescriptor(tableName);
180     HColumnDescriptor hcd = new HColumnDescriptor("value");
181     htd.addFamily(hcd);
182 
183     admin.createTable(htd, null);
184     try {
185       List<HRegionInfo> tableRegions = admin.getTableRegions(tableName);
186 
187       master.setInitialized(false); // fake it, set back later
188       admin.move(tableRegions.get(0).getEncodedNameAsBytes(), null);
189       fail("Region should not be moved since master is not initialized");
190     } catch (IOException ioe) {
191       assertTrue(StringUtils.stringifyException(ioe).contains("PleaseHoldException"));
192     } finally {
193       master.setInitialized(true);
194       TEST_UTIL.deleteTable(tableName);
195     }
196   }
197 
198   @Test (timeout = 300000)
199   public void testMoveRegionWhenMetaRegionInTransition()
200     throws IOException, InterruptedException, KeeperException {
201     TableName tableName = TableName.valueOf("testMoveRegionWhenMetaRegionInTransition");
202     HMaster master = TEST_UTIL.getMiniHBaseCluster().getMaster();
203     HTableDescriptor htd = new HTableDescriptor(tableName);
204     HColumnDescriptor hcd = new HColumnDescriptor("value");
205     RegionStates regionStates = master.getAssignmentManager().getRegionStates();
206     htd.addFamily(hcd);
207 
208     admin.createTable(htd, null);
209     try {
210       HRegionInfo hri = admin.getTableRegions(tableName).get(0);
211 
212       HRegionInfo metaRegion = admin.getTableRegions(TableName.META_TABLE_NAME).get(0);
213 
214       ServerName rs0 = TEST_UTIL.getHBaseCluster().getRegionServer(0).getServerName();
215       ServerName rs1 = TEST_UTIL.getHBaseCluster().getRegionServer(1).getServerName();
216 
217       admin.move(hri.getEncodedNameAsBytes(), rs0.getServerName().getBytes());
218       while (regionStates.isRegionInTransition(hri)) {
219         // Make sure the region is not in transition
220         Thread.sleep(1000);
221       }
222       // Meta region should be in transition
223       master.assignmentManager.unassign(metaRegion);
224       // Then move the region to a new region server.
225       try{
226         master.move(hri.getEncodedNameAsBytes(), rs1.getServerName().getBytes());
227         Assert.fail("Admin move should not be successful here.");
228       } catch (HBaseIOException e) {
229         assertTrue(e.getMessage().contains("Fail-fast"));
230       }
231       // Wait for the movement.
232       Thread.sleep(HConstants.HBASE_MASTER_WAITING_META_ASSIGNMENT_TIMEOUT_DEFAULT);
233       // The region should be still on rs0.
234       TEST_UTIL.assertRegionOnServer(hri, rs0, 5000);
235 
236       // Wait until the meta region is reassigned.
237       admin.assign(metaRegion.getEncodedNameAsBytes());
238       while (regionStates.isMetaRegionInTransition()) {
239         Thread.sleep(1000);
240       }
241 
242       // Try to move region to rs1 once again.
243       admin.move(hri.getEncodedNameAsBytes(), rs1.getServerName().getBytes());
244 
245       Thread.sleep(HConstants.HBASE_MASTER_WAITING_META_ASSIGNMENT_TIMEOUT_DEFAULT);
246       // It should be moved to rs1 this time.
247       TEST_UTIL.assertRegionOnServer(hri, rs1, 5000);
248     } finally {
249       TEST_UTIL.deleteTable(tableName);
250     }
251   }
252 
253   @Test
254   public void testInstallShutdownHook() {
255     // Test for HBASE-26977
256     assertTrue(TEST_UTIL.getMiniHBaseCluster().getMaster().isShutdownHookInstalled());
257   }
258 }
259