@@ -114,8 +114,7 @@ import Data.Hashable
114114import qualified Data.HashMap.Strict as HMap
115115import Data.HashSet (HashSet )
116116import qualified Data.HashSet as HSet
117- import Data.List.Extra (foldl' , partition ,
118- takeEnd )
117+ import Data.List.Extra (partition , takeEnd )
119118import qualified Data.Map.Strict as Map
120119import Data.Maybe
121120import qualified Data.SortedList as SL
@@ -814,20 +813,22 @@ delayedAction a = do
814813 liftIO $ shakeEnqueue extras a
815814
816815data PendingRestart = PendingRestart
817- { pendingRestartVFS :: ! VFSModified
818- , pendingRestartActionBetweenSessions :: ! [ IO [ Key ]]
819- , pendingRestartReasons :: ! [T. Text ]
820- , pendingRestartActions :: ! [DelayedActionInternal ]
821- , pendingRestartDoneSignals :: ! [TMVar () ]
816+ { pendingRestartVFS :: ! VFSModified
817+ , pendingRestartDirtyKeys :: ! KeySet
818+ , pendingRestartReasons :: ! [T. Text ]
819+ , pendingRestartActions :: ! [DelayedActionInternal ]
820+ , pendingRestartDoneSignals :: ! [TMVar () ]
822821 }
823822
823+ -- | TODO(crtschin): This isn't commutative because of VFS ordering. Make this a
824+ -- proper function.
824825instance Semigroup PendingRestart where
825- new <> old = PendingRestart
826- { pendingRestartVFS = newestVFSModified (pendingRestartVFS new ) (pendingRestartVFS old )
827- , pendingRestartReasons = pendingRestartReasons new ++ pendingRestartReasons old
828- , pendingRestartActions = pendingRestartActions new ++ pendingRestartActions old
829- , pendingRestartActionBetweenSessions = pendingRestartActionBetweenSessions new ++ pendingRestartActionBetweenSessions old
830- , pendingRestartDoneSignals = pendingRestartDoneSignals new ++ pendingRestartDoneSignals old
826+ older <> newer = PendingRestart
827+ { pendingRestartVFS = newestVFSModified (pendingRestartVFS newer ) (pendingRestartVFS older )
828+ , pendingRestartDirtyKeys = pendingRestartDirtyKeys older <> pendingRestartDirtyKeys newer
829+ , pendingRestartReasons = pendingRestartReasons older ++ pendingRestartReasons newer
830+ , pendingRestartActions = pendingRestartActions older ++ pendingRestartActions newer
831+ , pendingRestartDoneSignals = pendingRestartDoneSignals older ++ pendingRestartDoneSignals newer
831832 }
832833
833834newestVFSModified :: VFSModified -> VFSModified -> VFSModified
@@ -857,12 +858,20 @@ shakeRestart :: IdeState -> VFSModified -> T.Text -> [DelayedAction ()] -> IO [K
857858shakeRestart IdeState {.. } vfs reason acts ioActionBetweenShakeSession = do
858859 restartDone <- newEmptyTMVarIO
859860 let RestartSlot {.. } = restartSlot shakeExtras
860- -- Publish this restart's barrier, that dependents LSP requests can wait on.
861+ -- Run the between-session action here (not on the worker) so notification
862+ -- side effects are visible by the time the LSP notification handler returns.
863+ --
864+ -- If not here, then it would be hard to determine exactly where to place
865+ -- these side-effects when shake restarts are merged. While these side-effects
866+ -- do need to occur here, the keys they invalidate need to propagate to the
867+ -- worker so it can be used during the concrete restart.
868+ -- See Note [Housekeeping rule cache and dirty key outside of hls-graph].
869+ ! newDirty <- fromListKeySet <$> ioActionBetweenShakeSession
861870 atomically $ do
862871 writeTVar lastRestartBarrier restartDone
863872 addWorkerTask restartRef $ PendingRestart
864873 { pendingRestartVFS = vfs
865- , pendingRestartActionBetweenSessions = [ioActionBetweenShakeSession]
874+ , pendingRestartDirtyKeys = newDirty
866875 , pendingRestartReasons = [reason]
867876 , pendingRestartActions = acts
868877 , pendingRestartDoneSignals = [restartDone]
@@ -882,10 +891,11 @@ processPendingRestart' recorder ideMVar PendingRestart{..} = do
882891 flip finally (atomically $ traverse (flip tryPutTMVar () ) (reverse pendingRestartDoneSignals)) $ do
883892 let sessionAction runner = do
884893 (stopTime,() ) <- duration $ logErrorAfter 10 $ cancelShakeSession runner
885- keys <- fmap concat (sequence (reverse pendingRestartActionBetweenSessions))
886- -- it is every important to update the dirty keys after we enter the critical section
887- -- see Note [Housekeeping rule cache and dirty key outside of hls-graph]
888- atomically $ modifyTVar' (dirtyKeys shakeExtras) $ \ x -> foldl' (flip insertKeySet) x keys
894+ -- Apply dirty keys after the dying session's work thread is dead
895+ -- (cancelShakeSession is synchronous). This is the only placement
896+ -- immune to concern 1.2 in
897+ -- Note [Housekeeping rule cache and dirty key outside of hls-graph]
898+ atomically $ modifyTVar' (dirtyKeys shakeExtras) (<> pendingRestartDirtyKeys)
889899 res <- shakeDatabaseProfile shakeDb
890900 backlog <- readTVarIO $ dirtyKeys shakeExtras
891901 queue <- atomicallyNamed " actionQueue - peek" $ peekInProgress $ actionQueue shakeExtras
0 commit comments