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