Implement grid topology routing for the statement distribution subsystem (#5476)

* Move NewGossipTopology -> SessionGridTopology outside as this implementation is shared

* Add method to return peers difference between topologies

* Implement basic grid topology usage for the bitfield distribution

* Fix tests

* Oops, fix tests

* Add some tests for random routing

* Add a unit test for topology distribution

* Store the current and the previous topology to match sessions boundaries

* Update tests

* Update node/network/bitfield-distribution/src/lib.rs

Co-authored-by: Andronik <write@reusable.software>

* Update node/network/protocol/src/grid_topology.rs

Co-authored-by: Andronik <write@reusable.software>

* Update node/network/bitfield-distribution/src/lib.rs

Co-authored-by: Andronik <write@reusable.software>

* Add some debug

* Fix tests as HashSet order is undefined

* Move session bounded topology to the common code part

* Fix tests

* Allow to select routing by peer index

* Implement grid topology in the statement distribution subsystem

* Fix tests compilation

* Fix test

* Refactor API slightly

* Address review comments

* Reduce runtime error logging severity

* Update node/network/protocol/src/grid_topology.rs

Co-authored-by: Bernhard Schuster <bernhard@ahoi.io>

* Update node/network/bitfield-distribution/src/tests.rs

Co-authored-by: Bernhard Schuster <bernhard@ahoi.io>

* Fmt run

* Use named struct

* Fix logging stuff

* One more accidental fmt damage

* Increase active queue size and add metrics

Signed-off-by: Andrei Sandu <andrei-mihail@parity.io>

* Revert "Increase active queue size and add metrics"

This reverts commit c4f48e8bded6dfeb9c62814ba2f8d815c34b04cf.

* Use validator index to choose the routing strategy

Noted by: @rphmeier

* Fix test after distribution logic fix

Co-authored-by: Andronik <write@reusable.software>
Co-authored-by: Bernhard Schuster <bernhard@ahoi.io>
Co-authored-by: Andrei Sandu <andrei-mihail@parity.io>
This commit is contained in:
Vsevolod Stakhov
2022-05-18 13:27:06 +01:00
committed by GitHub
parent 28cae2ef45
commit 195b901cc9
8 changed files with 189 additions and 92 deletions
@@ -37,6 +37,8 @@ use std::{
fmt::Debug,
};
const LOG_TARGET: &str = "parachain::grid-topology";
/// The sample rate for randomly propagating messages. This
/// reduces the left tail of the binomial distribution but also
/// introduces a bias towards peers who we sample before others
@@ -60,9 +62,13 @@ pub struct SessionGridTopology {
}
impl SessionGridTopology {
/// Given the originator of a message, indicates the part of the topology
/// Given the originator of a message as a validator index, indicates the part of the topology
/// we're meant to send the message to.
pub fn required_routing_for(&self, originator: ValidatorIndex, local: bool) -> RequiredRouting {
pub fn required_routing_by_index(
&self,
originator: ValidatorIndex,
local: bool,
) -> RequiredRouting {
if local {
return RequiredRouting::GridXY
}
@@ -78,6 +84,31 @@ impl SessionGridTopology {
}
}
/// Given the originator of a message as a peer index, indicates the part of the topology
/// we're meant to send the message to.
pub fn required_routing_by_peer_id(&self, originator: PeerId, local: bool) -> RequiredRouting {
if local {
return RequiredRouting::GridXY
}
let grid_x = self.peers_x.contains(&originator);
let grid_y = self.peers_y.contains(&originator);
match (grid_x, grid_y) {
(false, false) => RequiredRouting::None,
(true, false) => RequiredRouting::GridY, // messages from X go to Y
(false, true) => RequiredRouting::GridX, // messages from Y go to X
(true, true) => {
gum::debug!(
target: LOG_TARGET,
?originator,
"Grid topology is unexpected, play it safe and send to X AND Y"
);
RequiredRouting::GridXY
}, // if the grid works as expected, this shouldn't happen.
}
}
/// Get a filter function based on this topology and the required routing
/// which returns `true` for peers that are within the required routing set
/// and false otherwise.
@@ -142,6 +173,59 @@ impl SessionGridTopologies {
}
}
}
/// A simple storage for a topology and the corresponding session index
#[derive(Default, Debug)]
pub struct GridTopologySessionBound {
topology: SessionGridTopology,
session_index: SessionIndex,
}
/// A storage for the current and maybe previous topology
#[derive(Default, Debug)]
pub struct SessionBoundGridTopologyStorage {
current_topology: GridTopologySessionBound,
prev_topology: Option<GridTopologySessionBound>,
}
impl SessionBoundGridTopologyStorage {
/// Return a grid topology based on the session index:
/// If we need a previous session and it is registered in the storage, then return that session.
/// Otherwise, return a current session to have some grid topology in any case
pub fn get_topology_or_fallback(&self, idx: SessionIndex) -> &SessionGridTopology {
self.get_topology(idx).unwrap_or(&self.current_topology.topology)
}
/// Return the grid topology for the specific session index, if no such a session is stored
/// returns `None`.
pub fn get_topology(&self, idx: SessionIndex) -> Option<&SessionGridTopology> {
if let Some(prev_topology) = &self.prev_topology {
if idx == prev_topology.session_index {
return Some(&prev_topology.topology)
}
}
if self.current_topology.session_index == idx {
return Some(&self.current_topology.topology)
}
None
}
/// Update the current topology preserving the previous one
pub fn update_topology(&mut self, session_index: SessionIndex, topology: SessionGridTopology) {
let old_current = std::mem::replace(
&mut self.current_topology,
GridTopologySessionBound { topology, session_index },
);
self.prev_topology.replace(old_current);
}
/// Returns a current grid topology
pub fn get_current_topology(&self) -> &SessionGridTopology {
&self.current_topology.topology
}
}
/// A representation of routing based on sample
#[derive(Debug, Clone, Copy)]
pub struct RandomRouting {