@@ -77,10 +77,11 @@ updateDirty = Focus.adjust $ \(KeyDetails status rdeps) ->
77
77
-- | Unwrap and build a list of keys in parallel
78
78
build
79
79
:: forall key value . (RuleResult key ~ value , Typeable key , Show key , Hashable key , Eq key , Typeable value )
80
- => Database -> [key ] -> IO ([Key ], [value ])
81
- build db keys = do
80
+ => Database -> Stack -> [key ] -> IO ([Key ], [value ])
81
+ -- build _ st k | traceShow ("build", st, k) False = undefined
82
+ build db stack keys = do
82
83
(ids, vs) <- runAIO $ fmap unzip $ either return liftIO =<<
83
- builder db (map Key keys)
84
+ builder db stack (map Key keys)
84
85
pure (ids, map (asV . resultValue) vs)
85
86
where
86
87
asV :: Value -> value
@@ -90,8 +91,9 @@ build db keys = do
90
91
-- If none of the keys are dirty, we can return the results immediately.
91
92
-- Otherwise, a blocking computation is returned *which must be evaluated asynchronously* to avoid deadlock.
92
93
builder
93
- :: Database -> [Key ] -> AIO (Either [(Key , Result )] (IO [(Key , Result )]))
94
- builder db@ Database {.. } keys = withRunInIO $ \ (RunInIO run) -> do
94
+ :: Database -> Stack -> [Key ] -> AIO (Either [(Key , Result )] (IO [(Key , Result )]))
95
+ -- builder _ st kk | traceShow ("builder", st,kk) False = undefined
96
+ builder db@ Database {.. } stack keys = withRunInIO $ \ (RunInIO run) -> do
95
97
-- Things that I need to force before my results are ready
96
98
toForce <- liftIO $ newTVarIO []
97
99
current <- liftIO $ readTVarIO databaseStep
@@ -103,11 +105,13 @@ builder db@Database{..} keys = withRunInIO $ \(RunInIO run) -> do
103
105
status <- SMap. lookup id databaseValues
104
106
val <- case viewDirty current $ maybe (Dirty Nothing ) keyStatus status of
105
107
Clean r -> pure r
106
- Running _ force val _ -> do
108
+ Running _ force val _
109
+ | memberStack id stack -> throw $ StackException stack
110
+ | otherwise -> do
107
111
modifyTVar' toForce (Wait force : )
108
112
pure val
109
113
Dirty s -> do
110
- let act = run (refresh db id s)
114
+ let act = run (refresh db stack id s)
111
115
(force, val) = splitIO (join act)
112
116
SMap. focus (updateStatus $ Running current force val s) id databaseValues
113
117
modifyTVar' toForce (Spawn force: )
@@ -127,32 +131,33 @@ builder db@Database{..} keys = withRunInIO $ \(RunInIO run) -> do
127
131
-- * If no dirty dependencies and we have evaluated the key previously, then we refresh it in the current thread.
128
132
-- This assumes that the implementation will be a lookup
129
133
-- * Otherwise, we spawn a new thread to refresh the dirty deps (if any) and the key itself
130
- refresh :: Database -> Key -> Maybe Result -> AIO (IO Result )
131
- refresh db key result @ ( Just me @ Result {resultDeps = ResultDeps deps}) = do
132
- res <- builder db deps
133
- case res of
134
- Left res ->
135
- if isDirty res
136
- then asyncWithCleanUp $ liftIO $ compute db key RunDependenciesChanged result
137
- else pure $ compute db key RunDependenciesSame result
138
- Right iores -> asyncWithCleanUp $ liftIO $ do
139
- res <- iores
140
- let mode = if isDirty res then RunDependenciesChanged else RunDependenciesSame
141
- compute db key mode result
142
- where
143
- isDirty = any ( \ (_,dep) -> resultBuilt me < resultChanged dep)
144
-
145
- refresh db key result =
146
- asyncWithCleanUp $ liftIO $ compute db key RunDependenciesChanged result
147
-
134
+ refresh :: Database -> Stack -> Key -> Maybe Result -> AIO (IO Result )
135
+ -- refresh _ st k _ | traceShow ("refresh", st, k) False = undefined
136
+ refresh db stack key result = case (addStack key stack, result) of
137
+ ( Left e, _) -> throw e
138
+ ( Right stack, Just me @ Result {resultDeps = ResultDeps deps}) -> do
139
+ res <- builder db stack deps
140
+ let isDirty = any ( \ (_,dep) -> resultBuilt me < resultChanged dep)
141
+ case res of
142
+ Left res ->
143
+ if isDirty res
144
+ then asyncWithCleanUp $ liftIO $ compute db stack key RunDependenciesChanged result
145
+ else pure $ compute db stack key RunDependenciesSame result
146
+ Right iores -> asyncWithCleanUp $ liftIO $ do
147
+ res <- iores
148
+ let mode = if isDirty res then RunDependenciesChanged else RunDependenciesSame
149
+ compute db stack key mode result
150
+ ( Right stack, _) ->
151
+ asyncWithCleanUp $ liftIO $ compute db stack key RunDependenciesChanged result
148
152
149
153
-- | Compute a key.
150
- compute :: Database -> Key -> RunMode -> Maybe Result -> IO Result
151
- compute db@ Database {.. } key mode result = do
154
+ compute :: Database -> Stack -> Key -> RunMode -> Maybe Result -> IO Result
155
+ -- compute _ st k _ _ | traceShow ("compute", st, k) False = undefined
156
+ compute db@ Database {.. } stack key mode result = do
152
157
let act = runRule databaseRules key (fmap resultData result) mode
153
158
deps <- newIORef UnknownDeps
154
159
(execution, RunResult {.. }) <-
155
- duration $ runReaderT (fromAction act) $ SAction db deps
160
+ duration $ runReaderT (fromAction act) $ SAction db deps stack
156
161
built <- readTVarIO databaseStep
157
162
deps <- readIORef deps
158
163
let changed = if runChanged == ChangedRecomputeDiff then built else maybe built resultChanged result
@@ -165,7 +170,7 @@ compute db@Database{..} key mode result = do
165
170
deps | not (null deps)
166
171
&& runChanged /= ChangedNothing
167
172
-> do
168
- void $ forkIO $
173
+ void $
169
174
updateReverseDeps key db
170
175
(getResultDepsDefault [] previousDeps)
171
176
(HSet. fromList deps)
0 commit comments