@@ -25,12 +25,19 @@ us = CachePool(Vector{S}, () -> Vector{S}(undef, num_us); thread_safe=false)
2525 end
2626end
2727```
28+
29+ !!! warning "Escaping values"
30+ You must not use an acquired value after you have released it;
31+ the memory may be immediately re-used by some other consumer of
32+ your cache pool. Do not allow the acquired value to escape
33+ outside of the `@with_cache` block, or past a `release!()`.
2834"""
2935mutable struct CachePool{T, THREAD_SAFE}
30- pool:: Vector{T}
31- alloc:: Function
36+ const pool:: Vector{T}
37+ const alloc:: Function
3238 lock:: ReentrantLock
3339 num_alloced:: Int
40+ num_acquired:: Int
3441
3542 function CachePool (T, alloc:: F ; thread_safe:: Bool = true ) where {F}
3643 return new {T,Val{thread_safe}} (T[], alloc, ReentrantLock (), 0 )
@@ -46,6 +53,7 @@ Returns a cached element of the cache pool, calling `cache.alloc()` if none
4653are available.
4754"""
4855Base. @inline function acquire! (cache:: CachePool{T} , _dummy = nothing ) where {T}
56+ cache. num_acquired += 1
4957 if isempty (cache. pool)
5058 cache. num_alloced += 1
5159 return cache. alloc ():: T
@@ -60,11 +68,17 @@ Returns the value `val` to the cache pool.
6068"""
6169Base. @inline function release! (cache:: CachePool , val, _dummy = nothing )
6270 push! (cache. pool, val)
71+ cache. num_acquired -= 1
72+ end
73+
74+ function is_fully_released (cache:: CachePool , _dummy = nothing )
75+ return cache. num_acquired == 0
6376end
6477
6578# Thread-safe versions just sub out to the other methods, using `_dummy` to force correct dispatch
6679acquire! (cache:: ThreadSafeCachePool ) = @lock cache. lock acquire! (cache, nothing )
6780release! (cache:: ThreadSafeCachePool , val) = @lock cache. lock release! (cache, val, nothing )
81+ is_fully_released (cache:: ThreadSafeCachePool ) = @lock cache. lock is_fully_released (cache, nothing )
6882
6983macro with_cache (cache, name, body)
7084 return quote
@@ -270,8 +284,8 @@ mutable struct IndependentlyLinearizedSolution{T, S, N}
270284 time_mask:: BitMatrix
271285
272286 # Temporary object used during construction, will be set to `nothing` at the end.
273- ilsc:: Union{Nothing,IndependentlyLinearizedSolutionChunks{T,S}}
274- ilsc_cache_pool:: Union{Nothing,ThreadSafeCachePool{IndependentlyLinearizedSolutionChunksCache{T,S}}}
287+ ilsc:: Union{Nothing,IndependentlyLinearizedSolutionChunks{T,S,N }}
288+ ilsc_cache_pool:: Union{Nothing,ThreadSafeCachePool{IndependentlyLinearizedSolutionChunksCache{T,S,N }}}
275289end
276290# Helper function to create an ILS wrapped around an in-progress ILSC
277291function IndependentlyLinearizedSolution (ilsc:: IndependentlyLinearizedSolutionChunks{T,S,N} , cache_pool = nothing ) where {T,S,N}
@@ -392,14 +406,17 @@ function finish!(ils::IndependentlyLinearizedSolution{T,S}) where {T,S}
392406 # Update our struct, release the `ilsc` and its caches
393407 for t_chunk in ilsc. t_chunks
394408 release! (ilsc. cache. t_chunks, t_chunk)
409+ @assert is_fully_released (ilsc. cache. t_chunks)
395410 end
396411 for u_idx in 1 : length (ilsc. u_chunks)
397412 for u_chunk in ilsc. u_chunks[u_idx]
398413 release! (ilsc. cache. u_chunks, u_chunk)
399414 end
415+ @assert is_fully_released (ilsc. cache. u_chunks)
400416 end
401417 for time_mask in ilsc. time_masks
402418 release! (ilsc. cache. time_masks, time_mask)
419+ @assert is_fully_released (ilsc. cache. time_masks)
403420 end
404421 if ils. ilsc_cache_pool != = nothing
405422 release! (ils. ilsc_cache_pool, ilsc. cache)
0 commit comments