Class ForkScanner

  • All Implemented Interfaces:
    Iterable<FlowNode>, Iterator<FlowNode>, Filterator<FlowNode>

    @NotThreadSafe
    public class ForkScanner
    extends AbstractFlowScanner
    Scanner that will scan down all forks when we hit parallel blocks before continuing, but generally runs in linear order

    Think of it as the opposite of DepthFirstScanner.

    This is a fairly efficient way to visit all FlowNodes, and provides four useful guarantees:

    • Every FlowNode is visited, and visited EXACTLY ONCE (not true for LinearScanner, which misses some)
    • All parallel branches are visited before we move past the parallel block (not true for DepthFirstScanner)
    • For parallels, we visit branches in reverse order (in fitting with end to start general flow)
    • For EVERY block, the BlockEndNode is visited before the BlockStartNode (not true for DepthFirstScanner, with parallels)

    The big advantages of this approach:

    • Blocks are visited in the order they end (no backtracking) - helps with working a block at a time
    • Points are visited in linear order within a block (easy to use for analysis)
    • Minimal state information needed
    • Branch information is available for use here
    Author:
    Sam Van Oort
    • Method Detail

      • getCurrentType

        @CheckForNull
        public org.jenkinsci.plugins.workflow.graphanalysis.ForkScanner.NodeType getCurrentType()
      • getNextType

        @CheckForNull
        public org.jenkinsci.plugins.workflow.graphanalysis.ForkScanner.NodeType getNextType()
      • reset

        protected void reset()
        Description copied from class: AbstractFlowScanner
        Reset internal state so that we can begin walking a new flow graph Public APIs need to invoke this before searches
        Specified by:
        reset in class AbstractFlowScanner
      • setParallelStartPredicate

        @Deprecated
        public static void setParallelStartPredicate​(@NonNull
                                                     com.google.common.base.Predicate<FlowNode> pred)
        Deprecated.
        Now a complete no-op -- originally this was a workaround for dependency issues with workflow-cps. Specifically, requiring classes from workflow-cps to detect if something is a parallel step.
      • isParallelStart

        public static boolean isParallelStart​(@CheckForNull
                                              FlowNode f)
      • isParallelEnd

        public static boolean isParallelEnd​(@CheckForNull
                                            FlowNode f)
      • isWalkingFromFinish

        public boolean isWalkingFromFinish()
        If true, we are walking from the flow end node and have a complete view of the flow Needed because there are implications when not walking from a finished flow (blocks without a BlockEndNode)
      • getCurrentParallelStartNode

        @CheckForNull
        public FlowNode getCurrentParallelStartNode()
        Return the node that begins the current parallel head, if we are known to be in a parallel block
        Returns:
        The FlowNode that marks current parallel start
      • getParallelDepth

        public int getParallelDepth()
        Return number of levels deep we are in parallel blocks
      • next

        protected FlowNode next​(@NonNull
                                FlowNode current,
                                @NonNull
                                Collection<FlowNode> blackList)
        Description copied from class: AbstractFlowScanner
        Actual meat of the iteration, get the next node to visit, using and updating state as needed
        Specified by:
        next in class AbstractFlowScanner
        Parameters:
        current - Current node to use in generating next value
        blackList - Nodes that are not eligible for visiting
        Returns:
        Next node to visit, or null if we've exhausted the node list