use lock pools throughout git-annex
The one exception is in Utility.Daemon. As long as a process only daemonizes once, which seems reasonable, and as long as it avoids calling checkDaemon once it's already running as a daemon, the fcntl locking gotchas won't be a problem there. Annex.LockFile has it's own separate lock pool layer, which has been renamed to LockCache. This is a persistent cache of locks that persist until closed. This is not quite done; lockContent stil needs to be converted.
This commit is contained in:
parent
6915b71c57
commit
ecb0d5c087
13 changed files with 45 additions and 44 deletions
6
Annex.hs
6
Annex.hs
|
@ -57,7 +57,7 @@ import Types.Messages
|
||||||
import Types.UUID
|
import Types.UUID
|
||||||
import Types.FileMatcher
|
import Types.FileMatcher
|
||||||
import Types.NumCopies
|
import Types.NumCopies
|
||||||
import Types.LockPool
|
import Types.LockCache
|
||||||
import Types.MetaData
|
import Types.MetaData
|
||||||
import Types.DesktopNotify
|
import Types.DesktopNotify
|
||||||
import Types.CleanupActions
|
import Types.CleanupActions
|
||||||
|
@ -120,7 +120,7 @@ data AnnexState = AnnexState
|
||||||
, trustmap :: Maybe TrustMap
|
, trustmap :: Maybe TrustMap
|
||||||
, groupmap :: Maybe GroupMap
|
, groupmap :: Maybe GroupMap
|
||||||
, ciphers :: M.Map StorableCipher Cipher
|
, ciphers :: M.Map StorableCipher Cipher
|
||||||
, lockpool :: LockPool
|
, lockcache :: LockCache
|
||||||
, flags :: M.Map String Bool
|
, flags :: M.Map String Bool
|
||||||
, fields :: M.Map String String
|
, fields :: M.Map String String
|
||||||
, modmeta :: [ModMeta]
|
, modmeta :: [ModMeta]
|
||||||
|
@ -166,7 +166,7 @@ newState c r = AnnexState
|
||||||
, trustmap = Nothing
|
, trustmap = Nothing
|
||||||
, groupmap = Nothing
|
, groupmap = Nothing
|
||||||
, ciphers = M.empty
|
, ciphers = M.empty
|
||||||
, lockpool = M.empty
|
, lockcache = M.empty
|
||||||
, flags = M.empty
|
, flags = M.empty
|
||||||
, fields = M.empty
|
, fields = M.empty
|
||||||
, modmeta = []
|
, modmeta = []
|
||||||
|
|
|
@ -58,7 +58,7 @@ import Annex.Perms
|
||||||
import Annex.Link
|
import Annex.Link
|
||||||
import Annex.Content.Direct
|
import Annex.Content.Direct
|
||||||
import Annex.ReplaceFile
|
import Annex.ReplaceFile
|
||||||
import Utility.LockFile
|
import Utility.LockPool
|
||||||
import Messages.Progress
|
import Messages.Progress
|
||||||
|
|
||||||
{- Checks if a given key's content is currently present. -}
|
{- Checks if a given key's content is currently present. -}
|
||||||
|
|
|
@ -8,26 +8,26 @@
|
||||||
{-# LANGUAGE CPP #-}
|
{-# LANGUAGE CPP #-}
|
||||||
|
|
||||||
module Annex.LockFile (
|
module Annex.LockFile (
|
||||||
lockFileShared,
|
lockFileCached,
|
||||||
unlockFile,
|
unlockFile,
|
||||||
getLockPool,
|
getLockCache,
|
||||||
withExclusiveLock,
|
withExclusiveLock,
|
||||||
tryExclusiveLock,
|
tryExclusiveLock,
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Common.Annex
|
import Common.Annex
|
||||||
import Annex
|
import Annex
|
||||||
import Types.LockPool
|
import Types.LockCache
|
||||||
import qualified Git
|
import qualified Git
|
||||||
import Annex.Perms
|
import Annex.Perms
|
||||||
import Utility.LockFile
|
import Utility.LockPool
|
||||||
|
|
||||||
import qualified Data.Map as M
|
import qualified Data.Map as M
|
||||||
|
|
||||||
{- Create a specified lock file, and takes a shared lock, which is retained
|
{- Create a specified lock file, and takes a shared lock, which is retained
|
||||||
- in the pool. -}
|
- in the cache. -}
|
||||||
lockFileShared :: FilePath -> Annex ()
|
lockFileCached :: FilePath -> Annex ()
|
||||||
lockFileShared file = go =<< fromLockPool file
|
lockFileCached file = go =<< fromLockCache file
|
||||||
where
|
where
|
||||||
go (Just _) = noop -- already locked
|
go (Just _) = noop -- already locked
|
||||||
go Nothing = do
|
go Nothing = do
|
||||||
|
@ -37,25 +37,25 @@ lockFileShared file = go =<< fromLockPool file
|
||||||
#else
|
#else
|
||||||
lockhandle <- liftIO $ waitToLock $ lockShared file
|
lockhandle <- liftIO $ waitToLock $ lockShared file
|
||||||
#endif
|
#endif
|
||||||
changeLockPool $ M.insert file lockhandle
|
changeLockCache $ M.insert file lockhandle
|
||||||
|
|
||||||
unlockFile :: FilePath -> Annex ()
|
unlockFile :: FilePath -> Annex ()
|
||||||
unlockFile file = maybe noop go =<< fromLockPool file
|
unlockFile file = maybe noop go =<< fromLockCache file
|
||||||
where
|
where
|
||||||
go lockhandle = do
|
go lockhandle = do
|
||||||
liftIO $ dropLock lockhandle
|
liftIO $ dropLock lockhandle
|
||||||
changeLockPool $ M.delete file
|
changeLockCache $ M.delete file
|
||||||
|
|
||||||
getLockPool :: Annex LockPool
|
getLockCache :: Annex LockCache
|
||||||
getLockPool = getState lockpool
|
getLockCache = getState lockcache
|
||||||
|
|
||||||
fromLockPool :: FilePath -> Annex (Maybe LockHandle)
|
fromLockCache :: FilePath -> Annex (Maybe LockHandle)
|
||||||
fromLockPool file = M.lookup file <$> getLockPool
|
fromLockCache file = M.lookup file <$> getLockCache
|
||||||
|
|
||||||
changeLockPool :: (LockPool -> LockPool) -> Annex ()
|
changeLockCache :: (LockCache -> LockCache) -> Annex ()
|
||||||
changeLockPool a = do
|
changeLockCache a = do
|
||||||
m <- getLockPool
|
m <- getLockCache
|
||||||
changeState $ \s -> s { lockpool = a m }
|
changeState $ \s -> s { lockcache = a m }
|
||||||
|
|
||||||
{- Runs an action with an exclusive lock held. If the lock is already
|
{- Runs an action with an exclusive lock held. If the lock is already
|
||||||
- held, blocks until it becomes free. -}
|
- held, blocks until it becomes free. -}
|
||||||
|
|
|
@ -37,7 +37,7 @@ import Types.CleanupActions
|
||||||
import Annex.Index (addGitEnv)
|
import Annex.Index (addGitEnv)
|
||||||
#ifndef mingw32_HOST_OS
|
#ifndef mingw32_HOST_OS
|
||||||
import Annex.Perms
|
import Annex.Perms
|
||||||
import Utility.LockFile
|
import Utility.LockPool
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
{- Generates parameters to ssh to a given host (or user@host) on a given
|
{- Generates parameters to ssh to a given host (or user@host) on a given
|
||||||
|
@ -126,13 +126,13 @@ prepSocket socketfile = do
|
||||||
-- If the lock pool is empty, this is the first ssh of this
|
-- If the lock pool is empty, this is the first ssh of this
|
||||||
-- run. There could be stale ssh connections hanging around
|
-- run. 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.
|
||||||
whenM (not . any isLock . M.keys <$> getLockPool)
|
whenM (not . any isLock . M.keys <$> getLockCache)
|
||||||
sshCleanup
|
sshCleanup
|
||||||
-- Cleanup at end of this run.
|
-- Cleanup at end of this run.
|
||||||
Annex.addCleanup SshCachingCleanup sshCleanup
|
Annex.addCleanup SshCachingCleanup sshCleanup
|
||||||
|
|
||||||
liftIO $ createDirectoryIfMissing True $ parentDir socketfile
|
liftIO $ createDirectoryIfMissing True $ parentDir socketfile
|
||||||
lockFileShared $ socket2lock socketfile
|
lockFileCached $ socket2lock socketfile
|
||||||
|
|
||||||
enumSocketFiles :: Annex [FilePath]
|
enumSocketFiles :: Annex [FilePath]
|
||||||
enumSocketFiles = go =<< sshCacheDir
|
enumSocketFiles = go =<< sshCacheDir
|
||||||
|
|
|
@ -23,7 +23,7 @@ import Logs.Transfer as X
|
||||||
import Annex.Notification as X
|
import Annex.Notification as X
|
||||||
import Annex.Perms
|
import Annex.Perms
|
||||||
import Utility.Metered
|
import Utility.Metered
|
||||||
import Utility.LockFile
|
import Utility.LockPool
|
||||||
|
|
||||||
import Control.Concurrent
|
import Control.Concurrent
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,7 @@ openDb u = do
|
||||||
liftIO $ do
|
liftIO $ do
|
||||||
void $ tryIO $ removeDirectoryRecursive dbdir
|
void $ tryIO $ removeDirectoryRecursive dbdir
|
||||||
rename tmpdbdir dbdir
|
rename tmpdbdir dbdir
|
||||||
lockFileShared =<< fromRepo (gitAnnexFsckDbLock u)
|
lockFileCached =<< fromRepo (gitAnnexFsckDbLock u)
|
||||||
h <- liftIO $ H.openDb db "fscked"
|
h <- liftIO $ H.openDb db "fscked"
|
||||||
return $ FsckHandle h u
|
return $ FsckHandle h u
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ import Utility.Metered
|
||||||
import Utility.Percentage
|
import Utility.Percentage
|
||||||
import Utility.QuickCheck
|
import Utility.QuickCheck
|
||||||
import Utility.PID
|
import Utility.PID
|
||||||
import Utility.LockFile
|
import Utility.LockPool
|
||||||
import Logs.TimeStamp
|
import Logs.TimeStamp
|
||||||
|
|
||||||
import Data.Time.Clock
|
import Data.Time.Clock
|
||||||
|
|
|
@ -16,7 +16,7 @@ import Types.Remote
|
||||||
import Types.CleanupActions
|
import Types.CleanupActions
|
||||||
import qualified Annex
|
import qualified Annex
|
||||||
import Annex.LockFile
|
import Annex.LockFile
|
||||||
import Utility.LockFile
|
import Utility.LockPool
|
||||||
#ifndef mingw32_HOST_OS
|
#ifndef mingw32_HOST_OS
|
||||||
import Annex.Perms
|
import Annex.Perms
|
||||||
#endif
|
#endif
|
||||||
|
@ -47,7 +47,7 @@ runHooks :: Remote -> Maybe String -> Maybe String -> Annex a -> Annex a
|
||||||
runHooks r starthook stophook a = do
|
runHooks r starthook stophook a = do
|
||||||
dir <- fromRepo gitAnnexRemotesDir
|
dir <- fromRepo gitAnnexRemotesDir
|
||||||
let lck = dir </> remoteid ++ ".lck"
|
let lck = dir </> remoteid ++ ".lck"
|
||||||
whenM (notElem lck . M.keys <$> getLockPool) $ do
|
whenM (notElem lck . M.keys <$> getLockCache) $ do
|
||||||
liftIO $ createDirectoryIfMissing True dir
|
liftIO $ createDirectoryIfMissing True dir
|
||||||
firstrun lck
|
firstrun lck
|
||||||
a
|
a
|
||||||
|
@ -62,7 +62,7 @@ runHooks r starthook stophook a = do
|
||||||
-- of it from running the stophook. If another
|
-- of it from running the stophook. If another
|
||||||
-- instance is shutting down right now, this
|
-- instance is shutting down right now, this
|
||||||
-- will block waiting for its exclusive lock to clear.
|
-- will block waiting for its exclusive lock to clear.
|
||||||
lockFileShared lck
|
lockFileCached lck
|
||||||
|
|
||||||
-- The starthook is run even if some other git-annex
|
-- The starthook is run even if some other git-annex
|
||||||
-- is already running, and ran it before.
|
-- is already running, and ran it before.
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
{- git-annex lock pool data types
|
{- git-annex lock cache data types
|
||||||
-
|
-
|
||||||
- Copyright 2014 Joey Hess <id@joeyh.name>
|
- Copyright 2014 Joey Hess <id@joeyh.name>
|
||||||
-
|
-
|
||||||
- Licensed under the GNU GPL version 3 or higher.
|
- Licensed under the GNU GPL version 3 or higher.
|
||||||
-}
|
-}
|
||||||
|
|
||||||
module Types.LockPool (
|
module Types.LockCache (
|
||||||
LockPool,
|
LockCache,
|
||||||
LockHandle
|
LockHandle
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import qualified Data.Map as M
|
import qualified Data.Map as M
|
||||||
import Utility.LockFile
|
import Utility.LockPool
|
||||||
|
|
||||||
type LockPool = M.Map FilePath LockHandle
|
type LockCache = M.Map FilePath LockHandle
|
|
@ -4,6 +4,9 @@
|
||||||
- This module does *not* attempt to be a portability shim, it just exposes
|
- This module does *not* attempt to be a portability shim, it just exposes
|
||||||
- the native locking of the OS.
|
- the native locking of the OS.
|
||||||
-
|
-
|
||||||
|
- Posix fcntl locks have some gotchas. So, consider using
|
||||||
|
- Utility.LockPool instead of using this module directly.
|
||||||
|
-
|
||||||
- Copyright 2014 Joey Hess <id@joeyh.name>
|
- Copyright 2014 Joey Hess <id@joeyh.name>
|
||||||
-
|
-
|
||||||
- License: BSD-2-clause
|
- License: BSD-2-clause
|
||||||
|
|
|
@ -18,11 +18,9 @@ module Utility.LockPool.Posix (
|
||||||
|
|
||||||
import qualified Utility.LockFile.Posix as F
|
import qualified Utility.LockFile.Posix as F
|
||||||
import qualified Utility.LockPool.STM as P
|
import qualified Utility.LockPool.STM as P
|
||||||
import Utility.LockPool.STM (LockPool, LockFile, LockMode(..))
|
import Utility.LockPool.STM (LockFile, LockMode(..))
|
||||||
import Utility.LockPool.LockHandle
|
import Utility.LockPool.LockHandle
|
||||||
import Utility.Monad
|
|
||||||
|
|
||||||
import Control.Concurrent.STM
|
|
||||||
import System.IO
|
import System.IO
|
||||||
import System.Posix
|
import System.Posix
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
|
|
|
@ -80,16 +80,15 @@ tryTakeLock pool file mode =
|
||||||
--
|
--
|
||||||
-- Note that the lock pool is left empty while the checker action is run.
|
-- Note that the lock pool is left empty while the checker action is run.
|
||||||
-- This allows checker actions that open/close files, and so would be in
|
-- This allows checker actions that open/close files, and so would be in
|
||||||
-- danger of conflicting with existing locks. Since the lock pool is
|
-- danger of conflicting with locks created at the same time this is
|
||||||
-- kept empty, anything that attempts to take a lock will block,
|
-- running. With the lock pool empty, anything that attempts
|
||||||
-- avoiding that race.
|
-- to take a lock will block, avoiding that race.
|
||||||
getLockStatus :: LockPool -> LockFile -> IO v -> IO (Maybe v) -> IO (Maybe v)
|
getLockStatus :: LockPool -> LockFile -> IO v -> IO (Maybe v) -> IO (Maybe v)
|
||||||
getLockStatus pool file getdefault checker = do
|
getLockStatus pool file getdefault checker = do
|
||||||
v <- atomically $ do
|
v <- atomically $ do
|
||||||
m <- takeTMVar pool
|
m <- takeTMVar pool
|
||||||
let threadlocked = case M.lookup file m of
|
let threadlocked = case M.lookup file m of
|
||||||
Just (LockStatus _ n)
|
Just (LockStatus _ n) | n > 0 -> True
|
||||||
| n > 0 -> True
|
|
||||||
_ -> False
|
_ -> False
|
||||||
if threadlocked
|
if threadlocked
|
||||||
then do
|
then do
|
||||||
|
|
1
debian/changelog
vendored
1
debian/changelog
vendored
|
@ -23,6 +23,7 @@ git-annex (5.20150508.2) UNRELEASED; urgency=medium
|
||||||
all refs used.
|
all refs used.
|
||||||
* webapp: Fix zombie xdg-open process left when opening file browser.
|
* webapp: Fix zombie xdg-open process left when opening file browser.
|
||||||
Closes: #785498
|
Closes: #785498
|
||||||
|
* Safer posix fctnl locking implementation, using lock pools and STM.
|
||||||
|
|
||||||
-- Joey Hess <id@joeyh.name> Mon, 11 May 2015 12:45:06 -0400
|
-- Joey Hess <id@joeyh.name> Mon, 11 May 2015 12:45:06 -0400
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue