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