HBASE-26416 Implement a new method for region replication instead of using replay...
[hbase.git] / hbase-server / src / test / java / org / apache / hadoop / hbase / master / TestMaster.java
blob65a205fd3c9307772a3e280cef4c4da022e002fa
1 /**
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 package org.apache.hadoop.hbase.master;
20 import static org.junit.Assert.assertArrayEquals;
21 import static org.junit.Assert.assertEquals;
22 import static org.junit.Assert.assertFalse;
23 import static org.junit.Assert.assertTrue;
24 import static org.junit.Assert.fail;
26 import java.io.IOException;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.concurrent.atomic.AtomicReference;
30 import org.apache.hadoop.conf.Configuration;
31 import org.apache.hadoop.fs.FileSystem;
32 import org.apache.hadoop.fs.Path;
33 import org.apache.hadoop.hbase.CatalogFamilyFormat;
34 import org.apache.hadoop.hbase.ClientMetaTableAccessor;
35 import org.apache.hadoop.hbase.HBaseClassTestRule;
36 import org.apache.hadoop.hbase.HBaseTestingUtil;
37 import org.apache.hadoop.hbase.HConstants;
38 import org.apache.hadoop.hbase.MetaTableAccessor;
39 import org.apache.hadoop.hbase.PleaseHoldException;
40 import org.apache.hadoop.hbase.ServerName;
41 import org.apache.hadoop.hbase.SingleProcessHBaseCluster;
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.ColumnFamilyDescriptor;
46 import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
47 import org.apache.hadoop.hbase.client.RegionInfo;
48 import org.apache.hadoop.hbase.client.RegionInfoBuilder;
49 import org.apache.hadoop.hbase.client.Result;
50 import org.apache.hadoop.hbase.client.Table;
51 import org.apache.hadoop.hbase.client.TableDescriptor;
52 import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
53 import org.apache.hadoop.hbase.client.TableState;
54 import org.apache.hadoop.hbase.testclassification.MasterTests;
55 import org.apache.hadoop.hbase.testclassification.MediumTests;
56 import org.apache.hadoop.hbase.util.Bytes;
57 import org.apache.hadoop.hbase.util.HBaseFsck;
58 import org.apache.hadoop.hbase.util.Pair;
59 import org.apache.hadoop.hbase.util.Threads;
60 import org.apache.hadoop.util.StringUtils;
61 import org.junit.AfterClass;
62 import org.junit.BeforeClass;
63 import org.junit.ClassRule;
64 import org.junit.Rule;
65 import org.junit.Test;
66 import org.junit.experimental.categories.Category;
67 import org.junit.rules.TestName;
68 import org.slf4j.Logger;
69 import org.slf4j.LoggerFactory;
71 import org.apache.hbase.thirdparty.com.google.common.base.Joiner;
73 @Category({MasterTests.class, MediumTests.class})
74 public class TestMaster {
76 @ClassRule
77 public static final HBaseClassTestRule CLASS_RULE =
78 HBaseClassTestRule.forClass(TestMaster.class);
80 private static final HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil();
81 private static final Logger LOG = LoggerFactory.getLogger(TestMaster.class);
82 private static final TableName TABLENAME = TableName.valueOf("TestMaster");
83 private static final byte[] FAMILYNAME = Bytes.toBytes("fam");
84 private static Admin admin;
86 @Rule
87 public TestName name = new TestName();
89 @BeforeClass
90 public static void beforeAllTests() throws Exception {
91 // we will retry operations when PleaseHoldException is thrown
92 TEST_UTIL.getConfiguration().setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, 3);
93 // Set hbase.min.version.move.system.tables as version 0 so that
94 // testMoveRegionWhenNotInitialized never fails even if hbase-default has valid default
95 // value present for production use-case.
96 // See HBASE-22923 for details.
97 TEST_UTIL.getConfiguration().set("hbase.min.version.move.system.tables", "0.0.0");
98 // Start a cluster of two regionservers.
99 TEST_UTIL.startMiniCluster(2);
100 admin = TEST_UTIL.getAdmin();
103 @AfterClass
104 public static void afterAllTests() throws Exception {
105 TEST_UTIL.shutdownMiniCluster();
109 * Return the region and current deployment for the region containing the given row. If the region
110 * cannot be found, returns null. If it is found, but not currently deployed, the second element
111 * of the pair may be null.
113 private Pair<RegionInfo, ServerName> getTableRegionForRow(HMaster master, TableName tableName,
114 byte[] rowKey) throws IOException {
115 final AtomicReference<Pair<RegionInfo, ServerName>> result = new AtomicReference<>(null);
117 ClientMetaTableAccessor.Visitor visitor = new ClientMetaTableAccessor.Visitor() {
118 @Override
119 public boolean visit(Result data) throws IOException {
120 if (data == null || data.size() <= 0) {
121 return true;
123 Pair<RegionInfo, ServerName> pair = new Pair<>(CatalogFamilyFormat.getRegionInfo(data),
124 CatalogFamilyFormat.getServerName(data, 0));
125 if (!pair.getFirst().getTable().equals(tableName)) {
126 return false;
128 result.set(pair);
129 return true;
133 MetaTableAccessor.scanMeta(master.getConnection(), visitor, tableName, rowKey, 1);
134 return result.get();
137 @Test
138 @SuppressWarnings("deprecation")
139 public void testMasterOpsWhileSplitting() throws Exception {
140 SingleProcessHBaseCluster cluster = TEST_UTIL.getHBaseCluster();
141 HMaster m = cluster.getMaster();
143 try (Table ht = TEST_UTIL.createTable(TABLENAME, FAMILYNAME)) {
144 assertTrue(m.getTableStateManager().isTableState(TABLENAME, TableState.State.ENABLED));
145 TEST_UTIL.loadTable(ht, FAMILYNAME, false);
148 List<Pair<RegionInfo, ServerName>> tableRegions = MetaTableAccessor.getTableRegionsAndLocations(
149 m.getConnection(), TABLENAME);
150 LOG.info("Regions after load: " + Joiner.on(',').join(tableRegions));
151 assertEquals(1, tableRegions.size());
152 assertArrayEquals(HConstants.EMPTY_START_ROW,
153 tableRegions.get(0).getFirst().getStartKey());
154 assertArrayEquals(HConstants.EMPTY_END_ROW,
155 tableRegions.get(0).getFirst().getEndKey());
157 // Now trigger a split and stop when the split is in progress
158 LOG.info("Splitting table");
159 TEST_UTIL.getAdmin().split(TABLENAME);
161 LOG.info("Making sure we can call getTableRegions while opening");
162 while (tableRegions.size() < 3) {
163 tableRegions = MetaTableAccessor.getTableRegionsAndLocations(m.getConnection(),
164 TABLENAME, false);
165 Thread.sleep(100);
167 LOG.info("Regions: " + Joiner.on(',').join(tableRegions));
168 // We have three regions because one is split-in-progress
169 assertEquals(3, tableRegions.size());
170 LOG.info("Making sure we can call getTableRegionClosest while opening");
171 Pair<RegionInfo, ServerName> pair = getTableRegionForRow(m, TABLENAME, Bytes.toBytes("cde"));
172 LOG.info("Result is: " + pair);
173 Pair<RegionInfo, ServerName> tableRegionFromName =
174 MetaTableAccessor.getRegion(m.getConnection(),
175 pair.getFirst().getRegionName());
176 assertTrue(RegionInfo.COMPARATOR.compare(tableRegionFromName.getFirst(), pair.getFirst()) == 0);
179 @Test
180 public void testMoveRegionWhenNotInitialized() {
181 SingleProcessHBaseCluster cluster = TEST_UTIL.getHBaseCluster();
182 HMaster m = cluster.getMaster();
183 try {
184 m.setInitialized(false); // fake it, set back later
185 RegionInfo meta = RegionInfoBuilder.FIRST_META_REGIONINFO;
186 m.move(meta.getEncodedNameAsBytes(), null);
187 fail("Region should not be moved since master is not initialized");
188 } catch (IOException ioe) {
189 assertTrue(ioe instanceof PleaseHoldException);
190 } finally {
191 m.setInitialized(true);
195 @Test
196 public void testMoveThrowsUnknownRegionException() throws IOException {
197 final TableName tableName = TableName.valueOf(name.getMethodName());
198 TableDescriptorBuilder tableDescriptorBuilder =
199 TableDescriptorBuilder.newBuilder(tableName);
200 ColumnFamilyDescriptor columnFamilyDescriptor =
201 ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes("value")).build();
202 tableDescriptorBuilder.setColumnFamily(columnFamilyDescriptor);
204 admin.createTable(tableDescriptorBuilder.build());
205 try {
206 RegionInfo hri = RegionInfoBuilder.newBuilder(tableName)
207 .setStartKey(Bytes.toBytes("A"))
208 .setEndKey(Bytes.toBytes("Z"))
209 .build();
210 admin.move(hri.getEncodedNameAsBytes());
211 fail("Region should not be moved since it is fake");
212 } catch (IOException ioe) {
213 assertTrue(ioe instanceof UnknownRegionException);
214 } finally {
215 TEST_UTIL.deleteTable(tableName);
219 @Test
220 public void testMoveThrowsPleaseHoldException() throws IOException {
221 final TableName tableName = TableName.valueOf(name.getMethodName());
222 HMaster master = TEST_UTIL.getMiniHBaseCluster().getMaster();
223 TableDescriptorBuilder tableDescriptorBuilder =
224 TableDescriptorBuilder.newBuilder(tableName);
225 ColumnFamilyDescriptor columnFamilyDescriptor =
226 ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes("value")).build();
227 tableDescriptorBuilder.setColumnFamily(columnFamilyDescriptor);
229 admin.createTable(tableDescriptorBuilder.build());
230 try {
231 List<RegionInfo> tableRegions = admin.getRegions(tableName);
233 master.setInitialized(false); // fake it, set back later
234 admin.move(tableRegions.get(0).getEncodedNameAsBytes());
235 fail("Region should not be moved since master is not initialized");
236 } catch (IOException ioe) {
237 assertTrue(StringUtils.stringifyException(ioe).contains("PleaseHoldException"));
238 } finally {
239 master.setInitialized(true);
240 TEST_UTIL.deleteTable(tableName);
244 @Test
245 public void testFlushedSequenceIdPersistLoad() throws Exception {
246 Configuration conf = TEST_UTIL.getConfiguration();
247 int msgInterval = conf.getInt("hbase.regionserver.msginterval", 100);
248 // insert some data into META
249 TableName tableName = TableName.valueOf("testFlushSeqId");
250 TableDescriptor tableDescriptor = TableDescriptorBuilder.newBuilder(tableName)
251 .setColumnFamily(ColumnFamilyDescriptorBuilder.of(Bytes.toBytes("cf"))).build();
252 Table table = TEST_UTIL.createTable(tableDescriptor, null);
253 // flush META region
254 TEST_UTIL.flush(TableName.META_TABLE_NAME);
255 // wait for regionserver report
256 Threads.sleep(msgInterval * 2);
257 // record flush seqid before cluster shutdown
258 Map<byte[], Long> regionMapBefore =
259 TEST_UTIL.getHBaseCluster().getMaster().getServerManager()
260 .getFlushedSequenceIdByRegion();
261 // restart hbase cluster which will cause flushed sequence id persist and reload
262 TEST_UTIL.getMiniHBaseCluster().shutdown();
263 TEST_UTIL.restartHBaseCluster(2);
264 TEST_UTIL.waitUntilNoRegionsInTransition();
265 // check equality after reloading flushed sequence id map
266 Map<byte[], Long> regionMapAfter =
267 TEST_UTIL.getHBaseCluster().getMaster().getServerManager()
268 .getFlushedSequenceIdByRegion();
269 assertTrue(regionMapBefore.equals(regionMapAfter));
272 @Test
273 public void testBlockingHbkc1WithLockFile() throws IOException {
274 // This is how the patch to the lock file is created inside in HBaseFsck. Too hard to use its
275 // actual method without disturbing HBaseFsck... Do the below mimic instead.
276 Path hbckLockPath = new Path(HBaseFsck.getTmpDir(TEST_UTIL.getConfiguration()),
277 HBaseFsck.HBCK_LOCK_FILE);
278 FileSystem fs = TEST_UTIL.getTestFileSystem();
279 assertTrue(fs.exists(hbckLockPath));
280 TEST_UTIL.getMiniHBaseCluster().
281 killMaster(TEST_UTIL.getMiniHBaseCluster().getMaster().getServerName());
282 assertTrue(fs.exists(hbckLockPath));
283 TEST_UTIL.getMiniHBaseCluster().startMaster();
284 TEST_UTIL.waitFor(30000, () -> TEST_UTIL.getMiniHBaseCluster().getMaster() != null &&
285 TEST_UTIL.getMiniHBaseCluster().getMaster().isInitialized());
286 assertTrue(fs.exists(hbckLockPath));
287 // Start a second Master. Should be fine.
288 TEST_UTIL.getMiniHBaseCluster().startMaster();
289 assertTrue(fs.exists(hbckLockPath));
290 fs.delete(hbckLockPath, true);
291 assertFalse(fs.exists(hbckLockPath));
292 // Kill all Masters.
293 TEST_UTIL.getMiniHBaseCluster().getLiveMasterThreads().stream().
294 map(sn -> sn.getMaster().getServerName()).forEach(sn -> {
295 try {
296 TEST_UTIL.getMiniHBaseCluster().killMaster(sn);
297 } catch (IOException e) {
298 e.printStackTrace();
301 // Start a new one.
302 TEST_UTIL.getMiniHBaseCluster().startMaster();
303 TEST_UTIL.waitFor(30000, () -> TEST_UTIL.getMiniHBaseCluster().getMaster() != null &&
304 TEST_UTIL.getMiniHBaseCluster().getMaster().isInitialized());
305 // Assert lock gets put in place again.
306 assertTrue(fs.exists(hbckLockPath));