public CreateRegionGroupsPlan genRegionGroupsAllocationPlan(
      final Map<String, Integer> allotmentMap, final TConsensusGroupType consensusGroupType)
      throws NotEnoughDataNodeException, DatabaseNotExistsException {

    // Some new RegionGroups will have to occupy unknown DataNodes
    // if the number of online DataNodes is insufficient
    final List<TDataNodeConfiguration> availableDataNodes =
        getNodeManager().filterDataNodeThroughStatus(NodeStatus.Running, NodeStatus.Unknown);

    // Make sure the number of available DataNodes is enough for allocating new RegionGroups
    for (final String database : allotmentMap.keySet()) {
      final int replicationFactor =
          getClusterSchemaManager().getReplicationFactor(database, consensusGroupType);
      if (availableDataNodes.size() < replicationFactor) {
        throw new NotEnoughDataNodeException(availableDataNodes, replicationFactor);
      }
    }

    final CreateRegionGroupsPlan createRegionGroupsPlan = new CreateRegionGroupsPlan();
    // Only considering the specified ConsensusGroupType when doing allocation
    final List<TRegionReplicaSet> allocatedRegionGroups =
        getPartitionManager().getAllReplicaSets(consensusGroupType);

    for (final Map.Entry<String, Integer> entry : allotmentMap.entrySet()) {
      final String database = entry.getKey();
      final int allotment = entry.getValue();
      final int replicationFactor =
          getClusterSchemaManager().getReplicationFactor(database, consensusGroupType);
      // Only considering the specified Database when doing allocation
      final List<TRegionReplicaSet> databaseAllocatedRegionGroups =
          getPartitionManager().getAllReplicaSets(database, consensusGroupType);

      for (int i = 0; i < allotment; i++) {
        // Prepare input data
        final Map<Integer, TDataNodeConfiguration> availableDataNodeMap =
            new HashMap<>(availableDataNodes.size());
        final Map<Integer, Double> freeDiskSpaceMap = new HashMap<>(availableDataNodes.size());
        availableDataNodes.forEach(
            dataNodeConfiguration -> {
              int dataNodeId = dataNodeConfiguration.getLocation().getDataNodeId();
              availableDataNodeMap.put(dataNodeId, dataNodeConfiguration);
              freeDiskSpaceMap.put(dataNodeId, getLoadManager().getFreeDiskSpace(dataNodeId));
            });

        // Generate allocation plan
        final TRegionReplicaSet newRegionGroup =
            regionGroupAllocator.generateOptimalRegionReplicasDistribution(
                availableDataNodeMap,
                freeDiskSpaceMap,
                allocatedRegionGroups,
                databaseAllocatedRegionGroups,
                replicationFactor,
                new TConsensusGroupId(
                    consensusGroupType, getPartitionManager().generateNextRegionGroupId()));
        createRegionGroupsPlan.addRegionGroup(database, newRegionGroup);

        // Mark the new RegionGroup as allocated
        allocatedRegionGroups.add(newRegionGroup);
        databaseAllocatedRegionGroups.add(newRegionGroup);
      }
    }

    return createRegionGroupsPlan;
  }
Generate a RegionGroups' allocation plan({@link CreateRegionGroupsPlan})

@param allotmentMap Map<DatabaseName, RegionGroup allotment>
@param consensusGroupType {@link TConsensusGroupType} of the new RegionGroups
@return CreateRegionGroupsPlan
@throws NotEnoughDataNodeException When the number of DataNodes is not enough for allocation
@throws DatabaseNotExistsException When some StorageGroups don't exist
iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/load/balancer/RegionBalancer.java