rethought the async protocol some more
Moving jobid generation to the git-annex side lets it be simplified a lot. Note that it will also be possible to generate one jobid per connection, rather than a new job per request. That will make overflow not an issue, and will avoid some work, and will simplify some of the code.
This commit is contained in:
parent
59cbb42ee2
commit
72561563d9
3 changed files with 104 additions and 182 deletions
120
Remote/External/AsyncExtension.hs
vendored
120
Remote/External/AsyncExtension.hs
vendored
|
@ -26,25 +26,17 @@ import qualified Data.Map.Strict as M
|
|||
runRelayToExternalAsync :: External -> ExternalState -> IO ExternalAsyncRelay
|
||||
runRelayToExternalAsync external st = do
|
||||
jidmap <- newTVarIO M.empty
|
||||
mapjid <- newTVarIO M.empty
|
||||
commcounter <- newTVarIO 0
|
||||
newconns <- newTVarIO []
|
||||
sendq <- newSendQueue
|
||||
void $ async $ sendloop st newconns mapjid jidmap sendq
|
||||
void $ async $ receiveloop external st newconns jidmap mapjid sendq
|
||||
nextjid <- newTVarIO (JobId 1)
|
||||
void $ async $ sendloop st nextjid jidmap sendq
|
||||
void $ async $ receiveloop external st jidmap sendq
|
||||
return $ ExternalAsyncRelay $ do
|
||||
n <- atomically $ do
|
||||
n <- readTVar commcounter
|
||||
let n' = succ n
|
||||
writeTVar commcounter n'
|
||||
return n'
|
||||
jidv <- newTVarIO Nothing
|
||||
receiveq <- newReceiveQueue
|
||||
return $ ExternalState
|
||||
{ externalSend = \msg ->
|
||||
atomically $ writeTBMChan sendq
|
||||
( toAsyncWrapped msg
|
||||
, (n, receiveq)
|
||||
)
|
||||
(toAsyncWrapped msg, (jidv, receiveq))
|
||||
, externalReceive = atomically (readTBMChan receiveq)
|
||||
-- This shuts down the whole relay.
|
||||
, externalShutdown = shutdown external st sendq
|
||||
|
@ -62,102 +54,64 @@ type ReceiveQueue = TBMChan String
|
|||
|
||||
type SendQueue = TBMChan (AsyncWrapped, Conn)
|
||||
|
||||
type ConnNum = Integer
|
||||
|
||||
type Conn = (ConnNum, ReceiveQueue)
|
||||
|
||||
type NewConns = TVar [Conn]
|
||||
|
||||
type MapJid = TVar (M.Map ConnNum JobId)
|
||||
type Conn = (TVar (Maybe JobId), ReceiveQueue)
|
||||
|
||||
type JidMap = TVar (M.Map JobId Conn)
|
||||
|
||||
type NextJid = TVar JobId
|
||||
|
||||
newReceiveQueue :: IO ReceiveQueue
|
||||
newReceiveQueue = newTBMChanIO 10
|
||||
|
||||
newSendQueue :: IO SendQueue
|
||||
newSendQueue = newTBMChanIO 10
|
||||
|
||||
receiveloop :: External -> ExternalState -> NewConns -> JidMap -> MapJid -> SendQueue -> IO ()
|
||||
receiveloop external st newconns jidmap mapjid sendq = externalReceive st >>= \case
|
||||
receiveloop :: External -> ExternalState -> JidMap -> SendQueue -> IO ()
|
||||
receiveloop external st jidmap sendq = externalReceive st >>= \case
|
||||
Just l -> case parseMessage l :: Maybe AsyncMessage of
|
||||
Just (RESULT_ASYNC msg) -> getnext newconns >>= \case
|
||||
Just (_n, c) -> do
|
||||
relayto c msg
|
||||
loop
|
||||
Nothing -> protoerr "unexpected RESULT-ASYNC"
|
||||
Just (START_ASYNC jid) -> getnext newconns >>= \case
|
||||
Just v@(n, _c) -> do
|
||||
atomically $ do
|
||||
modifyTVar' jidmap $ M.insert jid v
|
||||
modifyTVar' mapjid $ M.insert n jid
|
||||
loop
|
||||
Nothing -> protoerr "unexpected START-ASYNC"
|
||||
Just (ASYNC jid msg) -> getjid jid >>= \case
|
||||
Just (_n, c) -> do
|
||||
relayto c msg
|
||||
loop
|
||||
Nothing -> protoerr "ASYNC with unknown jobid"
|
||||
Just (AsyncMessage jid msg) ->
|
||||
M.lookup jid <$> readTVarIO jidmap >>= \case
|
||||
Just (_jidv, c) -> do
|
||||
atomically $ writeTBMChan c msg
|
||||
receiveloop external st jidmap sendq
|
||||
Nothing -> protoerr "unknown job number"
|
||||
_ -> protoerr "unexpected non-async message"
|
||||
Nothing -> closeandshutdown
|
||||
where
|
||||
loop = receiveloop external st newconns jidmap mapjid sendq
|
||||
|
||||
relayto q msg = atomically $ writeTBMChan q msg
|
||||
|
||||
closerelayto q = atomically $ closeTBMChan q
|
||||
|
||||
getnext l = atomically $ readTVar l >>= \case
|
||||
[] -> return Nothing
|
||||
(c:rest) -> do
|
||||
writeTVar l rest
|
||||
return (Just c)
|
||||
|
||||
getjid jid = M.lookup jid <$> readTVarIO jidmap
|
||||
|
||||
protoerr s = do
|
||||
warningIO $ "async external special remote protocol error: " ++ s
|
||||
closeandshutdown
|
||||
|
||||
closeandshutdown = do
|
||||
shutdown external st sendq True
|
||||
(m, l) <- atomically $ (,)
|
||||
<$> readTVar jidmap
|
||||
<*> readTVar newconns
|
||||
forM_ (M.elems m ++ l) (closerelayto . snd)
|
||||
m <- atomically $ readTVar jidmap
|
||||
forM_ (M.elems m) (atomically . closeTBMChan . snd)
|
||||
|
||||
sendloop :: ExternalState -> NewConns -> MapJid -> JidMap -> SendQueue -> IO ()
|
||||
sendloop st newconns mapjid jidmap sendq = atomically (readTBMChan sendq) >>= \case
|
||||
Just (wrappedmsg, c@(n, _)) -> do
|
||||
let newconn = atomically $ do
|
||||
-- This append is not too expensive,
|
||||
-- because the list length is limited
|
||||
-- to the maximum number of jobs.
|
||||
modifyTVar' newconns (++[c])
|
||||
M.lookup n <$> readTVar mapjid >>= \case
|
||||
Nothing -> return ()
|
||||
Just jid -> do
|
||||
modifyTVar' jidmap (M.delete jid)
|
||||
modifyTVar' mapjid (M.delete n)
|
||||
sendloop :: ExternalState -> NextJid -> JidMap -> SendQueue -> IO ()
|
||||
sendloop st nextjid jidmap sendq = atomically (readTBMChan sendq) >>= \case
|
||||
Just (wrappedmsg, conn@(jidv, _)) -> do
|
||||
case wrappedmsg of
|
||||
AsyncWrappedRequest msg -> do
|
||||
newconn
|
||||
externalSend st msg
|
||||
AsyncWrappedExceptionalMessage msg -> do
|
||||
newconn
|
||||
externalSend st msg
|
||||
jid <- atomically $ do
|
||||
jid@(JobId n) <- readTVar nextjid
|
||||
let !jid' = JobId (succ n)
|
||||
writeTVar nextjid jid'
|
||||
writeTVar jidv (Just jid)
|
||||
modifyTVar' jidmap $ M.insert jid conn
|
||||
return jid
|
||||
externalSend st $ wrapjid msg jid
|
||||
AsyncWrappedRemoteResponse msg ->
|
||||
externalSend st =<< wrapremoteresponse msg n
|
||||
AsyncWrappedAsyncReply msg ->
|
||||
readTVarIO jidv >>= \case
|
||||
Just jid -> externalSend st $ wrapjid msg jid
|
||||
Nothing -> error "failed to find jid"
|
||||
AsyncWrappedExceptionalMessage msg ->
|
||||
externalSend st msg
|
||||
sendloop st newconns mapjid jidmap sendq
|
||||
AsyncWrappedAsyncMessage msg ->
|
||||
externalSend st msg
|
||||
sendloop st nextjid jidmap sendq
|
||||
Nothing -> return ()
|
||||
where
|
||||
wrapremoteresponse msg n =
|
||||
M.lookup n <$> readTVarIO mapjid >>= \case
|
||||
Just jid -> return $ REPLY_ASYNC jid $
|
||||
unwords $ Proto.formatMessage msg
|
||||
Nothing -> error "failed to find jobid"
|
||||
wrapjid msg jid = AsyncMessage jid $ unwords $ Proto.formatMessage msg
|
||||
|
||||
shutdown :: External -> ExternalState -> SendQueue -> Bool -> IO ()
|
||||
shutdown external st sendq b = do
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue