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