From d7a4591b60aa57b6860f456e7ea08bc72da952fb Mon Sep 17 00:00:00 2001 From: Fendor Date: Mon, 11 Jan 2021 23:29:32 +0100 Subject: [PATCH 1/2] Add custom cache layer for session loading Achieves this by adding a HashMap from NormalizedFilePath to its respective hie.yaml location. This works nicely with the existing implementation, but increases the memory usage by an considerable amount. This change is motivated by https://github.com/mpickering/hie-bios/pull/264 where we set the build-dir for cabal based projects to some config directory in order to avoid recompilation issues whenever users invoked `cabal build`. However, this uncovered an issue in the existing code-base, as HLS will ask for the compilation options for generated modules, such as `Paths_*`, by looking for the responsible `hie.yaml` file and using an internal cache for the options. This used to be fine, until the aforementioned hie-bios change, since now `Paths_*` module will be in some `~/.cache/hie-bios/...` directory, which has no responsible `hie.yaml` which is why we see error messages such: `No hie.yaml found, use implicit hie-bios`. --- .../session-loader/Development/IDE/Session.hs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/ghcide/session-loader/Development/IDE/Session.hs b/ghcide/session-loader/Development/IDE/Session.hs index ef09e45726..03bbbdeae1 100644 --- a/ghcide/session-loader/Development/IDE/Session.hs +++ b/ghcide/session-loader/Development/IDE/Session.hs @@ -70,6 +70,7 @@ import NameCache import Packages import Control.Exception (evaluate) import Data.Void +import Control.Applicative (Alternative((<|>))) data CacheDirs = CacheDirs @@ -113,6 +114,11 @@ loadSessionWithOptions SessionLoadingOptions{..} dir = do hscEnvs <- newVar Map.empty :: IO (Var HieMap) -- Mapping from a Filepath to HscEnv fileToFlags <- newVar Map.empty :: IO (Var FlagsMap) + -- Mapping from a Filepath to its 'hie.yaml' location. + -- Should hold the same Filepaths as 'fileToFlags', otherwise + -- they are inconsistent. So, everywhere you modify 'fileToFlags', + -- you have to modify 'filesMap' as well. + filesMap <- newVar HM.empty :: IO (Var FilesMap) -- Version of the mappings above version <- newVar 0 let returnWithVersion fun = IdeGhcSession fun <$> liftIO (readVar version) @@ -271,6 +277,8 @@ loadSessionWithOptions SessionLoadingOptions{..} dir = do modifyVar_ fileToFlags $ \var -> do pure $ Map.insert hieYaml (HM.fromList (concatMap toFlagsMap all_targets)) var + modifyVar_ filesMap $ \var -> do + pure $ HM.union var (HM.fromList (zip (map fst $ concatMap toFlagsMap all_targets) (repeat hieYaml))) extendKnownTargets all_targets @@ -329,6 +337,8 @@ loadSessionWithOptions SessionLoadingOptions{..} dir = do let res = (map (renderCradleError ncfp) err, Nothing) modifyVar_ fileToFlags $ \var -> do pure $ Map.insertWith HM.union hieYaml (HM.singleton ncfp (res, dep_info)) var + modifyVar_ filesMap $ \var -> do + pure $ HM.insert ncfp hieYaml var return (res, maybe [] pure hieYaml ++ concatMap cradleErrorDependencies err) -- This caches the mapping from hie.yaml + Mod.hs -> [String] @@ -358,8 +368,10 @@ loadSessionWithOptions SessionLoadingOptions{..} dir = do -- before attempting to do so. let getOptions :: FilePath -> IO (IdeResult HscEnvEq, [FilePath]) getOptions file = do + ncfp <- toNormalizedFilePath' <$> canonicalizePath file + cachedHieYamlLocation <- HM.lookup ncfp <$> readVar filesMap hieYaml <- cradleLoc file - sessionOpts (hieYaml, file) `catch` \e -> + sessionOpts (join cachedHieYamlLocation <|> hieYaml, file) `catch` \e -> return (([renderPackageSetupException file e], Nothing), maybe [] pure hieYaml) returnWithVersion $ \file -> do @@ -543,7 +555,11 @@ renderCradleError nfp (CradleError _ _ec t) = -- See Note [Multi Cradle Dependency Info] type DependencyInfo = Map.Map FilePath (Maybe UTCTime) type HieMap = Map.Map (Maybe FilePath) (HscEnv, [RawComponentInfo]) +-- | Maps a "hie.yaml" location to all its Target Filepaths and options. type FlagsMap = Map.Map (Maybe FilePath) (HM.HashMap NormalizedFilePath (IdeResult HscEnvEq, DependencyInfo)) +-- | Maps a Filepath to its respective "hie.yaml" location. +-- It aims to be the reverse of 'FlagsMap'. +type FilesMap = HM.HashMap NormalizedFilePath (Maybe FilePath) -- This is pristine information about a component data RawComponentInfo = RawComponentInfo From 1391de43f7543c8e7c0b4974a52b63273c012aa0 Mon Sep 17 00:00:00 2001 From: Pepe Iborra Date: Thu, 28 Jan 2021 20:16:30 +0000 Subject: [PATCH 2/2] Apply suggestions from code review modifyVar with evaluate --- ghcide/session-loader/Development/IDE/Session.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ghcide/session-loader/Development/IDE/Session.hs b/ghcide/session-loader/Development/IDE/Session.hs index 03bbbdeae1..11c4278059 100644 --- a/ghcide/session-loader/Development/IDE/Session.hs +++ b/ghcide/session-loader/Development/IDE/Session.hs @@ -278,7 +278,7 @@ loadSessionWithOptions SessionLoadingOptions{..} dir = do modifyVar_ fileToFlags $ \var -> do pure $ Map.insert hieYaml (HM.fromList (concatMap toFlagsMap all_targets)) var modifyVar_ filesMap $ \var -> do - pure $ HM.union var (HM.fromList (zip (map fst $ concatMap toFlagsMap all_targets) (repeat hieYaml))) + evaluate $ HM.union var (HM.fromList (zip (map fst $ concatMap toFlagsMap all_targets) (repeat hieYaml))) extendKnownTargets all_targets @@ -338,7 +338,7 @@ loadSessionWithOptions SessionLoadingOptions{..} dir = do modifyVar_ fileToFlags $ \var -> do pure $ Map.insertWith HM.union hieYaml (HM.singleton ncfp (res, dep_info)) var modifyVar_ filesMap $ \var -> do - pure $ HM.insert ncfp hieYaml var + evaluate $ HM.insert ncfp hieYaml var return (res, maybe [] pure hieYaml ++ concatMap cradleErrorDependencies err) -- This caches the mapping from hie.yaml + Mod.hs -> [String]