Check for in-memory cache invalidation (Fix #683)

This commit is contained in:
Daniel Gröber 2015-11-18 21:41:19 +01:00
parent 82f33cdbd7
commit 8568a6785c
3 changed files with 44 additions and 46 deletions

View File

@ -11,8 +11,9 @@ import Data.Maybe
import Data.Binary (Binary, encode, decodeOrFail) import Data.Binary (Binary, encode, decodeOrFail)
import Data.Version import Data.Version
import Data.Label import Data.Label
import qualified Data.ByteString.Lazy as BS import qualified Data.ByteString.Lazy as LBS
import qualified Data.ByteString.Lazy.Char8 as BS8 import qualified Data.ByteString as BS
import qualified Data.ByteString.Char8 as BS8
import Data.Time (UTCTime, getCurrentTime) import Data.Time (UTCTime, getCurrentTime)
import System.FilePath import System.FilePath
import Utils (TimedFile(..), timeMaybe, mightExist) import Utils (TimedFile(..), timeMaybe, mightExist)
@ -30,25 +31,24 @@ cached :: forall m a d. (Gm m, MonadIO m, Binary a, Eq d, Binary d, Show d)
-> m a -> m a
cached dir cd d = do cached dir cd d = do
mcc <- readCache mcc <- readCache
tcfile <- liftIO $ timeMaybe (cacheFile cd)
case mcc of case mcc of
Nothing -> Nothing -> do
writeCache (TimedCacheFiles tcfile []) Nothing "cache missing or unreadable" t <- liftIO $ getCurrentTime
Just (_t, ifs, d', a) | d /= d' -> do writeCache (TimedCacheFiles t []) Nothing "cache missing or unreadable"
tcf <- timeCacheInput dir (cacheFile cd) ifs Just (t, ifs, d', a) | d /= d' -> do
writeCache tcf (Just a) $ "input data changed" -- ++ " was: " ++ show d ++ " is: " ++ show d' tcfs <- timeCacheInput dir ifs
Just (_t, ifs, _, a) -> do writeCache (TimedCacheFiles t tcfs) (Just a) $ "input data changed" -- ++ " was: " ++ show d ++ " is: " ++ show d'
tcf <- timeCacheInput dir (cacheFile cd) ifs Just (t, ifs, _, a) -> do
case invalidatingInputFiles tcf of tcfs <- timeCacheInput dir ifs
Just [] -> return a case invalidatingInputFiles $ TimedCacheFiles t tcfs of
Just _ -> writeCache tcf (Just a) "input files changed" [] -> return a
Nothing -> writeCache tcf (Just a) "cache missing, existed a sec ago WTF?" _ -> writeCache (TimedCacheFiles t tcfs) (Just a) "input files changed"
where where
cacheHeader = BS8.pack $ "Written by ghc-mod " ++ showVersion version ++ "\n" cacheHeader = BS8.pack $ "Written by ghc-mod " ++ showVersion version ++ "\n"
writeCache tcf ma cause = do writeCache tcfs ma cause = do
(ifs', a) <- (cachedAction cd) tcf d ma (ifs', a) <- (cachedAction cd) tcfs d ma
t <- liftIO $ getCurrentTime t <- liftIO $ getCurrentTime
gmLog GmDebug "" $ (text "regenerating cache") <+>: text (cacheFile cd) gmLog GmDebug "" $ (text "regenerating cache") <+>: text (cacheFile cd)
<+> parens (text cause) <+> parens (text cause)
@ -58,8 +58,10 @@ cached dir cd d = do
gmLog GmDebug "" $ (text "writing memory cache") <+>: text (cacheFile cd) gmLog GmDebug "" $ (text "writing memory cache") <+>: text (cacheFile cd)
setLabel label $ Just (t, ifs', d, a) setLabel label $ Just (t, ifs', d, a)
liftIO $ BS.writeFile (dir </> cacheFile cd) $ let c = BS.append cacheHeader $ LBS.toStrict $ encode (t, ifs', d, a)
BS.append cacheHeader $ encode (t, ifs', d, a)
liftIO $ BS.writeFile (dir </> cacheFile cd) c
return a return a
setLabel l x = do setLabel l x = do
@ -88,7 +90,8 @@ cached dir cd d = do
case first BS8.words $ BS8.span (/='\n') cc of case first BS8.words $ BS8.span (/='\n') cc of
(["Written", "by", "ghc-mod", ver], rest) (["Written", "by", "ghc-mod", ver], rest)
| BS8.unpack ver == showVersion version -> | BS8.unpack ver == showVersion version ->
return $ either (const Nothing) Just $ decodeE $ BS.drop 1 rest return $ either (const Nothing) Just $
decodeE $ LBS.fromStrict $ BS.drop 1 rest
_ -> return Nothing _ -> return Nothing
decodeE b = do decodeE b = do
@ -96,17 +99,13 @@ cached dir cd d = do
Left (_rest, _offset, errmsg) -> Left errmsg Left (_rest, _offset, errmsg) -> Left errmsg
Right (_reset, _offset, a) -> Right a Right (_reset, _offset, a) -> Right a
timeCacheInput :: MonadIO m => FilePath -> FilePath -> [FilePath] -> m TimedCacheFiles timeCacheInput :: MonadIO m => FilePath -> [FilePath] -> m [TimedFile]
timeCacheInput dir cfile ifs = liftIO $ do timeCacheInput dir ifs = liftIO $ do
-- TODO: is checking the times this way around race free?
ins <- (timeMaybe . (dir </>)) `mapM` ifs ins <- (timeMaybe . (dir </>)) `mapM` ifs
mtcfile <- timeMaybe cfile return $ catMaybes ins
return $ TimedCacheFiles mtcfile (catMaybes ins)
invalidatingInputFiles :: TimedCacheFiles -> Maybe [FilePath] invalidatingInputFiles :: TimedCacheFiles -> [FilePath]
invalidatingInputFiles tcf = invalidatingInputFiles (TimedCacheFiles tcreated tcfs) =
case tcCacheFile tcf of map tfPath $
Nothing -> Nothing -- get input files older than tcfile
Just tcfile -> Just $ map tfPath $ filter ((TimedFile "" tcreated)<) tcfs
-- get input files older than tcfile
filter (tcfile<) $ tcFiles tcf

View File

@ -43,7 +43,7 @@ data Cached m s d a = Cached {
} }
data TimedCacheFiles = TimedCacheFiles { data TimedCacheFiles = TimedCacheFiles {
tcCacheFile :: Maybe TimedFile, tcCreated :: ModTime,
-- ^ 'cacheFile' timestamp -- ^ 'cacheFile' timestamp
tcFiles :: [TimedFile] tcFiles :: [TimedFile]
-- ^ Timestamped files returned by the cached action -- ^ Timestamped files returned by the cached action

View File

@ -199,22 +199,21 @@ resolvedComponentsCache distdir = Cached {
cacheFile = resolvedComponentsCacheFile distdir, cacheFile = resolvedComponentsCacheFile distdir,
cachedAction = \tcfs comps ma -> do cachedAction = \tcfs comps ma -> do
Cradle {..} <- cradle Cradle {..} <- cradle
let iifsM = invalidatingInputFiles tcfs let iifs = invalidatingInputFiles tcfs
setupChanged =
(cradleRootDir </> setupConfigPath distdir) `elem` iifs
mums :: Maybe [Either FilePath ModuleName] mums :: Maybe [Either FilePath ModuleName]
mums = mums =
case iifsM of let
Nothing -> Nothing filterOutSetupCfg =
Just iifs -> filter (/= cradleRootDir </> setupConfigPath distdir)
let changedFiles = filterOutSetupCfg iifs
filterOutSetupCfg = in if null changedFiles
filter (/= cradleRootDir </> setupConfigPath distdir) then Nothing
changedFiles = filterOutSetupCfg iifs else Just $ map Left changedFiles
in if null changedFiles
then Nothing
else Just $ map Left changedFiles
setupChanged = maybe False
(elem $ cradleRootDir </> setupConfigPath distdir)
iifsM
case (setupChanged, ma) of case (setupChanged, ma) of
(False, Just mcs) -> gmsGet >>= \s -> gmsPut s { gmComponents = mcs } (False, Just mcs) -> gmsGet >>= \s -> gmsPut s { gmComponents = mcs }
_ -> return () _ -> return ()