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.mapreduce; 019 020import static org.apache.hadoop.hbase.HConstants.DEFAULT_REGIONSERVER_PORT; 021import static org.junit.jupiter.api.Assertions.assertEquals; 022import static org.mockito.Mockito.when; 023 024import java.io.IOException; 025import java.util.ArrayList; 026import java.util.Arrays; 027import java.util.Collections; 028import java.util.List; 029import org.apache.hadoop.conf.Configuration; 030import org.apache.hadoop.hbase.HRegionLocation; 031import org.apache.hadoop.hbase.RegionMetrics; 032import org.apache.hadoop.hbase.ServerName; 033import org.apache.hadoop.hbase.Size; 034import org.apache.hadoop.hbase.TableName; 035import org.apache.hadoop.hbase.client.Admin; 036import org.apache.hadoop.hbase.client.RegionInfo; 037import org.apache.hadoop.hbase.client.RegionLocator; 038import org.apache.hadoop.hbase.testclassification.MiscTests; 039import org.apache.hadoop.hbase.testclassification.SmallTests; 040import org.apache.hadoop.hbase.util.Bytes; 041import org.junit.jupiter.api.Tag; 042import org.junit.jupiter.api.Test; 043import org.mockito.Mockito; 044 045@Tag(MiscTests.TAG) 046@Tag(SmallTests.TAG) 047public class TestRegionSizeCalculator { 048 049 private Configuration configuration = new Configuration(); 050 private final long megabyte = 1024L * 1024L; 051 private final ServerName sn = 052 ServerName.valueOf("local-rs", DEFAULT_REGIONSERVER_PORT, ServerName.NON_STARTCODE); 053 054 @Test 055 public void testSimpleTestCase() throws Exception { 056 057 RegionLocator regionLocator = mockRegionLocator("region1", "region2", "region3"); 058 059 Admin admin = mockAdmin(mockRegion("region1", 123, 321), mockRegion("region3", 1232, 2321), 060 mockRegion("region2", 54321, 12345), mockRegion("region4", 6789, 0), 061 mockRegion("region5", 0, 4567)); 062 063 RegionSizeCalculator calculator = new RegionSizeCalculator(regionLocator, admin); 064 065 assertEquals((123 + 321) * megabyte, calculator.getRegionSize(Bytes.toBytes("region1"))); 066 assertEquals((54321 + 12345) * megabyte, calculator.getRegionSize(Bytes.toBytes("region2"))); 067 assertEquals((1232 + 2321) * megabyte, calculator.getRegionSize(Bytes.toBytes("region3"))); 068 assertEquals(6789 * megabyte, calculator.getRegionSize(Bytes.toBytes("region4"))); 069 assertEquals(4567 * megabyte, calculator.getRegionSize(Bytes.toBytes("region5"))); 070 071 // if regionCalculator does not know about a region, it should return 0 072 assertEquals(0, calculator.getRegionSize(Bytes.toBytes("otherTableRegion"))); 073 074 assertEquals(5, calculator.getRegionSizeMap().size()); 075 } 076 077 /** 078 * When size of region in megabytes is larger than largest possible integer there could be error 079 * caused by lost of precision. 080 */ 081 @Test 082 public void testLargeRegion() throws Exception { 083 084 RegionLocator regionLocator = mockRegionLocator("largeRegion"); 085 086 Admin admin = mockAdmin(mockRegion("largeRegion", Integer.MAX_VALUE, Integer.MAX_VALUE)); 087 088 RegionSizeCalculator calculator = new RegionSizeCalculator(regionLocator, admin); 089 090 assertEquals(((long) Integer.MAX_VALUE) * 2L * megabyte, 091 calculator.getRegionSize(Bytes.toBytes("largeRegion"))); 092 } 093 094 /** When calculator is disabled, it should return 0 for each request. */ 095 @Test 096 public void testDisabled() throws Exception { 097 String regionName = "cz.goout:/index.html"; 098 RegionLocator table = mockRegionLocator(regionName); 099 100 Admin admin = mockAdmin(mockRegion(regionName, 999, 888)); 101 102 // first request on enabled calculator 103 RegionSizeCalculator calculator = new RegionSizeCalculator(table, admin); 104 assertEquals((999 + 888) * megabyte, calculator.getRegionSize(Bytes.toBytes(regionName))); 105 106 // then disabled calculator. 107 configuration.setBoolean(RegionSizeCalculator.ENABLE_REGIONSIZECALCULATOR, false); 108 RegionSizeCalculator disabledCalculator = new RegionSizeCalculator(table, admin); 109 assertEquals(0, disabledCalculator.getRegionSize(Bytes.toBytes(regionName))); 110 assertEquals(0, disabledCalculator.getRegionSizeMap().size()); 111 } 112 113 @Test 114 public void testRegionWithNullServerName() throws Exception { 115 RegionLocator regionLocator = 116 mockRegionLocator(null, Collections.singletonList("someBigRegion")); 117 Admin admin = mockAdmin(mockRegion("someBigRegion", Integer.MAX_VALUE, Integer.MAX_VALUE)); 118 RegionSizeCalculator calculator = new RegionSizeCalculator(regionLocator, admin); 119 assertEquals(0, calculator.getRegionSize(Bytes.toBytes("someBigRegion"))); 120 } 121 122 /** 123 * Makes some table with given region names. 124 */ 125 private RegionLocator mockRegionLocator(String... regionNames) throws IOException { 126 return mockRegionLocator(sn, Arrays.asList(regionNames)); 127 } 128 129 private RegionLocator mockRegionLocator(ServerName serverName, List<String> regionNames) 130 throws IOException { 131 RegionLocator mockedTable = Mockito.mock(RegionLocator.class); 132 when(mockedTable.getName()).thenReturn(TableName.valueOf("sizeTestTable")); 133 List<HRegionLocation> regionLocations = new ArrayList<>(regionNames.size()); 134 when(mockedTable.getAllRegionLocations()).thenReturn(regionLocations); 135 136 for (String regionName : regionNames) { 137 RegionInfo info = Mockito.mock(RegionInfo.class); 138 when(info.getRegionName()).thenReturn(Bytes.toBytes(regionName)); 139 regionLocations.add(new HRegionLocation(info, serverName)); 140 } 141 142 return mockedTable; 143 } 144 145 /** 146 * Creates mock returning RegionLoad info about given servers. 147 */ 148 private Admin mockAdmin(RegionMetrics... regionLoadArray) throws Exception { 149 Admin mockAdmin = Mockito.mock(Admin.class); 150 List<RegionMetrics> regionLoads = new ArrayList<>(Arrays.asList(regionLoadArray)); 151 when(mockAdmin.getConfiguration()).thenReturn(configuration); 152 when(mockAdmin.getRegionMetrics(sn, TableName.valueOf("sizeTestTable"))) 153 .thenReturn(regionLoads); 154 return mockAdmin; 155 } 156 157 /** 158 * Creates mock of region with given name and size. 159 * @param fileSizeMb number of megabytes occupied by region in file store in megabytes 160 * @param memStoreSize number of megabytes occupied by region in memstore in megabytes 161 */ 162 private RegionMetrics mockRegion(String regionName, int fileSizeMb, int memStoreSize) { 163 RegionMetrics region = Mockito.mock(RegionMetrics.class); 164 when(region.getRegionName()).thenReturn(Bytes.toBytes(regionName)); 165 when(region.getNameAsString()).thenReturn(regionName); 166 when(region.getStoreFileSize()).thenReturn(new Size(fileSizeMb, Size.Unit.MEGABYTE)); 167 when(region.getMemStoreSize()).thenReturn(new Size(memStoreSize, Size.Unit.MEGABYTE)); 168 return region; 169 } 170}