Skip to content
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

Reference changes: Update mio-pollable std-net listener to not require dedicated thread/channels #3819

Merged
merged 4 commits into from
Apr 19, 2023

Conversation

Ben-PH
Copy link
Contributor

@Ben-PH Ben-PH commented Apr 12, 2023

the first commit: 2df8da1

split the creation and acceptance into two methods

accepting is a blocking function call analagous to a std-net accept, but with the additon of being waker-interuptable.

the draw-back is that the waker is something that needs to be managed seperately

the second commit is less important, but shows what changes are needed to the listener if we make minimal changes to how the listener plugs into the server.

massa-bootstrap/src/listener.rs Outdated Show resolved Hide resolved
Comment on lines -40 to +61
let mut events = Events::with_capacity(32);

// spawn a thread to handle events
std::thread::Builder::new()
.name("bs_listener".to_string())
.spawn(move || {
// HACK : create variable to move ownership of mio_server to the thread
// if mio_server is not moved, poll does not receive any event from listener
let _temp = mio_server;
let events = Events::with_capacity(32);
Ok((
waker,
BootstrapTcpListener {
poll,
server,
events,
_mio_server: mio_server,
},
))
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The intent here is to provide the server itself the ability to call a blocking-accept in the main-loop, and be able to determine if it needs to stop

Comment on lines 253 to 260
let (dplx, remote_addr) = match self.listener.accept() {
Ok(AcceptEvent::NewConnection((dplx, remote_addr))) => (dplx, remote_addr),
Ok(AcceptEvent::Stop) => break Ok(()),
Err(e) => {
error!("bootstrap listener error: {}", e);
break Err(e);
}
};
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the key.

Comment on lines +648 to +650
if let Some(bootstrap_manager) = bootstrap_manager {
bootstrap_manager.set_listener_stopper(waker);
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This pattern is problematic....

loop {
poll.poll(&mut events, None).unwrap();
impl BSListener for BootstrapTcpListener {
fn accept(&mut self) -> Result<AcceptEvent, BootstrapError> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm not a big fan of no thread the poll event, STOP_LISTENER is called only when we call accept() ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the stop-listener and the connection listener both get polled for. You can see the stop-waker being registered here: https://github.com/massalabs/massa/pull/3819/files#diff-75fc005ad20f9d19fed3694ee99b9d4e31d177cc1462e438607552996b8b823bR41-R61

The idea being, is that the main-loop has direct access to the BsListener. in the caso of using a BootstrapTcpListener in this Pr, you have access to:

  • a Poll, that has a waker registered to it
  • a TcpListener that is registered to the same poll

This means that the TcpListener can be written in such a way that it blocks until either the waker is signaled, or the listener can accept a connection, and is able to differentiate between the two.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In short: It's as if we could just use a a std::net::TcpListener like so:

let stoppable_listener = std::net::TcpListener::bind(...).with_stopper(&stopper_thing);
let server_thread =  std::thread::spawn(|| loop {

    let conn = match stopable_listener.stopable_accept() {
        Ok(Event::Accept(conn)) => conn,
        Ok(Event::stop => {
            info!("system-wide stopper invoked. exiting cleanly");
            return;
        },
        Err(e) => panic!("tcp listener errored out"),
    };
    // do thing with connection
});
// wait untill the stopper thing does its thing so the thread returns out
server_thread.join().unwrap();
info!("server succesfully shutdown gracefully after system-wide stop-signal invoked")

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok we can go with that;

Maybe stopable_accept can be rename to accept() wich return Err(...) when the stop is called. This allow to remove the Event and has a cleaner result.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the code i replied with is just an illustrative example. stopable_accept is a hypothetical method that would mirror the behavior as our current accept. No difference, other than the fact that the result can be "stop" or "here's the next connection" instead of just "here's the next connection" (assuming no error)

If something is an Err(...), that implies an incorrect, but handleable, event has occured. Trying to open a file that doesn't exist, for example.

In this case, it's perfectly expected to get a Stop.

@Ben-PH
Copy link
Contributor Author

Ben-PH commented Apr 19, 2023

Sorry about the optional waker...

@Ben-PH Ben-PH requested a review from modship April 19, 2023 16:11
@Ben-PH Ben-PH marked this pull request as ready for review April 19, 2023 16:12
@Ben-PH Ben-PH merged commit a2da610 into bootstrap/listener Apr 19, 2023
@AurelienFT AurelienFT deleted the bootstrap/listener-no-chan branch May 29, 2023 09:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants