diff options
author | Joey Hess <joeyh@joeyh.name> | 2015-10-08 14:27:37 -0400 |
---|---|---|
committer | Joey Hess <joeyh@joeyh.name> | 2015-10-08 14:29:35 -0400 |
commit | bab88f3596c570346a3d069af9e3c8ed92e473c9 (patch) | |
tree | 32384db58de249ef11c524446d1e0bf757c5fa10 /Annex | |
parent | 5434414bff35367aa62a4aaab0c4731a38dbe76e (diff) |
add lockContentShared
Also, rename lockContent to lockContentExclusive
inAnnexSafe should perhaps be eliminated, and instead use
`lockContentShared inAnnex`. However, I'm waiting on that, as there are
only 2 call sites for inAnnexSafe and it's fiddly.
Diffstat (limited to 'Annex')
-rw-r--r-- | Annex/Content.hs | 118 |
1 files changed, 83 insertions, 35 deletions
diff --git a/Annex/Content.hs b/Annex/Content.hs index 5032e2691..14dc4d4e5 100644 --- a/Annex/Content.hs +++ b/Annex/Content.hs @@ -12,7 +12,8 @@ module Annex.Content ( inAnnex', inAnnexSafe, inAnnexCheck, - lockContent, + lockContentShared, + lockContentExclusive, getViaTmp, getViaTmp', checkDiskSpaceToGet, @@ -165,57 +166,104 @@ contentLockFile key = ifM isDirect contentLockFile key = Just <$> calcRepo (gitAnnexContentLock key) #endif -newtype ContentLock = ContentLock Key +{- Prevents the content from being removed while the action is running. + - Uses a shared lock. + - + - Does not actually check if the content is present. Use inAnnex for that. + - However, since the contentLockFile is the content file in indirect mode, + - if the content is not present, locking it will fail. + - + - If locking fails, throws an exception rather than running the action. + - + - Note that, in direct mode, nothing prevents the user from directly + - editing or removing the content, even while it's locked by this. + -} +lockContentShared :: Key -> Annex a -> Annex a +lockContentShared = lockContentUsing lock + where +#ifndef mingw32_HOST_OS + lock contentfile Nothing = liftIO $ tryLockShared Nothing contentfile + lock _ (Just lockfile) = posixLocker tryLockShared lockfile +#else + lock = winLocker lockShared +#endif + +newtype ContentLockExclusive = ContentLockExclusive Key -{- Content is exclusively locked while running an action that might remove - - it. (If the content is not present, no locking is done.) +{- Exclusively locks content, while performing an action that + - might remove it. + - + - (If the content is not present, no locking is done.) -} -lockContent :: Key -> (ContentLock -> Annex a) -> Annex a -lockContent key a = do +lockContentExclusive :: Key -> (ContentLockExclusive -> Annex a) -> Annex a +lockContentExclusive key a = lockContentUsing lock key $ + a $ ContentLockExclusive key + where +#ifndef mingw32_HOST_OS + {- Since content files are stored with the write bit disabled, have + - to fiddle with permissions to open for an exclusive lock. -} + lock contentfile Nothing = bracket_ + (thawContent contentfile) + (freezeContent contentfile) + (liftIO $ tryLockExclusive Nothing contentfile) + lock _ (Just lockfile) = posixLocker tryLockExclusive lockfile +#else + lock = winLocker lockExclusive +#endif + +{- Passed the object content file, and maybe a separate lock file to use, + - when the content file itself should not be locked. -} +type ContentLocker = FilePath -> Maybe LockFile -> Annex (Maybe LockHandle) + +#ifndef mingw32_HOST_OS +posixLocker :: (Maybe FileMode -> LockFile -> IO (Maybe LockHandle)) -> LockFile -> Annex (Maybe LockHandle) +posixLocker takelock lockfile = do + mode <- annexFileMode + modifyContent lockfile $ + liftIO $ takelock (Just mode) lockfile + +#else +winLocker :: (LockFile -> IO (Maybe LockHandle)) -> ContentLocker +winLocker takelock _ (Just lockfile) = do + modifyContent lockfile $ + void $ liftIO $ tryIO $ + writeFile lockfile "" + liftIO $ takelock lockfile +-- never reached; windows always uses a separate lock file +winLocker _ _ Nothing = return Nothing +#endif + +lockContentUsing :: ContentLocker -> Key -> Annex a -> Annex a +lockContentUsing locker key a = do contentfile <- calcRepo $ gitAnnexLocation key lockfile <- contentLockFile key bracket (lock contentfile lockfile) (unlock lockfile) - (const $ a $ ContentLock key ) + (const $ a) where alreadylocked = error "content is locked" - cleanuplockfile lockfile = modifyContent lockfile $ - void $ liftIO $ tryIO $ - nukeFile lockfile -#ifndef mingw32_HOST_OS - {- Since content files are stored with the write bit disabled, have - - to fiddle with permissions to open for an exclusive lock. -} - lock contentfile Nothing = trylock $ bracket_ - (thawContent contentfile) - (freezeContent contentfile) + failedtolock e = error $ "failed to lock content: " ++ show e + + lock contentfile lockfile = (maybe alreadylocked return - =<< liftIO (tryLockExclusive Nothing contentfile)) - lock _ (Just lockfile) = trylock $ do - mode <- annexFileMode - maybe alreadylocked return - =<< modifyContent lockfile - (liftIO $ tryLockExclusive (Just mode) lockfile) + =<< locker contentfile lockfile) + `catchIO` failedtolock + +#ifndef mingw32_HOST_OS unlock mlockfile lck = do maybe noop cleanuplockfile mlockfile liftIO $ dropLock lck - - failedtolock e = error $ "failed to lock content: " ++ show e - trylock locker = locker `catchIO` failedtolock #else - lock _ (Just lockfile) = do - modifyContent lockfile $ - void $ liftIO $ tryIO $ - writeFile lockfile "" - maybe alreadylocked (return . Just) - =<< liftIO (lockExclusive lockfile) - -- never reached; windows always uses a separate lock file - lock _ Nothing = return Nothing unlock mlockfile mlockhandle = do liftIO $ maybe noop dropLock mlockhandle maybe noop cleanuplockfile mlockfile #endif + cleanuplockfile lockfile = modifyContent lockfile $ + void $ liftIO $ tryIO $ + nukeFile lockfile + {- Runs an action, passing it the temp file to get, - and if the action succeeds, verifies the file matches - the key and moves the file into the annex as a key's content. -} @@ -497,8 +545,8 @@ cleanObjectLoc key cleaner = do - In direct mode, deletes the associated files or files, and replaces - them with symlinks. -} -removeAnnex :: ContentLock -> Annex () -removeAnnex (ContentLock key) = withObjectLoc key remove removedirect +removeAnnex :: ContentLockExclusive -> Annex () +removeAnnex (ContentLockExclusive key) = withObjectLoc key remove removedirect where remove file = cleanObjectLoc key $ do secureErase file |