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.HBaseTestingUtility; 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 HBaseTestingUtility HBASE_TESTING_UTILITY = new HBaseTestingUtility(); 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()); 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()); 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()); 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 Map<ServerName, ServerMetrics> getLiveServerMetrics() { 237 Map<ServerName, ServerMetrics> liveServerMetrics = new HashMap<>(); 238 for (int i = 0; i < noOfLiveServer; i++) { 239 ServerName serverName = ServerName.valueOf("rs_" + i, 16010, 12345); 240 liveServerMetrics.put(serverName, TestRegionsRecoveryChore.getServerMetrics(i + 3)); 241 } 242 return liveServerMetrics; 243 } 244 245 @Nullable 246 @Override 247 public ServerName getMasterName() { 248 return null; 249 } 250 251 @Override 252 public List<ServerName> getBackupMasterNames() { 253 return null; 254 } 255 256 @Override 257 public List<RegionState> getRegionStatesInTransition() { 258 return null; 259 } 260 261 @Nullable 262 @Override 263 public String getClusterId() { 264 return null; 265 } 266 267 @Override 268 public List<String> getMasterCoprocessorNames() { 269 return null; 270 } 271 272 @Nullable 273 @Override 274 public Boolean getBalancerOn() { 275 return null; 276 } 277 278 @Override 279 public int getMasterInfoPort() { 280 return 0; 281 } 282 283 @Override 284 public List<ServerName> getServersName() { 285 return null; 286 } 287 288 @Override 289 public Map<TableName, RegionStatesCount> getTableRegionStatesCount() { 290 return null; 291 } 292 293 @Override 294 public List<ServerTask> getMasterTasks() { 295 return null; 296 } 297 298 }; 299 return clusterMetrics; 300 } 301 302 private static ServerMetrics getServerMetrics(int noOfRegions) { 303 ServerMetrics serverMetrics = new ServerMetrics() { 304 305 @Override 306 public ServerName getServerName() { 307 return null; 308 } 309 310 @Override 311 public long getRequestCountPerSecond() { 312 return 0; 313 } 314 315 @Override 316 public long getRequestCount() { 317 return 0; 318 } 319 320 @Override 321 public Size getUsedHeapSize() { 322 return null; 323 } 324 325 @Override 326 public Size getMaxHeapSize() { 327 return null; 328 } 329 330 @Override 331 public int getInfoServerPort() { 332 return 0; 333 } 334 335 @Override 336 public List<ReplicationLoadSource> getReplicationLoadSourceList() { 337 return null; 338 } 339 340 @Override 341 public Map<String, List<ReplicationLoadSource>> getReplicationLoadSourceMap() { 342 return null; 343 } 344 345 @Nullable 346 @Override 347 public ReplicationLoadSink getReplicationLoadSink() { 348 return null; 349 } 350 351 @Override 352 public Map<byte[], RegionMetrics> getRegionMetrics() { 353 Map<byte[], RegionMetrics> regionMetricsMap = new HashMap<>(); 354 for (int i = 0; i < noOfRegions; i++) { 355 byte[] regionName = Bytes.toBytes("region" + regionNo + "_" + i); 356 regionMetricsMap.put(regionName, 357 TestRegionsRecoveryChore.getRegionMetrics(regionName, 100 * i)); 358 ++regionNo; 359 } 360 return regionMetricsMap; 361 } 362 363 @Override 364 public Map<byte[], UserMetrics> getUserMetrics() { 365 return new HashMap<>(); 366 } 367 368 @Override 369 public Set<String> getCoprocessorNames() { 370 return null; 371 } 372 373 @Override 374 public long getReportTimestamp() { 375 return 0; 376 } 377 378 @Override 379 public long getLastReportTimestamp() { 380 return 0; 381 } 382 383 @Override 384 public List<ServerTask> getTasks() { 385 return null; 386 } 387 388 }; 389 return serverMetrics; 390 } 391 392 private static RegionMetrics getRegionMetrics(byte[] regionName, int compactedStoreRefCount) { 393 RegionMetrics regionMetrics = new RegionMetrics() { 394 395 @Override 396 public byte[] getRegionName() { 397 return regionName; 398 } 399 400 @Override 401 public int getStoreCount() { 402 return 0; 403 } 404 405 @Override 406 public int getStoreFileCount() { 407 return 0; 408 } 409 410 @Override 411 public Size getStoreFileSize() { 412 return null; 413 } 414 415 @Override 416 public Size getMemStoreSize() { 417 return null; 418 } 419 420 @Override 421 public long getReadRequestCount() { 422 return 0; 423 } 424 425 @Override 426 public long getWriteRequestCount() { 427 return 0; 428 } 429 430 @Override 431 public long getFilteredReadRequestCount() { 432 return 0; 433 } 434 435 @Override 436 public Size getStoreFileIndexSize() { 437 return null; 438 } 439 440 @Override 441 public Size getStoreFileRootLevelIndexSize() { 442 return null; 443 } 444 445 @Override 446 public Size getStoreFileUncompressedDataIndexSize() { 447 return null; 448 } 449 450 @Override 451 public Size getBloomFilterSize() { 452 return null; 453 } 454 455 @Override 456 public long getCompactingCellCount() { 457 return 0; 458 } 459 460 @Override 461 public long getCompactedCellCount() { 462 return 0; 463 } 464 465 @Override 466 public long getCompletedSequenceId() { 467 return 0; 468 } 469 470 @Override 471 public Map<byte[], Long> getStoreSequenceId() { 472 return null; 473 } 474 475 @Override 476 public Size getUncompressedStoreFileSize() { 477 return null; 478 } 479 480 @Override 481 public float getDataLocality() { 482 return 0; 483 } 484 485 @Override 486 public long getLastMajorCompactionTimestamp() { 487 return 0; 488 } 489 490 @Override 491 public int getStoreRefCount() { 492 return compactedStoreRefCount; 493 } 494 495 @Override 496 public int getMaxCompactedStoreFileRefCount() { 497 return compactedStoreRefCount; 498 } 499 500 @Override 501 public float getDataLocalityForSsd() { 502 return 0; 503 } 504 505 @Override 506 public long getBlocksLocalWeight() { 507 return 0; 508 } 509 510 @Override 511 public long getBlocksLocalWithSsdWeight() { 512 return 0; 513 } 514 515 @Override 516 public long getBlocksTotalWeight() { 517 return 0; 518 } 519 520 @Override 521 public CompactionState getCompactionState() { 522 return null; 523 } 524 }; 525 return regionMetrics; 526 } 527 528 private static RegionInfo getRegionInfo(byte[] regionNameBytes) { 529 RegionInfo regionInfo = new RegionInfo() { 530 531 @Override 532 public String getShortNameToLog() { 533 return null; 534 } 535 536 @Override 537 public long getRegionId() { 538 return 0; 539 } 540 541 @Override 542 public byte[] getRegionName() { 543 return new byte[0]; 544 } 545 546 @Override 547 public String getRegionNameAsString() { 548 try { 549 return new String(regionNameBytes, UTF_8_CHARSET); 550 } catch (UnsupportedEncodingException e) { 551 return ""; 552 } 553 } 554 555 @Override 556 public String getEncodedName() { 557 return null; 558 } 559 560 @Override 561 public byte[] getEncodedNameAsBytes() { 562 return new byte[0]; 563 } 564 565 @Override 566 public byte[] getStartKey() { 567 return new byte[0]; 568 } 569 570 @Override 571 public byte[] getEndKey() { 572 return new byte[0]; 573 } 574 575 @Override 576 public TableName getTable() { 577 String regionName; 578 try { 579 regionName = new String(regionNameBytes, UTF_8_CHARSET); 580 } catch (UnsupportedEncodingException e) { 581 regionName = ""; 582 } 583 int regionNo = Integer.parseInt(regionName.split("_")[1]); 584 TableName tableName = TableName.valueOf("table_" + regionNo % 3); 585 return tableName; 586 } 587 588 @Override 589 public int getReplicaId() { 590 return 0; 591 } 592 593 @Override 594 public boolean isSplit() { 595 return false; 596 } 597 598 @Override 599 public boolean isOffline() { 600 return false; 601 } 602 603 @Override 604 public boolean isSplitParent() { 605 return false; 606 } 607 608 @Override 609 public boolean isMetaRegion() { 610 return false; 611 } 612 613 @Override 614 public boolean containsRange(byte[] rangeStartKey, byte[] rangeEndKey) { 615 return false; 616 } 617 618 @Override 619 public boolean containsRow(byte[] row) { 620 return false; 621 } 622 623 }; 624 return regionInfo; 625 } 626 627 /** 628 * Simple helper class that just keeps track of whether or not its stopped. 629 */ 630 private static class StoppableImplementation implements Stoppable { 631 632 private volatile boolean stop = false; 633 634 @Override 635 public void stop(String why) { 636 this.stop = true; 637 } 638 639 @Override 640 public boolean isStopped() { 641 return this.stop; 642 } 643 644 } 645 646}