{-# LANGUAGE BangPatterns #-} -- | Limited cache control. module Database.VCache.Cache ( setVRefsCacheLimit , clearVRefsCache , clearVRefCache ) where import Data.IORef import Control.Concurrent.MVar import qualified Data.Map.Strict as Map import qualified System.Mem.Weak as Weak import Database.VCache.Types -- | VCache uses simple heuristics to decide which VRef contents to -- hold in memory. One heuristic is a target cache size. Developers -- may tune this to influence how many VRefs are kept in memory. -- -- The value is specified in bytes, and the default is ten megabytes. -- -- VCache size estimates are imprecise, converging on approximate -- size, albeit not accounting for memory amplification (e.g. from a -- compact UTF-8 string to Haskell's representation for [Char]). The -- limit given here is soft, influencing how aggressively content is -- removed from cache - i.e. there is no hard limit on content held -- by the cache. Estimated cache size is observable via vcacheStats. -- -- If developers need precise control over caching, they should use -- normal means to reason about GC of values in Haskell (i.e. VRef is -- cleared from cache upon GC). Or use vref' and deref' to avoid -- caching and use VCache as a simple serialization layer. -- setVRefsCacheLimit :: VSpace -> Int -> IO () setVRefsCacheLimit vc !n = writeIORef (vcache_climit vc) n {-# INLINE setVRefsCacheLimit #-} -- | clearVRefsCache will iterate over cached VRefs in Haskell memory -- at the time of the call, clearing the cache for each of them. This -- operation isn't recommended for common use. It is rather hostile to -- independent libraries working with VCache. But this function may -- find some use for benchmarks or staged applications. clearVRefsCache :: VSpace -> IO () clearVRefsCache vc = do cvrefs <- swapMVar (vcache_cvrefs vc) Map.empty mapM_ (mapM_ clearVREphCache . Map.elems) (Map.elems cvrefs) clearVREphCache :: VREph -> IO () clearVREphCache (VREph { vreph_cache = wc }) = Weak.deRefWeak wc >>= \ mbCache -> case mbCache of Nothing -> return () Just cache -> writeIORef cache NotCached -- | Immediately clear the cache associated with a VRef, allowing -- any contained data to be GC'd. Normally, VRef cached values are -- cleared either by a background thread or when the VRef itself -- is garbage collected from Haskell memory. But sometimes the -- programmer knows best. clearVRefCache :: VRef a -> IO () clearVRefCache v = do let vc = vref_space v modifyMVarMasked_ (vcache_cvrefs vc) $ \ cvrefs -> do case takeVREph (vref_addr v) (vref_type v) cvrefs of Nothing -> return cvrefs -- was not cached Just ( _ , cvrefs') -> return cvrefs' writeIORef (vref_cache v) NotCached {-# NOINLINE clearVRefCache #-}