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.regionserver; 019 020import java.io.IOException; 021import java.util.ArrayList; 022import java.util.Collection; 023 024import org.apache.hadoop.conf.Configuration; 025import org.apache.hadoop.hbase.HBaseClassTestRule; 026import org.apache.hadoop.hbase.HBaseTestingUtility; 027import org.apache.hadoop.hbase.HConstants; 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.RegionReplicaUtil; 032import org.apache.hadoop.hbase.client.Table; 033import org.apache.hadoop.hbase.client.TableDescriptorBuilder; 034import org.apache.hadoop.hbase.testclassification.MediumTests; 035import org.apache.hadoop.hbase.testclassification.RegionServerTests; 036import org.apache.hadoop.hbase.util.Bytes; 037import org.apache.hadoop.hbase.util.RegionSplitter; 038import org.junit.After; 039import org.junit.AfterClass; 040import org.junit.Before; 041import org.junit.BeforeClass; 042import org.junit.ClassRule; 043import org.junit.Rule; 044import org.junit.Test; 045import org.junit.experimental.categories.Category; 046import org.junit.rules.TestName; 047import org.slf4j.Logger; 048import org.slf4j.LoggerFactory; 049 050import static org.junit.Assert.*; 051 052@Category({RegionServerTests.class, MediumTests.class}) 053public class TestRegionReplicasWithRestartScenarios { 054 055 @ClassRule 056 public static final HBaseClassTestRule CLASS_RULE = 057 HBaseClassTestRule.forClass(TestRegionReplicasWithRestartScenarios.class); 058 059 private static final Logger LOG = 060 LoggerFactory.getLogger(TestRegionReplicasWithRestartScenarios.class); 061 062 @Rule public TestName name = new TestName(); 063 064 private static final int NB_SERVERS = 3; 065 private Table table; 066 private TableName tableName; 067 068 private static final HBaseTestingUtility HTU = new HBaseTestingUtility(); 069 private static final byte[] f = HConstants.CATALOG_FAMILY; 070 071 @BeforeClass 072 public static void beforeClass() throws Exception { 073 HTU.getConfiguration().setInt("hbase.master.wait.on.regionservers.mintostart", NB_SERVERS); 074 HTU.startMiniCluster(NB_SERVERS); 075 } 076 077 @Before 078 public void before() throws IOException { 079 this.tableName = TableName.valueOf(this.name.getMethodName()); 080 this.table = createTableDirectlyFromHTD(this.tableName); 081 } 082 083 @After 084 public void after() throws IOException { 085 this.table.close(); 086 HTU.deleteTable(this.tableName); 087 } 088 089 private static Table createTableDirectlyFromHTD(final TableName tableName) throws IOException { 090 TableDescriptorBuilder builder = TableDescriptorBuilder.newBuilder(tableName); 091 builder.setRegionReplication(3); 092 return HTU.createTable(builder.build(), new byte[][] { f }, getSplits(20), 093 new Configuration(HTU.getConfiguration())); 094 } 095 096 private static byte[][] getSplits(int numRegions) { 097 RegionSplitter.UniformSplit split = new RegionSplitter.UniformSplit(); 098 split.setFirstRow(Bytes.toBytes(0L)); 099 split.setLastRow(Bytes.toBytes(Long.MAX_VALUE)); 100 return split.split(numRegions); 101 } 102 103 @AfterClass 104 public static void afterClass() throws Exception { 105 HRegionServer.TEST_SKIP_REPORTING_TRANSITION = false; 106 HTU.shutdownMiniCluster(); 107 } 108 109 private HRegionServer getRS() { 110 return HTU.getMiniHBaseCluster().getRegionServer(0); 111 } 112 113 private HRegionServer getSecondaryRS() { 114 return HTU.getMiniHBaseCluster().getRegionServer(1); 115 } 116 117 private HRegionServer getTertiaryRS() { 118 return HTU.getMiniHBaseCluster().getRegionServer(2); 119 } 120 121 @Test 122 public void testRegionReplicasCreated() throws Exception { 123 assertReplicaDistributed(); 124 } 125 126 @Test 127 public void testWhenRestart() throws Exception { 128 // Start Region before stopping other so SCP has three servers to play with when it goes 129 // about assigning instead of two, depending on sequencing of SCP and RS stop/start. 130 // If two only, then it'll be forced to assign replicas alongside primaries. 131 HTU.getHBaseCluster().startRegionServerAndWait(60000).getRegionServer(); 132 HRegionServer stopRegionServer = getRS(); 133 ServerName serverName = stopRegionServer.getServerName(); 134 // Make a copy because this is actual instance from HRegionServer 135 Collection<HRegion> regionsOnStoppedServer = 136 new ArrayList<HRegion>(stopRegionServer.getOnlineRegionsLocalContext()); 137 HTU.getHBaseCluster().stopRegionServer(serverName); 138 HTU.getHBaseCluster().waitForRegionServerToStop(serverName, 60000); 139 HTU.waitTableAvailable(this.tableName); 140 assertReplicaDistributed(regionsOnStoppedServer); 141 } 142 143 private void assertReplicaDistributed() throws Exception { 144 assertReplicaDistributed(getRS().getOnlineRegionsLocalContext()); 145 } 146 147 private void assertReplicaDistributed(Collection<HRegion> onlineRegions) throws Exception { 148 LOG.info("ASSERT DISTRIBUTED {}", onlineRegions); 149 boolean res = checkDuplicates(onlineRegions); 150 assertFalse(res); 151 Collection<HRegion> onlineRegions2 = getSecondaryRS().getOnlineRegionsLocalContext(); 152 res = checkDuplicates(onlineRegions2); 153 assertFalse(res); 154 Collection<HRegion> onlineRegions3 = getTertiaryRS().getOnlineRegionsLocalContext(); 155 checkDuplicates(onlineRegions3); 156 assertFalse(res); 157 int totalRegions = HTU.getMiniHBaseCluster().getLiveRegionServerThreads().stream(). 158 mapToInt(l -> l.getRegionServer().getOnlineRegions().size()).sum(); 159 assertEquals(62, totalRegions); 160 } 161 162 private boolean checkDuplicates(Collection<HRegion> onlineRegions3) throws Exception { 163 ArrayList<Region> copyOfRegion = new ArrayList<Region>(onlineRegions3); 164 for (Region region : copyOfRegion) { 165 RegionInfo regionInfo = region.getRegionInfo(); 166 RegionInfo regionInfoForReplica = 167 RegionReplicaUtil.getRegionInfoForDefaultReplica(regionInfo); 168 int i = 0; 169 for (Region actualRegion : onlineRegions3) { 170 if (regionInfoForReplica.equals( 171 RegionReplicaUtil.getRegionInfoForDefaultReplica(actualRegion.getRegionInfo()))) { 172 i++; 173 if (i > 1) { 174 LOG.warn("Duplicate found {} and {}", actualRegion.getRegionInfo(), 175 region.getRegionInfo()); 176 assertTrue(Bytes.equals(region.getRegionInfo().getStartKey(), 177 actualRegion.getRegionInfo().getStartKey())); 178 assertTrue(Bytes.equals(region.getRegionInfo().getEndKey(), 179 actualRegion.getRegionInfo().getEndKey())); 180 return true; 181 } 182 } 183 } 184 } 185 return false; 186 } 187}