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}