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.procedure; 019 020import static org.junit.jupiter.api.Assertions.assertEquals; 021import static org.junit.jupiter.api.Assertions.assertTrue; 022 023import java.util.List; 024import org.apache.hadoop.conf.Configuration; 025import org.apache.hadoop.fs.FileSystem; 026import org.apache.hadoop.fs.Path; 027import org.apache.hadoop.hbase.HBaseTestingUtil; 028import org.apache.hadoop.hbase.ServerName; 029import org.apache.hadoop.hbase.TableName; 030import org.apache.hadoop.hbase.client.RegionInfo; 031import org.apache.hadoop.hbase.client.SnapshotDescription; 032import org.apache.hadoop.hbase.client.SnapshotType; 033import org.apache.hadoop.hbase.client.Table; 034import org.apache.hadoop.hbase.master.HMaster; 035import org.apache.hadoop.hbase.procedure2.ProcedureExecutor; 036import org.apache.hadoop.hbase.procedure2.ProcedureTestingUtility; 037import org.apache.hadoop.hbase.procedure2.RemoteProcedureDispatcher; 038import org.apache.hadoop.hbase.snapshot.SnapshotDescriptionUtils; 039import org.apache.hadoop.hbase.snapshot.SnapshotManifestV2; 040import org.apache.hadoop.hbase.testclassification.LargeTests; 041import org.apache.hadoop.hbase.testclassification.MasterTests; 042import org.apache.hadoop.hbase.util.Bytes; 043import org.apache.hadoop.hbase.util.CommonFSUtils; 044import org.apache.hadoop.hbase.util.Pair; 045import org.apache.hadoop.hbase.util.RegionSplitter; 046import org.junit.jupiter.api.AfterEach; 047import org.junit.jupiter.api.BeforeEach; 048import org.junit.jupiter.api.Tag; 049import org.junit.jupiter.api.Test; 050import org.slf4j.Logger; 051import org.slf4j.LoggerFactory; 052 053import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; 054import org.apache.hadoop.hbase.shaded.protobuf.generated.SnapshotProtos; 055 056@Tag(MasterTests.TAG) 057@Tag(LargeTests.TAG) 058public class TestSnapshotRegionProcedure { 059 private static final Logger LOG = LoggerFactory.getLogger(TestSnapshotRegionProcedure.class); 060 061 private static HBaseTestingUtil TEST_UTIL; 062 private HMaster master; 063 private TableName tableName; 064 private SnapshotProtos.SnapshotDescription snapshotProto; 065 private Path workingDir; 066 private FileSystem workingDirFs; 067 068 @BeforeEach 069 public void setup() throws Exception { 070 TEST_UTIL = new HBaseTestingUtil(); 071 Configuration conf = TEST_UTIL.getConfiguration(); 072 // disable info server. Info server is useful when we run unit tests locally, but it will 073 // fails integration testing of jenkins. 074 // conf.setInt(HConstants.MASTER_INFO_PORT, 8080); 075 076 // delay dispatch so that we can do something, for example kill a target server 077 conf.setInt(RemoteProcedureDispatcher.DISPATCH_DELAY_CONF_KEY, 10000); 078 conf.setInt(RemoteProcedureDispatcher.DISPATCH_MAX_QUEUE_SIZE_CONF_KEY, 128); 079 TEST_UTIL.startMiniCluster(3); 080 master = TEST_UTIL.getHBaseCluster().getMaster(); 081 tableName = TableName.valueOf(Bytes.toBytes("SRPTestTable")); 082 byte[] cf = Bytes.toBytes("cf"); 083 String SNAPSHOT_NAME = "SnapshotRegionProcedureTest"; 084 SnapshotDescription snapshot = 085 new SnapshotDescription(SNAPSHOT_NAME, tableName, SnapshotType.FLUSH); 086 snapshotProto = ProtobufUtil.createHBaseProtosSnapshotDesc(snapshot); 087 snapshotProto = SnapshotDescriptionUtils.validate(snapshotProto, master.getConfiguration()); 088 final byte[][] splitKeys = new RegionSplitter.HexStringSplit().split(10); 089 Table table = TEST_UTIL.createTable(tableName, cf, splitKeys); 090 TEST_UTIL.loadTable(table, cf, false); 091 Path rootDir = CommonFSUtils.getRootDir(conf); 092 this.workingDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(snapshotProto, rootDir, conf); 093 this.workingDirFs = workingDir.getFileSystem(conf); 094 if (!workingDirFs.exists(workingDir)) { 095 workingDirFs.mkdirs(workingDir); 096 } 097 } 098 099 private boolean assertRegionManifestGenerated(RegionInfo region) throws Exception { 100 // path: /<root dir>/<snapshot dir>/<working dir>/<snapshot name>/region-manifest.<encode name> 101 String regionManifest = SnapshotManifestV2.SNAPSHOT_MANIFEST_PREFIX + region.getEncodedName(); 102 Path targetPath = new Path(workingDir, regionManifest); 103 return workingDirFs.exists(targetPath); 104 } 105 106 @Test 107 public void testSimpleSnapshotRegion() throws Exception { 108 ProcedureExecutor<MasterProcedureEnv> procExec = master.getMasterProcedureExecutor(); 109 List<Pair<RegionInfo, ServerName>> regions = 110 master.getAssignmentManager().getTableRegionsAndLocations(tableName, true); 111 assertEquals(10, regions.size()); 112 Pair<RegionInfo, ServerName> region = regions.get(0); 113 SnapshotRegionProcedure srp = new SnapshotRegionProcedure(snapshotProto, region.getFirst()); 114 long procId = procExec.submitProcedure(srp); 115 ProcedureTestingUtility.waitProcedure(procExec, procId); 116 assertTrue(assertRegionManifestGenerated(region.getFirst())); 117 } 118 119 @Test 120 public void testRegionServerCrashWhileTakingSnapshotRegion() throws Exception { 121 ProcedureExecutor<MasterProcedureEnv> procExec = master.getMasterProcedureExecutor(); 122 List<Pair<RegionInfo, ServerName>> regions = 123 master.getAssignmentManager().getTableRegionsAndLocations(tableName, true); 124 assertEquals(10, regions.size()); 125 Pair<RegionInfo, ServerName> pair = regions.get(0); 126 SnapshotRegionProcedure srp = new SnapshotRegionProcedure(snapshotProto, pair.getFirst()); 127 long procId = procExec.submitProcedure(srp); 128 TEST_UTIL.getHBaseCluster().killRegionServer(pair.getSecond()); 129 TEST_UTIL.waitFor(60000, () -> !pair.getSecond().equals(master.getAssignmentManager() 130 .getRegionStates().getRegionStateNode(pair.getFirst()).getRegionLocation())); 131 TEST_UTIL.waitFor(60000, () -> srp.inRetrying()); 132 ProcedureTestingUtility.waitProcedure(procExec, procId); 133 assertTrue(assertRegionManifestGenerated(pair.getFirst())); 134 } 135 136 @AfterEach 137 public void teardown() throws Exception { 138 if (this.master != null) { 139 ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(master.getMasterProcedureExecutor(), 140 false); 141 } 142 TEST_UTIL.shutdownMiniCluster(); 143 } 144}