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.normalizer; 019 020import static java.lang.String.format; 021import static org.apache.hadoop.hbase.master.normalizer.SimpleRegionNormalizer.DEFAULT_MERGE_MIN_REGION_AGE_DAYS; 022import static org.apache.hadoop.hbase.master.normalizer.SimpleRegionNormalizer.MERGE_ENABLED_KEY; 023import static org.apache.hadoop.hbase.master.normalizer.SimpleRegionNormalizer.MERGE_MIN_REGION_AGE_DAYS_KEY; 024import static org.apache.hadoop.hbase.master.normalizer.SimpleRegionNormalizer.MERGE_MIN_REGION_SIZE_MB_KEY; 025import static org.apache.hadoop.hbase.master.normalizer.SimpleRegionNormalizer.MIN_REGION_COUNT_KEY; 026import static org.apache.hadoop.hbase.master.normalizer.SimpleRegionNormalizer.SPLIT_ENABLED_KEY; 027import static org.hamcrest.MatcherAssert.assertThat; 028import static org.hamcrest.Matchers.contains; 029import static org.hamcrest.Matchers.empty; 030import static org.hamcrest.Matchers.everyItem; 031import static org.hamcrest.Matchers.greaterThanOrEqualTo; 032import static org.hamcrest.Matchers.instanceOf; 033import static org.hamcrest.Matchers.not; 034import static org.junit.Assert.assertEquals; 035import static org.junit.Assert.assertFalse; 036import static org.junit.Assert.assertTrue; 037import static org.mockito.ArgumentMatchers.any; 038import static org.mockito.Mockito.RETURNS_DEEP_STUBS; 039import static org.mockito.Mockito.when; 040import java.time.Instant; 041import java.time.Period; 042import java.util.ArrayList; 043import java.util.Collections; 044import java.util.HashMap; 045import java.util.List; 046import java.util.Map; 047import org.apache.hadoop.conf.Configuration; 048import org.apache.hadoop.hbase.HBaseClassTestRule; 049import org.apache.hadoop.hbase.HBaseConfiguration; 050import org.apache.hadoop.hbase.RegionMetrics; 051import org.apache.hadoop.hbase.ServerName; 052import org.apache.hadoop.hbase.Size; 053import org.apache.hadoop.hbase.TableName; 054import org.apache.hadoop.hbase.TableNameTestRule; 055import org.apache.hadoop.hbase.client.RegionInfo; 056import org.apache.hadoop.hbase.client.RegionInfoBuilder; 057import org.apache.hadoop.hbase.master.MasterServices; 058import org.apache.hadoop.hbase.master.RegionState; 059import org.apache.hadoop.hbase.testclassification.MasterTests; 060import org.apache.hadoop.hbase.testclassification.SmallTests; 061import org.apache.hadoop.hbase.util.Bytes; 062import org.apache.hadoop.hbase.util.EnvironmentEdgeManager; 063import org.junit.Before; 064import org.junit.ClassRule; 065import org.junit.Rule; 066import org.junit.Test; 067import org.junit.experimental.categories.Category; 068import org.mockito.Mockito; 069 070/** 071 * Tests logic of {@link SimpleRegionNormalizer}. 072 */ 073@Category({MasterTests.class, SmallTests.class}) 074public class TestSimpleRegionNormalizer { 075 076 @ClassRule 077 public static final HBaseClassTestRule CLASS_RULE = 078 HBaseClassTestRule.forClass(TestSimpleRegionNormalizer.class); 079 080 private Configuration conf; 081 private SimpleRegionNormalizer normalizer; 082 private MasterServices masterServices; 083 084 @Rule 085 public TableNameTestRule name = new TableNameTestRule(); 086 087 @Before 088 public void before() { 089 conf = HBaseConfiguration.create(); 090 } 091 092 @Test 093 public void testNoNormalizationForMetaTable() { 094 TableName testTable = TableName.META_TABLE_NAME; 095 List<RegionInfo> RegionInfo = new ArrayList<>(); 096 Map<byte[], Integer> regionSizes = new HashMap<>(); 097 098 setupMocksForNormalizer(regionSizes, RegionInfo); 099 List<NormalizationPlan> plans = normalizer.computePlansForTable(testTable); 100 assertThat(plans, empty()); 101 } 102 103 @Test 104 public void testNoNormalizationIfTooFewRegions() { 105 final TableName tableName = name.getTableName(); 106 final List<RegionInfo> regionInfos = createRegionInfos(tableName, 2); 107 final Map<byte[], Integer> regionSizes = createRegionSizesMap(regionInfos, 10, 15); 108 setupMocksForNormalizer(regionSizes, regionInfos); 109 110 List<NormalizationPlan> plans = normalizer.computePlansForTable(tableName); 111 assertThat(plans, empty()); 112 } 113 114 @Test 115 public void testNoNormalizationOnNormalizedCluster() { 116 final TableName tableName = name.getTableName(); 117 final List<RegionInfo> regionInfos = createRegionInfos(tableName, 4); 118 final Map<byte[], Integer> regionSizes = 119 createRegionSizesMap(regionInfos, 10, 15, 8, 10); 120 setupMocksForNormalizer(regionSizes, regionInfos); 121 122 List<NormalizationPlan> plans = normalizer.computePlansForTable(tableName); 123 assertThat(plans, empty()); 124 } 125 126 private void noNormalizationOnTransitioningRegions(final RegionState.State state) { 127 final TableName tableName = name.getTableName(); 128 final List<RegionInfo> regionInfos = createRegionInfos(tableName, 3); 129 final Map<byte[], Integer> regionSizes = createRegionSizesMap(regionInfos, 10, 1, 100); 130 131 setupMocksForNormalizer(regionSizes, regionInfos); 132 when(masterServices.getAssignmentManager().getRegionStates() 133 .getRegionState(any(RegionInfo.class))) 134 .thenReturn(RegionState.createForTesting(null, state)); 135 assertThat(normalizer.getMinRegionCount(), greaterThanOrEqualTo(regionInfos.size())); 136 137 List<NormalizationPlan> plans = normalizer.computePlansForTable(tableName); 138 assertThat(format("Unexpected plans for RegionState %s", state), plans, empty()); 139 } 140 141 @Test 142 public void testNoNormalizationOnMergingNewRegions() { 143 noNormalizationOnTransitioningRegions(RegionState.State.MERGING_NEW); 144 } 145 146 @Test 147 public void testNoNormalizationOnMergingRegions() { 148 noNormalizationOnTransitioningRegions(RegionState.State.MERGING); 149 } 150 151 @Test 152 public void testNoNormalizationOnMergedRegions() { 153 noNormalizationOnTransitioningRegions(RegionState.State.MERGED); 154 } 155 156 @Test 157 public void testNoNormalizationOnSplittingNewRegions() { 158 noNormalizationOnTransitioningRegions(RegionState.State.SPLITTING_NEW); 159 } 160 161 @Test 162 public void testNoNormalizationOnSplittingRegions() { 163 noNormalizationOnTransitioningRegions(RegionState.State.SPLITTING); 164 } 165 166 @Test 167 public void testNoNormalizationOnSplitRegions() { 168 noNormalizationOnTransitioningRegions(RegionState.State.SPLIT); 169 } 170 171 @Test 172 public void testMergeOfSmallRegions() { 173 final TableName tableName = name.getTableName(); 174 final List<RegionInfo> regionInfos = createRegionInfos(tableName, 5); 175 final Map<byte[], Integer> regionSizes = 176 createRegionSizesMap(regionInfos, 15, 5, 5, 15, 16); 177 setupMocksForNormalizer(regionSizes, regionInfos); 178 179 assertThat( 180 normalizer.computePlansForTable(tableName), 181 contains(new MergeNormalizationPlan.Builder() 182 .addTarget(regionInfos.get(1), 5) 183 .addTarget(regionInfos.get(2), 5) 184 .build())); 185 } 186 187 // Test for situation illustrated in HBASE-14867 188 @Test 189 public void testMergeOfSecondSmallestRegions() { 190 final TableName tableName = name.getTableName(); 191 final List<RegionInfo> regionInfos = createRegionInfos(tableName, 6); 192 final Map<byte[], Integer> regionSizes = 193 createRegionSizesMap(regionInfos, 1, 10000, 10000, 10000, 2700, 2700); 194 setupMocksForNormalizer(regionSizes, regionInfos); 195 196 assertThat( 197 normalizer.computePlansForTable(tableName), 198 contains(new MergeNormalizationPlan.Builder() 199 .addTarget(regionInfos.get(4), 2700) 200 .addTarget(regionInfos.get(5), 2700) 201 .build())); 202 } 203 204 @Test 205 public void testMergeOfSmallNonAdjacentRegions() { 206 final TableName tableName = name.getTableName(); 207 final List<RegionInfo> regionInfos = createRegionInfos(tableName, 5); 208 final Map<byte[], Integer> regionSizes = 209 createRegionSizesMap(regionInfos, 15, 5, 16, 15, 5); 210 setupMocksForNormalizer(regionSizes, regionInfos); 211 212 List<NormalizationPlan> plans = normalizer.computePlansForTable(tableName); 213 assertThat(plans, empty()); 214 } 215 216 @Test 217 public void testSplitOfLargeRegion() { 218 final TableName tableName = name.getTableName(); 219 final List<RegionInfo> regionInfos = createRegionInfos(tableName, 4); 220 final Map<byte[], Integer> regionSizes = 221 createRegionSizesMap(regionInfos, 8, 6, 10, 30); 222 setupMocksForNormalizer(regionSizes, regionInfos); 223 224 assertThat(normalizer.computePlansForTable(tableName), contains( 225 new SplitNormalizationPlan(regionInfos.get(3), 30))); 226 } 227 228 @Test 229 public void testWithTargetRegionSize() throws Exception { 230 final TableName tableName = name.getTableName(); 231 final List<RegionInfo> regionInfos = createRegionInfos(tableName, 6); 232 final Map<byte[], Integer> regionSizes = 233 createRegionSizesMap(regionInfos, 20, 40, 60, 80, 100, 120); 234 setupMocksForNormalizer(regionSizes, regionInfos); 235 236 // test when target region size is 20 237 when(masterServices.getTableDescriptors().get(any()).getNormalizerTargetRegionSize()) 238 .thenReturn(20L); 239 assertThat(normalizer.computePlansForTable(tableName), contains( 240 new SplitNormalizationPlan(regionInfos.get(2), 60), 241 new SplitNormalizationPlan(regionInfos.get(3), 80), 242 new SplitNormalizationPlan(regionInfos.get(4), 100), 243 new SplitNormalizationPlan(regionInfos.get(5), 120) 244 )); 245 246 // test when target region size is 200 247 when(masterServices.getTableDescriptors().get(any()).getNormalizerTargetRegionSize()) 248 .thenReturn(200L); 249 assertThat( 250 normalizer.computePlansForTable(tableName), 251 contains( 252 new MergeNormalizationPlan.Builder() 253 .addTarget(regionInfos.get(0), 20) 254 .addTarget(regionInfos.get(1), 40) 255 .addTarget(regionInfos.get(2), 60) 256 .addTarget(regionInfos.get(3), 80) 257 .build())); 258 } 259 260 @Test 261 public void testSplitWithTargetRegionCount() throws Exception { 262 final TableName tableName = name.getTableName(); 263 final List<RegionInfo> regionInfos = createRegionInfos(tableName, 4); 264 final Map<byte[], Integer> regionSizes = 265 createRegionSizesMap(regionInfos, 20, 40, 60, 80); 266 setupMocksForNormalizer(regionSizes, regionInfos); 267 268 // test when target region count is 8 269 when(masterServices.getTableDescriptors().get(any()).getNormalizerTargetRegionCount()) 270 .thenReturn(8); 271 assertThat(normalizer.computePlansForTable(tableName), contains( 272 new SplitNormalizationPlan(regionInfos.get(2), 60), 273 new SplitNormalizationPlan(regionInfos.get(3), 80))); 274 275 // test when target region count is 3 276 when(masterServices.getTableDescriptors().get(any()).getNormalizerTargetRegionCount()) 277 .thenReturn(3); 278 assertThat( 279 normalizer.computePlansForTable(tableName), 280 contains(new MergeNormalizationPlan.Builder() 281 .addTarget(regionInfos.get(0), 20) 282 .addTarget(regionInfos.get(1), 40) 283 .build())); 284 } 285 286 @Test 287 public void testHonorsSplitEnabled() { 288 conf.setBoolean(SPLIT_ENABLED_KEY, true); 289 final TableName tableName = name.getTableName(); 290 final List<RegionInfo> regionInfos = createRegionInfos(tableName, 5); 291 final Map<byte[], Integer> regionSizes = 292 createRegionSizesMap(regionInfos, 5, 5, 20, 5, 5); 293 setupMocksForNormalizer(regionSizes, regionInfos); 294 assertThat( 295 normalizer.computePlansForTable(tableName), 296 contains(instanceOf(SplitNormalizationPlan.class))); 297 298 conf.setBoolean(SPLIT_ENABLED_KEY, false); 299 setupMocksForNormalizer(regionSizes, regionInfos); 300 assertThat(normalizer.computePlansForTable(tableName), empty()); 301 } 302 303 @Test 304 public void testHonorsMergeEnabled() { 305 conf.setBoolean(MERGE_ENABLED_KEY, true); 306 final TableName tableName = name.getTableName(); 307 final List<RegionInfo> regionInfos = createRegionInfos(tableName, 5); 308 final Map<byte[], Integer> regionSizes = 309 createRegionSizesMap(regionInfos, 20, 5, 5, 20, 20); 310 setupMocksForNormalizer(regionSizes, regionInfos); 311 assertThat( 312 normalizer.computePlansForTable(tableName), 313 contains(instanceOf(MergeNormalizationPlan.class))); 314 315 conf.setBoolean(MERGE_ENABLED_KEY, false); 316 setupMocksForNormalizer(regionSizes, regionInfos); 317 assertThat(normalizer.computePlansForTable(tableName), empty()); 318 } 319 320 @Test 321 public void testHonorsMinimumRegionCount() { 322 conf.setInt(MIN_REGION_COUNT_KEY, 1); 323 final TableName tableName = name.getTableName(); 324 final List<RegionInfo> regionInfos = createRegionInfos(tableName, 3); 325 // create a table topology that results in both a merge plan and a split plan. Assert that the 326 // merge is only created when the when the number of table regions is above the region count 327 // threshold, and that the split plan is create in both cases. 328 final Map<byte[], Integer> regionSizes = createRegionSizesMap(regionInfos, 1, 1, 10); 329 setupMocksForNormalizer(regionSizes, regionInfos); 330 331 List<NormalizationPlan> plans = normalizer.computePlansForTable(tableName); 332 assertThat(plans, contains( 333 new SplitNormalizationPlan(regionInfos.get(2), 10), 334 new MergeNormalizationPlan.Builder() 335 .addTarget(regionInfos.get(0), 1) 336 .addTarget(regionInfos.get(1), 1) 337 .build())); 338 339 // have to call setupMocks again because we don't have dynamic config update on normalizer. 340 conf.setInt(MIN_REGION_COUNT_KEY, 4); 341 setupMocksForNormalizer(regionSizes, regionInfos); 342 assertThat(normalizer.computePlansForTable(tableName), contains( 343 new SplitNormalizationPlan(regionInfos.get(2), 10))); 344 } 345 346 @Test 347 public void testHonorsMergeMinRegionAge() { 348 conf.setInt(MERGE_MIN_REGION_AGE_DAYS_KEY, 7); 349 final TableName tableName = name.getTableName(); 350 final List<RegionInfo> regionInfos = createRegionInfos(tableName, 4); 351 final Map<byte[], Integer> regionSizes = 352 createRegionSizesMap(regionInfos, 1, 1, 10, 10); 353 setupMocksForNormalizer(regionSizes, regionInfos); 354 assertEquals(Period.ofDays(7), normalizer.getMergeMinRegionAge()); 355 assertThat( 356 normalizer.computePlansForTable(tableName), 357 everyItem(not(instanceOf(MergeNormalizationPlan.class)))); 358 359 // have to call setupMocks again because we don't have dynamic config update on normalizer. 360 conf.unset(MERGE_MIN_REGION_AGE_DAYS_KEY); 361 setupMocksForNormalizer(regionSizes, regionInfos); 362 assertEquals( 363 Period.ofDays(DEFAULT_MERGE_MIN_REGION_AGE_DAYS), normalizer.getMergeMinRegionAge()); 364 final List<NormalizationPlan> plans = normalizer.computePlansForTable(tableName); 365 assertThat(plans, not(empty())); 366 assertThat(plans, everyItem(instanceOf(MergeNormalizationPlan.class))); 367 } 368 369 @Test 370 public void testHonorsMergeMinRegionSize() { 371 conf.setBoolean(SPLIT_ENABLED_KEY, false); 372 final TableName tableName = name.getTableName(); 373 final List<RegionInfo> regionInfos = createRegionInfos(tableName, 5); 374 final Map<byte[], Integer> regionSizes = 375 createRegionSizesMap(regionInfos, 1, 2, 0, 10, 10); 376 setupMocksForNormalizer(regionSizes, regionInfos); 377 378 assertFalse(normalizer.isSplitEnabled()); 379 assertEquals(1, normalizer.getMergeMinRegionSizeMb()); 380 assertThat( 381 normalizer.computePlansForTable(tableName), 382 contains(new MergeNormalizationPlan.Builder() 383 .addTarget(regionInfos.get(0), 1) 384 .addTarget(regionInfos.get(1), 2) 385 .build())); 386 387 conf.setInt(MERGE_MIN_REGION_SIZE_MB_KEY, 3); 388 setupMocksForNormalizer(regionSizes, regionInfos); 389 assertEquals(3, normalizer.getMergeMinRegionSizeMb()); 390 assertThat(normalizer.computePlansForTable(tableName), empty()); 391 } 392 393 @Test 394 public void testMergeEmptyRegions0() { 395 conf.setBoolean(SPLIT_ENABLED_KEY, false); 396 conf.setInt(MERGE_MIN_REGION_SIZE_MB_KEY, 0); 397 final TableName tableName = name.getTableName(); 398 final List<RegionInfo> regionInfos = createRegionInfos(tableName, 7); 399 final Map<byte[], Integer> regionSizes = 400 createRegionSizesMap(regionInfos, 0, 1, 10, 0, 9, 10, 0); 401 setupMocksForNormalizer(regionSizes, regionInfos); 402 403 assertFalse(normalizer.isSplitEnabled()); 404 assertEquals(0, normalizer.getMergeMinRegionSizeMb()); 405 assertThat(normalizer.computePlansForTable(tableName), contains( 406 new MergeNormalizationPlan.Builder() 407 .addTarget(regionInfos.get(0), 0) 408 .addTarget(regionInfos.get(1), 1) 409 .build(), 410 new MergeNormalizationPlan.Builder() 411 .addTarget(regionInfos.get(2), 10) 412 .addTarget(regionInfos.get(3), 0) 413 .build(), 414 new MergeNormalizationPlan.Builder() 415 .addTarget(regionInfos.get(5), 10) 416 .addTarget(regionInfos.get(6), 0) 417 .build())); 418 } 419 420 @Test 421 public void testMergeEmptyRegions1() { 422 conf.setBoolean(SPLIT_ENABLED_KEY, false); 423 conf.setInt(MERGE_MIN_REGION_SIZE_MB_KEY, 0); 424 final TableName tableName = name.getTableName(); 425 final List<RegionInfo> regionInfos = createRegionInfos(tableName, 8); 426 final Map<byte[], Integer> regionSizes = 427 createRegionSizesMap(regionInfos, 0, 1, 10, 0, 9, 0, 10, 0); 428 setupMocksForNormalizer(regionSizes, regionInfos); 429 430 assertFalse(normalizer.isSplitEnabled()); 431 assertEquals(0, normalizer.getMergeMinRegionSizeMb()); 432 assertThat(normalizer.computePlansForTable(tableName), contains( 433 new MergeNormalizationPlan.Builder() 434 .addTarget(regionInfos.get(0), 0) 435 .addTarget(regionInfos.get(1), 1) 436 .build(), 437 new MergeNormalizationPlan.Builder() 438 .addTarget(regionInfos.get(2), 10) 439 .addTarget(regionInfos.get(3), 0) 440 .build(), 441 new MergeNormalizationPlan.Builder() 442 .addTarget(regionInfos.get(4), 9) 443 .addTarget(regionInfos.get(5), 0) 444 .build(), 445 new MergeNormalizationPlan.Builder() 446 .addTarget(regionInfos.get(6), 10) 447 .addTarget(regionInfos.get(7), 0) 448 .build())); 449 } 450 451 @Test 452 public void testSplitAndMultiMerge() { 453 conf.setInt(MERGE_MIN_REGION_SIZE_MB_KEY, 0); 454 final TableName tableName = name.getTableName(); 455 final List<RegionInfo> regionInfos = createRegionInfos(tableName, 8); 456 final Map<byte[], Integer> regionSizes = 457 createRegionSizesMap(regionInfos, 3, 1, 1, 30, 9, 3, 1, 0); 458 setupMocksForNormalizer(regionSizes, regionInfos); 459 460 assertTrue(normalizer.isMergeEnabled()); 461 assertTrue(normalizer.isSplitEnabled()); 462 assertEquals(0, normalizer.getMergeMinRegionSizeMb()); 463 assertThat(normalizer.computePlansForTable(tableName), contains( 464 new SplitNormalizationPlan(regionInfos.get(3), 30), 465 new MergeNormalizationPlan.Builder() 466 .addTarget(regionInfos.get(0), 3) 467 .addTarget(regionInfos.get(1), 1) 468 .addTarget(regionInfos.get(2), 1) 469 .build(), 470 new MergeNormalizationPlan.Builder() 471 .addTarget(regionInfos.get(5), 3) 472 .addTarget(regionInfos.get(6), 1) 473 .addTarget(regionInfos.get(7), 0) 474 .build())); 475 } 476 477 // This test is to make sure that normalizer is only going to merge adjacent regions. 478 @Test 479 public void testNormalizerCannotMergeNonAdjacentRegions() { 480 final TableName tableName = name.getTableName(); 481 // create 5 regions with sizes to trigger merge of small regions. region ranges are: 482 // [, "aa"), ["aa", "aa1"), ["aa1", "aa1!"), ["aa1!", "aa2"), ["aa2", ) 483 // Region ["aa", "aa1") and ["aa1!", "aa2") are not adjacent, they are not supposed to 484 // merged. 485 final byte[][] keys = { 486 null, 487 Bytes.toBytes("aa"), 488 Bytes.toBytes("aa1!"), 489 Bytes.toBytes("aa1"), 490 Bytes.toBytes("aa2"), 491 null, 492 }; 493 final List<RegionInfo> regionInfos = createRegionInfos(tableName, keys); 494 final Map<byte[], Integer> regionSizes = 495 createRegionSizesMap(regionInfos, 3, 1, 1, 3, 5); 496 setupMocksForNormalizer(regionSizes, regionInfos); 497 498 // Compute the plan, no merge plan returned as they are not adjacent. 499 List<NormalizationPlan> plans = normalizer.computePlansForTable(tableName); 500 assertThat(plans, empty()); 501 } 502 503 @SuppressWarnings("MockitoCast") 504 private void setupMocksForNormalizer(Map<byte[], Integer> regionSizes, 505 List<RegionInfo> regionInfoList) { 506 masterServices = Mockito.mock(MasterServices.class, RETURNS_DEEP_STUBS); 507 508 // for simplicity all regions are assumed to be on one server; doesn't matter to us 509 ServerName sn = ServerName.valueOf("localhost", 0, 0L); 510 when(masterServices.getAssignmentManager().getRegionStates() 511 .getRegionsOfTable(any())).thenReturn(regionInfoList); 512 when(masterServices.getAssignmentManager().getRegionStates() 513 .getRegionServerOfRegion(any())).thenReturn(sn); 514 when(masterServices.getAssignmentManager().getRegionStates() 515 .getRegionState(any(RegionInfo.class))).thenReturn( 516 RegionState.createForTesting(null, RegionState.State.OPEN)); 517 518 for (Map.Entry<byte[], Integer> region : regionSizes.entrySet()) { 519 RegionMetrics regionLoad = Mockito.mock(RegionMetrics.class); 520 when(regionLoad.getRegionName()).thenReturn(region.getKey()); 521 when(regionLoad.getStoreFileSize()) 522 .thenReturn(new Size(region.getValue(), Size.Unit.MEGABYTE)); 523 524 // this is possibly broken with jdk9, unclear if false positive or not 525 // suppress it for now, fix it when we get to running tests on 9 526 // see: http://errorprone.info/bugpattern/MockitoCast 527 when((Object) masterServices.getServerManager().getLoad(sn) 528 .getRegionMetrics().get(region.getKey())).thenReturn(regionLoad); 529 } 530 531 when(masterServices.isSplitOrMergeEnabled(any())).thenReturn(true); 532 533 normalizer = new SimpleRegionNormalizer(); 534 normalizer.setConf(conf); 535 normalizer.setMasterServices(masterServices); 536 } 537 538 /** 539 * Create a list of {@link RegionInfo}s that represent a region chain of the specified length. 540 */ 541 private static List<RegionInfo> createRegionInfos(final TableName tableName, final int length) { 542 if (length < 1) { 543 throw new IllegalStateException("length must be greater than or equal to 1."); 544 } 545 546 final byte[] startKey = Bytes.toBytes("aaaaa"); 547 final byte[] endKey = Bytes.toBytes("zzzzz"); 548 if (length == 1) { 549 return Collections.singletonList(createRegionInfo(tableName, startKey, endKey)); 550 } 551 552 final byte[][] splitKeys = Bytes.split(startKey, endKey, length - 1); 553 final List<RegionInfo> ret = new ArrayList<>(length); 554 for (int i = 0; i < splitKeys.length - 1; i++) { 555 ret.add(createRegionInfo(tableName, splitKeys[i], splitKeys[i+1])); 556 } 557 return ret; 558 } 559 560 private static RegionInfo createRegionInfo(final TableName tableName, final byte[] startKey, 561 final byte[] endKey) { 562 return RegionInfoBuilder.newBuilder(tableName) 563 .setStartKey(startKey) 564 .setEndKey(endKey) 565 .setRegionId(generateRegionId()) 566 .build(); 567 } 568 569 private static long generateRegionId() { 570 return Instant.ofEpochMilli(EnvironmentEdgeManager.currentTime()) 571 .minus(Period.ofDays(DEFAULT_MERGE_MIN_REGION_AGE_DAYS + 1)) 572 .toEpochMilli(); 573 } 574 575 private static List<RegionInfo> createRegionInfos(final TableName tableName, 576 final byte[][] splitKeys) { 577 final List<RegionInfo> ret = new ArrayList<>(splitKeys.length); 578 for (int i = 0; i < splitKeys.length - 1; i++) { 579 ret.add(createRegionInfo(tableName, splitKeys[i], splitKeys[i+1])); 580 } 581 return ret; 582 } 583 584 private static Map<byte[], Integer> createRegionSizesMap(final List<RegionInfo> regionInfos, 585 int... sizes) { 586 if (regionInfos.size() != sizes.length) { 587 throw new IllegalStateException("Parameter lengths must match."); 588 } 589 590 final Map<byte[], Integer> ret = new HashMap<>(regionInfos.size()); 591 for (int i = 0; i < regionInfos.size(); i++) { 592 ret.put(regionInfos.get(i).getRegionName(), sizes[i]); 593 } 594 return ret; 595 } 596}