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; 019 020import edu.umd.cs.findbugs.annotations.Nullable; 021import java.io.UnsupportedEncodingException; 022import java.nio.charset.StandardCharsets; 023import java.util.HashMap; 024import java.util.List; 025import java.util.Map; 026import java.util.Set; 027import org.apache.hadoop.conf.Configuration; 028import org.apache.hadoop.hbase.ClusterMetrics; 029import org.apache.hadoop.hbase.HBaseClassTestRule; 030import org.apache.hadoop.hbase.HBaseTestingUtil; 031import org.apache.hadoop.hbase.RegionMetrics; 032import org.apache.hadoop.hbase.ServerMetrics; 033import org.apache.hadoop.hbase.ServerName; 034import org.apache.hadoop.hbase.ServerTask; 035import org.apache.hadoop.hbase.Size; 036import org.apache.hadoop.hbase.Stoppable; 037import org.apache.hadoop.hbase.TableName; 038import org.apache.hadoop.hbase.UserMetrics; 039import org.apache.hadoop.hbase.client.CompactionState; 040import org.apache.hadoop.hbase.client.RegionInfo; 041import org.apache.hadoop.hbase.client.RegionStatesCount; 042import org.apache.hadoop.hbase.master.assignment.AssignmentManager; 043import org.apache.hadoop.hbase.replication.ReplicationLoadSink; 044import org.apache.hadoop.hbase.replication.ReplicationLoadSource; 045import org.apache.hadoop.hbase.testclassification.MasterTests; 046import org.apache.hadoop.hbase.testclassification.SmallTests; 047import org.apache.hadoop.hbase.util.Bytes; 048import org.junit.After; 049import org.junit.Before; 050import org.junit.ClassRule; 051import org.junit.Test; 052import org.junit.experimental.categories.Category; 053import org.mockito.Mockito; 054import org.slf4j.Logger; 055import org.slf4j.LoggerFactory; 056 057/** 058 * Test for RegionsRecoveryChore 059 */ 060@Category({ MasterTests.class, SmallTests.class }) 061public class TestRegionsRecoveryChore { 062 063 @ClassRule 064 public static final HBaseClassTestRule CLASS_RULE = 065 HBaseClassTestRule.forClass(TestRegionsRecoveryChore.class); 066 067 private static final Logger LOG = LoggerFactory.getLogger(TestRegionsRecoveryChore.class); 068 069 private static final HBaseTestingUtil HBASE_TESTING_UTILITY = new HBaseTestingUtil(); 070 071 private static final String UTF_8_CHARSET = StandardCharsets.UTF_8.name(); 072 073 private HMaster hMaster; 074 075 private AssignmentManager assignmentManager; 076 077 private RegionsRecoveryChore regionsRecoveryChore; 078 079 private static int regionNo; 080 public static final byte[][] REGION_NAME_LIST = 081 new byte[][] { new byte[] { 114, 101, 103, 105, 111, 110, 50, 49, 95, 51 }, 082 new byte[] { 114, 101, 103, 105, 111, 110, 50, 53, 95, 51 }, 083 new byte[] { 114, 101, 103, 105, 111, 110, 50, 54, 95, 52 }, 084 new byte[] { 114, 101, 103, 105, 111, 110, 51, 50, 95, 53 }, 085 new byte[] { 114, 101, 103, 105, 111, 110, 51, 49, 95, 52 }, 086 new byte[] { 114, 101, 103, 105, 111, 110, 51, 48, 95, 51 }, 087 new byte[] { 114, 101, 103, 105, 111, 110, 50, 48, 95, 50 }, 088 new byte[] { 114, 101, 103, 105, 111, 110, 50, 52, 95, 50 }, 089 new byte[] { 114, 101, 103, 105, 111, 110, 50, 57, 95, 50 }, 090 new byte[] { 114, 101, 103, 105, 111, 110, 51, 53, 95, 50 }, 091 new byte[] { 114, 101, 103, 105, 111, 110, 49, 48, 56, 95, 49, 49 } }; 092 093 private Configuration getCustomConf() { 094 Configuration conf = HBASE_TESTING_UTILITY.getConfiguration(); 095 conf.setInt("hbase.master.regions.recovery.check.interval", 100); 096 return conf; 097 } 098 099 @Before 100 public void setUp() throws Exception { 101 this.hMaster = Mockito.mock(HMaster.class); 102 this.assignmentManager = Mockito.mock(AssignmentManager.class); 103 } 104 105 @After 106 public void tearDown() throws Exception { 107 Mockito.verifyNoMoreInteractions(this.hMaster); 108 Mockito.verifyNoMoreInteractions(this.assignmentManager); 109 } 110 111 @Test 112 public void testRegionReopensWithStoreRefConfig() throws Exception { 113 regionNo = 0; 114 ClusterMetrics clusterMetrics = TestRegionsRecoveryChore.getClusterMetrics(4); 115 final Map<ServerName, ServerMetrics> serverMetricsMap = clusterMetrics.getLiveServerMetrics(); 116 LOG.debug("All Region Names with refCount...."); 117 for (ServerMetrics serverMetrics : serverMetricsMap.values()) { 118 Map<byte[], RegionMetrics> regionMetricsMap = serverMetrics.getRegionMetrics(); 119 for (RegionMetrics regionMetrics : regionMetricsMap.values()) { 120 LOG.debug("name: " + new String(regionMetrics.getRegionName()) + " refCount: " 121 + regionMetrics.getStoreRefCount()); 122 } 123 } 124 Mockito.when(hMaster.getClusterMetrics()).thenReturn(clusterMetrics); 125 Mockito.when(hMaster.getAssignmentManager()).thenReturn(assignmentManager); 126 for (byte[] regionName : REGION_NAME_LIST) { 127 Mockito.when(assignmentManager.getRegionInfo(regionName)) 128 .thenReturn(TestRegionsRecoveryChore.getRegionInfo(regionName)); 129 } 130 Stoppable stoppable = new StoppableImplementation(); 131 Configuration configuration = getCustomConf(); 132 configuration.setInt("hbase.regions.recovery.store.file.ref.count", 300); 133 regionsRecoveryChore = new RegionsRecoveryChore(stoppable, configuration, hMaster); 134 regionsRecoveryChore.chore(); 135 136 // Verify that we need to reopen regions of 2 tables 137 Mockito.verify(hMaster, Mockito.times(2)).reopenRegions(Mockito.any(), Mockito.anyList(), 138 Mockito.anyLong(), Mockito.anyLong()); 139 Mockito.verify(hMaster, Mockito.times(1)).getClusterMetrics(); 140 141 // Verify that we need to reopen total 3 regions that have refCount > 300 142 Mockito.verify(hMaster, Mockito.times(3)).getAssignmentManager(); 143 Mockito.verify(assignmentManager, Mockito.times(3)).getRegionInfo(Mockito.any(byte[].class)); 144 } 145 146 @Test 147 public void testRegionReopensWithLessThreshold() throws Exception { 148 regionNo = 0; 149 ClusterMetrics clusterMetrics = TestRegionsRecoveryChore.getClusterMetrics(4); 150 final Map<ServerName, ServerMetrics> serverMetricsMap = clusterMetrics.getLiveServerMetrics(); 151 LOG.debug("All Region Names with refCount...."); 152 for (ServerMetrics serverMetrics : serverMetricsMap.values()) { 153 Map<byte[], RegionMetrics> regionMetricsMap = serverMetrics.getRegionMetrics(); 154 for (RegionMetrics regionMetrics : regionMetricsMap.values()) { 155 LOG.debug("name: " + new String(regionMetrics.getRegionName()) + " refCount: " 156 + regionMetrics.getStoreRefCount()); 157 } 158 } 159 Mockito.when(hMaster.getClusterMetrics()).thenReturn(clusterMetrics); 160 Mockito.when(hMaster.getAssignmentManager()).thenReturn(assignmentManager); 161 for (byte[] regionName : REGION_NAME_LIST) { 162 Mockito.when(assignmentManager.getRegionInfo(regionName)) 163 .thenReturn(TestRegionsRecoveryChore.getRegionInfo(regionName)); 164 } 165 Stoppable stoppable = new StoppableImplementation(); 166 Configuration configuration = getCustomConf(); 167 configuration.setInt("hbase.regions.recovery.store.file.ref.count", 400); 168 regionsRecoveryChore = new RegionsRecoveryChore(stoppable, configuration, hMaster); 169 regionsRecoveryChore.chore(); 170 171 // Verify that we need to reopen regions of only 1 table 172 Mockito.verify(hMaster, Mockito.times(1)).reopenRegions(Mockito.any(), Mockito.anyList(), 173 Mockito.anyLong(), Mockito.anyLong()); 174 Mockito.verify(hMaster, Mockito.times(1)).getClusterMetrics(); 175 176 // Verify that we need to reopen only 1 region with refCount > 400 177 Mockito.verify(hMaster, Mockito.times(1)).getAssignmentManager(); 178 Mockito.verify(assignmentManager, Mockito.times(1)).getRegionInfo(Mockito.any(byte[].class)); 179 } 180 181 @Test 182 public void testRegionReopensWithoutStoreRefConfig() throws Exception { 183 regionNo = 0; 184 ClusterMetrics clusterMetrics = TestRegionsRecoveryChore.getClusterMetrics(10); 185 final Map<ServerName, ServerMetrics> serverMetricsMap = clusterMetrics.getLiveServerMetrics(); 186 LOG.debug("All Region Names with refCount...."); 187 for (ServerMetrics serverMetrics : serverMetricsMap.values()) { 188 Map<byte[], RegionMetrics> regionMetricsMap = serverMetrics.getRegionMetrics(); 189 for (RegionMetrics regionMetrics : regionMetricsMap.values()) { 190 LOG.debug("name: " + new String(regionMetrics.getRegionName()) + " refCount: " 191 + regionMetrics.getStoreRefCount()); 192 } 193 } 194 Mockito.when(hMaster.getClusterMetrics()).thenReturn(clusterMetrics); 195 Mockito.when(hMaster.getAssignmentManager()).thenReturn(assignmentManager); 196 for (byte[] regionName : REGION_NAME_LIST) { 197 Mockito.when(assignmentManager.getRegionInfo(regionName)) 198 .thenReturn(TestRegionsRecoveryChore.getRegionInfo(regionName)); 199 } 200 Stoppable stoppable = new StoppableImplementation(); 201 Configuration configuration = getCustomConf(); 202 configuration.unset("hbase.regions.recovery.store.file.ref.count"); 203 regionsRecoveryChore = new RegionsRecoveryChore(stoppable, configuration, hMaster); 204 regionsRecoveryChore.chore(); 205 206 // Verify that by default the feature is turned off so no regions 207 // should be reopened 208 Mockito.verify(hMaster, Mockito.times(0)).reopenRegions(Mockito.any(), Mockito.anyList(), 209 Mockito.anyLong(), Mockito.anyLong()); 210 211 // default maxCompactedStoreFileRefCount is -1 (no regions to be reopened using AM) 212 Mockito.verify(hMaster, Mockito.times(0)).getAssignmentManager(); 213 Mockito.verify(assignmentManager, Mockito.times(0)).getRegionInfo(Mockito.any(byte[].class)); 214 } 215 216 private static ClusterMetrics getClusterMetrics(int noOfLiveServer) { 217 ClusterMetrics clusterMetrics = new ClusterMetrics() { 218 219 @Nullable 220 @Override 221 public String getHBaseVersion() { 222 return null; 223 } 224 225 @Override 226 public List<ServerName> getDeadServerNames() { 227 return null; 228 } 229 230 @Override 231 public List<ServerName> getUnknownServerNames() { 232 return null; 233 } 234 235 @Override 236 public List<ServerName> getDecommissionedServerNames() { 237 return null; 238 } 239 240 @Override 241 public Map<ServerName, ServerMetrics> getLiveServerMetrics() { 242 Map<ServerName, ServerMetrics> liveServerMetrics = new HashMap<>(); 243 for (int i = 0; i < noOfLiveServer; i++) { 244 ServerName serverName = ServerName.valueOf("rs_" + i, 16010, 12345); 245 liveServerMetrics.put(serverName, TestRegionsRecoveryChore.getServerMetrics(i + 3)); 246 } 247 return liveServerMetrics; 248 } 249 250 @Nullable 251 @Override 252 public ServerName getMasterName() { 253 return null; 254 } 255 256 @Override 257 public List<ServerName> getBackupMasterNames() { 258 return null; 259 } 260 261 @Override 262 public List<RegionState> getRegionStatesInTransition() { 263 return null; 264 } 265 266 @Nullable 267 @Override 268 public String getClusterId() { 269 return null; 270 } 271 272 @Override 273 public List<String> getMasterCoprocessorNames() { 274 return null; 275 } 276 277 @Nullable 278 @Override 279 public Boolean getBalancerOn() { 280 return null; 281 } 282 283 @Override 284 public int getMasterInfoPort() { 285 return 0; 286 } 287 288 @Override 289 public List<ServerName> getServersName() { 290 return null; 291 } 292 293 @Override 294 public Map<TableName, RegionStatesCount> getTableRegionStatesCount() { 295 return null; 296 } 297 298 @Override 299 public List<ServerTask> getMasterTasks() { 300 return null; 301 } 302 303 }; 304 return clusterMetrics; 305 } 306 307 private static ServerMetrics getServerMetrics(int noOfRegions) { 308 ServerMetrics serverMetrics = new ServerMetrics() { 309 310 @Override 311 public ServerName getServerName() { 312 return null; 313 } 314 315 @Override 316 public long getRequestCountPerSecond() { 317 return 0; 318 } 319 320 @Override 321 public long getRequestCount() { 322 return 0; 323 } 324 325 @Override 326 public long getReadRequestsCount() { 327 return 0; 328 } 329 330 @Override 331 public long getWriteRequestsCount() { 332 return 0; 333 } 334 335 @Override 336 public Size getUsedHeapSize() { 337 return null; 338 } 339 340 @Override 341 public Size getMaxHeapSize() { 342 return null; 343 } 344 345 @Override 346 public int getInfoServerPort() { 347 return 0; 348 } 349 350 @Override 351 public List<ReplicationLoadSource> getReplicationLoadSourceList() { 352 return null; 353 } 354 355 @Override 356 public Map<String, List<ReplicationLoadSource>> getReplicationLoadSourceMap() { 357 return null; 358 } 359 360 @Nullable 361 @Override 362 public ReplicationLoadSink getReplicationLoadSink() { 363 return null; 364 } 365 366 @Override 367 public Map<byte[], RegionMetrics> getRegionMetrics() { 368 Map<byte[], RegionMetrics> regionMetricsMap = new HashMap<>(); 369 for (int i = 0; i < noOfRegions; i++) { 370 byte[] regionName = Bytes.toBytes("region" + regionNo + "_" + i); 371 regionMetricsMap.put(regionName, 372 TestRegionsRecoveryChore.getRegionMetrics(regionName, 100 * i)); 373 ++regionNo; 374 } 375 return regionMetricsMap; 376 } 377 378 @Override 379 public Map<byte[], UserMetrics> getUserMetrics() { 380 return new HashMap<>(); 381 } 382 383 @Override 384 public Set<String> getCoprocessorNames() { 385 return null; 386 } 387 388 @Override 389 public long getReportTimestamp() { 390 return 0; 391 } 392 393 @Override 394 public long getLastReportTimestamp() { 395 return 0; 396 } 397 398 @Override 399 public List<ServerTask> getTasks() { 400 return null; 401 } 402 403 @Override 404 public Map<String, Integer> getRegionCachedInfo() { 405 return new HashMap<>(); 406 } 407 }; 408 return serverMetrics; 409 } 410 411 private static RegionMetrics getRegionMetrics(byte[] regionName, int compactedStoreRefCount) { 412 RegionMetrics regionMetrics = new RegionMetrics() { 413 414 @Override 415 public byte[] getRegionName() { 416 return regionName; 417 } 418 419 @Override 420 public int getStoreCount() { 421 return 0; 422 } 423 424 @Override 425 public int getStoreFileCount() { 426 return 0; 427 } 428 429 @Override 430 public Size getStoreFileSize() { 431 return null; 432 } 433 434 @Override 435 public Size getMemStoreSize() { 436 return null; 437 } 438 439 @Override 440 public long getReadRequestCount() { 441 return 0; 442 } 443 444 @Override 445 public long getWriteRequestCount() { 446 return 0; 447 } 448 449 @Override 450 public long getCpRequestCount() { 451 return 0; 452 } 453 454 @Override 455 public long getFilteredReadRequestCount() { 456 return 0; 457 } 458 459 @Override 460 public Size getStoreFileIndexSize() { 461 return null; 462 } 463 464 @Override 465 public Size getStoreFileRootLevelIndexSize() { 466 return null; 467 } 468 469 @Override 470 public Size getStoreFileUncompressedDataIndexSize() { 471 return null; 472 } 473 474 @Override 475 public Size getBloomFilterSize() { 476 return null; 477 } 478 479 @Override 480 public long getCompactingCellCount() { 481 return 0; 482 } 483 484 @Override 485 public long getCompactedCellCount() { 486 return 0; 487 } 488 489 @Override 490 public long getCompletedSequenceId() { 491 return 0; 492 } 493 494 @Override 495 public Map<byte[], Long> getStoreSequenceId() { 496 return null; 497 } 498 499 @Override 500 public Size getUncompressedStoreFileSize() { 501 return null; 502 } 503 504 @Override 505 public float getDataLocality() { 506 return 0; 507 } 508 509 @Override 510 public long getLastMajorCompactionTimestamp() { 511 return 0; 512 } 513 514 @Override 515 public int getStoreRefCount() { 516 return compactedStoreRefCount; 517 } 518 519 @Override 520 public int getMaxCompactedStoreFileRefCount() { 521 return compactedStoreRefCount; 522 } 523 524 @Override 525 public float getDataLocalityForSsd() { 526 return 0; 527 } 528 529 @Override 530 public long getBlocksLocalWeight() { 531 return 0; 532 } 533 534 @Override 535 public long getBlocksLocalWithSsdWeight() { 536 return 0; 537 } 538 539 @Override 540 public long getBlocksTotalWeight() { 541 return 0; 542 } 543 544 @Override 545 public CompactionState getCompactionState() { 546 return null; 547 } 548 549 @Override 550 public Size getRegionSizeMB() { 551 return null; 552 } 553 554 @Override 555 public float getCurrentRegionCachedRatio() { 556 return 0.0f; 557 } 558 }; 559 return regionMetrics; 560 } 561 562 private static RegionInfo getRegionInfo(byte[] regionNameBytes) { 563 RegionInfo regionInfo = new RegionInfo() { 564 565 @Override 566 public String getShortNameToLog() { 567 return null; 568 } 569 570 @Override 571 public long getRegionId() { 572 return 0; 573 } 574 575 @Override 576 public byte[] getRegionName() { 577 return new byte[0]; 578 } 579 580 @Override 581 public String getRegionNameAsString() { 582 try { 583 return new String(regionNameBytes, UTF_8_CHARSET); 584 } catch (UnsupportedEncodingException e) { 585 return ""; 586 } 587 } 588 589 @Override 590 public String getEncodedName() { 591 return null; 592 } 593 594 @Override 595 public byte[] getEncodedNameAsBytes() { 596 return new byte[0]; 597 } 598 599 @Override 600 public byte[] getStartKey() { 601 return new byte[0]; 602 } 603 604 @Override 605 public byte[] getEndKey() { 606 return new byte[0]; 607 } 608 609 @Override 610 public TableName getTable() { 611 String regionName; 612 try { 613 regionName = new String(regionNameBytes, UTF_8_CHARSET); 614 } catch (UnsupportedEncodingException e) { 615 regionName = ""; 616 } 617 int regionNo = Integer.parseInt(regionName.split("_")[1]); 618 TableName tableName = TableName.valueOf("table_" + regionNo % 3); 619 return tableName; 620 } 621 622 @Override 623 public int getReplicaId() { 624 return 0; 625 } 626 627 @Override 628 public boolean isSplit() { 629 return false; 630 } 631 632 @Override 633 public boolean isOffline() { 634 return false; 635 } 636 637 @Override 638 public boolean isSplitParent() { 639 return false; 640 } 641 642 @Override 643 public boolean isMetaRegion() { 644 return false; 645 } 646 647 @Override 648 public boolean containsRange(byte[] rangeStartKey, byte[] rangeEndKey) { 649 return false; 650 } 651 652 @Override 653 public boolean containsRow(byte[] row) { 654 return false; 655 } 656 657 }; 658 return regionInfo; 659 } 660 661 /** 662 * Simple helper class that just keeps track of whether or not its stopped. 663 */ 664 private static class StoppableImplementation implements Stoppable { 665 666 private volatile boolean stop = false; 667 668 @Override 669 public void stop(String why) { 670 this.stop = true; 671 } 672 673 @Override 674 public boolean isStopped() { 675 return this.stop; 676 } 677 678 } 679 680}