2012-07-06 20:39:07 +00:00
|
|
|
{- git-annex assistant transfer slots
|
|
|
|
-
|
|
|
|
- Copyright 2012 Joey Hess <joey@kitenet.net>
|
|
|
|
-
|
|
|
|
- Licensed under the GNU GPL version 3 or higher.
|
|
|
|
-}
|
|
|
|
|
2012-08-10 22:42:44 +00:00
|
|
|
{-# LANGUAGE DeriveDataTypeable #-}
|
|
|
|
|
2012-07-06 20:39:07 +00:00
|
|
|
module Assistant.TransferSlots where
|
|
|
|
|
2012-08-10 22:42:44 +00:00
|
|
|
import qualified Control.Exception as E
|
2012-07-06 20:39:07 +00:00
|
|
|
import Control.Concurrent
|
2012-08-10 22:42:44 +00:00
|
|
|
import Data.Typeable
|
2012-07-06 20:39:07 +00:00
|
|
|
|
2012-07-18 23:13:56 +00:00
|
|
|
import Common.Annex
|
2012-08-10 22:42:44 +00:00
|
|
|
import Utility.ThreadScheduler
|
2012-07-18 23:13:56 +00:00
|
|
|
|
2012-07-06 20:39:07 +00:00
|
|
|
type TransferSlots = QSemN
|
|
|
|
|
2012-08-10 22:42:44 +00:00
|
|
|
{- A special exception that can be thrown to pause or resume a transfer, while
|
|
|
|
- keeping its slot in use. -}
|
|
|
|
data TransferException = PauseTransfer | ResumeTransfer
|
|
|
|
deriving (Show, Eq, Typeable)
|
|
|
|
|
|
|
|
instance E.Exception TransferException
|
|
|
|
|
2012-08-12 16:36:08 +00:00
|
|
|
type TransferSlotRunner = TransferSlots -> IO () -> IO ThreadId
|
|
|
|
|
2012-07-06 20:39:07 +00:00
|
|
|
{- Number of concurrent transfers allowed to be run from the assistant.
|
|
|
|
-
|
|
|
|
- Transfers launched by other means, including by remote assistants,
|
|
|
|
- do not currently take up slots.
|
|
|
|
-}
|
|
|
|
numSlots :: Int
|
|
|
|
numSlots = 1
|
|
|
|
|
|
|
|
newTransferSlots :: IO TransferSlots
|
|
|
|
newTransferSlots = newQSemN numSlots
|
|
|
|
|
|
|
|
{- Waits until a transfer slot becomes available, and runs a transfer
|
2012-08-10 22:42:44 +00:00
|
|
|
- action in the slot, in its own thread.
|
2012-08-12 16:36:08 +00:00
|
|
|
-}
|
|
|
|
inTransferSlot :: TransferSlotRunner
|
|
|
|
inTransferSlot = runTransferSlot (\s -> waitQSemN s 1)
|
|
|
|
|
|
|
|
{- Runs a transfer action, without waiting for a slot to become available. -}
|
|
|
|
inImmediateTransferSlot :: TransferSlotRunner
|
|
|
|
inImmediateTransferSlot = runTransferSlot (\s -> signalQSemN s (-1))
|
|
|
|
|
|
|
|
{- Note that the action is subject to being killed when the transfer
|
2012-08-10 22:42:44 +00:00
|
|
|
- is canceled or paused.
|
|
|
|
-
|
|
|
|
- A PauseTransfer exception is handled by letting the action be killed,
|
|
|
|
- then pausing the thread until a ResumeTransfer exception is raised,
|
|
|
|
- then rerunning the action.
|
|
|
|
-}
|
2012-08-12 16:36:08 +00:00
|
|
|
runTransferSlot :: (QSemN -> IO ()) -> TransferSlotRunner
|
|
|
|
runTransferSlot allocator s transfer = do
|
|
|
|
allocator s
|
2012-08-10 22:42:44 +00:00
|
|
|
forkIO $ E.bracket_ noop (signalQSemN s 1) go
|
2012-07-07 03:45:08 +00:00
|
|
|
where
|
2012-08-10 22:42:44 +00:00
|
|
|
go = catchPauseResume transfer
|
|
|
|
pause = catchPauseResume $ runEvery (Seconds 86400) noop
|
|
|
|
catchPauseResume a = E.catch a handlePauseResume
|
|
|
|
handlePauseResume PauseTransfer = do
|
|
|
|
putStrLn "pause"
|
|
|
|
pause
|
|
|
|
handlePauseResume ResumeTransfer = do
|
|
|
|
putStrLn "resume"
|
|
|
|
go
|