From 3edfdead0fb8388256d6620cbde41bfc27110e42 Mon Sep 17 00:00:00 2001 From: Pierre Krieger <pierre.krieger1708@gmail.com> Date: Mon, 22 Mar 2021 17:51:57 +0100 Subject: [PATCH] Optimize the peerset a bit (#8416) * Only allocate slots for the relevant peer set * Do a pre-check before calling has_free_outgoing_slot * Oops, fix infinite loop --- substrate/client/peerset/src/lib.rs | 104 ++++++++++++--------- substrate/client/peerset/src/peersstate.rs | 9 +- 2 files changed, 64 insertions(+), 49 deletions(-) diff --git a/substrate/client/peerset/src/lib.rs b/substrate/client/peerset/src/lib.rs index 31162930efc..153e097dc8b 100644 --- a/substrate/client/peerset/src/lib.rs +++ b/substrate/client/peerset/src/lib.rs @@ -296,7 +296,10 @@ impl Peerset { } } - peerset.alloc_slots(); + for set_index in 0..peerset.data.num_sets() { + peerset.alloc_slots(SetId(set_index)); + } + (peerset, handle) } @@ -307,7 +310,7 @@ impl Peerset { } self.data.add_no_slot_node(set_id.0, peer_id); - self.alloc_slots(); + self.alloc_slots(set_id); } fn on_remove_reserved_peer(&mut self, set_id: SetId, peer_id: PeerId) { @@ -372,7 +375,7 @@ impl Peerset { } } else { - self.alloc_slots(); + self.alloc_slots(set_id); } } @@ -383,7 +386,7 @@ impl Peerset { pub fn add_to_peers_set(&mut self, set_id: SetId, peer_id: PeerId) { if let peersstate::Peer::Unknown(entry) = self.data.peer(set_id.0, &peer_id) { entry.discover(); - self.alloc_slots(); + self.alloc_slots(set_id); } } @@ -500,59 +503,68 @@ impl Peerset { } } - /// Try to fill available out slots with nodes. - fn alloc_slots(&mut self) { + /// Try to fill available out slots with nodes for the given set. + fn alloc_slots(&mut self, set_id: SetId) { self.update_time(); // Try to connect to all the reserved nodes that we are not connected to. - for set_index in 0..self.data.num_sets() { - for reserved_node in &self.reserved_nodes[set_index].0 { - let entry = match self.data.peer(set_index, reserved_node) { - peersstate::Peer::Unknown(n) => n.discover(), - peersstate::Peer::NotConnected(n) => n, - peersstate::Peer::Connected(_) => continue, - }; - - match entry.try_outgoing() { - Ok(conn) => self.message_queue.push_back(Message::Connect { - set_id: SetId(set_index), - peer_id: conn.into_peer_id() - }), - Err(_) => { - // An error is returned only if no slot is available. Reserved nodes are - // marked in the state machine with a flag saying "doesn't occupy a slot", - // and as such this should never happen. - debug_assert!(false); - log::error!( - target: "peerset", - "Not enough slots to connect to reserved node" - ); - } + for reserved_node in &self.reserved_nodes[set_id.0].0 { + let entry = match self.data.peer(set_id.0, reserved_node) { + peersstate::Peer::Unknown(n) => n.discover(), + peersstate::Peer::NotConnected(n) => n, + peersstate::Peer::Connected(_) => continue, + }; + + match entry.try_outgoing() { + Ok(conn) => self.message_queue.push_back(Message::Connect { + set_id, + peer_id: conn.into_peer_id() + }), + Err(_) => { + // An error is returned only if no slot is available. Reserved nodes are + // marked in the state machine with a flag saying "doesn't occupy a slot", + // and as such this should never happen. + debug_assert!(false); + log::error!( + target: "peerset", + "Not enough slots to connect to reserved node" + ); } } } // Now, we try to connect to other nodes. - for set_index in 0..self.data.num_sets() { - // Nothing more to do if we're in reserved mode. - if self.reserved_nodes[set_index].1 { - continue; + + // Nothing more to do if we're in reserved mode. + if self.reserved_nodes[set_id.0].1 { + return; + } + + // Try to grab the next node to attempt to connect to. + // Since `highest_not_connected_peer` is rather expensive to call, check beforehand + // whether we have an available slot. + while self.data.has_free_outgoing_slot(set_id.0) { + let next = match self.data.highest_not_connected_peer(set_id.0) { + Some(n) => n, + None => break + }; + + // Don't connect to nodes with an abysmal reputation. + if next.reputation() < BANNED_THRESHOLD { + break; } - // Try to grab the next node to attempt to connect to. - while let Some(next) = self.data.highest_not_connected_peer(set_index) { - // Don't connect to nodes with an abysmal reputation. - if next.reputation() < BANNED_THRESHOLD { + match next.try_outgoing() { + Ok(conn) => self.message_queue.push_back(Message::Connect { + set_id, + peer_id: conn.into_peer_id() + }), + Err(_) => { + // This branch can only be entered if there is no free slot, which is + // checked above. + debug_assert!(false); break; } - - match next.try_outgoing() { - Ok(conn) => self.message_queue.push_back(Message::Connect { - set_id: SetId(set_index), - peer_id: conn.into_peer_id() - }), - Err(_) => break, // No more slots available. - } } } } @@ -624,7 +636,7 @@ impl Peerset { self.on_remove_from_peers_set(set_id, peer_id); } - self.alloc_slots(); + self.alloc_slots(set_id); } /// Reports an adjustment to the reputation of the given peer. diff --git a/substrate/client/peerset/src/peersstate.rs b/substrate/client/peerset/src/peersstate.rs index c79dac5e10a..c200d2729e1 100644 --- a/substrate/client/peerset/src/peersstate.rs +++ b/substrate/client/peerset/src/peersstate.rs @@ -283,6 +283,11 @@ impl PeersState { } } + /// Returns `true` if there is a free outgoing slot available related to this set. + pub fn has_free_outgoing_slot(&self, set: usize) -> bool { + self.sets[set].num_out < self.sets[set].max_out + } + /// Add a node to the list of nodes that don't occupy slots. /// /// Has no effect if the node was already in the group. @@ -506,9 +511,7 @@ impl<'a> NotConnectedPeer<'a> { // Note that it is possible for num_out to be strictly superior to the max, in case we were // connected to reserved node then marked them as not reserved. - if self.state.sets[self.set].num_out >= self.state.sets[self.set].max_out - && !is_no_slot_occupy - { + if !self.state.has_free_outgoing_slot(self.set) && !is_no_slot_occupy { return Err(self); } -- GitLab