summaryrefslogtreecommitdiff
path: root/src/server/Cache.hs
blob: bde07745a5ab8e6192d9c7cff025435b8cc3f478 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
module Cache (Cache,newCache,flushCache,readCache,readCache') where

import Control.Concurrent.MVar
import Data.Map (Map)
import qualified Data.Map as Map 
import System.Directory (getModificationTime)
import System.Mem(performGC)
import Data.Time (UTCTime)
import Data.Time.Compat (toUTCTime)

data Cache a = Cache {
      cacheLoad :: FilePath -> IO a,
      cacheObjects :: MVar (Map FilePath (MVar (Maybe (UTCTime, a))))
    }

newCache :: (FilePath -> IO a) -> IO (Cache a)
newCache load = 
    do objs <- newMVar Map.empty
       return $ Cache { cacheLoad = load, cacheObjects = objs }

flushCache :: Cache a -> IO ()
flushCache c = do modifyMVar_ (cacheObjects c) (const (return Map.empty))
                  performGC

readCache :: Cache a -> FilePath -> IO a
readCache c file = snd `fmap` readCache' c file

readCache' :: Cache a -> FilePath -> IO (UTCTime,a)
readCache' c file =
    do v <- modifyMVar (cacheObjects c) findEntry
       modifyMVar v readObject
  where
    -- Find the cache entry, inserting a new one if neccessary.
    findEntry objs = case Map.lookup file objs of
                       Just v -> return (objs,v)
                       Nothing -> do v <- newMVar Nothing
                                     return (Map.insert file v objs, v)
    -- Check time stamp, and reload if different than the cache entry
    readObject m = do t' <- toUTCTime `fmap` getModificationTime file
                      x' <- case m of
                        Just (t,x) | t' == t -> return x
                        _                    -> cacheLoad c file
                      return (Just (t',x'), (t',x'))