fix sshCleanup race using STM

This commit is contained in:
Joey Hess 2017-05-11 18:29:51 -04:00
parent 191665e7f0
commit 3f4b671486
No known key found for this signature in database
GPG key ID: DB12DB0FF05F8F38
4 changed files with 19 additions and 22 deletions

View file

@ -71,6 +71,7 @@ import Utility.Url
import "mtl" Control.Monad.Reader import "mtl" Control.Monad.Reader
import Control.Concurrent import Control.Concurrent
import Control.Concurrent.Async import Control.Concurrent.Async
import Control.Concurrent.STM
import qualified Data.Map as M import qualified Data.Map as M
import qualified Data.Set as S import qualified Data.Set as S
@ -124,7 +125,7 @@ data AnnexState = AnnexState
, groupmap :: Maybe GroupMap , groupmap :: Maybe GroupMap
, ciphers :: M.Map StorableCipher Cipher , ciphers :: M.Map StorableCipher Cipher
, lockcache :: LockCache , lockcache :: LockCache
, sshstalecleaned :: MVar () , sshstalecleaned :: TMVar Bool
, flags :: M.Map String Bool , flags :: M.Map String Bool
, fields :: M.Map String String , fields :: M.Map String String
, cleanup :: M.Map CleanupAction (Annex ()) , cleanup :: M.Map CleanupAction (Annex ())
@ -147,7 +148,7 @@ newState :: GitConfig -> Git.Repo -> IO AnnexState
newState c r = do newState c r = do
emptyactiveremotes <- newMVar M.empty emptyactiveremotes <- newMVar M.empty
o <- newMessageState o <- newMessageState
sc <- newMVar () sc <- newTMVarIO False
return $ AnnexState return $ AnnexState
{ repo = r { repo = r
, repoadjustment = return , repoadjustment = return

View file

@ -43,7 +43,7 @@ import Annex.LockPool
#endif #endif
import Data.Hash.MD5 import Data.Hash.MD5
import Control.Concurrent import Control.Concurrent.STM
{- Some ssh commands are fed stdin on a pipe and so should be allowed to {- Some ssh commands are fed stdin on a pipe and so should be allowed to
- consume it. But ssh commands that are not piped stdin should generally - consume it. But ssh commands that are not piped stdin should generally
@ -173,23 +173,31 @@ prepSocket :: FilePath -> RemoteGitConfig -> [CommandParam] -> Annex ()
prepSocket socketfile gc sshparams = do prepSocket socketfile gc sshparams = do
-- There could be stale ssh connections hanging around -- There could be stale ssh connections hanging around
-- from a previous git-annex run that was interrupted. -- from a previous git-annex run that was interrupted.
-- This must run only once, before we have made any ssh connection. -- This must run only once, before we have made any ssh connection,
whenM (isJust <$> (liftIO . tryTakeMVar =<< Annex.getState Annex.sshstalecleaned)) $ -- and any other prepSocket calls must block while it's run.
sshCleanup tv <- Annex.getState Annex.sshstalecleaned
join $ liftIO $ atomically $ do
cleaned <- takeTMVar tv
if cleaned
then do
putTMVar tv cleaned
return noop
else return $ do
sshCleanup
liftIO $ atomically $ putTMVar tv True
-- Cleanup at shutdown. -- Cleanup at shutdown.
Annex.addCleanup SshCachingCleanup sshCleanup Annex.addCleanup SshCachingCleanup sshCleanup
liftIO $ createDirectoryIfMissing True $ parentDir socketfile liftIO $ createDirectoryIfMissing True $ parentDir socketfile
let socketlock = socket2lock socketfile let socketlock = socket2lock socketfile
prompt $ \s -> when (concurrentOutputEnabled s) $ prompt $ \s -> when (concurrentOutputEnabled s) $ do
-- If the LockCache already has the socketlock in it, -- If the LockCache already has the socketlock in it,
-- the connection has already been started. Otherwise, -- the connection has already been started. Otherwise,
-- get the connection started now. -- get the connection started now.
whenM (isNothing <$> fromLockCache socketlock) $ whenM (isNothing <$> fromLockCache socketlock) $
void $ liftIO $ boolSystem "ssh" $ void $ liftIO $ boolSystem "ssh" $
sshparams ++ startSshConnection gc sshparams ++ startSshConnection gc
lockFileCached socketlock lockFileCached socketlock
-- Parameters to get ssh connected to the remote host, -- Parameters to get ssh connected to the remote host,

View file

@ -15,6 +15,3 @@ up several ssh's at the same time, so connection caching didn't kick in,
and there could be a bunch of ssh password prompts at the same time. Now and there could be a bunch of ssh password prompts at the same time. Now
there will never be more than one ssh password prompt at once, and only one there will never be more than one ssh password prompt at once, and only one
prompt per host. (As long as connection caching is enabled.) prompt per host. (As long as connection caching is enabled.)
That mostly works, but `git annex drop -J` exposes a bug in it, which I'll
have to get back to tomorrow.

View file

@ -5,15 +5,6 @@
content=""" content="""
Current status: It's implemented, but not for `GIT_SSH` yet. Current status: It's implemented, but not for `GIT_SSH` yet.
`git annex get -J 3` seems to work well. The display is a bit ugly, because the ssh password prompt line
confuses the concurrent-output region manager.
`git annex drop -J 3` sometimes (once per 5 or so tries) runs
2 ssh processes both prompting at once. For example:
21555 pts/3 S+ 0:00 | \_ ssh localhost -S .git/annex/ssh/localhost -o ControlMaster=auto -o ControlPersist=yes -T git-annex-shell 'lockcontent' '/~/tmp/b/a' 'SHA256E-s30--ec748fe42378798b82ddf4e6b3e778a0cbc5d76d458685af01dc1f09cc423eb7' --uuid ad19d177-519e-4440-a9c9-0c9cddd99db2
21556 pts/3 S+ 0:00 | \_ ssh localhost -S .git/annex/ssh/localhost -o ControlMaster=auto -o ControlPersist=yes -n -T git-annex-shell inannex .
The inannex is what's used to bring up the ssh connection, so
I don't immediately understand how the lockcontent could run before
the ssh connection is brought up.
"""]] """]]