#channel #synchronization #message #dispatch

clocked-dispatch

Provides a clocked message dispatch service

16 stable releases (4 major)

4.0.1 Jan 30, 2017
4.0.0 Oct 25, 2016
3.0.1 Jul 21, 2016
2.1.3 May 3, 2016
0.1.0 Apr 25, 2016

#90 in Concurrency

Download history 34/week @ 2018-06-17 18/week @ 2018-06-24 223/week @ 2018-07-01 17/week @ 2018-07-08 51/week @ 2018-07-22 34/week @ 2018-07-29 97/week @ 2018-08-05 51/week @ 2018-08-12 17/week @ 2018-08-26 27/week @ 2018-09-02

74 downloads per month

MIT/Apache

54KB
635 lines

Clocked dispatch service in Rust

Crates.io Documentation Build Status

This Rust crate provides a clocked message dispatch service. Clocked dispatch is, at its heart, simply a set of channels. The difference is that each channel is aware of how many messages the system as a whole has processed. This can be useful to have different threads know how up-to-date another thread is.

For example, say a message m is sent to some receiver r. Another receiver r' who does not receive m will still be made aware that one message has been dispatched when it does a subsequent read.

To help illustrate why this is useful, consider two channel pairs, one between s1 and r1, and one between s2 and r2. Assume that r1 and r2 occasionally need to communicate. However, they want to wait until the other has seen any updates preceding those that they have received. Say that r1 has seen 7 updates, but r2 has not seen any. Is r2 sufficiently up-to-date? Well, it could be -- all the channel sends in the system could have been for r1!

Clocked dispatch simplifies by introducing a shared dispatcher that assigns monotonically increasing sequence numbers to all messages. It looks something like this:

  s1       s2
   +---+----+
       |
       + dispatcher
       |
   +---+----+
  r1       r2

When s1 wishes send a message m to r1, it instead sends m to the dispatcher. The dispatcher assigns a sequence number to m, forwards it to r1, and then sends a clock update to r2. This clock update allows r2, in the scenario described above, to see that 7 updates have passed it by, telling it that it has seen all the updated that r1 has seen.

The dispatcher introduces another subtle problem. Specifically, if r2 is slow to accept updates, it could block the dispatcher when it tries to send clock updates. To avoid this, the library implements a custom channel that conveys these sequence numbers without blocking the sender. Blocking will still happen if a message is being sent, but timestamp updates will not block the dispatcher. This means that s1.send(v) will not block even though r2 is not currently reading from its input channel.

Clocked dispatch instances can be composed by using forward instead of send for messages that have already been assigned a sequence number. The library ensures that such messages are delivered in-order, by delaying the delivery of messages until it can guarantee that no earlier messages will later arrive. See the crate documentation for details about this mode of operation.

TODOs

  • Avoid one slow path in the graph blocking sends through independent paths. This can be done by not sharing a single channel between all senders to a dispatcher. Instead, the dispatcher should have a separate channel for each sender, and select between those whose recipient has space in their buffer. Unless we switch to an external channel library, this blocks on rust#27800.

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Dependencies

~1MB
~13K SLoC