-
-
Notifications
You must be signed in to change notification settings - Fork 596
Reducing EndpointDriver state lock contention: split incoming accept around the endpoint lock #2633
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
base: main
Are you sure you want to change the base?
Changes from 5 commits
e449db0
8db425b
bdaea5d
885c1fc
a0bb530
395342d
4c89b14
1b0c4b5
ec4b67e
28ac4ed
22deddb
b920089
2ad9edc
3b9adda
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -343,7 +343,7 @@ impl Endpoint { | |
| trace!(initial_dcid = %remote_id); | ||
|
|
||
| let ch = ConnectionHandle(self.connections.vacant_key()); | ||
| let loc_cid = self.new_cid(ch); | ||
| let loc_cid = self.new_cid(RouteDatagramTo::Connection(ch)); | ||
| let params = TransportParameters::new( | ||
| &config.transport, | ||
| &self.config, | ||
|
|
@@ -385,7 +385,7 @@ impl Endpoint { | |
| ) -> ConnectionEvent { | ||
| let mut ids = vec![]; | ||
| for _ in 0..num { | ||
| let id = self.new_cid(ch); | ||
| let id = self.new_cid(RouteDatagramTo::Connection(ch)); | ||
| let meta = &mut self.connections[ch]; | ||
| let sequence = meta.cids_issued; | ||
| meta.cids_issued += 1; | ||
|
|
@@ -399,8 +399,8 @@ impl Endpoint { | |
| ConnectionEvent(ConnectionEventInner::NewIdentifiers(ids, now)) | ||
| } | ||
|
|
||
| /// Generate a connection ID for `ch` | ||
| fn new_cid(&mut self, ch: ConnectionHandle) -> ConnectionId { | ||
| /// Generate and reserve a local connection ID | ||
| fn new_cid(&mut self, route_to: RouteDatagramTo) -> ConnectionId { | ||
| loop { | ||
| let cid = self.local_cid_generator.generate_cid(); | ||
| if cid.is_empty() { | ||
|
|
@@ -409,7 +409,7 @@ impl Endpoint { | |
| return cid; | ||
| } | ||
| if let hash_map::Entry::Vacant(e) = self.index.connection_ids.entry(cid) { | ||
| e.insert(ch); | ||
| e.insert(route_to); | ||
| break cid; | ||
| } | ||
| } | ||
|
|
@@ -601,7 +601,7 @@ impl Endpoint { | |
| }; | ||
|
|
||
| let ch = ConnectionHandle(self.connections.vacant_key()); | ||
| let loc_cid = self.new_cid(ch); | ||
| let loc_cid = self.new_cid(RouteDatagramTo::Connection(ch)); | ||
| let mut params = TransportParameters::new( | ||
| &server_config.transport, | ||
| &self.config, | ||
|
|
@@ -615,7 +615,7 @@ impl Endpoint { | |
| params.retry_src_cid = incoming.token.retry_src_cid; | ||
| let mut pref_addr_cid = None; | ||
| if server_config.has_preferred_address() { | ||
| let cid = self.new_cid(ch); | ||
| let cid = self.new_cid(RouteDatagramTo::Connection(ch)); | ||
| pref_addr_cid = Some(cid); | ||
| params.preferred_address = Some(PreferredAddress { | ||
| address_v4: server_config.preferred_address_v4, | ||
|
|
@@ -815,14 +815,30 @@ impl Endpoint { | |
| addresses.remote, | ||
| addresses.local_ip, | ||
| tls, | ||
| self.local_cid_generator.as_ref(), | ||
| self.local_cid_generator.cid_len(), | ||
| self.local_cid_generator.cid_lifetime(), | ||
| now, | ||
| version, | ||
| self.allow_mtud, | ||
| rng_seed, | ||
| side_args, | ||
| ); | ||
|
|
||
| self.register_connection(ch, init_cid, loc_cid, pref_addr_cid, addresses, side); | ||
|
|
||
| conn | ||
| } | ||
|
|
||
| /// Register endpoint-owned metadata and routes for an active connection. | ||
| fn register_connection( | ||
| &mut self, | ||
| ch: ConnectionHandle, | ||
| init_cid: ConnectionId, | ||
| loc_cid: ConnectionId, | ||
| pref_addr_cid: Option<ConnectionId>, | ||
| addresses: FourTuple, | ||
| side: Side, | ||
| ) { | ||
| let mut cids_issued = 0; | ||
| let mut loc_cids = FxHashMap::default(); | ||
|
|
||
|
|
@@ -845,9 +861,27 @@ impl Endpoint { | |
| }); | ||
| debug_assert_eq!(id, ch.0, "connection handle allocation out of sync"); | ||
|
|
||
| self.index.insert_conn(addresses, loc_cid, ch, side); | ||
|
|
||
| conn | ||
| let conn_meta = &self.connections[ch]; | ||
| for cid in conn_meta.loc_cids.values() { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Okay, I got to "inline insert_conn into register_connection". For these changes, I want to split into (1) a commit that moves the code and (2) a commit that changes the code. (This is basically the same for all the changes you're submitting -- please self-review.) In order to make progress here, maybe submit a separate PR with the commits before this one, so we can get it merged? This is pretty hard to digest.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks! The first part is here #2771 |
||
| if cid.is_empty() { | ||
| match conn_meta.side { | ||
| Side::Server => { | ||
| self.index | ||
| .incoming_connection_remotes | ||
| .insert(conn_meta.addresses, ch); | ||
| } | ||
| Side::Client => { | ||
| self.index | ||
| .outgoing_connection_remotes | ||
| .insert(conn_meta.addresses.remote, ch); | ||
| } | ||
| } | ||
| } else { | ||
| self.index | ||
| .connection_ids | ||
| .insert(*cid, RouteDatagramTo::Connection(ch)); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| fn initial_close( | ||
|
|
@@ -984,7 +1018,7 @@ struct ConnectionIndex { | |
| /// Identifies connections based on locally created CIDs | ||
| /// | ||
| /// Uses a cheaper hash function since keys are locally created | ||
| connection_ids: FxHashMap<ConnectionId, ConnectionHandle>, | ||
| connection_ids: FxHashMap<ConnectionId, RouteDatagramTo>, | ||
| /// Identifies incoming connections with zero-length CIDs | ||
| /// | ||
| /// Uses a standard `HashMap` to protect against hash collision attacks. | ||
|
|
@@ -1033,32 +1067,6 @@ impl ConnectionIndex { | |
| .insert(dst_cid, RouteDatagramTo::Connection(connection)); | ||
| } | ||
|
|
||
| /// Associate a connection with its first locally-chosen destination CID if used, or otherwise | ||
| /// its current 4-tuple | ||
| fn insert_conn( | ||
| &mut self, | ||
| addresses: FourTuple, | ||
| dst_cid: ConnectionId, | ||
| connection: ConnectionHandle, | ||
| side: Side, | ||
| ) { | ||
| match dst_cid.len() { | ||
| 0 => match side { | ||
| Side::Server => { | ||
| self.incoming_connection_remotes | ||
| .insert(addresses, connection); | ||
| } | ||
| Side::Client => { | ||
| self.outgoing_connection_remotes | ||
| .insert(addresses.remote, connection); | ||
| } | ||
| }, | ||
| _ => { | ||
| self.connection_ids.insert(dst_cid, connection); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /// Discard a connection ID | ||
| fn retire(&mut self, dst_cid: ConnectionId) { | ||
| self.connection_ids.remove(&dst_cid); | ||
|
|
@@ -1083,13 +1091,13 @@ impl ConnectionIndex { | |
| /// Find the existing connection that `datagram` should be routed to, if any | ||
| fn get(&self, addresses: &FourTuple, datagram: &PartialDecode) -> Option<RouteDatagramTo> { | ||
| if !datagram.dst_cid().is_empty() { | ||
| if let Some(&ch) = self.connection_ids.get(&datagram.dst_cid()) { | ||
| return Some(RouteDatagramTo::Connection(ch)); | ||
| if let Some(&route) = self.connection_ids.get(&datagram.dst_cid()) { | ||
| return Some(route); | ||
| } | ||
| } | ||
| if datagram.is_initial() || datagram.is_0rtt() { | ||
| if let Some(&ch) = self.connection_ids_initial.get(&datagram.dst_cid()) { | ||
| return Some(ch); | ||
| if let Some(&route) = self.connection_ids_initial.get(&datagram.dst_cid()) { | ||
| return Some(route); | ||
| } | ||
| } | ||
| if datagram.dst_cid().is_empty() { | ||
|
|
||
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 reviewed up to this commit, the previous commits looked fine. I want a different commit history for this:
add_connection()into a separate methodregister_connection(). The new method should live below the existing one, since it is called by it and we follow top-down ordering.insert_conn()intoregister_connection().self.index.insert_initial()call.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.
Thanks for the feedback! Split it into 3 separate commits starting with 885c1fc