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.assignment; 019 020import java.util.ArrayList; 021import java.util.Collection; 022import java.util.Collections; 023import java.util.HashMap; 024import java.util.Iterator; 025import java.util.List; 026import java.util.Map; 027import java.util.concurrent.ConcurrentHashMap; 028import java.util.concurrent.ConcurrentSkipListMap; 029import java.util.concurrent.atomic.AtomicInteger; 030import java.util.function.Predicate; 031import java.util.stream.Collectors; 032import org.apache.hadoop.hbase.HRegionLocation; 033import org.apache.hadoop.hbase.ServerName; 034import org.apache.hadoop.hbase.TableName; 035import org.apache.hadoop.hbase.client.RegionInfo; 036import org.apache.hadoop.hbase.client.TableState; 037import org.apache.hadoop.hbase.master.RegionState; 038import org.apache.hadoop.hbase.master.RegionState.State; 039import org.apache.hadoop.hbase.master.TableStateManager; 040import org.apache.hadoop.hbase.util.Bytes; 041import org.apache.yetus.audience.InterfaceAudience; 042import org.slf4j.Logger; 043import org.slf4j.LoggerFactory; 044 045/** 046 * RegionStates contains a set of Maps that describes the in-memory state of the AM, with the 047 * regions available in the system, the region in transition, the offline regions and the servers 048 * holding regions. 049 */ 050@InterfaceAudience.Private 051public class RegionStates { 052 private static final Logger LOG = LoggerFactory.getLogger(RegionStates.class); 053 054 private final Object regionsMapLock = new Object(); 055 056 private final AtomicInteger activeTransitProcedureCount = new AtomicInteger(0); 057 058 // TODO: Replace the ConcurrentSkipListMaps 059 /** 060 * A Map from {@link RegionInfo#getRegionName()} to {@link RegionStateNode} 061 */ 062 private final ConcurrentSkipListMap<byte[], RegionStateNode> regionsMap = 063 new ConcurrentSkipListMap<>(Bytes.BYTES_COMPARATOR); 064 065 /** 066 * this map is a hack to lookup of region in master by encoded region name is O(n). must put and 067 * remove with regionsMap. 068 */ 069 private final ConcurrentSkipListMap<String, RegionStateNode> encodedRegionsMap = 070 new ConcurrentSkipListMap<>(); 071 072 /** 073 * Regions marked as offline on a read of hbase:meta. Unused or at least, once offlined, regions 074 * have no means of coming on line again. TODO. 075 */ 076 private final ConcurrentSkipListMap<RegionInfo, RegionStateNode> regionOffline = 077 new ConcurrentSkipListMap<RegionInfo, RegionStateNode>(); 078 079 private final ConcurrentSkipListMap<byte[], RegionFailedOpen> regionFailedOpen = 080 new ConcurrentSkipListMap<byte[], RegionFailedOpen>(Bytes.BYTES_COMPARATOR); 081 082 private final ConcurrentHashMap<ServerName, ServerStateNode> serverMap = 083 new ConcurrentHashMap<ServerName, ServerStateNode>(); 084 085 public RegionStates() { 086 } 087 088 /** 089 * Called on stop of AssignmentManager. 090 */ 091 public void clear() { 092 regionsMap.clear(); 093 encodedRegionsMap.clear(); 094 regionOffline.clear(); 095 serverMap.clear(); 096 } 097 098 // ========================================================================== 099 // RegionStateNode helpers 100 // ========================================================================== 101 RegionStateNode createRegionStateNode(RegionInfo regionInfo) { 102 synchronized (regionsMapLock) { 103 RegionStateNode node = regionsMap.computeIfAbsent(regionInfo.getRegionName(), 104 key -> new RegionStateNode(regionInfo, activeTransitProcedureCount)); 105 106 if (encodedRegionsMap.get(regionInfo.getEncodedName()) != node) { 107 encodedRegionsMap.put(regionInfo.getEncodedName(), node); 108 } 109 110 return node; 111 } 112 } 113 114 public RegionStateNode getOrCreateRegionStateNode(RegionInfo regionInfo) { 115 RegionStateNode node = getRegionStateNodeFromName(regionInfo.getRegionName()); 116 return node != null ? node : createRegionStateNode(regionInfo); 117 } 118 119 public RegionStateNode getRegionStateNodeFromName(byte[] regionName) { 120 return regionsMap.get(regionName); 121 } 122 123 public RegionStateNode getRegionStateNodeFromEncodedRegionName(final String encodedRegionName) { 124 return encodedRegionsMap.get(encodedRegionName); 125 } 126 127 public RegionStateNode getRegionStateNode(RegionInfo regionInfo) { 128 return getRegionStateNodeFromName(regionInfo.getRegionName()); 129 } 130 131 public void deleteRegion(final RegionInfo regionInfo) { 132 synchronized (regionsMapLock) { 133 regionsMap.remove(regionInfo.getRegionName()); 134 encodedRegionsMap.remove(regionInfo.getEncodedName()); 135 } 136 // Remove from the offline regions map too if there. 137 if (this.regionOffline.containsKey(regionInfo)) { 138 if (LOG.isTraceEnabled()) LOG.trace("Removing from regionOffline Map: " + regionInfo); 139 this.regionOffline.remove(regionInfo); 140 } 141 } 142 143 public void deleteRegions(final List<RegionInfo> regionInfos) { 144 regionInfos.forEach(this::deleteRegion); 145 } 146 147 List<RegionStateNode> getTableRegionStateNodes(final TableName tableName) { 148 final ArrayList<RegionStateNode> regions = new ArrayList<RegionStateNode>(); 149 for (RegionStateNode node : regionsMap.tailMap(tableName.getName()).values()) { 150 if (!node.getTable().equals(tableName)) break; 151 regions.add(node); 152 } 153 return regions; 154 } 155 156 ArrayList<RegionState> getTableRegionStates(final TableName tableName) { 157 final ArrayList<RegionState> regions = new ArrayList<RegionState>(); 158 for (RegionStateNode node : regionsMap.tailMap(tableName.getName()).values()) { 159 if (!node.getTable().equals(tableName)) break; 160 regions.add(node.toRegionState()); 161 } 162 return regions; 163 } 164 165 ArrayList<RegionInfo> getTableRegionsInfo(final TableName tableName) { 166 final ArrayList<RegionInfo> regions = new ArrayList<RegionInfo>(); 167 for (RegionStateNode node : regionsMap.tailMap(tableName.getName()).values()) { 168 if (!node.getTable().equals(tableName)) break; 169 regions.add(node.getRegionInfo()); 170 } 171 return regions; 172 } 173 174 /** Returns A view of region state nodes for all the regions. */ 175 public Collection<RegionStateNode> getRegionStateNodes() { 176 return Collections.unmodifiableCollection(regionsMap.values()); 177 } 178 179 /** Returns A snapshot of region state nodes for all the regions. */ 180 public ArrayList<RegionState> getRegionStates() { 181 final ArrayList<RegionState> regions = new ArrayList<>(regionsMap.size()); 182 for (RegionStateNode node : regionsMap.values()) { 183 regions.add(node.toRegionState()); 184 } 185 return regions; 186 } 187 188 // ========================================================================== 189 // RegionState helpers 190 // ========================================================================== 191 public RegionState getRegionState(final RegionInfo regionInfo) { 192 RegionStateNode regionStateNode = getRegionStateNode(regionInfo); 193 return regionStateNode == null ? null : regionStateNode.toRegionState(); 194 } 195 196 public RegionState getRegionState(final String encodedRegionName) { 197 final RegionStateNode node = encodedRegionsMap.get(encodedRegionName); 198 if (node == null) { 199 return null; 200 } 201 return node.toRegionState(); 202 } 203 204 // ============================================================================================ 205 // TODO: helpers 206 // ============================================================================================ 207 public boolean hasTableRegionStates(final TableName tableName) { 208 // TODO 209 return !getTableRegionStates(tableName).isEmpty(); 210 } 211 212 /** Returns Return online regions of table; does not include OFFLINE or SPLITTING regions. */ 213 public List<RegionInfo> getRegionsOfTable(TableName table) { 214 return getRegionsOfTable(table, regionNode -> !regionNode.isInState(State.OFFLINE, State.SPLIT) 215 && !regionNode.getRegionInfo().isSplitParent()); 216 } 217 218 private HRegionLocation createRegionForReopen(RegionStateNode node) { 219 node.lock(); 220 try { 221 if (!include(node, false)) { 222 return null; 223 } 224 if (node.isInState(State.OPEN)) { 225 return new HRegionLocation(node.getRegionInfo(), node.getRegionLocation(), 226 node.getOpenSeqNum()); 227 } else if (node.isInState(State.OPENING)) { 228 return new HRegionLocation(node.getRegionInfo(), node.getRegionLocation(), -1); 229 } else { 230 return null; 231 } 232 } finally { 233 node.unlock(); 234 } 235 } 236 237 /** 238 * Get the regions to be reopened when modifying a table. 239 * <p/> 240 * Notice that the {@code openSeqNum} in the returned HRegionLocation is also used to indicate the 241 * state of this region, positive means the region is in {@link State#OPEN}, -1 means 242 * {@link State#OPENING}. And for regions in other states we do not need reopen them. 243 */ 244 public List<HRegionLocation> getRegionsOfTableForReopen(TableName tableName) { 245 return getTableRegionStateNodes(tableName).stream().map(this::createRegionForReopen) 246 .filter(r -> r != null).collect(Collectors.toList()); 247 } 248 249 /** 250 * Check whether the region has been reopened. The meaning of the {@link HRegionLocation} is the 251 * same with {@link #getRegionsOfTableForReopen(TableName)}. 252 * <p/> 253 * For a region which is in {@link State#OPEN} before, if the region state is changed or the open 254 * seq num is changed, we can confirm that it has been reopened. 255 * <p/> 256 * For a region which is in {@link State#OPENING} before, usually it will be in {@link State#OPEN} 257 * now and we will schedule a MRP to reopen it. But there are several exceptions: 258 * <ul> 259 * <li>The region is in state other than {@link State#OPEN} or {@link State#OPENING}.</li> 260 * <li>The location of the region has been changed</li> 261 * </ul> 262 * Of course the region could still be in {@link State#OPENING} state and still on the same 263 * server, then here we will still return a {@link HRegionLocation} for it, just like 264 * {@link #getRegionsOfTableForReopen(TableName)}. 265 * @param oldLoc the previous state/location of this region 266 * @return null if the region has been reopened, otherwise a new {@link HRegionLocation} which 267 * means we still need to reopen the region. 268 * @see #getRegionsOfTableForReopen(TableName) 269 */ 270 public HRegionLocation checkReopened(HRegionLocation oldLoc) { 271 RegionStateNode node = getRegionStateNode(oldLoc.getRegion()); 272 // HBASE-20921 273 // if the oldLoc's state node does not exist, that means the region is 274 // merged or split, no need to check it 275 if (node == null) { 276 return null; 277 } 278 node.lock(); 279 try { 280 if (oldLoc.getSeqNum() >= 0) { 281 // in OPEN state before 282 if (node.isInState(State.OPEN)) { 283 if (node.getOpenSeqNum() > oldLoc.getSeqNum()) { 284 // normal case, the region has been reopened 285 return null; 286 } else { 287 // the open seq num does not change, need to reopen again 288 return new HRegionLocation(node.getRegionInfo(), node.getRegionLocation(), 289 node.getOpenSeqNum()); 290 } 291 } else { 292 // the state has been changed so we can make sure that the region has been reopened(not 293 // finished maybe, but not a problem). 294 return null; 295 } 296 } else { 297 // in OPENING state before 298 if (!node.isInState(State.OPEN, State.OPENING)) { 299 // not in OPEN or OPENING state, then we can make sure that the region has been 300 // reopened(not finished maybe, but not a problem) 301 return null; 302 } else { 303 if (!node.getRegionLocation().equals(oldLoc.getServerName())) { 304 // the region has been moved, so we can make sure that the region has been reopened. 305 return null; 306 } 307 // normal case, we are still in OPENING state, or the reopen has been opened and the state 308 // is changed to OPEN. 309 long openSeqNum = node.isInState(State.OPEN) ? node.getOpenSeqNum() : -1; 310 return new HRegionLocation(node.getRegionInfo(), node.getRegionLocation(), openSeqNum); 311 } 312 } 313 } finally { 314 node.unlock(); 315 } 316 } 317 318 /** 319 * Get the regions for enabling a table. 320 * <p/> 321 * Here we want the EnableTableProcedure to be more robust and can be used to fix some nasty 322 * states, so the checks in this method will be a bit strange. In general, a region can only be 323 * offline when it is split, for merging we will just delete the parent regions, but with HBCK we 324 * may force update the state of a region to fix some nasty bugs, so in this method we will try to 325 * bring the offline regions back if it is not split. That's why we only check for split state 326 * here. 327 */ 328 public List<RegionInfo> getRegionsOfTableForEnabling(TableName table) { 329 return getRegionsOfTable(table, 330 regionNode -> !regionNode.isInState(State.SPLIT) && !regionNode.getRegionInfo().isSplit()); 331 } 332 333 /** 334 * Returns all regions of the table, irrespective of assignment or split/offline state. 335 */ 336 public List<RegionInfo> getAllRegionsOfTable(TableName table) { 337 return getTableRegionStateNodes(table).stream().map(RegionStateNode::getRegionInfo) 338 .collect(Collectors.toList()); 339 } 340 341 /** 342 * Get the regions for deleting a table. 343 * <p/> 344 * Here we need to return all the regions irrespective of the states in order to archive them all. 345 * This is because if we don't archive OFFLINE/SPLIT regions and if a snapshot or a cloned table 346 * references to the regions, we will lose the data of the regions. 347 */ 348 public List<RegionInfo> getRegionsOfTableForDeleting(TableName table) { 349 return getAllRegionsOfTable(table); 350 } 351 352 /** Returns Return the regions of the table and filter them. */ 353 private List<RegionInfo> getRegionsOfTable(TableName table, Predicate<RegionStateNode> filter) { 354 return getTableRegionStateNodes(table).stream().filter(filter).map(n -> n.getRegionInfo()) 355 .collect(Collectors.toList()); 356 } 357 358 /** 359 * Utility. Whether to include region in list of regions. Default is to weed out split and offline 360 * regions. 361 * @return True if we should include the <code>node</code> (do not include if split or offline 362 * unless <code>offline</code> is set to true. 363 */ 364 private boolean include(final RegionStateNode node, final boolean offline) { 365 if (LOG.isTraceEnabled()) { 366 LOG.trace("WORKING ON " + node + " " + node.getRegionInfo()); 367 } 368 final RegionInfo hri = node.getRegionInfo(); 369 if (node.isInState(State.SPLIT) || hri.isSplit()) { 370 return false; 371 } 372 if ((node.isInState(State.OFFLINE) || hri.isOffline()) && !offline) { 373 return false; 374 } 375 return (!hri.isOffline() && !hri.isSplit()) || ((hri.isOffline() || hri.isSplit()) && offline); 376 } 377 378 // ============================================================================================ 379 // Split helpers 380 // These methods will only be called in ServerCrashProcedure, and at the end of SCP we will remove 381 // the ServerStateNode by calling removeServer. 382 // ============================================================================================ 383 384 private void setServerState(ServerName serverName, ServerState state) { 385 ServerStateNode serverNode = getServerNode(serverName); 386 synchronized (serverNode) { 387 serverNode.setState(state); 388 } 389 } 390 391 /** 392 * Call this when we start meta log splitting a crashed Server. 393 * @see #metaLogSplit(ServerName) 394 */ 395 public void metaLogSplitting(ServerName serverName) { 396 setServerState(serverName, ServerState.SPLITTING_META); 397 } 398 399 /** 400 * Called after we've split the meta logs on a crashed Server. 401 * @see #metaLogSplitting(ServerName) 402 */ 403 public void metaLogSplit(ServerName serverName) { 404 setServerState(serverName, ServerState.SPLITTING_META_DONE); 405 } 406 407 /** 408 * Call this when we start log splitting for a crashed Server. 409 * @see #logSplit(ServerName) 410 */ 411 public void logSplitting(final ServerName serverName) { 412 setServerState(serverName, ServerState.SPLITTING); 413 } 414 415 /** 416 * Called after we've split all logs on a crashed Server. 417 * @see #logSplitting(ServerName) 418 */ 419 public void logSplit(final ServerName serverName) { 420 setServerState(serverName, ServerState.OFFLINE); 421 } 422 423 public void updateRegionState(RegionInfo regionInfo, State state) { 424 RegionStateNode regionNode = getOrCreateRegionStateNode(regionInfo); 425 regionNode.lock(); 426 try { 427 regionNode.setState(state); 428 } finally { 429 regionNode.unlock(); 430 } 431 } 432 433 // ============================================================================================ 434 // TODO: 435 // ============================================================================================ 436 public List<RegionInfo> getAssignedRegions() { 437 final List<RegionInfo> result = new ArrayList<RegionInfo>(); 438 for (RegionStateNode node : regionsMap.values()) { 439 if (!node.isTransitionScheduled()) { 440 result.add(node.getRegionInfo()); 441 } 442 } 443 return result; 444 } 445 446 public boolean isRegionInState(RegionInfo regionInfo, State... state) { 447 RegionStateNode regionNode = getRegionStateNode(regionInfo); 448 if (regionNode != null) { 449 regionNode.lock(); 450 try { 451 return regionNode.isInState(state); 452 } finally { 453 regionNode.unlock(); 454 } 455 } 456 return false; 457 } 458 459 public boolean isRegionOnline(final RegionInfo regionInfo) { 460 return isRegionInState(regionInfo, State.OPEN); 461 } 462 463 /** Returns True if region is offline (In OFFLINE or CLOSED state). */ 464 public boolean isRegionOffline(final RegionInfo regionInfo) { 465 return isRegionInState(regionInfo, State.OFFLINE, State.CLOSED); 466 } 467 468 public Map<ServerName, List<RegionInfo>> 469 getSnapShotOfAssignment(final Collection<RegionInfo> regions) { 470 final Map<ServerName, List<RegionInfo>> result = new HashMap<ServerName, List<RegionInfo>>(); 471 if (regions != null) { 472 for (RegionInfo hri : regions) { 473 final RegionStateNode node = getRegionStateNode(hri); 474 if (node == null) { 475 continue; 476 } 477 createSnapshot(node, result); 478 } 479 } else { 480 for (RegionStateNode node : regionsMap.values()) { 481 if (node == null) { 482 continue; 483 } 484 createSnapshot(node, result); 485 } 486 } 487 return result; 488 } 489 490 private void createSnapshot(RegionStateNode node, Map<ServerName, List<RegionInfo>> result) { 491 final ServerName serverName = node.getRegionLocation(); 492 if (serverName == null) { 493 return; 494 } 495 496 List<RegionInfo> serverRegions = result.get(serverName); 497 if (serverRegions == null) { 498 serverRegions = new ArrayList<RegionInfo>(); 499 result.put(serverName, serverRegions); 500 } 501 serverRegions.add(node.getRegionInfo()); 502 } 503 504 public Map<RegionInfo, ServerName> getRegionAssignments() { 505 final HashMap<RegionInfo, ServerName> assignments = new HashMap<RegionInfo, ServerName>(); 506 for (RegionStateNode node : regionsMap.values()) { 507 assignments.put(node.getRegionInfo(), node.getRegionLocation()); 508 } 509 return assignments; 510 } 511 512 public Map<RegionState.State, List<RegionInfo>> getRegionByStateOfTable(TableName tableName) { 513 final State[] states = State.values(); 514 final Map<RegionState.State, List<RegionInfo>> tableRegions = 515 new HashMap<State, List<RegionInfo>>(states.length); 516 for (int i = 0; i < states.length; ++i) { 517 tableRegions.put(states[i], new ArrayList<RegionInfo>()); 518 } 519 520 for (RegionStateNode node : regionsMap.values()) { 521 if (node.getTable().equals(tableName)) { 522 tableRegions.get(node.getState()).add(node.getRegionInfo()); 523 } 524 } 525 return tableRegions; 526 } 527 528 public ServerName getRegionServerOfRegion(RegionInfo regionInfo) { 529 RegionStateNode regionNode = getRegionStateNode(regionInfo); 530 if (regionNode != null) { 531 regionNode.lock(); 532 try { 533 ServerName server = regionNode.getRegionLocation(); 534 return server != null ? server : regionNode.getLastHost(); 535 } finally { 536 regionNode.unlock(); 537 } 538 } 539 return null; 540 } 541 542 /** 543 * This is an EXPENSIVE clone. Cloning though is the safest thing to do. Can't let out original 544 * since it can change and at least the load balancer wants to iterate this exported list. We need 545 * to synchronize on regions since all access to this.servers is under a lock on this.regions. 546 * @return A clone of current open or opening assignments. 547 */ 548 public Map<TableName, Map<ServerName, List<RegionInfo>>> 549 getAssignmentsForBalancer(TableStateManager tableStateManager, List<ServerName> onlineServers) { 550 final Map<TableName, Map<ServerName, List<RegionInfo>>> result = new HashMap<>(); 551 for (RegionStateNode node : regionsMap.values()) { 552 // DisableTableProcedure first sets the table state to DISABLED and then force unassigns 553 // the regions in a loop. The balancer should ignore all regions for tables in DISABLED 554 // state because even if still currently open we expect them to be offlined very soon. 555 if (isTableDisabled(tableStateManager, node.getTable())) { 556 if (LOG.isTraceEnabled()) { 557 LOG.trace("Ignoring {} because table is disabled", node); 558 } 559 continue; 560 } 561 // When balancing, we are only interested in OPEN or OPENING regions. These can be 562 // expected to remain online until the next balancer iteration or unless the balancer 563 // decides to move it. Regions in other states are not eligible for balancing, because 564 // they are closing, splitting, merging, or otherwise already in transition. 565 if (!node.isInState(State.OPEN, State.OPENING)) { 566 if (LOG.isTraceEnabled()) { 567 LOG.trace("Ignoring {} because region is not OPEN or OPENING", node); 568 } 569 continue; 570 } 571 Map<ServerName, List<RegionInfo>> tableResult = 572 result.computeIfAbsent(node.getTable(), t -> new HashMap<>()); 573 final ServerName serverName = node.getRegionLocation(); 574 // A region in ONLINE or OPENING state should have a location. 575 if (serverName == null) { 576 LOG.warn("Skipping, no server for {}", node); 577 continue; 578 } 579 List<RegionInfo> serverResult = 580 tableResult.computeIfAbsent(serverName, s -> new ArrayList<>()); 581 serverResult.add(node.getRegionInfo()); 582 } 583 // Add online servers with no assignment for the table. 584 for (Map<ServerName, List<RegionInfo>> table : result.values()) { 585 for (ServerName serverName : onlineServers) { 586 table.computeIfAbsent(serverName, key -> new ArrayList<>()); 587 } 588 } 589 return result; 590 } 591 592 private boolean isTableDisabled(final TableStateManager tableStateManager, 593 final TableName tableName) { 594 return tableStateManager.isTableState(tableName, TableState.State.DISABLED, 595 TableState.State.DISABLING); 596 } 597 598 // ========================================================================== 599 // Region offline helpers 600 // ========================================================================== 601 // TODO: Populated when we read meta but regions never make it out of here. 602 public void addToOfflineRegions(final RegionStateNode regionNode) { 603 LOG.info("Added to offline, CURRENTLY NEVER CLEARED!!! " + regionNode); 604 regionOffline.put(regionNode.getRegionInfo(), regionNode); 605 } 606 607 public int getRegionTransitScheduledCount() { 608 return activeTransitProcedureCount.get(); 609 } 610 611 // ========================================================================== 612 // Region FAIL_OPEN helpers 613 // ========================================================================== 614 public static final class RegionFailedOpen { 615 private final RegionStateNode regionNode; 616 617 private volatile Exception exception = null; 618 private AtomicInteger retries = new AtomicInteger(); 619 620 public RegionFailedOpen(final RegionStateNode regionNode) { 621 this.regionNode = regionNode; 622 } 623 624 public RegionStateNode getRegionStateNode() { 625 return regionNode; 626 } 627 628 public RegionInfo getRegionInfo() { 629 return regionNode.getRegionInfo(); 630 } 631 632 public int incrementAndGetRetries() { 633 return this.retries.incrementAndGet(); 634 } 635 636 public int getRetries() { 637 return retries.get(); 638 } 639 640 public void setException(final Exception exception) { 641 this.exception = exception; 642 } 643 644 public Exception getException() { 645 return this.exception; 646 } 647 } 648 649 public RegionFailedOpen addToFailedOpen(final RegionStateNode regionNode) { 650 final byte[] key = regionNode.getRegionInfo().getRegionName(); 651 return regionFailedOpen.computeIfAbsent(key, (k) -> new RegionFailedOpen(regionNode)); 652 } 653 654 public RegionFailedOpen getFailedOpen(final RegionInfo regionInfo) { 655 return regionFailedOpen.get(regionInfo.getRegionName()); 656 } 657 658 public void removeFromFailedOpen(final RegionInfo regionInfo) { 659 regionFailedOpen.remove(regionInfo.getRegionName()); 660 } 661 662 public List<RegionState> getRegionFailedOpen() { 663 if (regionFailedOpen.isEmpty()) return Collections.emptyList(); 664 665 ArrayList<RegionState> regions = new ArrayList<RegionState>(regionFailedOpen.size()); 666 for (RegionFailedOpen r : regionFailedOpen.values()) { 667 regions.add(r.getRegionStateNode().toRegionState()); 668 } 669 return regions; 670 } 671 672 // ========================================================================== 673 // Servers 674 // ========================================================================== 675 676 /** 677 * Create the ServerStateNode when registering a new region server 678 */ 679 public void createServer(ServerName serverName) { 680 serverMap.computeIfAbsent(serverName, key -> new ServerStateNode(key)); 681 } 682 683 /** 684 * Called by SCP at end of successful processing. 685 */ 686 public void removeServer(ServerName serverName) { 687 serverMap.remove(serverName); 688 } 689 690 /** Returns Pertinent ServerStateNode or NULL if none found (Do not make modifications). */ 691 public ServerStateNode getServerNode(final ServerName serverName) { 692 return serverMap.get(serverName); 693 } 694 695 public double getAverageLoad() { 696 int numServers = 0; 697 int totalLoad = 0; 698 for (ServerStateNode node : serverMap.values()) { 699 totalLoad += node.getRegionCount(); 700 numServers++; 701 } 702 return numServers == 0 ? 0.0 : (double) totalLoad / (double) numServers; 703 } 704 705 public void addRegionToServer(final RegionStateNode regionNode) { 706 ServerStateNode serverNode = getServerNode(regionNode.getRegionLocation()); 707 serverNode.addRegion(regionNode); 708 } 709 710 public void removeRegionFromServer(final ServerName serverName, 711 final RegionStateNode regionNode) { 712 ServerStateNode serverNode = getServerNode(serverName); 713 // here the server node could be null. For example, if there is already a TRSP for a region and 714 // at the same time, the target server is crashed and there is a SCP. The SCP will interrupt the 715 // TRSP and the TRSP will first set the region as abnormally closed and remove it from the 716 // server node. But here, this TRSP is not a child procedure of the SCP, so it is possible that 717 // the SCP finishes, thus removes the server node for this region server, before the TRSP wakes 718 // up and enter here to remove the region node from the server node, then we will get a null 719 // server node here. 720 if (serverNode != null) { 721 serverNode.removeRegion(regionNode); 722 } 723 } 724 725 // ========================================================================== 726 // ToString helpers 727 // ========================================================================== 728 public static String regionNamesToString(final Collection<byte[]> regions) { 729 final StringBuilder sb = new StringBuilder(); 730 final Iterator<byte[]> it = regions.iterator(); 731 sb.append("["); 732 if (it.hasNext()) { 733 sb.append(Bytes.toStringBinary(it.next())); 734 while (it.hasNext()) { 735 sb.append(", "); 736 sb.append(Bytes.toStringBinary(it.next())); 737 } 738 } 739 sb.append("]"); 740 return sb.toString(); 741 } 742}