Skip to content

Commit 077e30c

Browse files
authored
Merge pull request #250 from smoothdeveloper/fix-memorycache-disposal
fix for #240
2 parents 16c2ce6 + 4ada0fe commit 077e30c

File tree

1 file changed

+29
-16
lines changed

1 file changed

+29
-16
lines changed

src/SqlClient/SingleRootTypeProvider.fs

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,25 @@ 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 disposingCache = false
13+
let mutable isDisposing = false
1814
let cache = new MemoryCache(providerName)
1915

20-
let disposeCache() =
21-
disposingCache <- true
16+
member x.ClearCache() =
2217
while not changeMonitors.IsEmpty do
2318
let removed, (monitor: CacheEntryChangeMonitor) = changeMonitors.TryTake()
2419
if removed then monitor.Dispose()
25-
cache.Dispose()
20+
21+
// http://stackoverflow.com/a/29916907
22+
cache
23+
|> Seq.map (fun e -> e.Key)
24+
|> Seq.toArray
25+
|> Array.iter (cache.Remove >> ignore)
2626

27-
let cacheGetOrAdd(key, value: Lazy<ProvidedTypeDefinition>, monitors) =
27+
member x.CacheGetOrAdd(key, value: Lazy<ProvidedTypeDefinition>, monitors, invalidate) =
2828
let policy = CacheItemPolicy()
2929
monitors |> Seq.iter policy.ChangeMonitors.Add
3030
let existing = cache.AddOrGetExisting(key, value, policy)
@@ -33,10 +33,8 @@ type SingleRootTypeProvider(config: TypeProviderConfig, providerName, parameters
3333
then
3434
let m = cache.CreateCacheEntryChangeMonitor [ key ]
3535
m.NotifyOnChanged(fun _ ->
36-
if not disposingCache
37-
then
38-
disposeCache()
39-
this.Invalidate()
36+
x.ClearCache()
37+
invalidate()
4038
)
4139
changeMonitors.Add(m)
4240
value
@@ -45,6 +43,21 @@ type SingleRootTypeProvider(config: TypeProviderConfig, providerName, parameters
4543

4644
cacheItem.Value
4745

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)
4861
do
4962
let isErased = defaultArg isErased true
5063
let nameSpace = this.GetType().Namespace
@@ -56,12 +69,12 @@ type SingleRootTypeProvider(config: TypeProviderConfig, providerName, parameters
5669
parameters = parameters,
5770
instantiationFunction = fun typeName args ->
5871
let typ, monitors = this.CreateRootType(assembly, nameSpace, typeName, args)
59-
cacheGetOrAdd(typeName, typ, monitors |> Seq.cast)
72+
cache.CacheGetOrAdd(typeName, typ, monitors |> Seq.cast, this.Invalidate)
6073
)
6174

6275
this.AddNamespace( nameSpace, [ providerType ])
6376

6477
do
65-
this.Disposing.Add <| fun _ -> disposeCache()
78+
this.Disposing.Add <| fun _ -> (cache :> IDisposable).Dispose()
6679

6780
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)