RouteSinkPublished on: 2025-09-07 19:45
Written by Alisa Feistel
This is the first in the series of blog entries on
Streams andSinks. In this one, I describe whatrucheiproject is currently being up to without going into too much detail (wait for other entries which will have that).
This basically just a Sink
but you need to specify a routing key in addition to the message. You wait until ready to receive
a message with a certain key, send that message, then flush it (on that specific key), or close all
routes at once.
We want a universal interface for “collection of connections” and “ZeroMQ-style router”.
Sink (yet)RouteSink on readying and flushing all routes is to hang forever, if
implemented over a set of connections.Sinks.There is a blanket impl.
With time, I’ve learned that this gets in the way more than provides any sort of convenience
(especially for other blanket impls).
LinkedSlab made
thinking of complex wake patterns doable.
See ruchei::deal::slab and
ruchei::multicast::bufferless_slab
for examples of its use (note that multicast one has bugs, which were fixed since then, and were
relatively easy to fix).
SlabFirst, we need to talk about Slab. I
believe it to be one of the most powerful data structures in the Rust ecosystem. It effectively
gives you a pointer-like access without the associated memory unsafeties. You can implement
all sorts
of data structures on top of that.
And it seems to perform well enough?
I’d say that but I don’t have concrete enough benchmarks for that claim, so you can ignore it.
What can I do with a
Slab?
Things you’d expect from an allocator, plus a bit more.
usize in return)
SlabNot only do you get a memory safe (compared to pointers) implementation for structures you make,
but you also can expose Slab-like interface to the outside (you’ll see that in LinkedSlab)
either by giving your users usize directly or
some sort of a handle.
LinkedSlabLinkedSlab<T, N>, in addition to base Slab<T> interface gives you N doubly-linked lists with
nodes tied to items in the slab. If you remove an item, its node is automatically removed from all
the lists. This creates an insertion-sorted subset overlay on the items of the slab.
LinkedSlabWhen working on ruchei, we have a lot of
combinators which are collections of streams that:
LinkedSlab solves all those.
With better tools to implement multi-stream combinators, we believe that it should be reasonable to
assume all RouteSinks to come with a valid poll_ready_any and poll_flush_all implementation.
As such, we can just treat poll_ready_route and poll_flush_route as optimisation-only tools.
RouteSink<Route, Msg>: Sink<(Route, Msg)> seems like a reasonable way forward.
Another addition that I want to see is DealSink<Route, Msg>: RouteSink<Route, Msg>, which also
provides poll_ready_some to get the next Route that we can start_send to.
LinkedSlab the best we can do?I think not? parrrate/ruchei#13
Having actual separate nodes and pointers gives you the following:
Waker can reuse the same pointer.
Unpin requirement.