In computer science, concurrency refers to the ability of different parts of a program, algorithm, or problem to be executed out of order or in partial order, without affecting the final result. Calculations (operations) can be executed on multiple processors, or executed on physically or virtually separate processors in different execution threads. A number of mathematical models have been developed for computations of concurrency in general including Petri nets, Calculi processes, the parallel random access machine model, the Actor Model and the Reo Language.
The Massa system is built mostly around message-passing. This involves bi-directional communication between components on bounded channels, which comes with a risk of deadlock. To manage this risk, a distinction is made between two types of messages:
- Events – Examples are: NetworkEvent, and ProtocolEvent. These are
messages that can be dropped if they haven’t been received, or added to the channel buffer, before a timeout. Care should be taken to ensure that dropping one of these does not result in livelock.
- Commands – Examples are: ProtocolCommand and NetworkCommand. Those
cannot be dropped.
How is deadlock prevented?
A deadlock occurs when two user processes each have a lock on a separate data page, index page, partition, row, or table and each wants to acquire a lock on the page, row, partition, or table locked by the other process.
When this happens, the first process is waiting for the second to release the lock, but the second process will not release it until the lock held by the first process is released.
In Massa , when two components communicate with each other, one of these channels should be using _Command type of messages, and the other _Event. This ensures that if both channels are full, _Event messages will start being dropped, ensuring that the _Command messages are handled and the system does not deadlock.
What risks are left?
First, dropping _Event messages could inadvertently result in the system not being able to make progress, a so-called livelock. Secondly, care should be taken not to introduce dependencies on _Command type of messages between components, even indirectly. For example, two components should not send each other _Command, not even indirectly via another, or multiple other, component(s).
If a component has a relationship with another by sending _Command type of messages than the receiving component cannot block on the sender, which means that it cannot send _Command type of messages to it, even indirectly via another, or several other, component(s).
- Network cannot block on Protocol, Bootstrap, and Massa-node, blocks on Node(s).
- Protocol cannot block on Consensus and Pool, blocks on Network.
- Pool cannot block on Consensus and Massa-node, blocks on Protocol.
- Consensus cannot block on Bootstrap and Massa-node, blocks on Protocol, Pool.
- API blocks on Massa-node.
- Massa-node cannot block on API, blocks on Consensus, Pool, and Network.