13
13
timing:: AtomicInterval , transaction:: VersionedTransaction , transport:: TransportError ,
14
14
} ,
15
15
std:: {
16
- collections:: BTreeMap ,
16
+ collections:: HashMap ,
17
17
net:: { IpAddr , Ipv4Addr , SocketAddr } ,
18
18
sync:: {
19
19
atomic:: { AtomicU64 , Ordering } ,
@@ -35,6 +35,8 @@ pub enum Connection {
35
35
struct ConnectionCacheStats {
36
36
cache_hits : AtomicU64 ,
37
37
cache_misses : AtomicU64 ,
38
+ cache_evictions : AtomicU64 ,
39
+ eviction_time_ms : AtomicU64 ,
38
40
sent_packets : AtomicU64 ,
39
41
total_batches : AtomicU64 ,
40
42
batch_success : AtomicU64 ,
@@ -84,6 +86,16 @@ impl ConnectionCacheStats {
84
86
self . cache_misses. swap( 0 , Ordering :: Relaxed ) ,
85
87
i64
86
88
) ,
89
+ (
90
+ "cache_evictions" ,
91
+ self . cache_evictions. swap( 0 , Ordering :: Relaxed ) ,
92
+ i64
93
+ ) ,
94
+ (
95
+ "eviction_time_ms" ,
96
+ self . eviction_time_ms. swap( 0 , Ordering :: Relaxed ) ,
97
+ i64
98
+ ) ,
87
99
(
88
100
"get_connection_ms" ,
89
101
self . get_connection_ms. swap( 0 , Ordering :: Relaxed ) ,
@@ -160,7 +172,8 @@ impl ConnectionCacheStats {
160
172
}
161
173
162
174
struct ConnectionMap {
163
- map : BTreeMap < SocketAddr , Connection > ,
175
+ map : HashMap < SocketAddr , Connection > ,
176
+ list_of_peers : Vec < SocketAddr > ,
164
177
stats : Arc < ConnectionCacheStats > ,
165
178
last_stats : AtomicInterval ,
166
179
use_quic : bool ,
@@ -169,7 +182,8 @@ struct ConnectionMap {
169
182
impl ConnectionMap {
170
183
pub fn new ( ) -> Self {
171
184
Self {
172
- map : BTreeMap :: new ( ) ,
185
+ map : HashMap :: with_capacity ( MAX_CONNECTIONS ) ,
186
+ list_of_peers : vec ! [ ] ,
173
187
stats : Arc :: new ( ConnectionCacheStats :: default ( ) ) ,
174
188
last_stats : AtomicInterval :: default ( ) ,
175
189
use_quic : false ,
@@ -194,32 +208,41 @@ struct GetConnectionResult {
194
208
connection : Connection ,
195
209
cache_hit : bool ,
196
210
report_stats : bool ,
197
- map_timing : u64 ,
198
- lock_timing : u64 ,
211
+ map_timing_ms : u64 ,
212
+ lock_timing_ms : u64 ,
199
213
connection_cache_stats : Arc < ConnectionCacheStats > ,
200
214
other_stats : Option < ( Arc < ClientStats > , ConnectionStats ) > ,
215
+ num_evictions : u64 ,
216
+ eviction_timing_ms : u64 ,
201
217
}
202
218
203
219
fn get_or_add_connection ( addr : & SocketAddr ) -> GetConnectionResult {
204
220
let mut get_connection_map_lock_measure = Measure :: start ( "get_connection_map_lock_measure" ) ;
205
221
let map = ( * CONNECTION_MAP ) . read ( ) . unwrap ( ) ;
206
222
get_connection_map_lock_measure. stop ( ) ;
207
223
208
- let mut lock_timing = get_connection_map_lock_measure. as_ms ( ) ;
224
+ let mut lock_timing_ms = get_connection_map_lock_measure. as_ms ( ) ;
209
225
210
226
let report_stats = map
211
227
. last_stats
212
228
. should_update ( CONNECTION_STAT_SUBMISSION_INTERVAL ) ;
213
229
214
230
let mut get_connection_map_measure = Measure :: start ( "get_connection_hit_measure" ) ;
215
- let ( connection, cache_hit, connection_cache_stats, maybe_stats) = match map. map . get ( addr) {
231
+ let (
232
+ connection,
233
+ cache_hit,
234
+ connection_cache_stats,
235
+ maybe_stats,
236
+ num_evictions,
237
+ eviction_timing_ms,
238
+ ) = match map. map . get ( addr) {
216
239
Some ( connection) => {
217
240
let mut stats = None ;
218
241
// update connection stats
219
242
if let Connection :: Quic ( conn) = connection {
220
243
stats = conn. stats ( ) . map ( |s| ( conn. base_stats ( ) , s) ) ;
221
244
}
222
- ( connection. clone ( ) , true , map. stats . clone ( ) , stats)
245
+ ( connection. clone ( ) , true , map. stats . clone ( ) , stats, 0 , 0 )
223
246
}
224
247
None => {
225
248
let ( _, send_socket) = solana_net_utils:: bind_in_range (
@@ -241,20 +264,31 @@ fn get_or_add_connection(addr: &SocketAddr) -> GetConnectionResult {
241
264
let mut map = ( * CONNECTION_MAP ) . write ( ) . unwrap ( ) ;
242
265
get_connection_map_lock_measure. stop ( ) ;
243
266
244
- lock_timing = lock_timing . saturating_add ( get_connection_map_lock_measure. as_ms ( ) ) ;
267
+ lock_timing_ms = lock_timing_ms . saturating_add ( get_connection_map_lock_measure. as_ms ( ) ) ;
245
268
246
- // evict a connection if the map is reaching upper bounds
247
- while map. map . len ( ) >= MAX_CONNECTIONS {
269
+ // evict a connection if the cache is reaching upper bounds
270
+ let mut num_evictions = 0 ;
271
+ let mut get_connection_cache_eviction_measure =
272
+ Measure :: start ( "get_connection_cache_eviction_measure" ) ;
273
+ while map. list_of_peers . len ( ) >= MAX_CONNECTIONS {
248
274
let mut rng = thread_rng ( ) ;
249
275
let n = rng. gen_range ( 0 , MAX_CONNECTIONS ) ;
250
- if let Some ( ( nth_addr, _) ) = map. map . iter ( ) . nth ( n) {
251
- let nth_addr = * nth_addr;
252
- map. map . remove ( & nth_addr) ;
253
- }
276
+ let nth_addr = map. list_of_peers . swap_remove ( n) ;
277
+ map. map . remove ( & nth_addr) ;
278
+ num_evictions += 1 ;
254
279
}
280
+ get_connection_cache_eviction_measure. stop ( ) ;
255
281
256
282
map. map . insert ( * addr, connection. clone ( ) ) ;
257
- ( connection, false , map. stats . clone ( ) , None )
283
+ map. list_of_peers . push ( * addr) ;
284
+ (
285
+ connection,
286
+ false ,
287
+ map. stats . clone ( ) ,
288
+ None ,
289
+ num_evictions,
290
+ get_connection_cache_eviction_measure. as_ms ( ) ,
291
+ )
258
292
}
259
293
} ;
260
294
get_connection_map_measure. stop ( ) ;
@@ -263,10 +297,12 @@ fn get_or_add_connection(addr: &SocketAddr) -> GetConnectionResult {
263
297
connection,
264
298
cache_hit,
265
299
report_stats,
266
- map_timing : get_connection_map_measure. as_ms ( ) ,
267
- lock_timing ,
300
+ map_timing_ms : get_connection_map_measure. as_ms ( ) ,
301
+ lock_timing_ms ,
268
302
connection_cache_stats,
269
303
other_stats : maybe_stats,
304
+ num_evictions,
305
+ eviction_timing_ms,
270
306
}
271
307
}
272
308
@@ -278,10 +314,12 @@ fn get_connection(addr: &SocketAddr) -> (Connection, Arc<ConnectionCacheStats>)
278
314
connection,
279
315
cache_hit,
280
316
report_stats,
281
- map_timing ,
282
- lock_timing ,
317
+ map_timing_ms ,
318
+ lock_timing_ms ,
283
319
connection_cache_stats,
284
320
other_stats,
321
+ num_evictions,
322
+ eviction_timing_ms,
285
323
} = get_or_add_connection ( addr) ;
286
324
287
325
if report_stats {
@@ -325,20 +363,26 @@ fn get_connection(addr: &SocketAddr) -> (Connection, Arc<ConnectionCacheStats>)
325
363
. fetch_add ( 1 , Ordering :: Relaxed ) ;
326
364
connection_cache_stats
327
365
. get_connection_hit_ms
328
- . fetch_add ( map_timing , Ordering :: Relaxed ) ;
366
+ . fetch_add ( map_timing_ms , Ordering :: Relaxed ) ;
329
367
} else {
330
368
connection_cache_stats
331
369
. cache_misses
332
370
. fetch_add ( 1 , Ordering :: Relaxed ) ;
333
371
connection_cache_stats
334
372
. get_connection_miss_ms
335
- . fetch_add ( map_timing, Ordering :: Relaxed ) ;
373
+ . fetch_add ( map_timing_ms, Ordering :: Relaxed ) ;
374
+ connection_cache_stats
375
+ . cache_evictions
376
+ . fetch_add ( num_evictions, Ordering :: Relaxed ) ;
377
+ connection_cache_stats
378
+ . eviction_time_ms
379
+ . fetch_add ( eviction_timing_ms, Ordering :: Relaxed ) ;
336
380
}
337
381
338
382
get_connection_measure. stop ( ) ;
339
383
connection_cache_stats
340
384
. get_connection_lock_ms
341
- . fetch_add ( lock_timing , Ordering :: Relaxed ) ;
385
+ . fetch_add ( lock_timing_ms , Ordering :: Relaxed ) ;
342
386
connection_cache_stats
343
387
. get_connection_ms
344
388
. fetch_add ( get_connection_measure. as_ms ( ) , Ordering :: Relaxed ) ;
0 commit comments