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