This commit is contained in:
sijie.sun
2025-11-02 10:31:45 +08:00
parent cf2038b6c1
commit ae731bdb3c

View File

@@ -275,12 +275,29 @@ impl RouteConnBitmap {
type Error = SyncRouteInfoError; type Error = SyncRouteInfoError;
#[derive(Debug, Clone)]
struct RouteConnInfo {
connected_peers: BTreeSet<PeerId>,
version: AtomicVersion,
last_update: SystemTime,
}
impl Default for RouteConnInfo {
fn default() -> Self {
Self {
connected_peers: BTreeSet::new(),
version: AtomicVersion::new(),
last_update: SystemTime::now(),
}
}
}
// constructed with all infos synced from all peers. // constructed with all infos synced from all peers.
struct SyncedRouteInfo { struct SyncedRouteInfo {
peer_infos: RwLock<OrderedHashMap<PeerId, RoutePeerInfo>>, peer_infos: RwLock<OrderedHashMap<PeerId, RoutePeerInfo>>,
// prost doesn't support unknown fields, so we use DynamicMessage to store raw infos and progate them to other peers. // prost doesn't support unknown fields, so we use DynamicMessage to store raw infos and progate them to other peers.
raw_peer_infos: DashMap<PeerId, DynamicMessage>, raw_peer_infos: DashMap<PeerId, DynamicMessage>,
conn_map: DashMap<PeerId, (BTreeSet<PeerId>, AtomicVersion)>, conn_map: RwLock<OrderedHashMap<PeerId, RouteConnInfo>>,
foreign_network: DashMap<ForeignNetworkRouteInfoKey, ForeignNetworkRouteInfoEntry>, foreign_network: DashMap<ForeignNetworkRouteInfoKey, ForeignNetworkRouteInfoEntry>,
group_trust_map: DashMap<PeerId, HashMap<String, Vec<u8>>>, group_trust_map: DashMap<PeerId, HashMap<String, Vec<u8>>>,
group_trust_map_cache: DashMap<PeerId, Arc<Vec<String>>>, // cache for group trust map, should sync with group_trust_map group_trust_map_cache: DashMap<PeerId, Arc<Vec<String>>>, // cache for group trust map, should sync with group_trust_map
@@ -303,21 +320,21 @@ impl Debug for SyncedRouteInfo {
impl SyncedRouteInfo { impl SyncedRouteInfo {
fn get_connected_peers<T: FromIterator<PeerId>>(&self, peer_id: PeerId) -> Option<T> { fn get_connected_peers<T: FromIterator<PeerId>>(&self, peer_id: PeerId) -> Option<T> {
self.conn_map self.conn_map
.read()
.get(&peer_id) .get(&peer_id)
.map(|x| x.0.clone().iter().copied().collect()) .map(|x| x.connected_peers.iter().copied().collect())
} }
fn remove_peer(&self, peer_id: PeerId) { fn remove_peer(&self, peer_id: PeerId) {
tracing::warn!(?peer_id, "remove_peer from synced_route_info"); tracing::warn!(?peer_id, "remove_peer from synced_route_info");
self.peer_infos.write().remove(&peer_id); self.peer_infos.write().remove(&peer_id);
self.raw_peer_infos.remove(&peer_id); self.raw_peer_infos.remove(&peer_id);
self.conn_map.remove(&peer_id); self.conn_map.write().remove(&peer_id);
self.foreign_network.retain(|k, _| k.peer_id != peer_id); self.foreign_network.retain(|k, _| k.peer_id != peer_id);
self.group_trust_map.remove(&peer_id); self.group_trust_map.remove(&peer_id);
self.group_trust_map_cache.remove(&peer_id); self.group_trust_map_cache.remove(&peer_id);
shrink_dashmap(&self.raw_peer_infos, None); shrink_dashmap(&self.raw_peer_infos, None);
shrink_dashmap(&self.conn_map, None);
shrink_dashmap(&self.foreign_network, None); shrink_dashmap(&self.foreign_network, None);
shrink_dashmap(&self.group_trust_map, None); shrink_dashmap(&self.group_trust_map, None);
shrink_dashmap(&self.group_trust_map_cache, None); shrink_dashmap(&self.group_trust_map_cache, None);
@@ -339,10 +356,14 @@ impl SyncedRouteInfo {
drop(guard); drop(guard);
} }
self.conn_map.entry(*peer_id).or_insert_with(|| { let guard = self.conn_map.upgradable_read();
if !guard.contains_key(peer_id) {
let mut guard = RwLockUpgradableReadGuard::upgrade(guard);
guard.insert(*peer_id, RouteConnInfo::default());
need_inc_version = true; need_inc_version = true;
(BTreeSet::new(), AtomicVersion::new()) } else {
}); drop(guard);
}
} }
if need_inc_version { if need_inc_version {
self.version.inc(); self.version.inc();
@@ -455,7 +476,31 @@ impl SyncedRouteInfo {
Ok(()) Ok(())
} }
fn update_conn_map(&self, conn_bitmap: &RouteConnBitmap) { fn update_conn_info_one_peer(
&self,
peer_id_version: &PeerIdVersion,
connected_peers: BTreeSet<PeerId>,
) -> bool {
let mut guard = self.conn_map.write();
if guard
.get_mut(&peer_id_version.peer_id)
.is_none_or(|old| peer_id_version.version > old.version.get())
{
guard.insert(
peer_id_version.peer_id,
RouteConnInfo {
connected_peers,
version: peer_id_version.version.into(),
last_update: SystemTime::now(),
},
);
return true;
}
false
}
fn update_conn_info_with_bitmap(&self, conn_bitmap: &RouteConnBitmap) {
self.fill_empty_peer_info(&conn_bitmap.peer_ids.iter().map(|x| x.peer_id).collect()); self.fill_empty_peer_info(&conn_bitmap.peer_ids.iter().map(|x| x.peer_id).collect());
let mut need_inc_version = false; let mut need_inc_version = false;
@@ -463,27 +508,14 @@ impl SyncedRouteInfo {
for (peer_idx, peer_id_version) in conn_bitmap.peer_ids.iter().enumerate() { for (peer_idx, peer_id_version) in conn_bitmap.peer_ids.iter().enumerate() {
let connceted_peers = conn_bitmap.get_connected_peers(peer_idx); let connceted_peers = conn_bitmap.get_connected_peers(peer_idx);
self.fill_empty_peer_info(&connceted_peers); self.fill_empty_peer_info(&connceted_peers);
need_inc_version = self.update_conn_info_one_peer(peer_id_version, connceted_peers);
self.conn_map
.entry(peer_id_version.peer_id)
.and_modify(|(old_conn_bitmap, old_version)| {
if peer_id_version.version > old_version.get() {
*old_conn_bitmap = connceted_peers.clone();
need_inc_version = true;
old_version.set(peer_id_version.version);
}
})
.or_insert_with(|| {
need_inc_version = true;
(connceted_peers, (peer_id_version.version).into())
});
} }
if need_inc_version { if need_inc_version {
self.version.inc(); self.version.inc();
} }
} }
fn update_conn_peer_list(&self, conn_peer_list: &RouteConnPeerList) { fn update_conn_info_with_list(&self, conn_peer_list: &RouteConnPeerList) {
let mut need_inc_version = false; let mut need_inc_version = false;
for peer_conn_info in &conn_peer_list.peer_conn_infos { for peer_conn_info in &conn_peer_list.peer_conn_infos {
@@ -492,23 +524,9 @@ impl SyncedRouteInfo {
}; };
let connected_peers: BTreeSet<PeerId> = let connected_peers: BTreeSet<PeerId> =
peer_conn_info.connected_peer_ids.iter().copied().collect(); peer_conn_info.connected_peer_ids.iter().copied().collect();
let (peer_id, version) = (peer_id_version.peer_id, peer_id_version.version);
self.fill_empty_peer_info(&connected_peers); self.fill_empty_peer_info(&connected_peers);
need_inc_version = self.update_conn_info_one_peer(&peer_id_version, connected_peers);
self.conn_map
.entry(peer_id)
.and_modify(|(old_conn_bitmap, old_version)| {
if version > old_version.get() {
*old_conn_bitmap = connected_peers.clone();
need_inc_version = true;
old_version.set(version);
}
})
.or_insert_with(|| {
need_inc_version = true;
(connected_peers, version.into())
});
} }
if need_inc_version { if need_inc_version {
self.version.inc(); self.version.inc();
@@ -518,10 +536,10 @@ impl SyncedRouteInfo {
fn update_conn_info(&self, conn_info: &ConnInfo) { fn update_conn_info(&self, conn_info: &ConnInfo) {
match conn_info { match conn_info {
ConnInfo::ConnBitmap(conn_bitmap) => { ConnInfo::ConnBitmap(conn_bitmap) => {
self.update_conn_map(conn_bitmap); self.update_conn_info_with_bitmap(conn_bitmap);
} }
ConnInfo::ConnPeerList(conn_peer_list) => { ConnInfo::ConnPeerList(conn_peer_list) => {
self.update_conn_peer_list(conn_peer_list); self.update_conn_info_with_list(conn_peer_list);
} }
} }
} }
@@ -592,18 +610,24 @@ impl SyncedRouteInfo {
fn update_my_conn_info(&self, my_peer_id: PeerId, connected_peers: BTreeSet<PeerId>) -> bool { fn update_my_conn_info(&self, my_peer_id: PeerId, connected_peers: BTreeSet<PeerId>) -> bool {
self.fill_empty_peer_info(&connected_peers); self.fill_empty_peer_info(&connected_peers);
let mut my_conn_info = self let guard = self.conn_map.upgradable_read();
.conn_map let my_conn_info = guard.get(&my_peer_id);
.entry(my_peer_id) let new_version = my_conn_info.map(|x| x.version.get()).unwrap_or(0) + 1;
.or_insert((BTreeSet::new(), AtomicVersion::new()));
if connected_peers == my_conn_info.value().0 { if my_conn_info.is_none_or(|old| old.connected_peers != connected_peers) {
false let mut guard = RwLockUpgradableReadGuard::upgrade(guard);
} else { guard.insert(
let _ = std::mem::replace(&mut my_conn_info.value_mut().0, connected_peers); my_peer_id,
my_conn_info.value().1.inc(); RouteConnInfo {
connected_peers,
version: new_version.into(),
last_update: SystemTime::now(),
},
);
self.version.inc(); self.version.inc();
true true
} else {
false
} }
} }
@@ -694,18 +718,6 @@ impl SyncedRouteInfo {
} }
} }
fn is_peer_bidirectly_connected(&self, src_peer_id: PeerId, dst_peer_id: PeerId) -> bool {
self.conn_map
.get(&src_peer_id)
.map(|x| x.0.contains(&dst_peer_id))
.unwrap_or(false)
}
fn is_peer_directly_connected(&self, src_peer_id: PeerId, dst_peer_id: PeerId) -> bool {
self.is_peer_bidirectly_connected(src_peer_id, dst_peer_id)
|| self.is_peer_bidirectly_connected(dst_peer_id, src_peer_id)
}
fn verify_and_update_group_trusts( fn verify_and_update_group_trusts(
&self, &self,
peer_infos: &[RoutePeerInfo], peer_infos: &[RoutePeerInfo],
@@ -1550,7 +1562,7 @@ impl PeerRouteServiceImpl {
synced_route_info: SyncedRouteInfo { synced_route_info: SyncedRouteInfo {
peer_infos: RwLock::new(OrderedHashMap::new()), peer_infos: RwLock::new(OrderedHashMap::new()),
raw_peer_infos: DashMap::new(), raw_peer_infos: DashMap::new(),
conn_map: DashMap::new(), conn_map: RwLock::new(OrderedHashMap::new()),
foreign_network: DashMap::new(), foreign_network: DashMap::new(),
group_trust_map: DashMap::new(), group_trust_map: DashMap::new(),
group_trust_map_cache: DashMap::new(), group_trust_map_cache: DashMap::new(),
@@ -1738,49 +1750,57 @@ impl PeerRouteServiceImpl {
// the conn_bitmap should contain complete list of directly connected peers. // the conn_bitmap should contain complete list of directly connected peers.
// use union of dst peers can preserve this property. // use union of dst peers can preserve this property.
let all_dst_peer_ids = self let mut all_peer_ids: BTreeMap<PeerId, Version> = BTreeMap::new();
.synced_route_info let mut add_to_all_peer_ids = |peer_id: PeerId, version: Version| {
.conn_map all_peer_ids
.iter() .entry(peer_id)
.flat_map(|x| x.value().clone().0.into_iter()) .and_modify(|x| {
.collect::<BTreeSet<_>>(); if *x < version {
*x = version;
let all_peer_ids = self }
.synced_route_info
.conn_map
.iter()
.map(|x| PeerIdVersion {
peer_id: *x.key(),
version: x.value().1.get(),
}) })
// do not sync conn info of peers that are not reachable from any peer. .or_insert(version);
.filter(|p| { };
all_dst_peer_ids.contains(&p.peer_id) || self.route_table.peer_reachable(p.peer_id) for item in self.synced_route_info.conn_map.read().iter() {
}) let src_peer_id = *item.0;
.collect::<Vec<_>>(); if !self.route_table.peer_reachable(src_peer_id) {
continue;
}
add_to_all_peer_ids(src_peer_id, item.1.version.get());
for dst_peer_id in item.1.connected_peers.iter() {
add_to_all_peer_ids(*dst_peer_id, 0);
}
}
let mut conn_bitmap = RouteConnBitmap { let mut conn_bitmap = RouteConnBitmap {
bitmap: vec![0; (all_peer_ids.len() * all_peer_ids.len()).div_ceil(8)], bitmap: vec![0; (all_peer_ids.len() * all_peer_ids.len()).div_ceil(8)],
peer_ids: all_peer_ids, peer_ids: all_peer_ids
.iter()
.map(|x| PeerIdVersion {
peer_id: *x.0,
version: *x.1,
})
.collect(),
}; };
let locked_conn_map = self.synced_route_info.conn_map.read();
let all_peer_ids = &conn_bitmap.peer_ids; let all_peer_ids = &conn_bitmap.peer_ids;
for (peer_idx, peer_id_version) in all_peer_ids.iter().enumerate() { for (peer_idx, peer_id_version) in all_peer_ids.iter().enumerate() {
let Some(connected) = self let Some(connected) = locked_conn_map.get(&peer_id_version.peer_id) else {
.synced_route_info
.conn_map
.get(&peer_id_version.peer_id)
else {
continue; continue;
}; };
for (idx, other_peer_id_version) in all_peer_ids.iter().enumerate() { for (idx, other_peer_id_version) in all_peer_ids.iter().enumerate() {
if connected.0.contains(&other_peer_id_version.peer_id) { if connected
.connected_peers
.contains(&other_peer_id_version.peer_id)
{
let bit_idx = peer_idx * all_peer_ids.len() + idx; let bit_idx = peer_idx * all_peer_ids.len() + idx;
conn_bitmap.bitmap[bit_idx / 8] |= 1 << (bit_idx % 8); conn_bitmap.bitmap[bit_idx / 8] |= 1 << (bit_idx % 8);
} }
} }
} }
drop(locked_conn_map);
let mut locked = self.cached_local_conn_map.lock().unwrap(); let mut locked = self.cached_local_conn_map.lock().unwrap();
if self if self
@@ -1895,25 +1915,22 @@ impl PeerRouteServiceImpl {
estimated_size: &mut usize, estimated_size: &mut usize,
) -> Option<RouteConnPeerList> { ) -> Option<RouteConnPeerList> {
let mut peer_conn_infos = Vec::new(); let mut peer_conn_infos = Vec::new();
let cached_conn_map = self.cached_local_conn_map.lock().unwrap();
*estimated_size = 0; *estimated_size = 0;
for peer_id_version in cached_conn_map.peer_ids.iter() { for (peer_id, conn_info) in self.synced_route_info.conn_map.read().iter() {
let (peer_id, local_version) = (peer_id_version.peer_id, peer_id_version.version); if session.check_saved_conn_version_update_to_date(*peer_id, conn_info.version.get()) {
if session.check_saved_conn_version_update_to_date(peer_id, local_version) {
continue; continue;
} }
let Some(connected) = self.synced_route_info.conn_map.get(&peer_id) else {
continue;
};
peer_conn_infos.push(PeerConnInfo { peer_conn_infos.push(PeerConnInfo {
peer_id: Some(*peer_id_version), peer_id: Some(PeerIdVersion {
connected_peer_ids: connected.0.iter().copied().collect(), peer_id: *peer_id,
version: conn_info.version.get(),
}),
connected_peer_ids: conn_info.connected_peers.iter().copied().collect(),
}); });
*estimated_size += std::mem::size_of::<PeerIdVersion>() *estimated_size += std::mem::size_of::<PeerIdVersion>()
+ connected.0.len() * std::mem::size_of::<PeerId>(); + conn_info.connected_peers.len() * std::mem::size_of::<PeerId>();
} }
if peer_conn_infos.is_empty() { if peer_conn_infos.is_empty() {
@@ -3225,13 +3242,13 @@ mod tests {
let synced_info = &p.service_impl.synced_route_info; let synced_info = &p.service_impl.synced_route_info;
for routable_peer in routable_peers.iter() { for routable_peer in routable_peers.iter() {
// check conn map // check conn map
let conns = synced_info let conns = {
.conn_map let guard = synced_info.conn_map.read();
.get(&routable_peer.my_peer_id()) guard.get(&routable_peer.my_peer_id()).cloned().unwrap()
.unwrap(); };
assert_eq!( assert_eq!(
conns.0, conns.connected_peers,
routable_peer routable_peer
.get_peer_map() .get_peer_map()
.list_peers() .list_peers()