@Override
 public GlobalProperties computeGlobalProperties(GlobalProperties gProps) {
   if (gProps.getUniqueFieldCombination() != null
       && gProps.getUniqueFieldCombination().size() > 0
       && gProps.getPartitioning() == PartitioningProperty.RANDOM_PARTITIONED) {
     gProps.setAnyPartitioning(gProps.getUniqueFieldCombination().iterator().next().toFieldList());
   }
   gProps.clearUniqueFieldCombinations();
   return gProps;
 }
  protected void instantiateCandidate(
      OperatorDescriptorSingle dps,
      Channel in,
      List<Set<? extends NamedChannel>> broadcastPlanChannels,
      List<PlanNode> target,
      CostEstimator estimator,
      RequestedGlobalProperties globPropsReq,
      RequestedLocalProperties locPropsReq) {
    final PlanNode inputSource = in.getSource();

    for (List<NamedChannel> broadcastChannelsCombination :
        Sets.cartesianProduct(broadcastPlanChannels)) {

      boolean validCombination = true;
      boolean requiresPipelinebreaker = false;

      // check whether the broadcast inputs use the same plan candidate at the branching point
      for (int i = 0; i < broadcastChannelsCombination.size(); i++) {
        NamedChannel nc = broadcastChannelsCombination.get(i);
        PlanNode bcSource = nc.getSource();

        // check branch compatibility against input
        if (!areBranchCompatible(bcSource, inputSource)) {
          validCombination = false;
          break;
        }

        // check branch compatibility against all other broadcast variables
        for (int k = 0; k < i; k++) {
          PlanNode otherBcSource = broadcastChannelsCombination.get(k).getSource();

          if (!areBranchCompatible(bcSource, otherBcSource)) {
            validCombination = false;
            break;
          }
        }

        // check if there is a common predecessor and whether there is a dam on the way to all
        // common predecessors
        if (in.isOnDynamicPath() && this.hereJoinedBranches != null) {
          for (OptimizerNode brancher : this.hereJoinedBranches) {
            PlanNode candAtBrancher = in.getSource().getCandidateAtBranchPoint(brancher);

            if (candAtBrancher == null) {
              // closed branch between two broadcast variables
              continue;
            }

            SourceAndDamReport res = in.getSource().hasDamOnPathDownTo(candAtBrancher);
            if (res == NOT_FOUND) {
              throw new CompilerException("Bug: Tracing dams for deadlock detection is broken.");
            } else if (res == FOUND_SOURCE) {
              requiresPipelinebreaker = true;
              break;
            } else if (res == FOUND_SOURCE_AND_DAM) {
              // good
            } else {
              throw new CompilerException();
            }
          }
        }
      }

      if (!validCombination) {
        continue;
      }

      if (requiresPipelinebreaker) {
        in.setTempMode(in.getTempMode().makePipelineBreaker());
      }

      final SingleInputPlanNode node = dps.instantiate(in, this);
      node.setBroadcastInputs(broadcastChannelsCombination);

      // compute how the strategy affects the properties
      GlobalProperties gProps = in.getGlobalProperties().clone();
      LocalProperties lProps = in.getLocalProperties().clone();
      gProps = dps.computeGlobalProperties(gProps);
      lProps = dps.computeLocalProperties(lProps);

      // filter by the user code field copies
      gProps =
          gProps.filterBySemanticProperties(getSemanticPropertiesForGlobalPropertyFiltering(), 0);
      lProps =
          lProps.filterBySemanticProperties(getSemanticPropertiesForLocalPropertyFiltering(), 0);

      // apply
      node.initProperties(gProps, lProps);
      node.updatePropertiesWithUniqueSets(getUniqueFields());
      target.add(node);
    }
  }