CRDT Streams
In Aqua, an ordinary value is a name that points to a single result:
A stream, on the other hand, is a name that points to zero or more results:
Stream is a kind of collection and can be used in place of other collections:
But the most powerful use of streams pertains to their use with parallel execution, which incurs non-determinism.
Streams: Lifecycle And Guarantees
A stream's lifecycle can be separated into three stages:
Source: (Parallel) Writes to a stream
Map: Handles the stream values
Sink: Converts the resulting stream into a scalar
Consider the following example:
In this case, for each peer p
in peers
, a new PeerID
is going to be obtained from the Srv.call
and written into the resp
stream.
Every peer p
in peers does not know anything about how the other iterations proceed.
Once PeerId
is written to the resp
stream, the second for
is triggered. This is the mapping stage.
And then the results are sent to the first peer, to call Op.identity there. This Op.identity waits until element number 5 is defined on resp2
stream.
When the join is complete, the stream is consumed by the concatenation service to produce a scalar value, which is returned.
During execution, involved peers have different views on the state of execution: each of the for
parallel branches has no view or access to the other branches' data and eventually, the execution flows to the initial peer. The initial peer then merges writes to the resp
stream and to the resp2
stream, respectively. These writes are done in a conflict-free fashion. Furthermore, the respective heads of the resp
, resp2
streams will not change from each peer's point of view as they are immutable and new values can only be appended. However, different peers may have a different order of the stream values depending on the order of receiving these values.
Stream restrictions
Restriction is a part of π calculus that bounds (restricts) a name to a scope. For Aqua streams it means that the stream is not accessible outside of definition scope, and the stream is always fresh when execution enters the scope.
These behaviors are introduced in Aqua 0.5.
You still can keep streams as streams by using them as *string
arguments, or by returning them as *string
.
Last updated
Was this helpful?