@@ -418,14 +418,33 @@ getHieDbLoc dir = do
418
418
createDirectoryIfMissing True cDir
419
419
pure (cDir </> db)
420
420
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
+
421
440
data 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 )
429
448
}
430
449
431
450
-- | Helper functions for SessionState management
@@ -434,34 +453,34 @@ data SessionState = SessionState
434
453
-- | Add a file to the set of files with errors during loading
435
454
addErrorLoadingFile :: SessionState -> FilePath -> IO ()
436
455
addErrorLoadingFile state file =
437
- atomicModifyIORef' (error_loading_files state) (\ xs -> (Set. insert file xs, () ))
456
+ atomicModifyIORef' (failedFiles state) (\ xs -> (Set. insert file xs, () ))
438
457
439
458
addErrorLoadingFiles :: SessionState -> [FilePath ] -> IO ()
440
459
addErrorLoadingFiles = mapM_ . addErrorLoadingFile
441
460
442
461
-- | Remove a file from the set of files with errors during loading
443
462
removeErrorLoadingFile :: SessionState -> FilePath -> IO ()
444
463
removeErrorLoadingFile state file =
445
- atomicModifyIORef' (error_loading_files state) (\ xs -> (Set. delete file xs, () ))
464
+ atomicModifyIORef' (failedFiles state) (\ xs -> (Set. delete file xs, () ))
446
465
447
466
addCradleFiles :: SessionState -> HashSet FilePath -> IO ()
448
467
addCradleFiles state files =
449
- atomicModifyIORef' (cradle_files state) (\ xs -> (files <> xs, () ))
468
+ atomicModifyIORef' (loadedFiles state) (\ xs -> (files <> xs, () ))
450
469
451
470
-- | Remove a file from the cradle files set
452
471
removeCradleFile :: SessionState -> FilePath -> IO ()
453
472
removeCradleFile state file =
454
- atomicModifyIORef' (cradle_files state) (\ xs -> (Set. delete file xs, () ))
473
+ atomicModifyIORef' (loadedFiles state) (\ xs -> (Set. delete file xs, () ))
455
474
456
475
-- | Clear error loading files and reset to empty set
457
476
clearErrorLoadingFiles :: SessionState -> IO ()
458
477
clearErrorLoadingFiles state =
459
- atomicModifyIORef' (error_loading_files state) (\ _ -> (Set. empty, () ))
478
+ atomicModifyIORef' (failedFiles state) (\ _ -> (Set. empty, () ))
460
479
461
480
-- | Clear cradle files and reset to empty set
462
481
clearCradleFiles :: SessionState -> IO ()
463
482
clearCradleFiles state =
464
- atomicModifyIORef' (cradle_files state) (\ _ -> (Set. empty, () ))
483
+ atomicModifyIORef' (loadedFiles state) (\ _ -> (Set. empty, () ))
465
484
466
485
-- | Reset the file maps in the session state
467
486
resetFileMaps :: SessionState -> STM ()
@@ -482,12 +501,12 @@ insertFileMapping state hieYaml ncfp =
482
501
-- | Remove a file from the pending file set
483
502
removeFromPending :: SessionState -> FilePath -> STM ()
484
503
removeFromPending state file =
485
- S. delete file (pendingFileSet state)
504
+ S. delete file (pendingFiles state)
486
505
487
506
-- | Add a file to the pending file set
488
507
addToPending :: SessionState -> FilePath -> STM ()
489
508
addToPending state file =
490
- S. insert file (pendingFileSet state)
509
+ S. insert file (pendingFiles state)
491
510
492
511
493
512
-- | Insert multiple file mappings at once
@@ -501,7 +520,7 @@ incrementVersion state = modifyVar' (version state) succ
501
520
502
521
-- | Get files from the pending file set
503
522
getPendingFiles :: SessionState -> IO (HashSet FilePath )
504
- getPendingFiles state = atomically $ Set. fromList <$> S. toUnOrderedList (pendingFileSet state)
523
+ getPendingFiles state = atomically $ Set. fromList <$> S. toUnOrderedList (pendingFiles state)
505
524
506
525
-- | Handle errors during session loading by recording file as having error and removing from pending
507
526
handleSessionError :: SessionState -> Maybe FilePath -> FilePath -> PackageSetupException -> IO ()
@@ -527,8 +546,8 @@ handleFileProcessingError state hieYaml file diags extraDepFiles = do
527
546
getExtraFilesToLoad :: SessionState -> FilePath -> IO [FilePath ]
528
547
getExtraFilesToLoad state cfp = do
529
548
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)
532
551
-- if the file is in error loading files, we fall back to single loading mode
533
552
return $
534
553
Set. toList $
@@ -537,6 +556,19 @@ getExtraFilesToLoad state cfp = do
537
556
-- remove error files from pending files since error loading need to load one by one
538
557
else (Set. delete cfp $ pendingFiles `Set.difference` errorFiles) <> old_files
539
558
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
+
540
572
-- | Given a root directory, return a Shake 'Action' which setups an
541
573
-- 'IdeGhcSession' given a file.
542
574
-- Some of the many things this does:
@@ -555,16 +587,7 @@ loadSessionWithOptions :: Recorder (WithPriority Log) -> SessionLoadingOptions -
555
587
loadSessionWithOptions recorder SessionLoadingOptions {.. } rootDir que = do
556
588
let toAbsolutePath = toAbsolute rootDir -- see Note [Root Directory]
557
589
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
568
591
biosSessionLoadingVar <- newVar Nothing :: IO (Var (Maybe SessionLoadingPreferenceConfig ))
569
592
let returnWithVersion fun = IdeGhcSession fun <$> liftIO (readVar (version sessionState))
570
593
@@ -709,13 +732,13 @@ loadSessionWithOptions recorder SessionLoadingOptions{..} rootDir que = do
709
732
])
710
733
Nothing
711
734
712
- pendingFiles <- getPendingFiles sessionState
735
+ pendings <- getPendingFiles sessionState
713
736
-- 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)
715
738
atomically $ do
716
739
STM. insert this_flags_map hieYaml (fileToFlags sessionState)
717
740
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)
719
742
720
743
logWith recorder Info $ LogSessionNewLoadedFiles $ Set. toList newLoaded
721
744
-- remove all new loaded file from error loading files
@@ -781,15 +804,15 @@ loadSessionWithOptions recorder SessionLoadingOptions{..} rootDir que = do
781
804
Left err -> do
782
805
-- what if the error to load file is one of old_files ?
783
806
let attemptToLoadFiles = Set. delete cfp $ Set. fromList $ concatMap cradleErrorLoadingFiles err
784
- old_files <- readIORef (cradle_files sessionState)
807
+ old_files <- readIORef (loadedFiles sessionState)
785
808
let errorToLoadNewFiles = cfp : Set. toList (attemptToLoadFiles `Set.difference` old_files)
786
809
if length errorToLoadNewFiles > 1
787
810
then do
788
811
-- we are loading more files and failed, we need to retry
789
812
-- mark as less loaded files as failedLoadingFiles as possible
790
813
-- limitation is that when we are loading files, and the dependencies of old_files
791
814
-- 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 .
793
816
-- And make other files failed to load in batch mode.
794
817
addErrorLoadingFiles sessionState errorToLoadNewFiles
795
818
-- retry without other files
@@ -869,7 +892,7 @@ loadSessionWithOptions recorder SessionLoadingOptions{..} rootDir que = do
869
892
let getOptionsLoop :: IO ()
870
893
getOptionsLoop = do
871
894
-- Get the next file to load
872
- file <- atomically $ S. readQueue (pendingFileSet sessionState)
895
+ file <- atomically $ S. readQueue (pendingFiles sessionState)
873
896
logWith recorder Debug (LogGetOptionsLoop file)
874
897
let ncfp = toNormalizedFilePath' file
875
898
cachedHieYamlLocation <- join <$> atomically (STM. lookup ncfp (filesMap sessionState))
@@ -887,7 +910,7 @@ loadSessionWithOptions recorder SessionLoadingOptions{..} rootDir que = do
887
910
let ncfp = toNormalizedFilePath' absFile
888
911
res <- atomically $ do
889
912
-- 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
891
914
-- check if in the cache
892
915
checkInCache ncfp
893
916
logWith recorder Debug $ LogLookupSessionCache absFile
0 commit comments