@Override
    public void visitRegionState(Result result, final RegionInfo regionInfo, final State state,
      final ServerName regionLocation, final ServerName lastHost, final long openSeqNum) {
      if (
        state == null && regionLocation == null && lastHost == null
          && openSeqNum == SequenceId.NO_SEQUENCE_ID
      ) {
        // This is a row with nothing in it.
        LOG.warn("Skipping empty row={}", result);
        return;
      }
      State localState = state;
      if (localState == null) {
        // No region state column data in hbase:meta table! Are I doing a rolling upgrade from
        // hbase1 to hbase2? Am I restoring a SNAPSHOT or otherwise adding a region to hbase:meta?
        // In any of these cases, state is empty. For now, presume OFFLINE but there are probably
        // cases where we need to probe more to be sure this correct; TODO informed by experience.
        LOG.info(regionInfo.getEncodedName() + " regionState=null; presuming " + State.OFFLINE);
        localState = State.OFFLINE;
      }
      RegionStateNode regionNode = regionStates.getOrCreateRegionStateNode(regionInfo);
      // Do not need to lock on regionNode, as we can make sure that before we finish loading
      // meta, all the related procedures can not be executed. The only exception is for meta
      // region related operations, but here we do not load the informations for meta region.
      regionNode.setState(localState);
      regionNode.setLastHost(lastHost);
      regionNode.setRegionLocation(regionLocation);
      regionNode.setOpenSeqNum(openSeqNum);

      // Note: keep consistent with other methods, see region(Opening|Opened|Closing)
      // RIT/ServerCrash handling should take care of the transiting regions.
      if (
        localState.matches(State.OPEN, State.OPENING, State.CLOSING, State.SPLITTING, State.MERGING)
      ) {
        assert regionLocation != null : "found null region location for " + regionNode;
        // TODO: this could lead to some orphan server state nodes, as it is possible that the
        // region server is already dead and its SCP has already finished but we have
        // persisted an opening state on this region server. Finally the TRSP will assign the
        // region to another region server, so it will not cause critical problems, just waste
        // some memory as no one will try to cleanup these orphan server state nodes.
        regionStates.createServer(regionLocation);
        regionStates.addRegionToServer(regionNode);
      } else if (localState == State.OFFLINE || regionInfo.isOffline()) {
        regionStates.addToOfflineRegions(regionNode);
      }
      if (regionNode.getProcedure() != null) {
        regionNode.getProcedure().stateLoaded(AssignmentManager.this, regionNode);
      }
    }
Create assign procedure for offline regions. Just follow the old
processofflineServersWithOnlineRegions method. Since now we do not need to deal with dead
server any more, we only deal with the regions in OFFLINE state in this method. And this is a
bit strange, that for new regions, we will add it in CLOSED state instead of OFFLINE state, and
usually there will be a procedure to track them. The processofflineServersWithOnlineRegions is
a legacy from long ago, as things are going really different now, maybe we do not need this
method any more. Need to revisit later.
hbase-server/src/main/java/org/apache/hadoop/hbase/master/assignment/AssignmentManager.java