@@ -379,51 +379,75 @@ public async Task LRUEviction_WithConcurrentAccess_BehavesReasonably()
379379 var cache = new MemoryCache < string , IReadOnlyList < int > > ( SizeLimit ) ;
380380 var cacheAccessor = cache . GetTestAccessor ( ) ;
381381
382- using var cancellationSource = new CancellationTokenSource ( ) ;
382+ var hotAccessEstablished = new TaskCompletionSource < bool > ( ) ;
383+ var coldEntryAdded = false ;
383384
384385 // Add initial entries
385- var initialKeys = new List < string > ( ) ;
386+ var initialKeys = new string [ SizeLimit ] ;
387+
386388 for ( var i = 0 ; i < SizeLimit ; i ++ )
387389 {
388390 var key = $ "initial-{ i } ";
389- initialKeys . Add ( key ) ;
391+ initialKeys [ i ] = key ;
390392 cache . Set ( key , [ i ] ) ;
391393 }
392394
393- // Continuously access first few entries to make them "hot"
394- var hotKeys = initialKeys . Take ( 2 ) . ToList ( ) ;
395+ // Continuously access first couple entries to make them "hot"
396+ var hotKeys = initialKeys . Take ( 2 ) . ToArray ( ) ;
395397 var keepHotTask = Task . Run ( async ( ) =>
396398 {
397399 try
398400 {
399- while ( ! cancellationSource . IsCancellationRequested )
401+ // Establish hot key access
402+ for ( var i = 0 ; i < 10 ; i ++ )
400403 {
401- foreach ( var key in hotKeys )
402- {
403- _ = cache . TryGetValue ( key , out _ ) ;
404- }
404+ await AccessHotKeysAsync ( hotKeys , cache ) ;
405+ }
405406
406- await Task . Delay ( 1 , cancellationSource . Token ) ;
407+ hotAccessEstablished . TrySetResult ( true ) ;
408+
409+ // Continue accessing hot keys while waiting for cold entry to be added
410+ while ( ! coldEntryAdded )
411+ {
412+ await AccessHotKeysAsync ( hotKeys , cache ) ;
413+ }
414+
415+ // Continue accessing hot keys until finished.
416+ for ( var i = 0 ; i < 100 ; i ++ )
417+ {
418+ await AccessHotKeysAsync ( hotKeys , cache ) ;
407419 }
408420 }
409421 catch ( OperationCanceledException )
410422 {
411423 // Expected when cancellation token is canceled
412424 }
425+
426+ async Task AccessHotKeysAsync ( string [ ] hotKeys , MemoryCache < string , IReadOnlyList < int > > cache )
427+ {
428+ foreach ( var key in hotKeys )
429+ {
430+ _ = cache . TryGetValue ( key , out _ ) ;
431+ }
432+
433+ await Task . Delay ( 1 , DisposalToken ) ;
434+ }
413435 } ) ;
414436
415437 // Trigger compaction
416- await Task . Delay ( 10 ) ; // Let hot access pattern establish
438+ await hotAccessEstablished . Task ;
417439 cache . Set ( "trigger-compaction" , [ 999 ] ) ;
418440
419- cancellationSource . Cancel ( ) ;
441+ // Signal that the cold entry was added
442+ coldEntryAdded = true ;
443+
420444 await keepHotTask ;
421445
422446 // Verify hot entries are more likely to survive
423447 var hotSurvivalCount = hotKeys . Count ( key => cache . TryGetValue ( key , out _ ) ) ;
424448 var coldSurvivalCount = initialKeys . Skip ( 2 ) . Count ( key => cache . TryGetValue ( key , out _ ) ) ;
425449
426- // Hot entries should have better survival rate (though this is probabilistic)
450+ // Hot entries should have better survival rate
427451 Assert . True ( hotSurvivalCount >= coldSurvivalCount ,
428452 $ "Hot entries ({ hotSurvivalCount } ) should survive at least as well as cold entries ({ coldSurvivalCount } )") ;
429453 }
0 commit comments