lrucaching 0.2.1 → 0.3.0
raw patch · 5 files changed
+97/−5 lines, 5 filesdep ~hspecPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: hspec
API changes (from Hackage documentation)
- Data.LruCache.IO: newStripedHandle :: Int -> Int -> IO (StripedLruHandle k v)
+ Data.LruCache.IO: newStripedLruHandle :: Int -> Int -> IO (StripedLruHandle k v)
+ Data.LruCache.IO.Finalizer: LruHandle :: (IORef (LruCache k (v, v -> IO ()))) -> LruHandle k v
+ Data.LruCache.IO.Finalizer: StripedLruHandle :: (Vector (LruHandle k v)) -> StripedLruHandle k v
+ Data.LruCache.IO.Finalizer: cached :: (Hashable k, Ord k) => LruHandle k v -> k -> IO v -> (v -> IO ()) -> IO v
+ Data.LruCache.IO.Finalizer: newLruHandle :: Int -> IO (LruHandle k v)
+ Data.LruCache.IO.Finalizer: newStripedLruHandle :: Int -> Int -> IO (StripedLruHandle k v)
+ Data.LruCache.IO.Finalizer: newtype LruHandle k v
+ Data.LruCache.IO.Finalizer: newtype StripedLruHandle k v
+ Data.LruCache.IO.Finalizer: stripedCached :: (Hashable k, Ord k) => StripedLruHandle k v -> k -> IO v -> (v -> IO ()) -> IO v
Files
- CHANGELOG.md +6/−0
- README.md +1/−1
- lrucaching.cabal +2/−1
- src/Data/LruCache/IO.hs +5/−3
- src/Data/LruCache/IO/Finalizer.hs +83/−0
CHANGELOG.md view
@@ -1,3 +1,9 @@+0.3.0+-----+* Add `Data.LruCache.IO.Finalizer` for automatically running finalizer+ when evicting cache entrvies.+* Rename `newStripedHandle` to `newStripedLruHandle`+ 0.2.1 ----- * Fix build with GHC 7.8
README.md view
@@ -1,7 +1,7 @@ # lrucaching [](https://travis-ci.org/cocreature/lrucaching)-[]()+[](https://hackage.haskell.org/package/lrucaching) An implementation of lrucaches based on a [blogpost](https://jaspervdj.be/posts/2015-02-24-lru-cache.html) by
lrucaching.cabal view
@@ -1,5 +1,5 @@ name: lrucaching-version: 0.2.1+version: 0.3.0 synopsis: LRU cache description: Please see README.md homepage: https://github.com/cocreature/lrucaching#readme@@ -19,6 +19,7 @@ hs-source-dirs: src exposed-modules: Data.LruCache Data.LruCache.IO+ Data.LruCache.IO.Finalizer Data.LruCache.Internal build-depends: base >= 4.7 && < 5 , base-compat >= 0.9 && < 0.10
src/Data/LruCache/IO.hs view
@@ -5,6 +5,8 @@ License : BSD3 Maintainer : moritz.kiefer@purelyfunctional.org Convenience module for the common case of caching results of IO actions.+See 'Data.LruCache.IO.Finalizer' if you want to run finalizers+automatically when cache entries are evicted -} module Data.LruCache.IO ( LruHandle(..)@@ -12,7 +14,7 @@ , newLruHandle , StripedLruHandle(..) , stripedCached- , newStripedHandle+ , newStripedLruHandle ) where import Control.Applicative ((<$>))@@ -53,8 +55,8 @@ -- | Create a new 'StripedHandle' with the given number of stripes and -- the given capacity for each stripe.-newStripedHandle :: Int -> Int -> IO (StripedLruHandle k v)-newStripedHandle numStripes capacityPerStripe =+newStripedLruHandle :: Int -> Int -> IO (StripedLruHandle k v)+newStripedLruHandle numStripes capacityPerStripe = StripedLruHandle <$> Vector.replicateM numStripes (newLruHandle capacityPerStripe) -- | Striped version of 'cached'.
+ src/Data/LruCache/IO/Finalizer.hs view
@@ -0,0 +1,83 @@+{-# LANGUAGE BangPatterns #-}+{-|+Module : Data.LruCache.IO.Finalizer+Copyright : (c) Moritz Kiefer, 2016+ (c) Jasper Van der Jeugt, 2015+License : BSD3+Maintainer : moritz.kiefer@purelyfunctional.org+Convenience module for the common case of caching results of IO actions +when finalizers have to be run when cache entries are evicted.+-}+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++-- | Store a LRU cache in an 'IORef to be able to conveniently update it.+newtype LruHandle k v = LruHandle (IORef (LruCache k (v, v -> IO ())))++-- | Create a new LRU cache of the given size.+newLruHandle :: Int -> IO (LruHandle k v)+newLruHandle capacity = LruHandle <$> newIORef (empty capacity)++-- | Return the cached result of the action or, in the case of a cache+-- miss, execute the action and insert it in the cache.+cached ::+ (Hashable k, Ord k) =>+ LruHandle k v ->+ k ->+ IO v ->+ (v -> IO ()) {- ^ finalizer -} ->+ 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++-- | Using a stripe of multiple handles can improve the performance in+-- the case of concurrent accesses since several handles can be+-- accessed in parallel.+newtype StripedLruHandle k v = StripedLruHandle (Vector (LruHandle k v))++-- | Create a new 'StripedHandle' with the given number of stripes and+-- the given capacity for each stripe.+newStripedLruHandle :: Int -> Int -> IO (StripedLruHandle k v)+newStripedLruHandle numStripes capacityPerStripe =+ StripedLruHandle <$> Vector.replicateM numStripes (newLruHandle capacityPerStripe)++-- | Striped version of 'cached'.+stripedCached ::+ (Hashable k, Ord k) =>+ StripedLruHandle k v ->+ k ->+ IO v ->+ (v -> IO ()) {- ^ finalizer -} ->+ IO v+stripedCached (StripedLruHandle v) k =+ cached (v Vector.! idx) k+ where+ idx = hash k `mod` Vector.length v