@@ -915,18 +915,33 @@ supplyMergeCredits (ScaledCredits c) (MergingRun _ _ var) = do
915
915
916
916
-- If we previously performed too many merge steps, then we perform
917
917
-- fewer now.
918
- let stepsToDo = totalCredits - totalSteps + c
919
- -- Merge.steps guarantees that stepsDone >= stepsToDo
918
+ let stepsToDo = max 0 (totalCredits + c - totalSteps)
919
+ -- Merge.steps guarantees that stepsDone >= stepsToDo /unless/ the merge
920
+ -- was just now finished in fewer than stepsToDo steps, in which case
921
+ -- stepsDone <= stepsToDo.
920
922
(stepsDone, stepResult) <- Merge. steps m stepsToDo
923
+ assert (case stepResult of
924
+ MergeInProgress -> stepsDone >= stepsToDo
925
+ MergeComplete -> stepsDone <= stepsToDo
926
+ ) $ pure ()
921
927
922
928
-- This should be the only point at which we write to these variables.
923
- -- Since we we never perform fewer merge steps than we requested, the
924
- -- invariant is that @readPrimVar totalStepsVar >= readPrimVar
925
- -- totalCreditsVar@. That is also why we update totalStepsVar before
926
- -- totalCreditsVar, in case an asynchronous exception is thrown in
927
- -- between the writes.
929
+ --
930
+ -- Unless the merge was finished in fewer than stepsToDo steps, we can
931
+ -- guarantee that totalSteps' >= totalCredits'
932
+ let totalSteps' = totalSteps + stepsDone
933
+ let totalCredits' = totalCredits + c
934
+ -- If an exception happens between the next two writes, then only
935
+ -- totalCreditsVar will be outdated, which is okay because we will
936
+ -- resupply credits. It also means we can maintain that @readPrimVar
937
+ -- totalStepsVar >= readPrimVar totalCreditsVar@, unless the merge
938
+ -- finished in fewer than stepsToDo steps.
928
939
writePrimVar totalStepsVar $! totalSteps + stepsDone
929
940
writePrimVar totalCreditsVar $! totalCredits + c
941
+ assert (case stepResult of
942
+ MergeInProgress -> totalSteps' >= totalCredits'
943
+ MergeComplete -> totalSteps' <= totalCredits'
944
+ ) $ pure ()
930
945
931
946
pure $ stepResult == MergeComplete
932
947
when mergeIsDone $
0 commit comments