Package eu.stratosphere.compiler.deadlockdetect

Source Code of eu.stratosphere.compiler.deadlockdetect.DeadlockPreventer

/***********************************************************************************************************************
* Copyright (C) 2010-2013 by the Stratosphere project (http://stratosphere.eu)
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
**********************************************************************************************************************/

package eu.stratosphere.compiler.deadlockdetect;

import java.util.ArrayList;
import java.util.List;

import eu.stratosphere.compiler.plan.BulkIterationPlanNode;
import eu.stratosphere.compiler.plan.DualInputPlanNode;
import eu.stratosphere.compiler.plan.PlanNode;
import eu.stratosphere.compiler.plan.SingleInputPlanNode;
import eu.stratosphere.compiler.plan.WorksetIterationPlanNode;
import eu.stratosphere.pact.runtime.task.DamBehavior;
import eu.stratosphere.pact.runtime.task.DriverStrategy;
import eu.stratosphere.util.Visitor;

/**
*   Certain pipelined flows may lead to deadlocks, in which case we need to make sure the pipelines are broken or made elastic enough to prevent that.
*
*  This is only relevat to pipelined data flows where one operator has more than one consumers (successors in the flow).
*  Most cases are caught by the general logic that deals with branching/joining flows. The following cases need additional checks:
*
*                    <build>
*  (source1) ------ (join)
*            \    /    <probe>
*             \  /
*              \/
*              /\
*             /  \
*            /    \    <probe>
*  (source2) ------(join)
*                      <build>
*  Since both sources pipeline their data into a build and a probe side, they get stalled by the back pressure from the probe side (which waits for the build side to complete) and never finish the build side.
*  We can model dependencies of pipelined / materialized connections and do a reguar cyclic dependencies check to detect such situations. Pipelined connections have a dependency from sender to receiver, non-pipelined (fully dammed) connections have a dependency from receiver to sender.
*
*/
public class DeadlockPreventer implements Visitor<PlanNode> {
 
  private DeadlockGraph g;
 
  public DeadlockPreventer() {
    this.g = new DeadlockGraph();
  }

  public void resolveDeadlocks(List<? extends PlanNode> sinks) {

    for(PlanNode s : sinks) {
      s.accept(this);
    }
    if(g.hasCycle()) {
     
      // in the remaining plan is a cycle
      for(DeadlockVertex v : g.vertices) {

        // first strategy to fix -> swap build and probe side
        if(v.getOriginal().getDriverStrategy().equals(DriverStrategy.HYBRIDHASH_BUILD_FIRST)) {

          v.getOriginal().setDriverStrategy(DriverStrategy.HYBRIDHASH_BUILD_SECOND);
         
          if(hasDeadlock(sinks)) {
            // Didn't fix anything -> revert
            v.getOriginal().setDriverStrategy(DriverStrategy.HYBRIDHASH_BUILD_FIRST);
          }
          else {
            // deadlock resolved
            break;
          }
        }
       
        // other direction
        if(v.getOriginal().getDriverStrategy().equals(DriverStrategy.HYBRIDHASH_BUILD_SECOND)) {
         
          v.getOriginal().setDriverStrategy(DriverStrategy.HYBRIDHASH_BUILD_FIRST);
         
          if(hasDeadlock(sinks)) {
            // Didn't fix anything -> revert
            v.getOriginal().setDriverStrategy(DriverStrategy.HYBRIDHASH_BUILD_SECOND);
          }
          else {
            // deadlock resolved
            break;
          }
        }
      }
     
      // switching build and probe side did not help -> pipeline breaker
      for(DeadlockVertex v : g.vertices) {
        if(v.getOriginal() instanceof DualInputPlanNode) {
          DualInputPlanNode n = (DualInputPlanNode) v.getOriginal();
         
          // what is the pipelined side? (other side should be a dam, otherwise operator could not be source of deadlock)
          if(!(n.getDriverStrategy().firstDam().equals(DamBehavior.FULL_DAM) || n.getInput1().getLocalStrategy().dams() || n.getInput1().getTempMode().breaksPipeline())
              && (n.getDriverStrategy().secondDam().equals(DamBehavior.FULL_DAM) || n.getInput2().getLocalStrategy().dams() || n.getInput2().getTempMode().breaksPipeline())) {
            n.getInput1().setTempMode(n.getInput1().getTempMode().makePipelineBreaker());
          }
          else if( !(n.getDriverStrategy().secondDam().equals(DamBehavior.FULL_DAM) || n.getInput2().getLocalStrategy().dams() || n.getInput2().getTempMode().breaksPipeline())
              && (n.getDriverStrategy().firstDam().equals(DamBehavior.FULL_DAM) || n.getInput1().getLocalStrategy().dams() || n.getInput1().getTempMode().breaksPipeline())) {
            n.getInput2().setTempMode(n.getInput2().getTempMode().makePipelineBreaker());
          }
         
          // Deadlock resolved?
          if(!hasDeadlock(sinks)) {
            break;
          }
        }
      }
    }
 
  }
 
  /**
   * Creates new DeadlockGraph from plan and checks for cycles
   *
   * @param plan
   * @return
   */
  public boolean hasDeadlock(List<? extends PlanNode> sinks) {
    this.g = new DeadlockGraph();
   
    for(PlanNode s : sinks) {
      s.accept(this);
    }
   
    if(g.hasCycle()) {
      return true;
    } else {
      return false;
    }
  }

  /**
   *
   * @param visitable
   * @return
   */
  @Override
  public boolean preVisit(PlanNode visitable) {
   
    g.addVertex(visitable);
    return true;
  }

  @Override
  public void postVisit(PlanNode visitable) {
    if(visitable instanceof SingleInputPlanNode) {
      SingleInputPlanNode n = (SingleInputPlanNode) visitable;
     
      if(n.getDriverStrategy().firstDam().equals(DamBehavior.FULL_DAM) || n.getInput().getLocalStrategy().dams() || n.getInput().getTempMode().breaksPipeline()) {
        g.addEdge(n, n.getPredecessor());
      }
      else {
        g.addEdge(n.getPredecessor(), n);
      }
    }
    else if(visitable instanceof DualInputPlanNode) {
      DualInputPlanNode n = (DualInputPlanNode) visitable;
     
      if(n.getDriverStrategy().firstDam().equals(DamBehavior.FULL_DAM) || n.getInput1().getLocalStrategy().dams() || n.getInput1().getTempMode().breaksPipeline()) {
        g.addEdge(n, n.getInput1().getSource());
      }
      else {
        g.addEdge(n.getInput1().getSource(), n);
      }
     
      if(!n.getDriverStrategy().equals(DriverStrategy.NONE) && (n.getDriverStrategy().secondDam().equals(DamBehavior.FULL_DAM) || n.getInput2().getLocalStrategy().dams() || n.getInput2().getTempMode().breaksPipeline())) {
        g.addEdge(n, n.getInput2().getSource());
      }
      else {
        g.addEdge(n.getInput2().getSource(), n);
      }
    }
   
   
    // recursively fix iterations
    if (visitable instanceof BulkIterationPlanNode) {
     
      DeadlockPreventer dp = new DeadlockPreventer();
      List<PlanNode> planSinks = new ArrayList<PlanNode>(1);
     
      BulkIterationPlanNode pspn = (BulkIterationPlanNode) visitable;
      planSinks.add(pspn.getRootOfStepFunction());
     
      dp.resolveDeadlocks(planSinks);
     
    }
    else if (visitable instanceof WorksetIterationPlanNode) {
     
      DeadlockPreventer dp = new DeadlockPreventer();
      List<PlanNode> planSinks = new ArrayList<PlanNode>(2);
     
      WorksetIterationPlanNode pspn = (WorksetIterationPlanNode) visitable;
      planSinks.add(pspn.getSolutionSetDeltaPlanNode());
      planSinks.add(pspn.getNextWorkSetPlanNode());
     
      dp.resolveDeadlocks(planSinks);
     
    }
  }
}
TOP

Related Classes of eu.stratosphere.compiler.deadlockdetect.DeadlockPreventer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.