Backpressure and the ConnectionHandler
interface
#4585
Replies: 2 comments 3 replies
-
I'm wondering if Because if it does then it may not cover one of the use cases where action might be initiated, but later cancelled. For example there could be two ways to retrieve something racing with each other and whichever succeeds first should result in the other one being aborted/cancelled. |
Beta Was this translation helpful? Give feedback.
-
I think this is an improvement worth exploring. Though instead of designing a generic mechanism right away, I suggest solving #4667 or #3710 first, and from there try to find a generic mechanism. |
Beta Was this translation helpful? Give feedback.
-
We have a tracking issue around backpressure in
rust-libp2p
: #3078. Recently, a discussion came up where lack of backpressure actually causes nodes to crash because they run out of memory: #4572. In this particular case, we'd need backpressure from theBehaviour
to theConnectionHandler
s.If we were to adapt this interface, we'd have to add several new functions to
NetworkBehaviour
andConnectionHandler
. Something likeNetworkBehaviour::poll_next_message
to send a new message to aConnectionHandler
and we'd need apoll_ready
-like function onConnectionHandler
where it can reports its current state.In light of #2863, I would like to suggest a somewhat radical idea of how we could easily fix this:
NetworkBehaviour
andConnectionHandler
and with it, theConnectionHandler::{To,From}Behaviour
associated typesmpmc::Channels
(naming subject to bike-shedding)If a protocol needs to communicate between
NetworkBehaviour
andConnectionHandler
, theNetworkBehaviour
would own an instance ofmpmc::Channels
. When constructing a newConnectionHandler
, the behaviour registers a new key withinmpmc::Channels
for the new connection.mpmc::Channels
would internally retain a mapping of keys => channelsmpmc::Channels::poll
reads messages from all connected channels and "tags" them with the corresponding key (in our case,ConnectionId
)mpmc::Channels
would offer several functions for sending messages:poll_all_ready(&mut self, cx: &mut Context)
: Checks if all connected channels are ready to receive an item.send_to_all(&mut self, msg: M) where M: Clone -> Result<()>
: Sends a message into all channels. Fails if any channel is not ready. Should be paired withpoll_all_ready
.poll_ready(&mut self, key: K, cx: &mut Context)
send_to(&mut self, key: K, msg: M) -> Result<()>
Channel
which implementsSink + Stream
. TheNetworkBehaviour
hands that to theConnectionHandler
.I see several advantages of this scheme:
NetworkBehaviour
andConnectionHandler
without extending any APIs.ConnectionHandler
interface becomes simpler because the associated types go away.libp2p-swarm
will be simpler because I think it should be possible to implement the above in a standalone crate.ToSwarm
andConnetionHandlerEvent
will become simpler.mpmc::Channels
that support advanced usecases like:The only downside is that users have to add a struct to their custom behaviours and manually poll something within the provided poll functions. However, I'd consider that to be pretty simple scaffholding that is easy to apply once understood. We already expect users to understand
poll
-like interfaces when they implement a customNetworkBehaviour
so I'd say this is fine.@libp2p/rust-libp2p-maintainers Please voice your opinions.
Beta Was this translation helpful? Give feedback.
All reactions