public void start() throws IOException, KeeperException {
    if (!running.compareAndSet(false, true)) {
      return;
    }

    LOG.trace("Starting assignment manager");

    // Start the Assignment Thread
    startAssignmentThread();
    // load meta region states.
    // here we are still in the early steps of active master startup. There is only one thread(us)
    // can access AssignmentManager and create region node, so here we do not need to lock the
    // region node.
    try (ResultScanner scanner =
      masterRegion.getScanner(new Scan().addFamily(HConstants.CATALOG_FAMILY))) {
      for (;;) {
        Result result = scanner.next();
        if (result == null) {
          break;
        }
        RegionStateStore
          .visitMetaEntry((r, regionInfo, state, regionLocation, lastHost, openSeqNum) -> {
            RegionStateNode regionNode = regionStates.getOrCreateRegionStateNode(regionInfo);
            regionNode.setState(state);
            regionNode.setLastHost(lastHost);
            regionNode.setRegionLocation(regionLocation);
            regionNode.setOpenSeqNum(openSeqNum);
            if (regionNode.getProcedure() != null) {
              regionNode.getProcedure().stateLoaded(this, regionNode);
            }
            if (regionLocation != null) {
              // 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);
            }
            if (RegionReplicaUtil.isDefaultReplica(regionInfo.getReplicaId())) {
              setMetaAssigned(regionInfo, state == State.OPEN);
            }
            LOG.debug("Loaded hbase:meta {}", regionNode);
          }, result);
      }
    }
    mirrorMetaLocations();
  }
When the operator uses this configuration option, any version between the current cluster
version and the value of "hbase.min.version.move.system.tables" does not trigger any
auto-region movement. Auto-region movement here refers to auto-migration of system table
regions to newer server versions. It is assumed that the configured range of versions does not
require special handling of moving system table regions to higher versioned RegionServer. This
auto-migration is done by {@link #checkIfShouldMoveSystemRegionAsync()}. Example: Let's assume
the cluster is on version 1.4.0 and we have set "hbase.min.version.move.system.tables" as
"2.0.0". Now if we upgrade one RegionServer on 1.4.0 cluster to 1.6.0 (< 2.0.0), then
AssignmentManager will not move hbase:meta, hbase:namespace and other system table regions to
newly brought up RegionServer 1.6.0 as part of auto-migration. However, if we upgrade one
RegionServer on 1.4.0 cluster to 2.2.0 (> 2.0.0), then AssignmentManager will move all system
table regions to newly brought up RegionServer 2.2.0 as part of auto-migration done by
{@link #checkIfShouldMoveSystemRegionAsync()}. "hbase.min.version.move.system.tables" is
introduced as part of HBASE-22923.
hbase-server/src/main/java/org/apache/hadoop/hbase/master/assignment/AssignmentManager.java