Tpl Dataflow (ISourceBlock) – Part 3
the previous post discus the concept ITargetBlock
which is the TDF consumer contract.
this post will focus on the source block which is the producer contract.
as mention in previous post, sources and targets engage in a protocol for transferring messages between them.
the source block main responsibility is to produce (or manipulate) data which will be consume by the target.
as we learn in previous post the target may consume the data either directly (push) or indirectly (pull).
a target can be attached to source using the ISourceBlock<T> LinkTo method :
link to provide the ability to link one or more targets to a source, this is how we can build a Dataflow network.
when target is linked to sources the sources automatically propagate any data they contain to targets (asynchronously upon the source distribution strategy).
Detaching linked target from a source:
the LinkTo method returns a IDisposable which can be use to detach the target from the source (at nay time).
actually we can dynamically change the Dataflow network at runtime while attaching and detaching blocks.
When source push data to a target, the protocol employed may allow the target to simply accept and take ownership on the offered data, or it may require the target to communicate back to the source (pull).
see the previous post for more details.
when a target is pulling data out of one or more sources it may have to ensure that the data does not simultaneously consumed by other targets.
it is getting even more complicate when a target try to atomically consume messages from multiple sources (which mean either succeeding to consume all messages on none).
by using the two-phase commit protocol the target can atomically consume multiple messages (from one or more sources).
the ISourceBlock<T> define the following methods in order to enable two-phase commit protocol:
- ConsumeMeassage (commit)
- ReserveMessage (prepare)
- ReleaseMessage (roll-back)
Two-phase commit in action:
when target want to atomically consume messages from one or more sources:
- it try to reserve the messages on each source (the message header has the message identifier).
- if it failed to reserve one of the messages, it should release other reservation using ReleaseResarvation (roll back).
- if all reservation succeed it can safely consume the messages, using ConsumeMessage (commit).
even without two-phase commit, the ConsumeMessage design to handle race condition.
when ever we call the consume message, the source block assign the consume message’s messageConsumed out parameter to indicate whether the consume operation has succeed. this way the source can ensure that the message will be consume by a single target and avoid race conditions.
using the TDF source and target contract we can apply push and pulling strategy while avoiding race condition.
in the following posts I will speak about the blocks house keeping contract and propagating.