C# (CSharp) Akka.Streams.Implementation.Fusing Namespace

Classes

Name Description
GraphInterpreter INTERNAL API From an external viewpoint, the GraphInterpreter takes an assembly of graph processing stages encoded as a Assembly object and provides facilities to execute and interact with this assembly. The lifecycle of the Interpreter is roughly the following: - Boundary logics are attached via AttachDownstreamBoundary and AttachUpstreamBoundary - Init is called - Execute is called whenever there is need for execution, providing an upper limit on the processed events - Finish is called before the interpreter is disposed, preferably after IsCompleted returned true, although in abort cases this is not strictly necessary The Execute method of the interpreter accepts an upper bound on the events it will process. After this limit is reached or there are no more pending events to be processed, the call returns. It is possible to inspect if there are unprocessed events left via the IsSuspended method. IsCompleted returns true once all stages reported completion inside the interpreter. The internal architecture of the interpreter is based on the usage of arrays and optimized for reducing allocations on the hot paths. One of the basic abstractions inside the interpreter is the notion of connection. In the abstract sense a connection represents an output-input port pair (an analogue for a connected RS Publisher-Subscriber pair), while in the practical sense a connection is a number which represents slots in certain arrays. In particular - portStates contains a bitfield that tracks the states of the ports (output-input) corresponding to this connection. This bitfield is used to decode the event that is in-flight. - connectionSlots is a mapping from a connection id to a potential element or exception that accompanies the event encoded in the portStates bitfield - inHandlers is a mapping from a connection id to the InHandlers instance that handles the events corresponding to the input port of the connection - outHandlers is a mapping from a connection id to the OutHandlers instance that handles the events corresponding to the output port of the connection On top of these lookup tables there is an eventQueue, represented as a circular buffer of integers. The integers it contains represents connections that have pending events to be processed. The pending event itself is encoded in the portStates bitfield. This implies that there can be only one event in flight for a given connection, which is true in almost all cases, except a complete-after-push or fail-after-push. The layout of the portStates bitfield is the following: |- state machn.-| Only one bit is hot among these bits 64 32 16 | 8 4 2 1 | +---+---+---|---+---+---+---| | | | | | | | | | | | | | | From the following flags only one is active in any given time. These bits encode | | | | | | | state machine states, and they are "moved" around using XOR masks to keep other bits | | | | | | | intact. | | | | | | | | | | | | | +- InReady: The input port is ready to be pulled | | | | | +----- Pulling: A pull is active, but have not arrived yet (queued) | | | | +--------- Pushing: A push is active, but have not arrived yet (queued) | | | +------------- OutReady: The output port is ready to be pushed | | | | | +----------------- InClosed: The input port is closed and will not receive any events. | | A push might be still in flight which will be then processed first. | +--------------------- OutClosed: The output port is closed and will not receive any events. +------------------------- InFailed: Always set in conjunction with InClosed. Indicates that the close event is a failure Sending an event is usually the following sequence: - An action is requested by a stage logic (push, pull, complete, etc.) - the state machine in portStates is transitioned from a ready state to a pending event - the id of the affected connection is enqueued Receiving an event is usually the following sequence: - id of connection to be processed is dequeued - the type of the event is determined from the bits set on portStates - the state machine in portStates is transitioned to a ready state - using the inHandlers/outHandlers table the corresponding callback is called on the stage logic. Because of the FIFO construction of the queue the interpreter is fair, i.e. a pending event is always executed after a bounded number of other events. This property, together with suspendability means that even infinite cycles can be modeled, or even dissolved (if preempted and a "stealing" external event is injected; for example the non-cycle edge of a balance is pulled, dissolving the original cycle).
GraphInterpreter.DownstreamBoundaryStageLogic
GraphInterpreter.Empty Marker object that indicates that a port holds no element since it was already grabbed. The port is still pullable, but there is no more element to grab.
GraphInterpreter.Failed
GraphInterpreter.UpstreamBoundaryStageLogic