@@ -348,6 +348,58 @@ public void WhenKeysAreContinuouslyRequestedInTheOrderTheyAreAddedCountIsBounded
348348 testOutputHelper . WriteLine ( $ "Total: { lru . Count } Hot: { lru . HotCount } Warm: { lru . WarmCount } Cold: { lru . ColdCount } ") ;
349349 lru . Count . Should ( ) . BeLessOrEqualTo ( capacity + 1 ) ;
350350 }
351+ }
352+
353+ public class KeysInOrderTestDataGenerator : IEnumerable < object [ ] >
354+ {
355+ private readonly List < object [ ] > _data = new List < object [ ] >
356+ {
357+ new object [ ] { new EqualCapacityPartition ( hotCap + warmCap + coldCap ) } ,
358+ new object [ ] { new EqualCapacityPartition ( 128 ) } ,
359+ new object [ ] { new EqualCapacityPartition ( 256 ) } ,
360+ new object [ ] { new EqualCapacityPartition ( 1024 ) } ,
361+ new object [ ] { new FavorWarmPartition ( 128 ) } ,
362+ new object [ ] { new FavorWarmPartition ( 256 ) } ,
363+ new object [ ] { new FavorWarmPartition ( 1024 ) } ,
364+ new object [ ] { new FavorWarmPartition ( 128 , 0.6 ) } ,
365+ new object [ ] { new FavorWarmPartition ( 256 , 0.6 ) } ,
366+ new object [ ] { new FavorWarmPartition ( 1024 , 0.6 ) } ,
367+ //new object[] { new FavorWarmPartition(10*1024, 0.6) },
368+ //new object[] { new FavorWarmPartition(100*1024, 0.6) },
369+ } ;
370+
371+ public IEnumerator < object [ ] > GetEnumerator ( ) => _data . GetEnumerator ( ) ;
372+
373+ IEnumerator IEnumerable . GetEnumerator ( ) => GetEnumerator ( ) ;
374+ }
375+
376+ [ Theory ]
377+ [ ClassData ( typeof ( KeysInOrderTestDataGenerator ) ) ]
378+ public void WhenKeysAreContinuouslyRequestedInTheOrderTheyAreAddedCountIsBounded2 ( ICapacityPartition p )
379+ {
380+ int capacity = p . Hot + p . Cold + p . Warm ;
381+ lru = new ConcurrentLru < int , string > ( capacity , p , EqualityComparer < int > . Default ) ;
382+
383+ testOutputHelper . WriteLine ( $ "Capacity: { lru . Capacity } (Hot: { p . Hot } Warm: { p . Warm } Cold: { p . Cold } )") ;
384+
385+ for ( int i = 0 ; i < capacity + 10 ; i ++ )
386+ {
387+ lru . GetOrAdd ( i , valueFactory . Create ) ;
388+
389+ // Touch all items already cached in hot, warm and cold.
390+ // This is worst case scenario, since we touch them in the exact order they
391+ // were added.
392+ for ( int j = 0 ; j < i ; j ++ )
393+ {
394+ lru . GetOrAdd ( j , valueFactory . Create ) ;
395+ }
396+ }
397+
398+ // For larger cache sizes, I have observed capacity + 5. This is linked to the number of attempts.
399+ // This is clearly a bug that needs further investigation, but considered not harmful at this point
400+ // since growth is bounded, we just allow 4 more items than we should in the absolute worst case.
401+ testOutputHelper . WriteLine ( $ "Total: { lru . Count } Hot: { lru . HotCount } Warm: { lru . WarmCount } Cold: { lru . ColdCount } ") ;
402+ lru . Count . Should ( ) . BeLessOrEqualTo ( capacity + 1 ) ;
351403 }
352404
353405 [ Fact ]
0 commit comments