22// Licensed under the MIT License. See LICENSE in the project root for license information.
33
44using System . Collections ;
5+ using System . Collections . Concurrent ;
56using System . Linq . Expressions ;
67using System . Reflection ;
78using System . Runtime . CompilerServices ;
@@ -191,35 +192,21 @@ private static Func<int, IList> GenerateArrayFactory(Type elementType)
191192 var cache = GetKeyedRegistrationCache ( registry ) ;
192193 var registryStamp = GetRegistryStamp ( registry ) ;
193194
194- lock ( cache )
195- {
196- if ( cache . TryGetValue ( elementType , out var entry ) && entry . Stamp == registryStamp )
197- {
198- return entry . Registrations ;
199- }
200-
201- var registrations = BuildKeyedRegistrationList ( registry , elementType ) ;
202- cache [ elementType ] = new KeyedRegistrationCacheEntry ( registryStamp , registrations ) ;
203- return registrations ;
204- }
195+ return cache . GetOrUpdate (
196+ elementType ,
197+ registryStamp ,
198+ ( ) => BuildKeyedRegistrationList ( registry , elementType ) ) ;
205199 }
206200
207201 private static IReadOnlyList < ServiceRegistration > GetStandardRegistrationList ( IComponentRegistry registry , Service elementTypeService )
208202 {
209203 var cache = GetStandardRegistrationCache ( registry ) ;
210204 var registryStamp = GetRegistryStamp ( registry ) ;
211205
212- lock ( cache )
213- {
214- if ( cache . TryGetValue ( elementTypeService , out var entry ) && entry . Stamp == registryStamp )
215- {
216- return entry . Registrations ;
217- }
218-
219- var registrations = BuildStandardRegistrationList ( registry , elementTypeService ) ;
220- cache [ elementTypeService ] = new StandardRegistrationCacheEntry ( registryStamp , registrations ) ;
221- return registrations ;
222- }
206+ return cache . GetOrUpdate (
207+ elementTypeService ,
208+ registryStamp ,
209+ ( ) => BuildStandardRegistrationList ( registry , elementTypeService ) ) ;
223210 }
224211
225212 private static IReadOnlyList < ServiceRegistration > BuildStandardRegistrationList ( IComponentRegistry registry , Service elementTypeService )
@@ -358,14 +345,19 @@ private static IList BuildCollection(
358345 return output ;
359346 }
360347
361- private static Dictionary < Type , KeyedRegistrationCacheEntry > GetKeyedRegistrationCache ( IComponentRegistry registry )
348+ private static KeyedRegistrationCacheStore . RegistryCache GetKeyedRegistrationCache ( IComponentRegistry registry )
362349 => KeyedCacheStore . GetOrCreateRegistryCache ( registry ) ;
363350
364- private static Dictionary < Service , StandardRegistrationCacheEntry > GetStandardRegistrationCache ( IComponentRegistry registry )
351+ private static StandardRegistrationCacheStore . RegistryCache GetStandardRegistrationCache ( IComponentRegistry registry )
365352 => StandardCacheStore . GetOrCreateRegistryCache ( registry ) ;
366353
367354 private static int GetRegistryStamp ( IComponentRegistry registry )
368355 {
356+ if ( registry is IRegistrationDiagnostics diagnostics )
357+ {
358+ return diagnostics . RegistrationsVersion ;
359+ }
360+
369361 if ( registry . Registrations is ICollection < IComponentRegistration > collection )
370362 {
371363 return collection . Count ;
@@ -414,11 +406,11 @@ private sealed class KeyedRegistrationCacheStore : IReflectionCache
414406
415407 public ReflectionCacheUsage Usage { get ; } = ReflectionCacheUsage . All ;
416408
417- public Dictionary < Type , KeyedRegistrationCacheEntry > GetOrCreateRegistryCache ( IComponentRegistry registry )
409+ public RegistryCache GetOrCreateRegistryCache ( IComponentRegistry registry )
418410 {
419411 var cache = _registries . GetValue ( registry , static _ => new RegistryCache ( ) ) ;
420412 RegisterCacheReference ( cache ) ;
421- return cache . Entries ;
413+ return cache ;
422414 }
423415
424416 public void Clear ( )
@@ -506,37 +498,43 @@ private void CleanupDeadRegistryReferences()
506498 /// <summary>
507499 /// Holds the cached keyed registrations for a single registry instance.
508500 /// </summary>
509- private sealed class RegistryCache
501+ public sealed class RegistryCache
510502 {
503+ private readonly ConcurrentDictionary < Type , KeyedRegistrationCacheEntry > _entries = new ( ) ;
511504 private int _registrationState ;
512505
513- public Dictionary < Type , KeyedRegistrationCacheEntry > Entries { get ; } = new ( ) ;
514-
515- public void ClearAll ( )
506+ public IReadOnlyList < ( Service Service , ServiceRegistration Registration ) > GetOrUpdate (
507+ Type elementType ,
508+ int stamp ,
509+ Func < IReadOnlyList < ( Service Service , ServiceRegistration Registration ) > > valueFactory )
516510 {
517- lock ( Entries )
511+ if ( _entries . TryGetValue ( elementType , out var existing ) && existing . Stamp == stamp )
518512 {
519- Entries . Clear ( ) ;
513+ return existing . Registrations ;
520514 }
515+
516+ var updated = _entries . AddOrUpdate (
517+ elementType ,
518+ _ => new KeyedRegistrationCacheEntry ( stamp , valueFactory ( ) ) ,
519+ ( _ , current ) => current . Stamp == stamp ? current : new KeyedRegistrationCacheEntry ( stamp , valueFactory ( ) ) ) ;
520+
521+ return updated . Registrations ;
521522 }
522523
523- public void Clear ( ReflectionCacheClearPredicate predicate )
524+ public void ClearAll ( )
524525 {
525- lock ( Entries )
526- {
527- if ( Entries . Count == 0 )
528- {
529- return ;
530- }
526+ _entries . Clear ( ) ;
527+ }
531528
532- var assemblySet = new HashSet < Assembly > ( ) ;
533- var keysToRemove = Entries . Keys
534- . Where ( key => predicate ( key , TypeAssemblyReferenceProvider . GetAllReferencedAssemblies ( key , assemblySet ) ) )
535- . ToArray ( ) ;
529+ public void Clear ( ReflectionCacheClearPredicate predicate )
530+ {
531+ var assemblySet = new HashSet < Assembly > ( ) ;
536532
537- foreach ( var key in keysToRemove )
533+ foreach ( var key in _entries . Keys )
534+ {
535+ if ( predicate ( key , TypeAssemblyReferenceProvider . GetAllReferencedAssemblies ( key , assemblySet ) ) )
538536 {
539- Entries . Remove ( key ) ;
537+ _entries . TryRemove ( key , out _ ) ;
540538 }
541539 }
542540 }
@@ -561,11 +559,11 @@ private sealed class StandardRegistrationCacheStore : IReflectionCache
561559
562560 public ReflectionCacheUsage Usage { get ; } = ReflectionCacheUsage . All ;
563561
564- public Dictionary < Service , StandardRegistrationCacheEntry > GetOrCreateRegistryCache ( IComponentRegistry registry )
562+ public RegistryCache GetOrCreateRegistryCache ( IComponentRegistry registry )
565563 {
566564 var cache = _registries . GetValue ( registry , static _ => new RegistryCache ( ) ) ;
567565 RegisterCacheReference ( cache ) ;
568- return cache . Entries ;
566+ return cache ;
569567 }
570568
571569 public void Clear ( )
@@ -649,37 +647,43 @@ private void CleanupDeadRegistryReferences()
649647 }
650648 }
651649
652- private sealed class RegistryCache
650+ public sealed class RegistryCache
653651 {
652+ private readonly ConcurrentDictionary < Service , StandardRegistrationCacheEntry > _entries = new ( ) ;
654653 private int _registrationState ;
655654
656- public Dictionary < Service , StandardRegistrationCacheEntry > Entries { get ; } = new ( ) ;
657-
658- public void ClearAll ( )
655+ public IReadOnlyList < ServiceRegistration > GetOrUpdate (
656+ Service service ,
657+ int stamp ,
658+ Func < IReadOnlyList < ServiceRegistration > > valueFactory )
659659 {
660- lock ( Entries )
660+ if ( _entries . TryGetValue ( service , out var existing ) && existing . Stamp == stamp )
661661 {
662- Entries . Clear ( ) ;
662+ return existing . Registrations ;
663663 }
664+
665+ var updated = _entries . AddOrUpdate (
666+ service ,
667+ _ => new StandardRegistrationCacheEntry ( stamp , valueFactory ( ) ) ,
668+ ( _ , current ) => current . Stamp == stamp ? current : new StandardRegistrationCacheEntry ( stamp , valueFactory ( ) ) ) ;
669+
670+ return updated . Registrations ;
664671 }
665672
666- public void Clear ( ReflectionCacheClearPredicate predicate )
673+ public void ClearAll ( )
667674 {
668- lock ( Entries )
669- {
670- if ( Entries . Count == 0 )
671- {
672- return ;
673- }
675+ _entries . Clear ( ) ;
676+ }
674677
675- var assemblySet = new HashSet < Assembly > ( ) ;
676- var keysToRemove = Entries . Keys
677- . Where ( service => ShouldRemove ( service , predicate , assemblySet ) )
678- . ToArray ( ) ;
678+ public void Clear ( ReflectionCacheClearPredicate predicate )
679+ {
680+ var assemblySet = new HashSet < Assembly > ( ) ;
679681
680- foreach ( var key in keysToRemove )
682+ foreach ( var key in _entries . Keys )
683+ {
684+ if ( ShouldRemove ( key , predicate , assemblySet ) )
681685 {
682- Entries . Remove ( key ) ;
686+ _entries . TryRemove ( key , out _ ) ;
683687 }
684688 }
685689 }
0 commit comments