@@ -40,7 +40,6 @@ use crate::io_extras::{copy, sink};
40
40
use crate :: prelude:: * ;
41
41
use core:: { cmp, fmt} ;
42
42
use crate :: sync:: { RwLock , RwLockReadGuard , LockTestExt } ;
43
- #[ cfg( feature = "std" ) ]
44
43
use core:: sync:: atomic:: { AtomicUsize , Ordering } ;
45
44
use crate :: sync:: Mutex ;
46
45
use core:: ops:: { Bound , Deref } ;
@@ -184,6 +183,8 @@ pub struct NetworkGraph<L: Deref> where L::Target: Logger {
184
183
// Lock order: channels -> nodes
185
184
channels : RwLock < IndexedMap < u64 , ChannelInfo > > ,
186
185
nodes : RwLock < IndexedMap < NodeId , NodeInfo > > ,
186
+ removed_node_counters : Mutex < Vec < u32 > > ,
187
+ next_node_counter : AtomicUsize ,
187
188
// Lock order: removed_channels -> removed_nodes
188
189
//
189
190
// NOTE: In the following `removed_*` maps, we use seconds since UNIX epoch to track time instead
@@ -1333,15 +1334,27 @@ impl Readable for NodeAlias {
1333
1334
}
1334
1335
}
1335
1336
1336
- #[ derive( Clone , Debug , PartialEq , Eq ) ]
1337
+ #[ derive( Clone , Debug , Eq ) ]
1337
1338
/// Details about a node in the network, known from the network announcement.
1338
1339
pub struct NodeInfo {
1339
1340
/// All valid channels a node has announced
1340
1341
pub channels : Vec < u64 > ,
1341
1342
/// More information about a node from node_announcement.
1342
1343
/// Optional because we store a Node entry after learning about it from
1343
1344
/// a channel announcement, but before receiving a node announcement.
1344
- pub announcement_info : Option < NodeAnnouncementInfo >
1345
+ pub announcement_info : Option < NodeAnnouncementInfo > ,
1346
+ /// In memory, each node is assigned a unique ID. They are eagerly reused, ensuring they remain
1347
+ /// relatively dense.
1348
+ ///
1349
+ /// These IDs allow the router to avoid a `HashMap` lookup by simply using this value as an
1350
+ /// index in a `Vec`, skipping a big step in some of the hottest code when routing.
1351
+ pub ( crate ) node_counter : u32 ,
1352
+ }
1353
+
1354
+ impl PartialEq for NodeInfo {
1355
+ fn eq ( & self , o : & NodeInfo ) -> bool {
1356
+ self . channels == o. channels && self . announcement_info == o. announcement_info
1357
+ }
1345
1358
}
1346
1359
1347
1360
impl NodeInfo {
@@ -1411,6 +1424,7 @@ impl Readable for NodeInfo {
1411
1424
Ok ( NodeInfo {
1412
1425
announcement_info : announcement_info_wrap. map ( |w| w. 0 ) ,
1413
1426
channels,
1427
+ node_counter : u32:: max_value ( ) ,
1414
1428
} )
1415
1429
}
1416
1430
}
@@ -1420,6 +1434,8 @@ const MIN_SERIALIZATION_VERSION: u8 = 1;
1420
1434
1421
1435
impl < L : Deref > Writeable for NetworkGraph < L > where L :: Target : Logger {
1422
1436
fn write < W : Writer > ( & self , writer : & mut W ) -> Result < ( ) , io:: Error > {
1437
+ self . test_node_counter_consistency ( ) ;
1438
+
1423
1439
write_ver_prefix ! ( writer, SERIALIZATION_VERSION , MIN_SERIALIZATION_VERSION ) ;
1424
1440
1425
1441
self . chain_hash . write ( writer) ?;
@@ -1458,11 +1474,13 @@ impl<L: Deref> ReadableArgs<L> for NetworkGraph<L> where L::Target: Logger {
1458
1474
channels. insert ( chan_id, chan_info) ;
1459
1475
}
1460
1476
let nodes_count: u64 = Readable :: read ( reader) ?;
1477
+ if nodes_count > u32:: max_value ( ) as u64 / 2 { return Err ( DecodeError :: InvalidValue ) ; }
1461
1478
// In Nov, 2023 there were about 69K channels; we cap allocations to 1.5x that.
1462
1479
let mut nodes = IndexedMap :: with_capacity ( cmp:: min ( nodes_count as usize , 103500 ) ) ;
1463
- for _ in 0 ..nodes_count {
1480
+ for i in 0 ..nodes_count {
1464
1481
let node_id = Readable :: read ( reader) ?;
1465
- let node_info = Readable :: read ( reader) ?;
1482
+ let mut node_info: NodeInfo = Readable :: read ( reader) ?;
1483
+ node_info. node_counter = i as u32 ;
1466
1484
nodes. insert ( node_id, node_info) ;
1467
1485
}
1468
1486
@@ -1477,6 +1495,8 @@ impl<L: Deref> ReadableArgs<L> for NetworkGraph<L> where L::Target: Logger {
1477
1495
logger,
1478
1496
channels : RwLock :: new ( channels) ,
1479
1497
nodes : RwLock :: new ( nodes) ,
1498
+ removed_node_counters : Mutex :: new ( Vec :: new ( ) ) ,
1499
+ next_node_counter : AtomicUsize :: new ( nodes_count as usize ) ,
1480
1500
last_rapid_gossip_sync_timestamp : Mutex :: new ( last_rapid_gossip_sync_timestamp) ,
1481
1501
removed_nodes : Mutex :: new ( new_hash_map ( ) ) ,
1482
1502
removed_channels : Mutex :: new ( new_hash_map ( ) ) ,
@@ -1522,15 +1542,42 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
1522
1542
logger,
1523
1543
channels : RwLock :: new ( IndexedMap :: new ( ) ) ,
1524
1544
nodes : RwLock :: new ( IndexedMap :: new ( ) ) ,
1545
+ next_node_counter : AtomicUsize :: new ( 0 ) ,
1546
+ removed_node_counters : Mutex :: new ( Vec :: new ( ) ) ,
1525
1547
last_rapid_gossip_sync_timestamp : Mutex :: new ( None ) ,
1526
1548
removed_channels : Mutex :: new ( new_hash_map ( ) ) ,
1527
1549
removed_nodes : Mutex :: new ( new_hash_map ( ) ) ,
1528
1550
pending_checks : utxo:: PendingChecks :: new ( ) ,
1529
1551
}
1530
1552
}
1531
1553
1554
+ fn test_node_counter_consistency ( & self ) {
1555
+ #[ cfg( debug_assertions) ] {
1556
+ let nodes = self . nodes . read ( ) . unwrap ( ) ;
1557
+ let removed_node_counters = self . removed_node_counters . lock ( ) . unwrap ( ) ;
1558
+ let next_counter = self . next_node_counter . load ( Ordering :: Acquire ) ;
1559
+ assert ! ( next_counter < ( u32 :: max_value( ) as usize ) / 2 ) ;
1560
+ let mut used_node_counters = vec ! [ 0u8 ; next_counter / 8 + 1 ] ;
1561
+
1562
+ for counter in removed_node_counters. iter ( ) {
1563
+ let pos = ( * counter as usize ) / 8 ;
1564
+ let bit = 1 << ( counter % 8 ) ;
1565
+ assert_eq ! ( used_node_counters[ pos] & bit, 0 ) ;
1566
+ used_node_counters[ pos] |= bit;
1567
+ }
1568
+ for ( _, node) in nodes. unordered_iter ( ) {
1569
+ assert ! ( ( node. node_counter as usize ) < next_counter) ;
1570
+ let pos = ( node. node_counter as usize ) / 8 ;
1571
+ let bit = 1 << ( node. node_counter % 8 ) ;
1572
+ assert_eq ! ( used_node_counters[ pos] & bit, 0 ) ;
1573
+ used_node_counters[ pos] |= bit;
1574
+ }
1575
+ }
1576
+ }
1577
+
1532
1578
/// Returns a read-only view of the network graph.
1533
1579
pub fn read_only ( & ' _ self ) -> ReadOnlyNetworkGraph < ' _ > {
1580
+ self . test_node_counter_consistency ( ) ;
1534
1581
let channels = self . channels . read ( ) . unwrap ( ) ;
1535
1582
let nodes = self . nodes . read ( ) . unwrap ( ) ;
1536
1583
ReadOnlyNetworkGraph {
@@ -1717,7 +1764,7 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
1717
1764
// b) we don't track UTXOs of channels we know about and remove them if they
1718
1765
// get reorg'd out.
1719
1766
// c) it's unclear how to do so without exposing ourselves to massive DoS risk.
1720
- Self :: remove_channel_in_nodes ( & mut nodes, & entry. get ( ) , short_channel_id) ;
1767
+ self . remove_channel_in_nodes ( & mut nodes, & entry. get ( ) , short_channel_id) ;
1721
1768
* entry. get_mut ( ) = channel_info;
1722
1769
} else {
1723
1770
return Err ( LightningError { err : "Already have knowledge of channel" . to_owned ( ) , action : ErrorAction :: IgnoreDuplicateGossip } ) ;
@@ -1734,9 +1781,13 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
1734
1781
node_entry. into_mut ( ) . channels . push ( short_channel_id) ;
1735
1782
} ,
1736
1783
IndexedMapEntry :: Vacant ( node_entry) => {
1784
+ let mut removed_node_counters = self . removed_node_counters . lock ( ) . unwrap ( ) ;
1785
+ let node_counter = removed_node_counters. pop ( )
1786
+ . unwrap_or ( self . next_node_counter . fetch_add ( 1 , Ordering :: Relaxed ) as u32 ) ;
1737
1787
node_entry. insert ( NodeInfo {
1738
1788
channels : vec ! ( short_channel_id) ,
1739
1789
announcement_info : None ,
1790
+ node_counter,
1740
1791
} ) ;
1741
1792
}
1742
1793
} ;
@@ -1855,7 +1906,7 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
1855
1906
if let Some ( chan) = channels. remove ( & short_channel_id) {
1856
1907
let mut nodes = self . nodes . write ( ) . unwrap ( ) ;
1857
1908
self . removed_channels . lock ( ) . unwrap ( ) . insert ( short_channel_id, current_time_unix) ;
1858
- Self :: remove_channel_in_nodes ( & mut nodes, & chan, short_channel_id) ;
1909
+ self . remove_channel_in_nodes ( & mut nodes, & chan, short_channel_id) ;
1859
1910
}
1860
1911
}
1861
1912
@@ -1874,6 +1925,7 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
1874
1925
let mut removed_nodes = self . removed_nodes . lock ( ) . unwrap ( ) ;
1875
1926
1876
1927
if let Some ( node) = nodes. remove ( & node_id) {
1928
+ let mut removed_node_counters = self . removed_node_counters . lock ( ) . unwrap ( ) ;
1877
1929
for scid in node. channels . iter ( ) {
1878
1930
if let Some ( chan_info) = channels. remove ( scid) {
1879
1931
let other_node_id = if node_id == chan_info. node_one { chan_info. node_two } else { chan_info. node_one } ;
@@ -1882,12 +1934,14 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
1882
1934
* scid != * chan_id
1883
1935
} ) ;
1884
1936
if other_node_entry. get ( ) . channels . is_empty ( ) {
1937
+ removed_node_counters. push ( other_node_entry. get ( ) . node_counter ) ;
1885
1938
other_node_entry. remove_entry ( ) ;
1886
1939
}
1887
1940
}
1888
1941
removed_channels. insert ( * scid, current_time_unix) ;
1889
1942
}
1890
1943
}
1944
+ removed_node_counters. push ( node. node_counter ) ;
1891
1945
removed_nodes. insert ( node_id, current_time_unix) ;
1892
1946
}
1893
1947
}
@@ -1963,7 +2017,7 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
1963
2017
let mut nodes = self . nodes . write ( ) . unwrap ( ) ;
1964
2018
for scid in scids_to_remove {
1965
2019
let info = channels. remove ( & scid) . expect ( "We just accessed this scid, it should be present" ) ;
1966
- Self :: remove_channel_in_nodes ( & mut nodes, & info, scid) ;
2020
+ self . remove_channel_in_nodes ( & mut nodes, & info, scid) ;
1967
2021
self . removed_channels . lock ( ) . unwrap ( ) . insert ( scid, Some ( current_time_unix) ) ;
1968
2022
}
1969
2023
}
@@ -2145,14 +2199,15 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
2145
2199
Ok ( ( ) )
2146
2200
}
2147
2201
2148
- fn remove_channel_in_nodes ( nodes : & mut IndexedMap < NodeId , NodeInfo > , chan : & ChannelInfo , short_channel_id : u64 ) {
2202
+ fn remove_channel_in_nodes ( & self , nodes : & mut IndexedMap < NodeId , NodeInfo > , chan : & ChannelInfo , short_channel_id : u64 ) {
2149
2203
macro_rules! remove_from_node {
2150
2204
( $node_id: expr) => {
2151
2205
if let IndexedMapEntry :: Occupied ( mut entry) = nodes. entry( $node_id) {
2152
2206
entry. get_mut( ) . channels. retain( |chan_id| {
2153
2207
short_channel_id != * chan_id
2154
2208
} ) ;
2155
2209
if entry. get( ) . channels. is_empty( ) {
2210
+ self . removed_node_counters. lock( ) . unwrap( ) . push( entry. get( ) . node_counter) ;
2156
2211
entry. remove_entry( ) ;
2157
2212
}
2158
2213
} else {
@@ -3574,6 +3629,7 @@ pub(crate) mod tests {
3574
3629
let valid_node_info = NodeInfo {
3575
3630
channels : Vec :: new ( ) ,
3576
3631
announcement_info : Some ( valid_node_ann_info) ,
3632
+ node_counter : 0 ,
3577
3633
} ;
3578
3634
3579
3635
let mut encoded_valid_node_info = Vec :: new ( ) ;
0 commit comments