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; 019 020import static org.junit.Assert.assertFalse; 021import static org.junit.Assert.assertNotNull; 022import static org.junit.Assert.assertTrue; 023 024import java.io.IOException; 025import java.util.ArrayList; 026import java.util.List; 027import org.apache.hadoop.conf.Configuration; 028import org.apache.hadoop.hbase.HBaseClassTestRule; 029import org.apache.hadoop.hbase.HBaseTestingUtility; 030import org.apache.hadoop.hbase.HRegionLocation; 031import org.apache.hadoop.hbase.MetaMockingUtil; 032import org.apache.hadoop.hbase.MetaTableAccessor; 033import org.apache.hadoop.hbase.TableName; 034import org.apache.hadoop.hbase.client.Admin; 035import org.apache.hadoop.hbase.client.Connection; 036import org.apache.hadoop.hbase.client.ConnectionFactory; 037import org.apache.hadoop.hbase.client.Get; 038import org.apache.hadoop.hbase.client.RegionInfo; 039import org.apache.hadoop.hbase.client.RegionLocator; 040import org.apache.hadoop.hbase.client.Result; 041import org.apache.hadoop.hbase.client.Table; 042import org.apache.hadoop.hbase.master.assignment.AssignmentManager; 043import org.apache.hadoop.hbase.testclassification.MasterTests; 044import org.apache.hadoop.hbase.testclassification.MediumTests; 045import org.apache.hadoop.hbase.util.Bytes; 046import org.apache.hadoop.hbase.util.PairOfSameType; 047import org.apache.hadoop.hbase.util.Threads; 048import org.junit.AfterClass; 049import org.junit.BeforeClass; 050import org.junit.ClassRule; 051import org.junit.Rule; 052import org.junit.Test; 053import org.junit.experimental.categories.Category; 054import org.junit.rules.TestName; 055import org.slf4j.Logger; 056import org.slf4j.LoggerFactory; 057 058@Category({MasterTests.class, MediumTests.class}) 059public class TestCatalogJanitorInMemoryStates { 060 061 @ClassRule 062 public static final HBaseClassTestRule CLASS_RULE = 063 HBaseClassTestRule.forClass(TestCatalogJanitorInMemoryStates.class); 064 065 private static final Logger LOG = LoggerFactory.getLogger(TestCatalogJanitorInMemoryStates.class); 066 @Rule public final TestName name = new TestName(); 067 protected final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility(); 068 private static byte [] ROW = Bytes.toBytes("testRow"); 069 private static byte [] FAMILY = Bytes.toBytes("testFamily"); 070 private static byte [] QUALIFIER = Bytes.toBytes("testQualifier"); 071 private static byte [] VALUE = Bytes.toBytes("testValue"); 072 073 /** 074 * @throws java.lang.Exception 075 */ 076 @BeforeClass 077 public static void setUpBeforeClass() throws Exception { 078 Configuration conf = TEST_UTIL.getConfiguration(); 079 TEST_UTIL.startMiniCluster(1); 080 } 081 082 /** 083 * @throws java.lang.Exception 084 */ 085 @AfterClass 086 public static void tearDownAfterClass() throws Exception { 087 TEST_UTIL.shutdownMiniCluster(); 088 } 089 090 /** 091 * Test clearing a split parent from memory. 092 */ 093 @Test 094 public void testInMemoryParentCleanup() throws Exception { 095 final AssignmentManager am = TEST_UTIL.getHBaseCluster().getMaster().getAssignmentManager(); 096 final ServerManager sm = TEST_UTIL.getHBaseCluster().getMaster().getServerManager(); 097 final CatalogJanitor janitor = TEST_UTIL.getHBaseCluster().getMaster().getCatalogJanitor(); 098 099 Admin admin = TEST_UTIL.getAdmin(); 100 admin.enableCatalogJanitor(false); 101 102 final TableName tableName = TableName.valueOf(name.getMethodName()); 103 Table t = TEST_UTIL.createTable(tableName, FAMILY); 104 int rowCount = TEST_UTIL.loadTable(t, FAMILY, false); 105 106 RegionLocator locator = TEST_UTIL.getConnection().getRegionLocator(tableName); 107 List<HRegionLocation> allRegionLocations = locator.getAllRegionLocations(); 108 109 // We need to create a valid split with daughter regions 110 HRegionLocation parent = allRegionLocations.get(0); 111 List<HRegionLocation> daughters = splitRegion(parent.getRegionInfo()); 112 LOG.info("Parent region: " + parent); 113 LOG.info("Daughter regions: " + daughters); 114 assertNotNull("Should have found daughter regions for " + parent, daughters); 115 116 assertTrue("Parent region should exist in RegionStates", 117 am.getRegionStates().isRegionInRegionStates(parent.getRegionInfo())); 118 assertTrue("Parent region should exist in ServerManager", 119 sm.isRegionInServerManagerStates(parent.getRegionInfo())); 120 121 // clean the parent 122 Result r = MetaMockingUtil.getMetaTableRowResult(parent.getRegionInfo(), null, 123 daughters.get(0).getRegionInfo(), daughters.get(1).getRegionInfo()); 124 janitor.cleanParent(parent.getRegionInfo(), r); 125 assertFalse("Parent region should have been removed from RegionStates", 126 am.getRegionStates().isRegionInRegionStates(parent.getRegionInfo())); 127 assertFalse("Parent region should have been removed from ServerManager", 128 sm.isRegionInServerManagerStates(parent.getRegionInfo())); 129 130 } 131 132 /** 133 * Splits a region 134 * @param r Region to split. 135 * @return List of region locations 136 */ 137 private List<HRegionLocation> splitRegion(final RegionInfo r) 138 throws Exception { 139 List<HRegionLocation> locations = new ArrayList<>(); 140 // Split this table in two. 141 Admin admin = TEST_UTIL.getAdmin(); 142 Connection connection = TEST_UTIL.getConnection(); 143 admin.splitRegionAsync(r.getEncodedNameAsBytes()).get(); 144 admin.close(); 145 PairOfSameType<RegionInfo> regions = waitOnDaughters(r); 146 if (regions != null) { 147 try (RegionLocator rl = connection.getRegionLocator(r.getTable())) { 148 locations.add(rl.getRegionLocation(regions.getFirst().getEncodedNameAsBytes())); 149 locations.add(rl.getRegionLocation(regions.getSecond().getEncodedNameAsBytes())); 150 } 151 return locations; 152 } 153 return locations; 154 } 155 156 /* 157 * Wait on region split. May return because we waited long enough on the split 158 * and it didn't happen. Caller should check. 159 * @param r 160 * @return Daughter regions; caller needs to check table actually split. 161 */ 162 private PairOfSameType<RegionInfo> waitOnDaughters(final RegionInfo r) 163 throws IOException { 164 long start = System.currentTimeMillis(); 165 PairOfSameType<RegionInfo> pair = null; 166 try (Connection conn = ConnectionFactory.createConnection(TEST_UTIL.getConfiguration()); 167 Table metaTable = conn.getTable(TableName.META_TABLE_NAME)) { 168 Result result = null; 169 RegionInfo region = null; 170 while ((System.currentTimeMillis() - start) < 60000) { 171 result = metaTable.get(new Get(r.getRegionName())); 172 if (result == null) { 173 break; 174 } 175 region = MetaTableAccessor.getRegionInfo(result); 176 if (region.isSplitParent()) { 177 LOG.debug(region.toString() + " IS a parent!"); 178 pair = MetaTableAccessor.getDaughterRegions(result); 179 break; 180 } 181 Threads.sleep(100); 182 } 183 184 if (pair.getFirst() == null || pair.getSecond() == null) { 185 throw new IOException("Failed to get daughters, for parent region: " + r); 186 } 187 return pair; 188 } 189 } 190}