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.assignment; 019 020import static org.junit.Assert.assertEquals; 021import static org.junit.Assert.assertFalse; 022import static org.junit.Assert.assertTrue; 023 024import java.util.Collections; 025import java.util.List; 026import java.util.Map; 027import java.util.concurrent.Future; 028import org.apache.hadoop.conf.Configuration; 029import org.apache.hadoop.hbase.HBaseClassTestRule; 030import org.apache.hadoop.hbase.HRegionInfo; 031import org.apache.hadoop.hbase.ServerName; 032import org.apache.hadoop.hbase.TableName; 033import org.apache.hadoop.hbase.client.RegionInfo; 034import org.apache.hadoop.hbase.client.RegionInfoBuilder; 035import org.apache.hadoop.hbase.client.TableState; 036import org.apache.hadoop.hbase.master.HbckChore; 037import org.apache.hadoop.hbase.master.TableStateManager; 038import org.apache.hadoop.hbase.regionserver.HRegion; 039import org.apache.hadoop.hbase.testclassification.MasterTests; 040import org.apache.hadoop.hbase.testclassification.MediumTests; 041import org.apache.hadoop.hbase.util.Bytes; 042import org.apache.hadoop.hbase.util.CommonFSUtils; 043import org.apache.hadoop.hbase.util.FSUtils; 044import org.apache.hadoop.hbase.util.Pair; 045import org.junit.Before; 046import org.junit.ClassRule; 047import org.junit.Test; 048import org.junit.experimental.categories.Category; 049import org.mockito.Mockito; 050import org.slf4j.Logger; 051import org.slf4j.LoggerFactory; 052 053@Category({ MasterTests.class, MediumTests.class }) 054public class TestHbckChore extends TestAssignmentManagerBase { 055 private static final Logger LOG = LoggerFactory.getLogger(TestHbckChore.class); 056 057 @ClassRule 058 public static final HBaseClassTestRule CLASS_RULE = 059 HBaseClassTestRule.forClass(TestHbckChore.class); 060 061 private HbckChore hbckChore; 062 063 @Before 064 public void setUp() throws Exception { 065 super.setUp(); 066 hbckChore = new HbckChore(master); 067 } 068 069 @Test 070 public void testForMeta() { 071 byte[] metaRegionNameAsBytes = RegionInfoBuilder.FIRST_META_REGIONINFO.getRegionName(); 072 String metaRegionName = RegionInfoBuilder.FIRST_META_REGIONINFO.getRegionNameAsString(); 073 List<ServerName> serverNames = master.getServerManager().getOnlineServersList(); 074 assertEquals(NSERVERS, serverNames.size()); 075 076 hbckChore.choreForTesting(); 077 Map<String, Pair<ServerName, List<ServerName>>> inconsistentRegions = 078 hbckChore.getInconsistentRegions(); 079 080 // Test for case1: Master thought this region opened, but no regionserver reported it. 081 assertTrue(inconsistentRegions.containsKey(metaRegionName)); 082 Pair<ServerName, List<ServerName>> pair = inconsistentRegions.get(metaRegionName); 083 ServerName locationInMeta = pair.getFirst(); 084 List<ServerName> reportedRegionServers = pair.getSecond(); 085 assertTrue(serverNames.contains(locationInMeta)); 086 assertEquals(0, reportedRegionServers.size()); 087 088 // Reported right region location. Then not in problematic regions. 089 am.reportOnlineRegions(locationInMeta, Collections.singleton(metaRegionNameAsBytes)); 090 hbckChore.choreForTesting(); 091 inconsistentRegions = hbckChore.getInconsistentRegions(); 092 assertFalse(inconsistentRegions.containsKey(metaRegionName)); 093 } 094 095 @Test 096 public void testForUserTable() throws Exception { 097 TableName tableName = TableName.valueOf("testForUserTable"); 098 RegionInfo hri = createRegionInfo(tableName, 1); 099 String regionName = hri.getRegionNameAsString(); 100 rsDispatcher.setMockRsExecutor(new GoodRsExecutor()); 101 Future<byte[]> future = submitProcedure(createAssignProcedure(hri)); 102 waitOnFuture(future); 103 104 List<ServerName> serverNames = master.getServerManager().getOnlineServersList(); 105 assertEquals(NSERVERS, serverNames.size()); 106 107 // Test for case1: Master thought this region opened, but no regionserver reported it. 108 hbckChore.choreForTesting(); 109 Map<String, Pair<ServerName, List<ServerName>>> inconsistentRegions = 110 hbckChore.getInconsistentRegions(); 111 assertTrue(inconsistentRegions.containsKey(regionName)); 112 Pair<ServerName, List<ServerName>> pair = inconsistentRegions.get(regionName); 113 ServerName locationInMeta = pair.getFirst(); 114 List<ServerName> reportedRegionServers = pair.getSecond(); 115 assertTrue(serverNames.contains(locationInMeta)); 116 assertEquals(0, reportedRegionServers.size()); 117 118 // Test for case2: Master thought this region opened on Server1, but regionserver reported 119 // Server2 120 final ServerName tempLocationInMeta = locationInMeta; 121 final ServerName anotherServer = 122 serverNames.stream().filter(s -> !s.equals(tempLocationInMeta)).findFirst().get(); 123 am.reportOnlineRegions(anotherServer, Collections.singleton(hri.getRegionName())); 124 hbckChore.choreForTesting(); 125 inconsistentRegions = hbckChore.getInconsistentRegions(); 126 assertTrue(inconsistentRegions.containsKey(regionName)); 127 pair = inconsistentRegions.get(regionName); 128 locationInMeta = pair.getFirst(); 129 reportedRegionServers = pair.getSecond(); 130 assertEquals(1, reportedRegionServers.size()); 131 assertFalse(reportedRegionServers.contains(locationInMeta)); 132 assertTrue(reportedRegionServers.contains(anotherServer)); 133 134 // Test for case3: More than one regionservers reported opened this region. 135 am.reportOnlineRegions(locationInMeta, Collections.singleton(hri.getRegionName())); 136 hbckChore.choreForTesting(); 137 inconsistentRegions = hbckChore.getInconsistentRegions(); 138 assertTrue(inconsistentRegions.containsKey(regionName)); 139 pair = inconsistentRegions.get(regionName); 140 locationInMeta = pair.getFirst(); 141 reportedRegionServers = pair.getSecond(); 142 assertEquals(2, reportedRegionServers.size()); 143 assertTrue(reportedRegionServers.contains(locationInMeta)); 144 assertTrue(reportedRegionServers.contains(anotherServer)); 145 146 // Reported right region location, then not in inconsistent regions. 147 am.reportOnlineRegions(anotherServer, Collections.EMPTY_SET); 148 hbckChore.choreForTesting(); 149 inconsistentRegions = hbckChore.getInconsistentRegions(); 150 assertFalse(inconsistentRegions.containsKey(regionName)); 151 } 152 153 @Test 154 public void testForDisabledTable() throws Exception { 155 TableName tableName = TableName.valueOf("testForDisabledTable"); 156 RegionInfo hri = createRegionInfo(tableName, 1); 157 String regionName = hri.getRegionNameAsString(); 158 rsDispatcher.setMockRsExecutor(new GoodRsExecutor()); 159 Future<byte[]> future = submitProcedure(createAssignProcedure(hri)); 160 waitOnFuture(future); 161 162 List<ServerName> serverNames = master.getServerManager().getOnlineServersList(); 163 assertEquals(NSERVERS, serverNames.size()); 164 165 hbckChore.choreForTesting(); 166 Map<String, Pair<ServerName, List<ServerName>>> inconsistentRegions = 167 hbckChore.getInconsistentRegions(); 168 assertTrue(inconsistentRegions.containsKey(regionName)); 169 Pair<ServerName, List<ServerName>> pair = inconsistentRegions.get(regionName); 170 ServerName locationInMeta = pair.getFirst(); 171 List<ServerName> reportedRegionServers = pair.getSecond(); 172 assertTrue(serverNames.contains(locationInMeta)); 173 assertEquals(0, reportedRegionServers.size()); 174 175 // Set table state to disabled, then not in inconsistent regions. 176 TableStateManager tableStateManager = master.getTableStateManager(); 177 Mockito.when(tableStateManager.isTableState(tableName, TableState.State.DISABLED)). 178 thenReturn(true); 179 hbckChore.choreForTesting(); 180 inconsistentRegions = hbckChore.getInconsistentRegions(); 181 assertFalse(inconsistentRegions.containsKey(regionName)); 182 } 183 184 @Test 185 public void testForSplitParent() throws Exception { 186 TableName tableName = TableName.valueOf("testForSplitParent"); 187 RegionInfo hri = RegionInfoBuilder.newBuilder(tableName).setStartKey(Bytes.toBytes(0)) 188 .setEndKey(Bytes.toBytes(1)).setSplit(true).setOffline(true).setRegionId(0).build(); 189 String regionName = hri.getEncodedName(); 190 rsDispatcher.setMockRsExecutor(new GoodRsExecutor()); 191 Future<byte[]> future = submitProcedure(createAssignProcedure(hri)); 192 waitOnFuture(future); 193 194 List<ServerName> serverNames = master.getServerManager().getOnlineServersList(); 195 assertEquals(NSERVERS, serverNames.size()); 196 197 hbckChore.choreForTesting(); 198 Map<String, Pair<ServerName, List<ServerName>>> inconsistentRegions = 199 hbckChore.getInconsistentRegions(); 200 assertFalse(inconsistentRegions.containsKey(regionName)); 201 } 202 203 @Test 204 public void testOrphanRegionsOnFS() throws Exception { 205 TableName tableName = TableName.valueOf("testOrphanRegionsOnFS"); 206 RegionInfo regionInfo = RegionInfoBuilder.newBuilder(tableName).build(); 207 Configuration conf = util.getConfiguration(); 208 209 hbckChore.choreForTesting(); 210 assertEquals(0, hbckChore.getOrphanRegionsOnFS().size()); 211 212 HRegion.createRegionDir(conf, regionInfo, CommonFSUtils.getRootDir(conf)); 213 hbckChore.choreForTesting(); 214 assertEquals(1, hbckChore.getOrphanRegionsOnFS().size()); 215 assertTrue(hbckChore.getOrphanRegionsOnFS().containsKey(regionInfo.getEncodedName())); 216 217 FSUtils.deleteRegionDir(conf, new HRegionInfo(regionInfo)); 218 hbckChore.choreForTesting(); 219 assertEquals(0, hbckChore.getOrphanRegionsOnFS().size()); 220 } 221 222 @Test 223 public void testChoreDisable() { 224 // The way to disable to chore is to set hbase.master.hbck.chore.interval <= 0 225 // When the interval is > 0, the chore should run. 226 long lastRunTime = hbckChore.getCheckingEndTimestamp(); 227 hbckChore.choreForTesting(); 228 boolean ran = lastRunTime != hbckChore.getCheckingEndTimestamp(); 229 assertTrue(ran); 230 231 // When the interval <= 0, the chore shouldn't run 232 master.getConfiguration().setInt("hbase.master.hbck.chore.interval", 0); 233 HbckChore hbckChoreWithChangedConf = new HbckChore(master); 234 lastRunTime = hbckChoreWithChangedConf.getCheckingEndTimestamp(); 235 hbckChoreWithChangedConf.choreForTesting(); 236 ran = lastRunTime != hbckChoreWithChangedConf.getCheckingEndTimestamp(); 237 assertFalse(ran); 238 } 239}