private void assignEndpoints(
      Collection<DrillbitEndpoint> allNodes,
      PlanningSet planningSet,
      int globalMaxWidth,
      int maxWidthPerEndpoint)
      throws PhysicalOperatorSetupException {
    // First we determine the amount of parallelization for a fragment. This will be between 1 and
    // maxWidth based on
    // cost. (Later could also be based on cluster operation.) then we decide endpoints based on
    // affinity (later this
    // could be based on endpoint load)
    for (Wrapper wrapper : planningSet) {

      Stats stats = wrapper.getStats();

      // figure out width.
      int width = Math.min(stats.getMaxWidth(), globalMaxWidth);
      float diskCost = stats.getDiskCost();
      //      logger.debug("Frag max width: {} and diskCost: {}", stats.getMaxWidth(), diskCost);

      // TODO: right now we'll just assume that each task is cost 1 so we'll set the breadth at the
      // lesser of the number
      // of tasks or the maximum width of the fragment.
      if (diskCost < width) {
        //        width = (int) diskCost;
      }

      width = Math.min(width, maxWidthPerEndpoint * allNodes.size());

      if (width < 1) width = 1;
      //      logger.debug("Setting width {} on fragment {}", width, wrapper);
      wrapper.setWidth(width);
      // figure out endpoint assignments. also informs the exchanges about their respective
      // endpoints.
      wrapper.assignEndpoints(allNodes);
    }
  }