split and lift Assistant.Pushes

This commit is contained in:
Joey Hess 2012-10-29 17:52:43 -04:00
parent d5a5c05a79
commit 87ba4f8677
8 changed files with 82 additions and 64 deletions

View file

@ -7,7 +7,8 @@
module Assistant.Pushes where
import Common.Annex
import Assistant.Common
import Assistant.Types.Pushes
import Utility.TSet
import Control.Concurrent.STM
@ -15,59 +16,39 @@ import Control.Concurrent.MSampleVar
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 FailedPushMap = TMVar PushMap
{- The TSet is recent, successful pushes that other remotes should be
- notified about.
-
- The MSampleVar is written to when the PushNotifier thread should be
- restarted for some reason.
-}
data PushNotifier = PushNotifier (TSet UUID) (MSampleVar ())
{- 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
{- 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
getFailedPushesBefore :: NominalDiffTime -> Assistant [Remote]
getFailedPushesBefore duration = do
v <- getAssistant failedPushMap
liftIO $ do
m <- atomically $ readTMVar v
now <- getCurrentTime
return $ M.keys $ M.filter (not . toorecent now) m
where
toorecent now time = now `diffUTCTime` time < duration
{- Modifies the map. -}
changeFailedPushMap :: FailedPushMap -> (PushMap -> PushMap) -> IO ()
changeFailedPushMap v a = atomically $
store . a . fromMaybe M.empty =<< tryTakeTMVar v
changeFailedPushMap :: (PushMap -> PushMap) -> Assistant ()
changeFailedPushMap a = do
v <- getAssistant failedPushMap
liftIO $ atomically $ store v . a . fromMaybe M.empty =<< tryTakeTMVar v
where
{- tryTakeTMVar empties the TMVar; refill it only if
- the modified map is not itself empty -}
store m
store v m
| m == M.empty = noop
| otherwise = putTMVar v $! m
newPushNotifier :: IO PushNotifier
newPushNotifier = PushNotifier
<$> newTSet
<*> newEmptySV
notifyPush :: [UUID] -> Assistant ()
notifyPush us = flip putTSet us <<~ (pushNotifierSuccesses . pushNotifier)
notifyPush :: [UUID] -> PushNotifier -> IO ()
notifyPush us (PushNotifier s _) = putTSet s us
waitPush :: Assistant [UUID]
waitPush = getTSet <<~ (pushNotifierSuccesses . pushNotifier)
waitPush :: PushNotifier -> IO [UUID]
waitPush (PushNotifier s _) = getTSet s
notifyRestart :: Assistant ()
notifyRestart = flip writeSV () <<~ (pushNotifierWaiter . pushNotifier)
notifyRestart :: PushNotifier -> IO ()
notifyRestart (PushNotifier _ sv) = writeSV sv ()
waitRestart :: PushNotifier -> IO ()
waitRestart (PushNotifier _ sv) = readSV sv
waitRestart :: Assistant ()
waitRestart = readSV <<~ (pushNotifierWaiter . pushNotifier)