Display a message when git-annex has to wait for a pid lock file held by another process
This commit is contained in:
parent
b24ba92231
commit
b68f214312
7 changed files with 69 additions and 32 deletions
|
@ -1,7 +1,7 @@
|
||||||
{- Wraps Utility.LockPool, making pid locks be used when git-annex is so
|
{- Wraps Utility.LockPool, making pid locks be used when git-annex is so
|
||||||
- configured.
|
- configured.
|
||||||
-
|
-
|
||||||
- Copyright 2015 Joey Hess <id@joeyh.name>
|
- Copyright 2015-2020 Joey Hess <id@joeyh.name>
|
||||||
-
|
-
|
||||||
- Licensed under the GNU AGPL version 3 or higher.
|
- Licensed under the GNU AGPL version 3 or higher.
|
||||||
-}
|
-}
|
||||||
|
@ -31,6 +31,7 @@ import Utility.LockFile.Posix (openLockFile)
|
||||||
import Utility.LockPool.STM (LockFile)
|
import Utility.LockPool.STM (LockFile)
|
||||||
import Utility.LockFile.LockStatus
|
import Utility.LockFile.LockStatus
|
||||||
import Config (pidLockFile)
|
import Config (pidLockFile)
|
||||||
|
import Messages (warning)
|
||||||
|
|
||||||
import System.Posix
|
import System.Posix
|
||||||
|
|
||||||
|
@ -72,9 +73,8 @@ pidLock m f posixlock = debugLocks $ go =<< pidLockFile
|
||||||
go Nothing = liftIO posixlock
|
go Nothing = liftIO posixlock
|
||||||
go (Just pidlock) = do
|
go (Just pidlock) = do
|
||||||
timeout <- annexPidLockTimeout <$> Annex.getGitConfig
|
timeout <- annexPidLockTimeout <$> Annex.getGitConfig
|
||||||
liftIO $ do
|
liftIO $ dummyPosixLock m f
|
||||||
dummyPosixLock m f
|
Pid.waitLock timeout pidlock warning
|
||||||
Pid.waitLock timeout pidlock
|
|
||||||
|
|
||||||
tryPidLock :: Maybe FileMode -> LockFile -> IO (Maybe LockHandle) -> Annex (Maybe LockHandle)
|
tryPidLock :: Maybe FileMode -> LockFile -> IO (Maybe LockHandle) -> Annex (Maybe LockHandle)
|
||||||
tryPidLock m f posixlock = debugLocks $ liftIO . go =<< pidLockFile
|
tryPidLock m f posixlock = debugLocks $ liftIO . go =<< pidLockFile
|
||||||
|
|
|
@ -12,6 +12,8 @@ git-annex (8.20200815) UNRELEASED; urgency=medium
|
||||||
* Fix reversion in 8.20200617 that made annex.pidlock being enabled
|
* Fix reversion in 8.20200617 that made annex.pidlock being enabled
|
||||||
result in some commands stalling, particularly those needing to
|
result in some commands stalling, particularly those needing to
|
||||||
autoinit.
|
autoinit.
|
||||||
|
* Display a message when git-annex has to wait for a pid lock file
|
||||||
|
held by another process.
|
||||||
|
|
||||||
-- Joey Hess <id@joeyh.name> Fri, 14 Aug 2020 14:57:45 -0400
|
-- Joey Hess <id@joeyh.name> Fri, 14 Aug 2020 14:57:45 -0400
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,8 @@ import System.Posix.IO
|
||||||
import System.Posix.Types
|
import System.Posix.Types
|
||||||
import System.Posix.Files
|
import System.Posix.Files
|
||||||
import System.Posix.Process
|
import System.Posix.Process
|
||||||
|
import Control.Monad
|
||||||
|
import Control.Monad.IO.Class (liftIO, MonadIO)
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
import Data.List
|
import Data.List
|
||||||
import Network.BSD
|
import Network.BSD
|
||||||
|
@ -240,19 +242,24 @@ checkInsaneLustre dest = do
|
||||||
|
|
||||||
-- | Waits as necessary to take a lock.
|
-- | Waits as necessary to take a lock.
|
||||||
--
|
--
|
||||||
-- Uses a 1 second wait-loop.
|
-- Uses a 1 second wait-loop, retrying until a timeout.
|
||||||
--
|
--
|
||||||
-- May wait until timeout if the lock file is stale and is on a network file
|
-- After the first second waiting, runs the callback to display a message,
|
||||||
-- system, or on a system where the side lock cannot be taken.
|
-- so the user knows why it's stalled.
|
||||||
waitLock :: Seconds -> LockFile -> IO LockHandle
|
waitLock :: MonadIO m => Seconds -> LockFile -> (String -> m ()) -> m LockHandle
|
||||||
waitLock (Seconds timeout) lockfile = go timeout
|
waitLock (Seconds timeout) lockfile displaymessage = go timeout
|
||||||
where
|
where
|
||||||
go n
|
go n
|
||||||
| n > 0 = maybe (threadDelaySeconds (Seconds 1) >> go (pred n)) return
|
| n > 0 = liftIO (tryLock lockfile) >>= \case
|
||||||
=<< tryLock lockfile
|
Nothing -> do
|
||||||
|
when (n == pred timeout) $
|
||||||
|
displaymessage $ "waiting for pid lock file " ++ lockfile ++ " which is held by another process (or may be stale)"
|
||||||
|
liftIO $ threadDelaySeconds (Seconds 1)
|
||||||
|
go (pred n)
|
||||||
|
Just lckh -> return lckh
|
||||||
| otherwise = do
|
| otherwise = do
|
||||||
hPutStrLn stderr $ show timeout ++ " second timeout exceeded while waiting for pid lock file " ++ lockfile
|
displaymessage $ show timeout ++ " second timeout exceeded while waiting for pid lock file " ++ lockfile
|
||||||
giveup $ "Gave up waiting for possibly stale pid lock file " ++ lockfile
|
giveup $ "Gave up waiting for pid lock file " ++ lockfile
|
||||||
|
|
||||||
dropLock :: LockHandle -> IO ()
|
dropLock :: LockHandle -> IO ()
|
||||||
dropLock (LockHandle lockfile _ sidelock) = do
|
dropLock (LockHandle lockfile _ sidelock) = do
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{- Handles for lock pools.
|
{- Handles for lock pools.
|
||||||
-
|
-
|
||||||
- Copyright 2015 Joey Hess <id@joeyh.name>
|
- Copyright 2015-2020 Joey Hess <id@joeyh.name>
|
||||||
-
|
-
|
||||||
- License: BSD-2-clause
|
- License: BSD-2-clause
|
||||||
-}
|
-}
|
||||||
|
@ -23,7 +23,8 @@ import Utility.LockPool.STM (LockFile)
|
||||||
import Utility.DebugLocks
|
import Utility.DebugLocks
|
||||||
|
|
||||||
import Control.Concurrent.STM
|
import Control.Concurrent.STM
|
||||||
import Control.Exception
|
import Control.Monad.Catch
|
||||||
|
import Control.Monad.IO.Class (liftIO, MonadIO)
|
||||||
import Control.Applicative
|
import Control.Applicative
|
||||||
import Prelude
|
import Prelude
|
||||||
|
|
||||||
|
@ -47,27 +48,39 @@ checkSaneLock lockfile (LockHandle _ flo) = fCheckSaneLock flo lockfile
|
||||||
-- Take a lock, by first updating the lock pool, and then taking the file
|
-- Take a lock, by first updating the lock pool, and then taking the file
|
||||||
-- lock. If taking the file lock fails for any reason, take care to
|
-- lock. If taking the file lock fails for any reason, take care to
|
||||||
-- release the lock in the lock pool.
|
-- release the lock in the lock pool.
|
||||||
makeLockHandle :: P.LockPool -> LockFile -> (P.LockPool -> LockFile -> STM P.LockHandle) -> (LockFile -> IO FileLockOps) -> IO LockHandle
|
makeLockHandle
|
||||||
|
:: (MonadIO m, MonadMask m)
|
||||||
|
=> P.LockPool
|
||||||
|
-> LockFile
|
||||||
|
-> (P.LockPool -> LockFile -> STM P.LockHandle)
|
||||||
|
-> (LockFile -> m FileLockOps)
|
||||||
|
-> m LockHandle
|
||||||
makeLockHandle pool file pa fa = bracketOnError setup cleanup go
|
makeLockHandle pool file pa fa = bracketOnError setup cleanup go
|
||||||
where
|
where
|
||||||
setup = debugLocks $ atomically (pa pool file)
|
setup = debugLocks $ liftIO $ atomically (pa pool file)
|
||||||
cleanup ph = debugLocks $ P.releaseLock ph
|
cleanup ph = debugLocks $ liftIO $ P.releaseLock ph
|
||||||
go ph = mkLockHandle ph =<< fa file
|
go ph = liftIO . mkLockHandle ph =<< fa file
|
||||||
|
|
||||||
tryMakeLockHandle :: P.LockPool -> LockFile -> (P.LockPool -> LockFile -> STM (Maybe P.LockHandle)) -> (LockFile -> IO (Maybe FileLockOps)) -> IO (Maybe LockHandle)
|
tryMakeLockHandle
|
||||||
|
:: (MonadIO m, MonadMask m)
|
||||||
|
=> P.LockPool
|
||||||
|
-> LockFile
|
||||||
|
-> (P.LockPool -> LockFile -> STM (Maybe P.LockHandle))
|
||||||
|
-> (LockFile -> m (Maybe FileLockOps))
|
||||||
|
-> m (Maybe LockHandle)
|
||||||
tryMakeLockHandle pool file pa fa = bracketOnError setup cleanup go
|
tryMakeLockHandle pool file pa fa = bracketOnError setup cleanup go
|
||||||
where
|
where
|
||||||
setup = atomically (pa pool file)
|
setup = liftIO $ atomically (pa pool file)
|
||||||
cleanup Nothing = return ()
|
cleanup Nothing = return ()
|
||||||
cleanup (Just ph) = P.releaseLock ph
|
cleanup (Just ph) = liftIO $ P.releaseLock ph
|
||||||
go Nothing = return Nothing
|
go Nothing = return Nothing
|
||||||
go (Just ph) = do
|
go (Just ph) = do
|
||||||
mfo <- fa file
|
mfo <- fa file
|
||||||
case mfo of
|
case mfo of
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
cleanup (Just ph)
|
liftIO $ cleanup (Just ph)
|
||||||
return Nothing
|
return Nothing
|
||||||
Just fo -> Just <$> mkLockHandle ph fo
|
Just fo -> liftIO $ Just <$> mkLockHandle ph fo
|
||||||
|
|
||||||
mkLockHandle :: P.LockHandle -> FileLockOps -> IO LockHandle
|
mkLockHandle :: P.LockHandle -> FileLockOps -> IO LockHandle
|
||||||
mkLockHandle ph fo = do
|
mkLockHandle ph fo = do
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{- Pid locks, using lock pools.
|
{- Pid locks, using lock pools.
|
||||||
-
|
-
|
||||||
- Copyright 2015 Joey Hess <id@joeyh.name>
|
- Copyright 2015-2020 Joey Hess <id@joeyh.name>
|
||||||
-
|
-
|
||||||
- License: BSD-2-clause
|
- License: BSD-2-clause
|
||||||
-}
|
-}
|
||||||
|
@ -27,16 +27,23 @@ import Utility.ThreadScheduler
|
||||||
import System.IO
|
import System.IO
|
||||||
import System.Posix
|
import System.Posix
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
|
import Control.Monad.Catch
|
||||||
|
import Control.Monad.IO.Class
|
||||||
import Control.Applicative
|
import Control.Applicative
|
||||||
import Prelude
|
import Prelude
|
||||||
|
|
||||||
-- Takes a pid lock, blocking until the lock is available or the timeout.
|
-- Takes a pid lock, blocking until the lock is available or the timeout.
|
||||||
waitLock :: Seconds -> LockFile -> IO LockHandle
|
waitLock
|
||||||
waitLock timeout file = makeLockHandle P.lockPool file
|
:: (MonadIO m, MonadMask m)
|
||||||
|
=> Seconds
|
||||||
|
-> LockFile
|
||||||
|
-> (String -> m ())
|
||||||
|
-> m LockHandle
|
||||||
|
waitLock timeout file displaymessage = makeLockHandle P.lockPool file
|
||||||
-- LockShared for STM lock, because a pid lock can be the top-level
|
-- LockShared for STM lock, because a pid lock can be the top-level
|
||||||
-- lock with various other STM level locks gated behind it.
|
-- lock with various other STM level locks gated behind it.
|
||||||
(\p f -> P.waitTakeLock p f LockShared)
|
(\p f -> P.waitTakeLock p f LockShared)
|
||||||
(\f -> mk <$> F.waitLock timeout f)
|
(\f -> mk <$> F.waitLock timeout f displaymessage)
|
||||||
|
|
||||||
-- Tries to take a pid lock, but does not block.
|
-- Tries to take a pid lock, but does not block.
|
||||||
tryLock :: LockFile -> IO (Maybe LockHandle)
|
tryLock :: LockFile -> IO (Maybe LockHandle)
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
[[!comment format=mdwn
|
||||||
|
username="joey"
|
||||||
|
subject="""comment 7"""
|
||||||
|
date="2020-08-26T17:02:26Z"
|
||||||
|
content="""
|
||||||
|
Added that message after the first second waiting on a pid lock.
|
||||||
|
"""]]
|
|
@ -1186,14 +1186,15 @@ Like other git commands, git-annex is configured via `.git/config`.
|
||||||
the other node is holding a pid lock. Caveat emptor.
|
the other node is holding a pid lock. Caveat emptor.
|
||||||
|
|
||||||
* `annex.pidlocktimeout`
|
* `annex.pidlocktimeout`
|
||||||
|
|
||||||
|
git-annex will wait up to this many seconds for the pid lock
|
||||||
|
file to go away, and will then abort if it cannot continue. Default: 300
|
||||||
|
|
||||||
When using pid lock files, it's possible for a stale lock file to get
|
When using pid lock files, it's possible for a stale lock file to get
|
||||||
left behind by previous run of git-annex that crashed or was interrupted.
|
left behind by previous run of git-annex that crashed or was interrupted.
|
||||||
This is mostly avoided, but can occur especially when using a network
|
This is mostly avoided, but can occur especially when using a network
|
||||||
file system.
|
file system. This timeout prevents git-annex waiting forever in such a
|
||||||
|
situation.
|
||||||
git-annex will wait up to this many seconds for the pid lock
|
|
||||||
file to go away, and will then abort if it cannot continue. Default: 300
|
|
||||||
|
|
||||||
* `annex.cachecreds`
|
* `annex.cachecreds`
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue