Skip to content

Commit 4ada0fe

Browse files
* make separate CacheWithMonitors class (so we can eventually unit test it)
* renamed clearingCache to isDisposing and using it only in IDisposable.Dispose implementation
1 parent 471cf07 commit 4ada0fe

File tree

1 file changed

+23
-17
lines changed

1 file changed

+23
-17
lines changed

src/SqlClient/SingleRootTypeProvider.fs

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,14 @@ open System.Runtime.Caching
66
open System
77
open System.Collections.Concurrent
88

9-
[<AbstractClass>]
10-
[<CompilerMessageAttribute("This API supports the FSharp.Data.SqlClient infrastructure and is not intended to be used directly from your code.", 101, IsHidden = true)>]
11-
type SingleRootTypeProvider(config: TypeProviderConfig, providerName, parameters, ?isErased) as this =
12-
inherit TypeProviderForNamespaces()
13-
9+
type CacheWithMonitors (providerName) =
1410
//cache
1511
let changeMonitors = ConcurrentBag()
1612
[<VolatileField>]
17-
let mutable clearingCache = false
13+
let mutable isDisposing = false
1814
let cache = new MemoryCache(providerName)
1915

20-
let clearCache() =
21-
clearingCache <- true
16+
member x.ClearCache() =
2217
while not changeMonitors.IsEmpty do
2318
let removed, (monitor: CacheEntryChangeMonitor) = changeMonitors.TryTake()
2419
if removed then monitor.Dispose()
@@ -29,7 +24,7 @@ type SingleRootTypeProvider(config: TypeProviderConfig, providerName, parameters
2924
|> Seq.toArray
3025
|> Array.iter (cache.Remove >> ignore)
3126

32-
let cacheGetOrAdd(key, value: Lazy<ProvidedTypeDefinition>, monitors) =
27+
member x.CacheGetOrAdd(key, value: Lazy<ProvidedTypeDefinition>, monitors, invalidate) =
3328
let policy = CacheItemPolicy()
3429
monitors |> Seq.iter policy.ChangeMonitors.Add
3530
let existing = cache.AddOrGetExisting(key, value, policy)
@@ -38,10 +33,8 @@ type SingleRootTypeProvider(config: TypeProviderConfig, providerName, parameters
3833
then
3934
let m = cache.CreateCacheEntryChangeMonitor [ key ]
4035
m.NotifyOnChanged(fun _ ->
41-
if not clearingCache
42-
then
43-
clearCache()
44-
this.Invalidate()
36+
x.ClearCache()
37+
invalidate()
4538
)
4639
changeMonitors.Add(m)
4740
value
@@ -50,6 +43,21 @@ type SingleRootTypeProvider(config: TypeProviderConfig, providerName, parameters
5043

5144
cacheItem.Value
5245

46+
interface IDisposable with
47+
member x.Dispose () =
48+
if not isDisposing then
49+
isDisposing <- true
50+
x.ClearCache()
51+
cache.Dispose()
52+
53+
54+
55+
[<AbstractClass>]
56+
[<CompilerMessageAttribute("This API supports the FSharp.Data.SqlClient infrastructure and is not intended to be used directly from your code.", 101, IsHidden = true)>]
57+
type SingleRootTypeProvider(config: TypeProviderConfig, providerName, parameters, ?isErased) as this =
58+
inherit TypeProviderForNamespaces()
59+
60+
let cache = new CacheWithMonitors(providerName)
5361
do
5462
let isErased = defaultArg isErased true
5563
let nameSpace = this.GetType().Namespace
@@ -61,14 +69,12 @@ type SingleRootTypeProvider(config: TypeProviderConfig, providerName, parameters
6169
parameters = parameters,
6270
instantiationFunction = fun typeName args ->
6371
let typ, monitors = this.CreateRootType(assembly, nameSpace, typeName, args)
64-
cacheGetOrAdd(typeName, typ, monitors |> Seq.cast)
72+
cache.CacheGetOrAdd(typeName, typ, monitors |> Seq.cast, this.Invalidate)
6573
)
6674

6775
this.AddNamespace( nameSpace, [ providerType ])
6876

6977
do
70-
this.Disposing.Add <| fun _ ->
71-
clearCache()
72-
cache.Dispose()
78+
this.Disposing.Add <| fun _ -> (cache :> IDisposable).Dispose()
7379

7480
abstract CreateRootType: assemblyName: Assembly * nameSpace: string * typeName: string * args: obj[] -> Lazy<ProvidedTypeDefinition> * obj[] // ChangeMonitor[] underneath but there is a problem https://github.com/fsprojects/FSharp.Data.SqlClient/issues/234#issuecomment-240694390

0 commit comments

Comments
 (0)