This visitor's callbacks are invoked as we walk through a pipeline flow graph, and it splits it into chunks.
A
ForkScanner#visitSimpleChunks(SimpleChunkVisitor,ChunkFinder) creates these FlowChunks using a
ChunkFinder to define the chunk boundaries.
We walk through the
FlowNodes in reverse order from end to start, so end callbacks are invoked before
their corresponding start callbacks.
Callback types
There are two kinds of callbacks - chunk callbacks, and parallel structure callbacks
Chunk Callbacks:
-
#chunkStart(FlowNode,FlowNode,ForkScanner) - detected the start of a chunk beginning with a node
-
#chunkEnd(FlowNode,FlowNode,ForkScanner) - detected the end of a chunk, terminating with a node
-
#atomNode(FlowNode,FlowNode,FlowNode,ForkScanner) - most nodes, which aren't boundaries of chunks
Chunk callback rules:
- For a single node, it may have EITHER OR BOTH chunkStart and chunkEnd events
- Every node that doesn't get a startChunk/endChunk callback gets an atomNode callback.
- For
ChunkFinder implementations that match the
BlockStartNode and
BlockEndNode should never have both for a single node.
- You cannot have multiple of any of the same specific type of callbacks for the same flownode
- You cannot have a atomNode callback AND a start/end for the same flownode (application of the above).
Parallel Structure Callbacks: Zero, One, or (in niche cases) several different ones may be invoked for any given FlowNode
These are used to provide awareness of parallel/branching structures if they need special handling.
-
#parallelStart(FlowNode,FlowNode,ForkScanner)
-
#parallelEnd(FlowNode,FlowNode,ForkScanner)
-
#parallelBranchStart(FlowNode,FlowNode,ForkScanner)
-
#parallelBranchEnd(FlowNode,FlowNode,ForkScanner)
The cases where a node triggers multiple callbacks are where it is one of several forked branches of an incomplete parallel
block. In this case it can be a parallelBranchEnd, also potentially a parallelEnd, plus whatever role that node might normally
have (such as the start of another parallel).
Implementations get to decide how to use and handle chunks, and should be stateful.
At a minimum they should handle:
- Cases where there is no enclosing chunk (no start/end found, or outside a chunk)
- Cases where there is no chunk end to match the start, because we haven't finished running a block
- Nesting of chunks