use a TMVar
SampleMVar won't work; between getting the current value and changing it, another thread could made a change, which would get lost. TMVar works well; this update situation is handled by atomic transactions.
This commit is contained in:
parent
e0a65247ae
commit
67c8ef7de2
4 changed files with 61 additions and 47 deletions
|
@ -8,30 +8,39 @@
|
|||
module Assistant.Pushes where
|
||||
|
||||
import Common.Annex
|
||||
import Control.Concurrent.SampleVar
|
||||
|
||||
import Control.Concurrent.STM
|
||||
import Data.Time.Clock
|
||||
import qualified Data.Map as M
|
||||
|
||||
{- Track the most recent push failure for each remote. -}
|
||||
type PushMap = M.Map Remote UTCTime
|
||||
type FailedPushes = SampleVar PushMap
|
||||
type FailedPushMap = TMVar PushMap
|
||||
|
||||
newFailedPushChan :: IO FailedPushChan
|
||||
newFailedPushChan = newEmptySampleVar
|
||||
{- The TMVar starts empty, and is left empty when there are no
|
||||
- failed pushes. This way we can block until there are some failed pushes.
|
||||
-}
|
||||
newFailedPushMap :: IO FailedPushMap
|
||||
newFailedPushMap = atomically newEmptyTMVar
|
||||
|
||||
{- Gets all failed pushes. Blocks until set. -}
|
||||
getFailedPushes :: FailedPushChan -> IO PushMap
|
||||
getFailedPushes = readSampleVar
|
||||
{- Blocks until there are failed pushes.
|
||||
- Returns Remotes whose pushes failed a given time duration or more ago.
|
||||
- (This may be an empty list.) -}
|
||||
getFailedPushesBefore :: FailedPushMap -> NominalDiffTime -> IO [Remote]
|
||||
getFailedPushesBefore v duration = do
|
||||
m <- atomically $ readTMVar v
|
||||
now <- getCurrentTime
|
||||
return $ M.keys $ M.filter (not . toorecent now) m
|
||||
where
|
||||
toorecent now time = now `diffUTCTime` time < duration
|
||||
|
||||
{- Sets all failed pushes to passed PushMap -}
|
||||
setFailedPushes :: FailedPushChan -> PushMap -> IO ()
|
||||
setFailedPushes = writeSampleVar
|
||||
|
||||
{- Indicates a failure to push to a single remote. -}
|
||||
failedPush :: FailedPushChan -> Remote -> IO ()
|
||||
failedPush c r =
|
||||
|
||||
{- Indicates that a remote was pushed to successfully. -}
|
||||
successfulPush :: FailedPushChan -> Remote -> IO ()
|
||||
successfulPush c r =
|
||||
{- Modifies the map. -}
|
||||
changeFailedPushMap :: FailedPushMap -> (PushMap -> PushMap) -> IO ()
|
||||
changeFailedPushMap v a = atomically $
|
||||
store . a . fromMaybe M.empty =<< tryTakeTMVar v
|
||||
where
|
||||
{- tryTakeTMVar empties the TMVar; refill it only if
|
||||
- the modified map is not itself empty -}
|
||||
store m
|
||||
| m == M.empty = noop
|
||||
| otherwise = putTMVar v $! m
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue