module Data.LruCache.IO.Finalizer
( LruHandle(..)
, newLruHandle
, cached
, StripedLruHandle(..)
, newStripedLruHandle
, stripedCached
) where
import Control.Applicative ((<$>))
import Data.Foldable (traverse_)
import Data.Hashable (Hashable, hash)
import Data.IORef (IORef, atomicModifyIORef', newIORef)
import Data.Tuple (swap)
import Data.Vector (Vector)
import qualified Data.Vector as Vector
import Prelude hiding (lookup)
import Data.LruCache
newtype LruHandle k v = LruHandle (IORef (LruCache k (v, v -> IO ())))
newLruHandle :: Int -> IO (LruHandle k v)
newLruHandle capacity = LruHandle <$> newIORef (empty capacity)
cached ::
(Hashable k, Ord k) =>
LruHandle k v ->
k ->
IO v ->
(v -> IO ()) ->
IO v
cached (LruHandle ref) k io finalizer =
do lookupRes <- atomicModifyIORef' ref $ \c ->
case lookup k c of
Nothing -> (c, Nothing)
Just (v, c') -> (c', Just v)
case lookupRes of
Just (!v,_) -> return v
Nothing ->
do v <- io
evicted <- atomicModifyIORef' ref $ \c ->
swap (insertView k (v,finalizer) c)
traverse_ (\(_,(v',finalize')) -> finalize' v') evicted
return v
newtype StripedLruHandle k v = StripedLruHandle (Vector (LruHandle k v))
newStripedLruHandle :: Int -> Int -> IO (StripedLruHandle k v)
newStripedLruHandle numStripes capacityPerStripe =
StripedLruHandle <$> Vector.replicateM numStripes (newLruHandle capacityPerStripe)
stripedCached ::
(Hashable k, Ord k) =>
StripedLruHandle k v ->
k ->
IO v ->
(v -> IO ()) ->
IO v
stripedCached (StripedLruHandle v) k =
cached (v Vector.! idx) k
where
idx = hash k `mod` Vector.length v