@@ -41,15 +41,15 @@ use crate::{
4141
4242mod guarded_channel;
4343
44- // TODO: use this
45- // /// Number of addresses that are not active that we keep around per endpoint.
46- // ///
47- // /// See [`EndpointState::prune_direct_addresses`].
48- // pub(super) const MAX_INACTIVE_DIRECT_ADDRESSES: usize = 20;
44+ /// Number of addresses that are not active that we keep around per endpoint.
45+ ///
46+ /// See [`EndpointState::prune_ip_addresses`].
47+ pub ( super ) const MAX_INACTIVE_IP_ADDRESSES : usize = 20 ;
4948
50- // TODO: use this
51- // /// How long since an endpoint path was last alive before it might be pruned.
52- // const LAST_ALIVE_PRUNE_DURATION: Duration = Duration::from_secs(120);
49+ /// Max duration of how long ago we learned about this source before we are willing
50+ /// to prune it, if the path for this ip address is inactive.
51+ /// TODO(ramfox): fix this comment it's not clear enough
52+ const LAST_SOURCE_PRUNE_DURATION : Duration = Duration :: from_secs ( 120 ) ;
5353
5454// TODO: use this
5555// /// The latency at or under which we don't try to upgrade to a better path.
@@ -1372,3 +1372,83 @@ impl Future for OnClosed {
13721372 Poll :: Ready ( self . conn_id )
13731373 }
13741374}
1375+
1376+ fn prune_paths (
1377+ paths : & mut FxHashMap < transports:: Addr , PathState > ,
1378+ pending : & VecDeque < transports:: Addr > ,
1379+ selected_path : & Option < transports:: Addr > ,
1380+ open_paths : & Vec < transports:: Addr > ,
1381+ ) {
1382+ let ip_paths: BTreeSet < _ > = paths
1383+ . keys ( )
1384+ . filter ( |p| {
1385+ if p. is_ip ( ) {
1386+ return true ;
1387+ }
1388+ return false ;
1389+ } )
1390+ . cloned ( )
1391+ . collect ( ) ;
1392+ // if the total number of ip paths is less than the allowed number of inactive
1393+ // paths, just return early;
1394+ if ip_paths. len ( ) < MAX_INACTIVE_IP_ADDRESSES {
1395+ return ;
1396+ }
1397+
1398+ let mut protected_paths = std:: collections:: BTreeSet :: new ( ) ;
1399+ for addr in pending {
1400+ protected_paths. insert ( addr. clone ( ) ) ;
1401+ }
1402+ if let Some ( path) = selected_path {
1403+ protected_paths. insert ( path. clone ( ) ) ;
1404+ }
1405+ for path in open_paths {
1406+ protected_paths. insert ( path. clone ( ) ) ;
1407+ }
1408+
1409+ let inactive_paths: Vec < _ > = ip_paths. difference ( & protected_paths) . collect ( ) ;
1410+
1411+ if inactive_paths. len ( ) < MAX_INACTIVE_IP_ADDRESSES {
1412+ return ;
1413+ }
1414+
1415+ let mut keep_paths = Vec :: new ( ) ;
1416+ let now = Instant :: now ( ) ;
1417+ // if the last instance in the source was CONST time ago, it can be pruned
1418+ for ( addr, state) in paths {
1419+ if inactive_paths. contains ( & & addr) {
1420+ let mut is_expired = true ;
1421+ for ( _source, instant) in & state. sources {
1422+ // it's been less than LAST_SOURCE_PRUNE_DURATION since we
1423+ // last learned about this source
1424+ if * instant + LAST_SOURCE_PRUNE_DURATION < now {
1425+ is_expired = false ;
1426+ break ;
1427+ }
1428+ }
1429+ if !is_expired {
1430+ keep_paths. push ( addr) ;
1431+ }
1432+ continue ;
1433+ } else {
1434+ keep_paths. push ( addr) ;
1435+ }
1436+ }
1437+
1438+ * paths = paths
1439+ . iter ( )
1440+ . to_owned ( )
1441+ . filter ( |( addr, _) | keep_paths. contains ( addr) )
1442+ . map ( |( addr, state) | ( addr. clone ( ) , state. clone ( ) ) )
1443+ . collect ( ) ;
1444+ }
1445+
1446+ #[ cfg( test) ]
1447+ mod tests {
1448+ use n0_error:: Result ;
1449+
1450+ #[ test]
1451+ fn test_prune_paths ( ) -> Result {
1452+ todo ! ( ) ;
1453+ }
1454+ }
0 commit comments