@@ -418,14 +418,33 @@ getHieDbLoc dir = do
418418 createDirectoryIfMissing True cDir
419419 pure (cDir </> db)
420420
421+ {- Note [SessionState and batch load]
422+ SessionState manages the state for batch loading files in the session loader.
423+
424+ - When a new file needs to be loaded, it is added to the pendingFiles set.
425+ - The loader processes files from pendingFiles, attempting to load them in batches.
426+ - If a file is already in failedFiles, it is loaded individually (single-file mode).
427+ - Otherwise, the loader tries to load as many files as possible together (batch mode).
428+
429+ On success:
430+ - All successfully loaded files are removed from pendingFiles and failedFiles,
431+ and added to loadedFiles.
432+
433+ On failure:
434+ - If loading a single file fails, it is added to failedFiles and removed from loadedFiles and pendingFiles.
435+ - If batch loading fails, all files attempted are added to failedFiles.
436+
437+ This approach ensures efficient batch loading while isolating problematic files for individual handling.
438+ -}
439+
421440data SessionState = SessionState
422- { cradle_files :: ! (IORef (HashSet FilePath ))
423- , error_loading_files :: ! (IORef (HashSet FilePath ))
424- , hscEnvs :: ! (Var HieMap )
425- , fileToFlags :: ! (STM. Map ( Maybe FilePath ) ( HashMap NormalizedFilePath ( IdeResult HscEnvEq , DependencyInfo )))
426- , filesMap :: ! (STM. Map NormalizedFilePath (Maybe FilePath ))
427- , pendingFileSet :: ! (S. OrderedSet FilePath )
428- , version :: ! (Var Int )
441+ { loadedFiles :: ! (IORef (HashSet FilePath )),
442+ failedFiles :: ! (IORef (HashSet FilePath )),
443+ pendingFiles :: ! (S. OrderedSet FilePath ),
444+ hscEnvs :: ! (Var HieMap ),
445+ fileToFlags :: ! (STM. Map (Maybe FilePath ) ( HashMap NormalizedFilePath ( IdeResult HscEnvEq , DependencyInfo ))),
446+ filesMap :: ! (STM. Map NormalizedFilePath ( Maybe FilePath )),
447+ version :: ! (Var Int )
429448 }
430449
431450-- | Helper functions for SessionState management
@@ -434,34 +453,34 @@ data SessionState = SessionState
434453-- | Add a file to the set of files with errors during loading
435454addErrorLoadingFile :: SessionState -> FilePath -> IO ()
436455addErrorLoadingFile state file =
437- atomicModifyIORef' (error_loading_files state) (\ xs -> (Set. insert file xs, () ))
456+ atomicModifyIORef' (failedFiles state) (\ xs -> (Set. insert file xs, () ))
438457
439458addErrorLoadingFiles :: SessionState -> [FilePath ] -> IO ()
440459addErrorLoadingFiles = mapM_ . addErrorLoadingFile
441460
442461-- | Remove a file from the set of files with errors during loading
443462removeErrorLoadingFile :: SessionState -> FilePath -> IO ()
444463removeErrorLoadingFile state file =
445- atomicModifyIORef' (error_loading_files state) (\ xs -> (Set. delete file xs, () ))
464+ atomicModifyIORef' (failedFiles state) (\ xs -> (Set. delete file xs, () ))
446465
447466addCradleFiles :: SessionState -> HashSet FilePath -> IO ()
448467addCradleFiles state files =
449- atomicModifyIORef' (cradle_files state) (\ xs -> (files <> xs, () ))
468+ atomicModifyIORef' (loadedFiles state) (\ xs -> (files <> xs, () ))
450469
451470-- | Remove a file from the cradle files set
452471removeCradleFile :: SessionState -> FilePath -> IO ()
453472removeCradleFile state file =
454- atomicModifyIORef' (cradle_files state) (\ xs -> (Set. delete file xs, () ))
473+ atomicModifyIORef' (loadedFiles state) (\ xs -> (Set. delete file xs, () ))
455474
456475-- | Clear error loading files and reset to empty set
457476clearErrorLoadingFiles :: SessionState -> IO ()
458477clearErrorLoadingFiles state =
459- atomicModifyIORef' (error_loading_files state) (\ _ -> (Set. empty, () ))
478+ atomicModifyIORef' (failedFiles state) (\ _ -> (Set. empty, () ))
460479
461480-- | Clear cradle files and reset to empty set
462481clearCradleFiles :: SessionState -> IO ()
463482clearCradleFiles state =
464- atomicModifyIORef' (cradle_files state) (\ _ -> (Set. empty, () ))
483+ atomicModifyIORef' (loadedFiles state) (\ _ -> (Set. empty, () ))
465484
466485-- | Reset the file maps in the session state
467486resetFileMaps :: SessionState -> STM ()
@@ -482,12 +501,12 @@ insertFileMapping state hieYaml ncfp =
482501-- | Remove a file from the pending file set
483502removeFromPending :: SessionState -> FilePath -> STM ()
484503removeFromPending state file =
485- S. delete file (pendingFileSet state)
504+ S. delete file (pendingFiles state)
486505
487506-- | Add a file to the pending file set
488507addToPending :: SessionState -> FilePath -> STM ()
489508addToPending state file =
490- S. insert file (pendingFileSet state)
509+ S. insert file (pendingFiles state)
491510
492511
493512-- | Insert multiple file mappings at once
@@ -501,7 +520,7 @@ incrementVersion state = modifyVar' (version state) succ
501520
502521-- | Get files from the pending file set
503522getPendingFiles :: SessionState -> IO (HashSet FilePath )
504- getPendingFiles state = atomically $ Set. fromList <$> S. toUnOrderedList (pendingFileSet state)
523+ getPendingFiles state = atomically $ Set. fromList <$> S. toUnOrderedList (pendingFiles state)
505524
506525-- | Handle errors during session loading by recording file as having error and removing from pending
507526handleSessionError :: SessionState -> Maybe FilePath -> FilePath -> PackageSetupException -> IO ()
@@ -527,8 +546,8 @@ handleFileProcessingError state hieYaml file diags extraDepFiles = do
527546getExtraFilesToLoad :: SessionState -> FilePath -> IO [FilePath ]
528547getExtraFilesToLoad state cfp = do
529548 pendingFiles <- getPendingFiles state
530- errorFiles <- readIORef (error_loading_files state)
531- old_files <- readIORef (cradle_files state)
549+ errorFiles <- readIORef (failedFiles state)
550+ old_files <- readIORef (loadedFiles state)
532551 -- if the file is in error loading files, we fall back to single loading mode
533552 return $
534553 Set. toList $
@@ -537,6 +556,19 @@ getExtraFilesToLoad state cfp = do
537556 -- remove error files from pending files since error loading need to load one by one
538557 else (Set. delete cfp $ pendingFiles `Set.difference` errorFiles) <> old_files
539558
559+ newSessionState :: IO SessionState
560+ newSessionState = do
561+ -- Initialize SessionState
562+ sessionState <- SessionState
563+ <$> newIORef (Set. fromList [] ) -- loadedFiles
564+ <*> newIORef (Set. fromList [] ) -- failedFiles
565+ <*> S. newIO -- pendingFiles
566+ <*> newVar Map. empty -- hscEnvs
567+ <*> STM. newIO -- fileToFlags
568+ <*> STM. newIO -- filesMap
569+ <*> newVar 0 -- version
570+ return sessionState
571+
540572-- | Given a root directory, return a Shake 'Action' which setups an
541573-- 'IdeGhcSession' given a file.
542574-- Some of the many things this does:
@@ -555,16 +587,7 @@ loadSessionWithOptions :: Recorder (WithPriority Log) -> SessionLoadingOptions -
555587loadSessionWithOptions recorder SessionLoadingOptions {.. } rootDir que = do
556588 let toAbsolutePath = toAbsolute rootDir -- see Note [Root Directory]
557589
558- -- Initialize SessionState
559- sessionState <- SessionState
560- <$> newIORef (Set. fromList [] ) -- cradle_files
561- <*> newIORef (Set. fromList [] ) -- error_loading_files
562- <*> newVar Map. empty -- hscEnvs
563- <*> STM. newIO -- fileToFlags
564- <*> STM. newIO -- filesMap
565- <*> S. newIO -- pendingFileSet
566- <*> newVar 0 -- version
567-
590+ sessionState <- newSessionState
568591 biosSessionLoadingVar <- newVar Nothing :: IO (Var (Maybe SessionLoadingPreferenceConfig ))
569592 let returnWithVersion fun = IdeGhcSession fun <$> liftIO (readVar (version sessionState))
570593
@@ -709,13 +732,13 @@ loadSessionWithOptions recorder SessionLoadingOptions{..} rootDir que = do
709732 ])
710733 Nothing
711734
712- pendingFiles <- getPendingFiles sessionState
735+ pendings <- getPendingFiles sessionState
713736 -- this_flags_map might contains files not in pendingFiles, take the intersection
714- let newLoaded = pendingFiles `Set.intersection` Set. fromList (fromNormalizedFilePath <$> HM. keys this_flags_map)
737+ let newLoaded = pendings `Set.intersection` Set. fromList (fromNormalizedFilePath <$> HM. keys this_flags_map)
715738 atomically $ do
716739 STM. insert this_flags_map hieYaml (fileToFlags sessionState)
717740 insertAllFileMappings sessionState $ map ((hieYaml,) . fst ) $ concatMap toFlagsMap all_targets
718- forM_ newLoaded $ flip S. delete (pendingFileSet sessionState)
741+ forM_ newLoaded $ flip S. delete (pendingFiles sessionState)
719742
720743 logWith recorder Info $ LogSessionNewLoadedFiles $ Set. toList newLoaded
721744 -- remove all new loaded file from error loading files
@@ -781,15 +804,15 @@ loadSessionWithOptions recorder SessionLoadingOptions{..} rootDir que = do
781804 Left err -> do
782805 -- what if the error to load file is one of old_files ?
783806 let attemptToLoadFiles = Set. delete cfp $ Set. fromList $ concatMap cradleErrorLoadingFiles err
784- old_files <- readIORef (cradle_files sessionState)
807+ old_files <- readIORef (loadedFiles sessionState)
785808 let errorToLoadNewFiles = cfp : Set. toList (attemptToLoadFiles `Set.difference` old_files)
786809 if length errorToLoadNewFiles > 1
787810 then do
788811 -- we are loading more files and failed, we need to retry
789812 -- mark as less loaded files as failedLoadingFiles as possible
790813 -- limitation is that when we are loading files, and the dependencies of old_files
791814 -- are changed, and old_files are not valid anymore.
792- -- but they will still be in the old_files, and will not move to error_loading_files .
815+ -- but they will still be in the old_files, and will not move to failedFiles .
793816 -- And make other files failed to load in batch mode.
794817 addErrorLoadingFiles sessionState errorToLoadNewFiles
795818 -- retry without other files
@@ -869,7 +892,7 @@ loadSessionWithOptions recorder SessionLoadingOptions{..} rootDir que = do
869892 let getOptionsLoop :: IO ()
870893 getOptionsLoop = do
871894 -- Get the next file to load
872- file <- atomically $ S. readQueue (pendingFileSet sessionState)
895+ file <- atomically $ S. readQueue (pendingFiles sessionState)
873896 logWith recorder Debug (LogGetOptionsLoop file)
874897 let ncfp = toNormalizedFilePath' file
875898 cachedHieYamlLocation <- join <$> atomically (STM. lookup ncfp (filesMap sessionState))
@@ -887,7 +910,7 @@ loadSessionWithOptions recorder SessionLoadingOptions{..} rootDir que = do
887910 let ncfp = toNormalizedFilePath' absFile
888911 res <- atomically $ do
889912 -- wait until target file is not in pendingFiles
890- Extra. whenM (S. lookup absFile (pendingFileSet sessionState)) STM. retry
913+ Extra. whenM (S. lookup absFile (pendingFiles sessionState)) STM. retry
891914 -- check if in the cache
892915 checkInCache ncfp
893916 logWith recorder Debug $ LogLookupSessionCache absFile
0 commit comments