New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(kad): introduce AsyncBehaviour #5294
base: master
Are you sure you want to change the base?
Conversation
d36c250
to
b6cf27f
Compare
I think it's OK to drop some messages though, they are not that important. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi François, thanks for starting this! I think this is a great idea for kademlia to offer async await friendly primitives, left some notes to help move this forward
/// with an [`Event::OutboundQueryProgressed`] like nothing happen. | ||
/// | ||
/// For more information, see [`Behaviour`]. | ||
pub struct AsyncBehaviour<TStore> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah it would probably be great !!
I'm thinking about it but I really don't see how I could implement it since I need to capture the events emitted by the kad::Behaviour
. Do you have an idea ?
} | ||
} | ||
|
||
type UnboundedQueryResultSender<T> = mpsc::UnboundedSender<AsyncQueryResult<T>>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wdyt of using a wrapper structure that impl's Future
and abstracts UnboundedSender
(we shouldn't expose third party types as it introduces possible breaking change see here for a discussion on it).
Like AsyncQueryResult<T>
where T
could be BootstrapResult
, GetClosestPeersResult
etc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah you're right. I'm going to introduce a wrapper AsyncQueryResultStream
around UnboundedQueryResultReceiver
which implement futures::Stream
. It will still depends on the definition of futures::Stream
but I don't think it is possible to remove it and since it is done in protocols/stream/src/control.rs
for IncomingStreams
I think it is ok.
rust-libp2p/protocols/stream/src/control.rs
Lines 127 to 133 in 9bb2a87
impl futures::Stream for IncomingStreams { | |
type Item = (PeerId, Stream); | |
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { | |
self.receiver.poll_next_unpin(cx) | |
} | |
} |
Is it ok ?
@@ -387,6 +387,43 @@ impl<TOutEvent, THandlerIn> ToSwarm<TOutEvent, THandlerIn> { | |||
}, | |||
} | |||
} | |||
|
|||
/// Map the event the swarm will return to an optional one. | |||
pub fn map_out_opt<E>( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we need this? I see it's only called on poll
so why not do it there?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah indeed. It is just that we use it in our fork because we have several Behaviour
wrapper and we often need to map an event into a different optional event. Currently there is no method like this on ToSwarm
. I thought it was a good idea to upstream it. But if you prefer I can make it private in the async_behaviour.rs
file.
b6cf27f
to
48cf62a
Compare
48cf62a
to
83480f9
Compare
@jxs like I mentioned in this PR description (in section Notes and open questions), I have used unbounded channels thinking that this could not cause a memory issue more than what there is already since all the sent events are already in memory. Still, I really don't have an opinion on this. |
It would be preferred to use bounded channels so we dont introduce that vector. |
This pull request has merge conflicts. Could you please resolve them @stormshield-frb? 🙏 |
Description
The more things our software is doing, the more it is complicated to track Kademlia queries. We find ourselves needing to have distinct
HashMap
to keep track of every queries we are doing so we can link them back to where and why there were triggered and we needed them. This began to be very messy and that is why we have implemented a wrapper of thekad::Behaviour
with the goal of simplifying the tracking of Kademlia queries.This wrapper is pretty simple and has one method for each of the possible Kademlia queries (
bootstrap
,get_closest_peers
, etc) respectively suffixed_async
(bootstrap_async
,get_closest_peers_async
, etc). Those methods, instead of returning aQueryId
, return a typedUnboundedQueryResultReceiver
that will receive everyEvent::OutboundQueryProgressed
corresponding to theQueryId
. The only purpose of this wrapper is to map anOutboundQueryProgressed
to the corresponding sender and send it.Doing so, it is very easy for the developer to track his queries and keep a correct state in his application specific code.
Notes & open questions
I have chosen to use
UnboundedChannel
considering that the data transmitted is already in memory since this we obtain it when receiving anOutboundQueryProgressed
. That is why I don't think there is a particular risk of running out of memory. If there is, I can rework my wrapper to work with bounded channels.Change checklist