-
Notifications
You must be signed in to change notification settings - Fork 43
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
src/connection: Process command or socket result immediately #138
Conversation
> The `frame` future might be _ready_ with an `Error` from the underlying socket (i.e. here `libp2p-websocket`). Though given that the result of the `control_command` `Future` is handled first, `on_control_command` is called despite `frame` having returned an `Error`. `on_control_command` itself may try to write to the underlying socket, which will panic given that the socket returned an error earlier via the `frame` `Future`. With this patch, once any of `next_stream_command`, `next_control_command` or `next_frame` `Future` is ready, the result is processed right away, without additionally polling the remaining pending `Future`s, thus surfacing errors as early as possible. See libp2p/rust-libp2p#2598 for details.
I am not happy with At this point I don't think we should refactor this Yamux implementation. Instead I suggest to focus on the two new transport implementations libp2p/rust-libp2p#2289 and libp2p/rust-libp2p#2622, as these leverage more powerful stream multiplexing protocols (i.e. QUIC's multiplexer and SCTP). |
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.
This makes sense to me. Just one suggestion :)
let combined_future = future::select( | ||
future::select(next_stream_command, next_control_command), | ||
next_frame, | ||
); | ||
match combined_future.await { | ||
Either::Left((Either::Left((cmd, _)), _)) => self.on_stream_command(cmd).await?, | ||
Either::Left((Either::Right((cmd, _)), _)) => self.on_control_command(cmd).await?, | ||
Either::Right((frame, _)) => { | ||
if let Some(stream) = | ||
self.on_frame(frame.transpose().map_err(Into::into)).await? | ||
{ | ||
return Ok(Some(stream)); | ||
} | ||
} |
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.
Have you considered using the futures::select!
macro instead of nesting future::select
calls?
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.
I have, though I favor futures::future::select
over futures::select!
due to the following reasons:
-
While more verbose, I find
futures::future::select
easier to reason about thanfutures::select!
. -
In general I prefer functions over macros.
-
I understand the inner workings of
futures::future::select
. The implementation is very simple. -
I don't fully understand the guarantees of
futures::select!
, e.g.:If multiple futures are ready, one will be pseudo-randomly selected at runtime.
https://docs.rs/futures/latest/futures/macro.select.html
What happens to the result of the non-selected ready futures?
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.
SGTM!
Been tested without further panics libp2p/rust-libp2p#2598 (comment) |
With this patch, once any of
next_stream_command
,next_control_command
ornext_frame
Future
is ready, the result is processed right away, withoutadditionally polling the remaining pending
Future
s, thus surfacing errors asearly as possible.
See libp2p/rust-libp2p#2598 for details.
@elenaf9 @thomaseizinger could either of you do me a favor and take a look here? Happy to expand on the pull request description in case more context is needed.