aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Joey Hess <joeyh@joeyh.name>2015-11-12 17:47:31 -0400
committerGravatar Joey Hess <joeyh@joeyh.name>2015-11-12 17:50:34 -0400
commitba78630681ab7e987b70e67acaaf477912fe00bb (patch)
treeffe1202f212114fca535db22dba02de229d00330
parent00fdc3063fe586cdce35ba8dbe2f1b024479522c (diff)
pid locking configuration and abstraction layer for git-annex
(not actually used anywhere yet)
-rw-r--r--Annex/LockPool.hs17
-rw-r--r--Annex/LockPool/PosixOrPid.hs74
-rw-r--r--Locations.hs5
-rw-r--r--Types/GitConfig.hs8
-rw-r--r--Utility/LockFile/Posix.hs2
-rw-r--r--debian/changelog2
-rw-r--r--doc/git-annex.mdwn24
7 files changed, 131 insertions, 1 deletions
diff --git a/Annex/LockPool.hs b/Annex/LockPool.hs
new file mode 100644
index 000000000..c6a34720e
--- /dev/null
+++ b/Annex/LockPool.hs
@@ -0,0 +1,17 @@
+{- Wraps Utility.LockPool, making pid locks be used when git-annex is so
+ - configured.
+ -
+ - Copyright 2015 Joey Hess <id@joeyh.name>
+ -
+ - Licensed under the GNU GPL version 3 or higher.
+ -}
+
+{-# LANGUAGE CPP #-}
+
+module Annex.LockPool (module X) where
+
+#ifndef mingw32_HOST_OS
+import Annex.LockPool.PosixOrPid as X
+#else
+import Utility.LockPool.Windows as X
+#endif
diff --git a/Annex/LockPool/PosixOrPid.hs b/Annex/LockPool/PosixOrPid.hs
new file mode 100644
index 000000000..71c4f0eee
--- /dev/null
+++ b/Annex/LockPool/PosixOrPid.hs
@@ -0,0 +1,74 @@
+{- Wraps Utility.LockPool, making pid locks be used when git-annex is so
+ - configured.
+ -
+ - Copyright 2015 Joey Hess <id@joeyh.name>
+ -
+ - Licensed under the GNU GPL version 3 or higher.
+ -}
+
+module Annex.LockPool.PosixOrPid where
+
+import Common.Annex
+import qualified Annex
+import qualified Utility.LockPool.Posix as Posix
+import qualified Utility.LockPool.PidLock as Pid
+import Utility.LockFile.Posix (openLockFile)
+import Utility.LockPool.STM (LockFile)
+import Utility.LockPool.LockHandle
+import Utility.LockFile.LockStatus
+
+import System.Posix
+
+lockShared :: Maybe FileMode -> LockFile -> Annex LockHandle
+lockShared m f = pidLock m f $ Posix.lockShared m f
+
+lockExclusive :: Maybe FileMode -> LockFile -> Annex LockHandle
+lockExclusive m f = pidLock m f $ Posix.lockExclusive m f
+
+tryLockShared :: Maybe FileMode -> LockFile -> Annex (Maybe LockHandle)
+tryLockShared m f = tryPidLock m f $ Posix.tryLockShared m f
+
+tryLockExclusive :: Maybe FileMode -> LockFile -> Annex (Maybe LockHandle)
+tryLockExclusive m f = tryPidLock m f $ Posix.tryLockExclusive m f
+
+checkLocked :: LockFile -> Annex (Maybe Bool)
+checkLocked f = Posix.checkLocked f
+ `pidLockCheck` Pid.checkLocked
+
+getLockStatus :: LockFile -> Annex LockStatus
+getLockStatus f = Posix.getLockStatus f
+ `pidLockCheck` Pid.getLockStatus
+
+pidLockFile :: Annex (Maybe FilePath)
+pidLockFile = ifM (annexPidLock <$> Annex.getGitConfig)
+ ( Just <$> fromRepo gitAnnexPidLockFile
+ , pure Nothing
+ )
+
+pidLockCheck :: IO a -> (LockFile -> IO a) -> Annex a
+pidLockCheck posixcheck pidcheck =
+ liftIO . maybe posixcheck pidcheck =<< pidLockFile
+
+pidLock :: Maybe FileMode -> LockFile -> IO LockHandle -> Annex LockHandle
+pidLock m f posixlock = go =<< pidLockFile
+ where
+ go Nothing = liftIO posixlock
+ go (Just pidlock) = do
+ timeout <- annexPidLockTimeout <$> Annex.getGitConfig
+ liftIO $ do
+ dummyPosixLock m f
+ Pid.waitLock timeout pidlock
+
+tryPidLock :: Maybe FileMode -> LockFile -> IO (Maybe LockHandle) -> Annex (Maybe LockHandle)
+tryPidLock m f posixlock = liftIO . go =<< pidLockFile
+ where
+ go Nothing = posixlock
+ go (Just pidlock) = do
+ dummyPosixLock m f
+ Pid.tryLock pidlock
+
+-- The posix lock file is created even when using pid locks, in order to
+-- avoid complicating any code that might expect to be able to see that
+-- lock file.
+dummyPosixLock :: Maybe FileMode -> LockFile -> IO ()
+dummyPosixLock m f = closeFd =<< openLockFile ReadLock m f
diff --git a/Locations.hs b/Locations.hs
index c3d9c7ab2..bcbac34db 100644
--- a/Locations.hs
+++ b/Locations.hs
@@ -51,6 +51,7 @@ module Locations (
gitAnnexViewLog,
gitAnnexIgnoredRefs,
gitAnnexPidFile,
+ gitAnnexPidLockFile,
gitAnnexDaemonStatusFile,
gitAnnexLogFile,
gitAnnexFuzzTestLogFile,
@@ -334,6 +335,10 @@ gitAnnexIgnoredRefs r = gitAnnexDir r </> "ignoredrefs"
gitAnnexPidFile :: Git.Repo -> FilePath
gitAnnexPidFile r = gitAnnexDir r </> "daemon.pid"
+{- Pid lock file for pidlock mode -}
+gitAnnexPidLockFile :: Git.Repo -> FilePath
+gitAnnexPidLockFile r = gitAnnexDir r </> "pidlock"
+
{- Status file for daemon mode. -}
gitAnnexDaemonStatusFile :: Git.Repo -> FilePath
gitAnnexDaemonStatusFile r = gitAnnexDir r </> "daemon.status"
diff --git a/Types/GitConfig.hs b/Types/GitConfig.hs
index 9dde2b91d..1eb1f3227 100644
--- a/Types/GitConfig.hs
+++ b/Types/GitConfig.hs
@@ -1,6 +1,6 @@
{- git-annex configuration
-
- - Copyright 2012-2014 Joey Hess <id@joeyh.name>
+ - Copyright 2012-2015 Joey Hess <id@joeyh.name>
-
- Licensed under the GNU GPL version 3 or higher.
-}
@@ -26,6 +26,7 @@ import Types.Difference
import Types.RefSpec
import Utility.HumanTime
import Utility.Gpg (GpgCmd, mkGpgCmd)
+import Utility.ThreadScheduler (Seconds(..))
{- Main git-annex settings. Each setting corresponds to a git-config key
- such as annex.foo -}
@@ -62,6 +63,8 @@ data GitConfig = GitConfig
, annexDifferences :: Differences
, annexUsedRefSpec :: Maybe RefSpec
, annexVerify :: Bool
+ , annexPidLock :: Bool
+ , annexPidLockTimeout :: Seconds
, coreSymlinks :: Bool
, coreSharedRepository :: SharedRepository
, gcryptId :: Maybe String
@@ -105,6 +108,9 @@ extractGitConfig r = GitConfig
, annexUsedRefSpec = either (const Nothing) Just . parseRefSpec
=<< getmaybe (annex "used-refspec")
, annexVerify = getbool (annex "verify") True
+ , annexPidLock = getbool (annex "pidlock") False
+ , annexPidLockTimeout = Seconds $ fromMaybe 300 $
+ getmayberead (annex "pidlocktimeout")
, coreSymlinks = getbool "core.symlinks" True
, coreSharedRepository = getSharedRepository r
, gcryptId = getmaybe "core.gcrypt-id"
diff --git a/Utility/LockFile/Posix.hs b/Utility/LockFile/Posix.hs
index b1c4cc551..b45bca088 100644
--- a/Utility/LockFile/Posix.hs
+++ b/Utility/LockFile/Posix.hs
@@ -16,6 +16,8 @@ module Utility.LockFile.Posix (
LockStatus(..),
dropLock,
checkSaneLock,
+ LockRequest(..),
+ openLockFile,
) where
import Utility.Exception
diff --git a/debian/changelog b/debian/changelog
index ae0ece428..764823e6c 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -27,6 +27,8 @@ git-annex (5.20151102.2) UNRELEASED; urgency=medium
dead repo.
* assistant: Pass ssh-options through 3 more git pull/push calls
that were missed before.
+ * Added annex.pidlock and annex.pidlocktimeout configuration to support
+ filesystems where POSIX fcntl locks cannot be used.
-- Joey Hess <id@joeyh.name> Wed, 04 Nov 2015 12:50:20 -0400
diff --git a/doc/git-annex.mdwn b/doc/git-annex.mdwn
index d35702804..c28d8af6c 100644
--- a/doc/git-annex.mdwn
+++ b/doc/git-annex.mdwn
@@ -965,6 +965,30 @@ Here are all the supported configuration settings.
which does not support symbolic links, or hard links, or unix permissions.
This is automatically probed by "git annex init".
+* `annex.pidlock`
+
+ Normally, git-annex uses fine-grained lock files to allow multiple
+ processes to run concurrently without getting in each others' way.
+ That works great, unless you are using git-annex on a filesystem that
+ does not support POSIX fcntl locks. This is sometimes the case when
+ using NFS or Lustre filesystems.
+
+ To support such situations, you can set annex.pidlock to true, and it
+ will fall back to a single top-level pid file lock.
+
+ (Although, often, you'd really be better off fixing your networked
+ filesystem configuration to support POSIX locks..)
+
+* `annex.pidlocktimeout`
+
+ 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.
+ This is mostly avoided, but can occur especially when using a network
+ file system.
+
+ 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
+
* `remote.<name>.annex-cost`
When determining which repository to