packages feed

filecache 0.2.3 → 0.2.4

raw patch · 2 files changed

+34/−57 lines, 2 filesdep +stmdep ~strict-base-types

Dependencies added: stm

Dependency ranges changed: strict-base-types

Files

Data/FileCache.hs view
@@ -12,21 +12,17 @@  import qualified Data.HashMap.Strict as HM import System.INotify-import Control.Concurrent+import Control.Concurrent.STM import qualified Data.Either.Strict as S import Control.Exception-import Control.Monad import Control.Monad.Error.Class import Control.Exception.Lens--data Messages r a = Invalidate !FilePath-                  | Query !FilePath !(IO (S.Either r a)) !(MVar (S.Either r a))-                  | GetCopy !(MVar (HM.HashMap FilePath (S.Either r a, WatchDescriptor)))-                  | Stop+import Control.Applicative+import Control.Monad (join)  -- | The main FileCache type, for queries returning 'Either r a'. The r -- type must be an instance of 'Error'.-data FileCacheR r a = FileCache !(Chan (Messages r a))+data FileCacheR r a = FileCache !(TVar (HM.HashMap FilePath (S.Either r a, WatchDescriptor))) !INotify  -- | A default type synonym, for String errors. type FileCache = FileCacheR String@@ -34,50 +30,21 @@ -- | Generates a new file cache. The opaque type is for use with other -- functions. newFileCache :: Error r => IO (FileCacheR r a)-newFileCache = do-    q <- newChan-    ino <- initINotify-    void $ forkIO (mapMaster HM.empty q ino)-    return (FileCache q)+newFileCache = FileCache <$> newTVarIO HM.empty <*> initINotify  -- | Destroys the thread running the FileCache. Pretty dangerous stuff. killFileCache :: FileCacheR r a -> IO ()-killFileCache (FileCache q) = writeChan q Stop--mapMaster :: Error r => HM.HashMap FilePath (S.Either r a, WatchDescriptor) -> Chan (Messages r a) -> INotify -> IO ()-mapMaster mp q ino = do-    let nochange = return (Just mp)-        change x = return (Just (x mp))-    msg <- readChan q-    nmp <- case msg of-            Stop -> killINotify ino >> return Nothing-            Invalidate fp ->-                case HM.lookup fp mp of-                    Nothing -> nochange-                    Just (_,desc) -> catching_ id (removeWatch desc) (return ()) >> change (HM.delete fp)-            Query fp action respvar ->-                case HM.lookup fp mp of-                    Just (x,_) -> putMVar respvar x >> nochange-                    Nothing -> do-                        let addw value = do-                                wm <- addWatch ino [CloseWrite,Delete,Move,Attrib,Create] fp (const $ invalidate fp (FileCache q))-                                change (HM.insert fp (value,wm))-                            withWatch value = do-                                putMVar respvar value-                                catching_ id (addw value) nochange-                            noWatch x = putMVar respvar x >> nochange-                        catches (action >>= withWatch)-                            [ handler _IOException (\io -> noWatch   (S.Left (strMsg $ show io)))-                            , handler id           (\e  -> withWatch (S.Left (strMsg $ show e)))-                            ]-            GetCopy mv -> putMVar mv mp >> nochange-    case nmp of-        Just x -> mapMaster x q ino-        Nothing -> return ()+killFileCache (FileCache _ ino) = killINotify ino  -- | Manually invalidates an entry. invalidate :: Error r => FilePath -> FileCacheR r a -> IO ()-invalidate fp (FileCache q) = writeChan q (Invalidate fp)+invalidate fp (FileCache q _) = join $ atomically $ do+    mp <- readTVar q+    case HM.lookup fp mp of+        Nothing -> return (return ())+        Just (_,desc) -> do+            writeTVar q (HM.delete fp mp)+            return (removeWatch desc)  -- | Queries the cache, populating it if necessary, returning a strict -- 'Either' (from "Data.Either.Strict").@@ -90,11 +57,23 @@       -> FilePath -- ^ Path of the file entry       -> IO (S.Either r a) -- ^ The computation that will be used to populate the cache       -> IO (S.Either r a)-query (FileCache q) fp generate = do-    v <- newEmptyMVar-    writeChan q (Query fp generate v)-    readMVar v-+query f@(FileCache q ino) fp action = do+    mp <- getCache f+    case HM.lookup fp mp of+        Just (x,_) -> return x+        Nothing -> do+            let addw value = do+                    wm <- addWatch ino [CloseWrite,Delete,Move,Attrib,Create] fp (const $ invalidate fp f)+                    change (HM.insert fp (value,wm))+                withWatch value = do+                    catching_ id (addw value) nochange+                    return value+                change = atomically . modifyTVar q+                nochange = return ()+            catches (action >>= withWatch)+                [ handler _IOException (\io -> return    (S.Left (strMsg $ show io)))+                , handler id           (\e  -> withWatch (S.Left (strMsg $ show e)))+                ] -- | Just like `query`, but with the standard "Either" type. lazyQuery :: Error r       => FileCacheR r a@@ -110,8 +89,5 @@  -- | Gets a copy of the cache. getCache :: Error r => FileCacheR r a -> IO (HM.HashMap FilePath (S.Either r a, WatchDescriptor))-getCache (FileCache q) = do-    v <- newEmptyMVar-    writeChan q (GetCopy v)-    readMVar v+getCache (FileCache q _) = atomically (readTVar q) 
filecache.cabal view
@@ -2,7 +2,7 @@ -- documentation, see http://haskell.org/cabal/users-guide/  name:                filecache-version:             0.2.3+version:             0.2.4 synopsis:            A Linux-only cache system associating values to files. description:         A Linux-only cache system, that works by associating computation results with file names. When the files are modified, the cache entries are discarded. homepage:            http://lpuppet.banquise.net/@@ -30,6 +30,7 @@                      , unordered-containers == 0.2.*                      , hashable             >= 1.2   && < 1.3                      , hinotify             >= 0.3.6 && < 0.4-                     , strict-base-types    >= 0.2+                     , strict-base-types    >= 0.2.2                      , mtl                  == 2.1.*                      , lens                 >= 3.9 && < 5+                     , stm