aboutsummaryrefslogtreecommitdiff
path: root/Annex/LockFile.hs
diff options
context:
space:
mode:
authorGravatar Joey Hess <joeyh@joeyh.name>2015-02-17 13:04:22 -0400
committerGravatar Joey Hess <joeyh@joeyh.name>2015-02-17 13:30:24 -0400
commitc18aca6a6a1673d17467e25eb5c900f824c8231c (patch)
tree0ef32f822433fc6a6306db0b31640588224e19e8 /Annex/LockFile.hs
parentd14b4c2a607409fbec81fedd2cc89ee77ba6a62e (diff)
avoid crash when starting fsck --incremental when one is already running
Turns out sqlite does not like having its database deleted out from underneath it. It might suffice to empty the table, but I would rather start each fsck over with a new database, so I added a lock file, and running incremental fscks use a shared lock. This leaves one concurrency bug left; running two concurrent fsck --more will lead to: "SQLite3 returned ErrorBusy while attempting to perform step." and one or both will fail. This is a concurrent writers problem.
Diffstat (limited to 'Annex/LockFile.hs')
-rw-r--r--Annex/LockFile.hs21
1 files changed, 20 insertions, 1 deletions
diff --git a/Annex/LockFile.hs b/Annex/LockFile.hs
index 18e876c75..62a101aa5 100644
--- a/Annex/LockFile.hs
+++ b/Annex/LockFile.hs
@@ -1,6 +1,6 @@
{- git-annex lock files.
-
- - 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.
-}
@@ -12,6 +12,7 @@ module Annex.LockFile (
unlockFile,
getLockPool,
withExclusiveLock,
+ tryExclusiveLock,
) where
import Common.Annex
@@ -70,3 +71,21 @@ withExclusiveLock getlockfile a = do
#else
lock _mode = waitToLock . lockExclusive
#endif
+
+{- Tries to take an exclusive lock and run an action. If the lock is
+ - already held, returns Nothing. -}
+tryExclusiveLock :: (Git.Repo -> FilePath) -> Annex a -> Annex (Maybe a)
+tryExclusiveLock getlockfile a = do
+ lockfile <- fromRepo getlockfile
+ createAnnexDirectory $ takeDirectory lockfile
+ mode <- annexFileMode
+ bracketIO (lock mode lockfile) unlock go
+ where
+#ifndef mingw32_HOST_OS
+ lock mode = noUmask mode . tryLockExclusive (Just mode)
+#else
+ lock _mode = lockExclusive
+#endif
+ unlock = maybe noop dropLock
+ go Nothing = return Nothing
+ go (Just _) = Just <$> a