protected List chooseDatanodesInternal()

in hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/placement/algorithms/SCMContainerPlacementRackAware.java [104:258]


  protected List<DatanodeDetails> chooseDatanodesInternal(
      List<DatanodeDetails> usedNodes,
      List<DatanodeDetails> excludedNodes,
      List<DatanodeDetails> favoredNodes, int nodesRequired,
      long metadataSizeRequired, long dataSizeRequired)
      throws SCMException {
    Map<String, Long> mapSizeRequired = new HashMap<>();
    mapSizeRequired.put(META_DATA_SIZE_REQUIRED, metadataSizeRequired);
    mapSizeRequired.put(DATA_SIZE_REQUIRED, dataSizeRequired);

    if (!usedNodesPassed(usedNodes)) {
      // If interface is called without used nodes
      // In this case consider only exclude nodes to determine racks
      return chooseDatanodesInternalLegacy(excludedNodes,
          favoredNodes, nodesRequired, mapSizeRequired);
    }
    Preconditions.checkArgument(nodesRequired > 0);
    metrics.incrDatanodeRequestCount(nodesRequired);
    int datanodeCount = networkTopology.getNumOfLeafNode(NetConstants.ROOT);
    int excludedNodesCount = excludedNodes == null ? 0 : excludedNodes.size();
    int usedNodesCount = usedNodes == null ? 0 : usedNodes.size();
    if (datanodeCount < nodesRequired + excludedNodesCount + usedNodesCount) {
      throw new SCMException("No enough datanodes to choose. " +
          "TotalNode = " + datanodeCount + " RequiredNode = " + nodesRequired +
          " ExcludedNode = " + excludedNodesCount +
          " UsedNode = " + usedNodesCount, null);
    }
    List<DatanodeDetails> mutableFavoredNodes = favoredNodes;
    // sanity check of favoredNodes
    if (mutableFavoredNodes != null && excludedNodes != null) {
      mutableFavoredNodes = new ArrayList<>();
      mutableFavoredNodes.addAll(favoredNodes);
      mutableFavoredNodes.removeAll(excludedNodes);
    }
    int favoredNodeNum = mutableFavoredNodes == null ? 0 :
        mutableFavoredNodes.size();
    List<DatanodeDetails> chosenNodes = new ArrayList<>();
    List<DatanodeDetails> mutableUsedNodes = new ArrayList<>();
    mutableUsedNodes.addAll(usedNodes);
    List<DatanodeDetails> mutableExcludedNodes = new ArrayList<>();
    if (excludedNodes != null) {
      mutableExcludedNodes.addAll(excludedNodes);
    }
    DatanodeDetails favoredNode;
    int favorIndex = 0;
    if (mutableUsedNodes.isEmpty()) {
      // choose all nodes for a new pipeline case
      // choose first datanode from scope ROOT or from favoredNodes if not null
      favoredNode = favoredNodeNum > favorIndex ?
          mutableFavoredNodes.get(favorIndex) : null;
      DatanodeDetails firstNode;
      if (favoredNode != null) {
        firstNode = favoredNode;
        favorIndex++;
      } else {
        firstNode = chooseNode(mutableExcludedNodes, null,
            null, metadataSizeRequired,
            dataSizeRequired);
      }
      chosenNodes.add(firstNode);
      nodesRequired--;
      if (nodesRequired == 0) {
        return Arrays.asList(chosenNodes.toArray(new DatanodeDetails[0]));
      }
      // choose second datanode on the same rack as first one
      favoredNode = favoredNodeNum > favorIndex ?
          mutableFavoredNodes.get(favorIndex) : null;
      DatanodeDetails secondNode;
      if (favoredNode != null &&
          networkTopology.isSameParent(firstNode, favoredNode)) {
        secondNode = favoredNode;
        favorIndex++;
      } else {
        mutableExcludedNodes.add(firstNode);
        secondNode = chooseNode(mutableExcludedNodes, Arrays.asList(firstNode),
            Arrays.asList(firstNode), metadataSizeRequired, dataSizeRequired);
      }
      chosenNodes.add(secondNode);
      nodesRequired--;
      if (nodesRequired == 0) {
        return Arrays.asList(chosenNodes.toArray(new DatanodeDetails[0]));
      }
      mutableUsedNodes.addAll(chosenNodes);
      // choose remaining datanodes on different rack as first and second
      mutableExcludedNodes.add(secondNode);
    } else {
      // choose node to meet replication requirement
      // case 1: one used node, choose one on the same rack as the used
      // node, choose others on different racks.
      if (mutableUsedNodes.size() == 1) {
        favoredNode = favoredNodeNum > favorIndex ?
            mutableFavoredNodes.get(favorIndex) : null;
        DatanodeDetails firstNode;
        if (favoredNode != null &&
            networkTopology.isSameParent(mutableUsedNodes.get(0),
            favoredNode)) {
          firstNode = favoredNode;
          favorIndex++;
        } else {
          firstNode = chooseNode(mutableExcludedNodes, mutableUsedNodes,
              mutableUsedNodes, metadataSizeRequired, dataSizeRequired);
        }
        chosenNodes.add(firstNode);
        nodesRequired--;
        if (nodesRequired == 0) {
          return Arrays.asList(chosenNodes.toArray(new DatanodeDetails[0]));
        }
        // choose remaining nodes on different racks
        mutableExcludedNodes.add(firstNode);
        mutableExcludedNodes.addAll(mutableUsedNodes);
      } else {
        // case 2: two or more used nodes, if these two nodes are
        // in the same rack, then choose nodes on different racks, otherwise,
        // choose one on the same rack as one of used
        // nodes, remaining chosen
        // are on different racks.
        for (int i = 0; i < usedNodesCount; i++) {
          for (int j = i + 1; j < usedNodesCount; j++) {
            if (networkTopology.isSameParent(
                usedNodes.get(i), usedNodes.get(j))) {
              // choose remaining nodes on different racks
              mutableExcludedNodes.addAll(mutableUsedNodes);
              return chooseNodes(mutableExcludedNodes, chosenNodes,
                  mutableFavoredNodes, mutableUsedNodes, favorIndex,
                  nodesRequired, mapSizeRequired);
            }
          }
        }
        // choose one data on the same rack with one used node
        favoredNode = favoredNodeNum > favorIndex ?
            mutableFavoredNodes.get(favorIndex) : null;
        DatanodeDetails secondNode;
        if (favoredNode != null && networkTopology.isSameParent(
            chosenNodes.get(0), favoredNode)) {
          secondNode = favoredNode;
          favorIndex++;
        } else {
          secondNode =
              chooseNode(mutableExcludedNodes, mutableUsedNodes,
                  mutableUsedNodes, metadataSizeRequired, dataSizeRequired);
        }
        chosenNodes.add(secondNode);
        mutableExcludedNodes.add(secondNode);
        mutableExcludedNodes.addAll(mutableUsedNodes);
        mutableUsedNodes.addAll(chosenNodes);
        nodesRequired--;
        if (nodesRequired == 0) {
          return Arrays.asList(chosenNodes.toArray(new DatanodeDetails[0]));
        }
      }
    }
    // choose remaining nodes on different racks
    return chooseNodes(mutableExcludedNodes, chosenNodes, mutableFavoredNodes,
        mutableUsedNodes, favorIndex, nodesRequired, mapSizeRequired);
  }