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.util; 019 020import java.util.ArrayList; 021import java.util.List; 022import java.util.stream.Collectors; 023import java.util.stream.IntStream; 024import org.apache.hadoop.hbase.HBaseClassTestRule; 025import org.apache.hadoop.hbase.HBaseTestingUtil; 026import org.apache.hadoop.hbase.ServerName; 027import org.apache.hadoop.hbase.SingleProcessHBaseCluster; 028import org.apache.hadoop.hbase.TableName; 029import org.apache.hadoop.hbase.client.Admin; 030import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder; 031import org.apache.hadoop.hbase.client.Put; 032import org.apache.hadoop.hbase.client.Table; 033import org.apache.hadoop.hbase.client.TableDescriptor; 034import org.apache.hadoop.hbase.client.TableDescriptorBuilder; 035import org.apache.hadoop.hbase.master.RackManager; 036import org.apache.hadoop.hbase.regionserver.HRegion; 037import org.apache.hadoop.hbase.regionserver.HRegionServer; 038import org.apache.hadoop.hbase.testclassification.LargeTests; 039import org.apache.hadoop.hbase.testclassification.MiscTests; 040import org.junit.AfterClass; 041import org.junit.Assert; 042import org.junit.Before; 043import org.junit.BeforeClass; 044import org.junit.ClassRule; 045import org.junit.Rule; 046import org.junit.Test; 047import org.junit.experimental.categories.Category; 048import org.junit.rules.TestName; 049 050@Category({ MiscTests.class, LargeTests.class }) 051public class TestRegionMover3 { 052 053 @ClassRule 054 public static final HBaseClassTestRule CLASS_RULE = 055 HBaseClassTestRule.forClass(TestRegionMover3.class); 056 057 @Rule 058 public TestName name = new TestName(); 059 060 private static final HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil(); 061 private static ServerName rs0; 062 private static ServerName rs1; 063 private static ServerName rs2; 064 065 @BeforeClass 066 public static void setUpBeforeClass() throws Exception { 067 TEST_UTIL.startMiniCluster(3); 068 SingleProcessHBaseCluster cluster = TEST_UTIL.getHBaseCluster(); 069 rs0 = cluster.getRegionServer(0).getServerName(); 070 rs1 = cluster.getRegionServer(1).getServerName(); 071 rs2 = cluster.getRegionServer(2).getServerName(); 072 TEST_UTIL.getAdmin().balancerSwitch(false, true); 073 } 074 075 @AfterClass 076 public static void tearDownAfterClass() throws Exception { 077 TEST_UTIL.shutdownMiniCluster(); 078 } 079 080 @Before 081 public void setUp() throws Exception { 082 final TableName tableName = TableName.valueOf(name.getMethodName()); 083 TableDescriptor tableDesc = TableDescriptorBuilder.newBuilder(tableName) 084 .setColumnFamily(ColumnFamilyDescriptorBuilder.of("fam1")).build(); 085 int startKey = 0; 086 int endKey = 80000; 087 TEST_UTIL.getAdmin().createTable(tableDesc, Bytes.toBytes(startKey), Bytes.toBytes(endKey), 9); 088 } 089 090 @Test 091 public void testRegionUnloadWithRack() throws Exception { 092 final TableName tableName = TableName.valueOf(name.getMethodName()); 093 SingleProcessHBaseCluster cluster = TEST_UTIL.getHBaseCluster(); 094 Admin admin = TEST_UTIL.getAdmin(); 095 Table table = TEST_UTIL.getConnection().getTable(tableName); 096 List<Put> puts = IntStream.range(10, 50000).mapToObj(i -> new Put(Bytes.toBytes(i)) 097 .addColumn(Bytes.toBytes("fam1"), Bytes.toBytes("q1"), Bytes.toBytes("val_" + i))) 098 .collect(Collectors.toList()); 099 table.put(puts); 100 admin.flush(tableName); 101 admin.compact(tableName); 102 Thread.sleep(3000); 103 HRegionServer hRegionServer0 = cluster.getRegionServer(0); 104 HRegionServer hRegionServer1 = cluster.getRegionServer(1); 105 HRegionServer hRegionServer2 = cluster.getRegionServer(2); 106 int numRegions0 = hRegionServer0.getNumberOfOnlineRegions(); 107 int numRegions1 = hRegionServer1.getNumberOfOnlineRegions(); 108 int numRegions2 = hRegionServer2.getNumberOfOnlineRegions(); 109 110 Assert.assertTrue(numRegions0 >= 3); 111 Assert.assertTrue(numRegions1 >= 3); 112 Assert.assertTrue(numRegions2 >= 3); 113 int totalRegions = numRegions0 + numRegions1 + numRegions2; 114 115 // source RS: rs0 116 String sourceRSName = rs0.getAddress().toString(); 117 118 // move all regions from rs1 to rs0 119 for (HRegion region : hRegionServer1.getRegions()) { 120 TEST_UTIL.getAdmin().move(region.getRegionInfo().getEncodedNameAsBytes(), rs0); 121 } 122 TEST_UTIL.waitFor(5000, () -> { 123 int newNumRegions0 = hRegionServer0.getNumberOfOnlineRegions(); 124 int newNumRegions1 = hRegionServer1.getNumberOfOnlineRegions(); 125 return newNumRegions1 == 0 && newNumRegions0 == (numRegions0 + numRegions1); 126 }); 127 128 // regionMover obj on rs0. While unloading regions from rs0 129 // with default rackManager, which resolves "/default-rack" for each server, no region 130 // is moved while using unloadFromRack() as all rs belong to same rack. 131 RegionMover.RegionMoverBuilder rmBuilder = 132 new RegionMover.RegionMoverBuilder(sourceRSName, TEST_UTIL.getConfiguration()).ack(true) 133 .maxthreads(8); 134 try (RegionMover regionMover = rmBuilder.build()) { 135 regionMover.unloadFromRack(); 136 int newNumRegions0 = hRegionServer0.getNumberOfOnlineRegions(); 137 int newNumRegions1 = hRegionServer1.getNumberOfOnlineRegions(); 138 int newNumRegions2 = hRegionServer2.getNumberOfOnlineRegions(); 139 Assert.assertEquals(0, newNumRegions1); 140 Assert.assertEquals(totalRegions, newNumRegions0 + newNumRegions2); 141 } 142 143 // use custom rackManager, which resolves "rack-1" for rs0 and rs1, 144 // while "rack-2" for rs2. Hence, unloadFromRack() from rs0 should move all 145 // regions that belong to rs0 to rs2 only, and nothing should be moved to rs1 146 // as rs0 and rs1 belong to same rack. 147 rmBuilder.rackManager(new MockRackManager()); 148 try (RegionMover regionMover = rmBuilder.build()) { 149 regionMover.unloadFromRack(); 150 int newNumRegions0 = hRegionServer0.getNumberOfOnlineRegions(); 151 int newNumRegions1 = hRegionServer1.getNumberOfOnlineRegions(); 152 int newNumRegions2 = hRegionServer2.getNumberOfOnlineRegions(); 153 Assert.assertEquals(0, newNumRegions0); 154 Assert.assertEquals(0, newNumRegions1); 155 Assert.assertEquals(totalRegions, newNumRegions2); 156 } 157 158 } 159 160 private static class MockRackManager extends RackManager { 161 162 private static final String RACK_2 = "rack-2"; 163 private static final String RACK_1 = "rack-1"; 164 165 @Override 166 public String getRack(ServerName server) { 167 return rs2.equals(server) ? RACK_2 : RACK_1; 168 } 169 170 @Override 171 public List<String> getRack(List<ServerName> servers) { 172 List<String> racks = new ArrayList<>(); 173 servers.forEach(serverName -> { 174 if (rs2.equals(serverName)) { 175 racks.add(RACK_2); 176 } else { 177 racks.add(RACK_1); 178 } 179 }); 180 return racks; 181 } 182 } 183 184}