Add locking to avoid races when changing the git-annex branch.
This commit is contained in:
parent
f77979b8b5
commit
d357556141
4 changed files with 29 additions and 12 deletions
33
Branch.hs
33
Branch.hs
|
@ -29,6 +29,8 @@ import Data.Maybe
|
||||||
import System.IO
|
import System.IO
|
||||||
import System.IO.Binary
|
import System.IO.Binary
|
||||||
import System.Posix.Process
|
import System.Posix.Process
|
||||||
|
import System.Posix.IO
|
||||||
|
import System.Posix.Files
|
||||||
import System.Exit
|
import System.Exit
|
||||||
import qualified Data.ByteString.Lazy.Char8 as L
|
import qualified Data.ByteString.Lazy.Char8 as L
|
||||||
|
|
||||||
|
@ -129,16 +131,17 @@ create = unlessM hasBranch $ do
|
||||||
|
|
||||||
{- Stages the journal, and commits staged changes to the branch. -}
|
{- Stages the journal, and commits staged changes to the branch. -}
|
||||||
commit :: String -> Annex ()
|
commit :: String -> Annex ()
|
||||||
commit message = whenM stageJournalFiles $ do
|
commit message = lockJournal $
|
||||||
g <- Annex.gitRepo
|
whenM stageJournalFiles $ do
|
||||||
withIndex $ liftIO $ Git.commit g message fullname [fullname]
|
g <- Annex.gitRepo
|
||||||
|
withIndex $ liftIO $ Git.commit g message fullname [fullname]
|
||||||
|
|
||||||
{- Ensures that the branch is up-to-date; should be called before
|
{- Ensures that the branch is up-to-date; should be called before
|
||||||
- data is read from it. Runs only once per git-annex run. -}
|
- data is read from it. Runs only once per git-annex run. -}
|
||||||
update :: Annex ()
|
update :: Annex ()
|
||||||
update = do
|
update = do
|
||||||
state <- getState
|
state <- getState
|
||||||
unless (branchUpdated state) $ withIndex $ do
|
unless (branchUpdated state) $ withIndex $ lockJournal $ do
|
||||||
{- Since branches get merged into the index, it's important to
|
{- Since branches get merged into the index, it's important to
|
||||||
- first stage the journal into the index. Otherwise, any
|
- first stage the journal into the index. Otherwise, any
|
||||||
- changes in the journal would later get staged, and might
|
- changes in the journal would later get staged, and might
|
||||||
|
@ -154,6 +157,7 @@ update = do
|
||||||
g <- Annex.gitRepo
|
g <- Annex.gitRepo
|
||||||
unless (null updated && not staged) $ liftIO $
|
unless (null updated && not staged) $ liftIO $
|
||||||
Git.commit g "update" fullname (fullname:updated)
|
Git.commit g "update" fullname (fullname:updated)
|
||||||
|
|
||||||
Annex.changeState $ \s -> s { Annex.branchstate = state { branchUpdated = True } }
|
Annex.changeState $ \s -> s { Annex.branchstate = state { branchUpdated = True } }
|
||||||
invalidateCache
|
invalidateCache
|
||||||
|
|
||||||
|
@ -215,13 +219,7 @@ updateRef ref
|
||||||
|
|
||||||
{- Applies a function to modifiy the content of a file. -}
|
{- Applies a function to modifiy the content of a file. -}
|
||||||
change :: FilePath -> (String -> String) -> Annex ()
|
change :: FilePath -> (String -> String) -> Annex ()
|
||||||
change file a = do
|
change file a = lockJournal $ get file >>= return . a >>= set file
|
||||||
lock
|
|
||||||
get file >>= return . a >>= set file
|
|
||||||
unlock
|
|
||||||
where
|
|
||||||
lock = return ()
|
|
||||||
unlock = return ()
|
|
||||||
|
|
||||||
{- Records new content of a file into the journal. -}
|
{- Records new content of a file into the journal. -}
|
||||||
set :: FilePath -> String -> Annex ()
|
set :: FilePath -> String -> Annex ()
|
||||||
|
@ -277,7 +275,7 @@ setJournalFile file content = do
|
||||||
writeBinaryFile tmpfile content
|
writeBinaryFile tmpfile content
|
||||||
renameFile tmpfile jfile
|
renameFile tmpfile jfile
|
||||||
|
|
||||||
{- Gets journalled content for a file in the branch. -}
|
{- Gets any journalled content for a file in the branch. -}
|
||||||
getJournalFile :: FilePath -> Annex (Maybe String)
|
getJournalFile :: FilePath -> Annex (Maybe String)
|
||||||
getJournalFile file = do
|
getJournalFile file = do
|
||||||
g <- Annex.gitRepo
|
g <- Annex.gitRepo
|
||||||
|
@ -346,3 +344,14 @@ journalFile repo file = gitAnnexJournalDir repo </> concatMap mangle file
|
||||||
- filename on the branch. -}
|
- filename on the branch. -}
|
||||||
fileJournal :: FilePath -> FilePath
|
fileJournal :: FilePath -> FilePath
|
||||||
fileJournal = replace "//" "_" . replace "_" "/"
|
fileJournal = replace "//" "_" . replace "_" "/"
|
||||||
|
|
||||||
|
{- Runs an action that modifies the journal, using locking to avoid
|
||||||
|
- contention with other git-annex processes. -}
|
||||||
|
lockJournal :: Annex a -> Annex a
|
||||||
|
lockJournal a = do
|
||||||
|
g <- Annex.gitRepo
|
||||||
|
h <- liftIO $ createFile (gitAnnexJournalLock g) stdFileMode
|
||||||
|
liftIO $ waitToSetLock h (WriteLock, AbsoluteSeek, 0, 0)
|
||||||
|
r <- a
|
||||||
|
liftIO $ closeFd h
|
||||||
|
return r
|
||||||
|
|
|
@ -18,6 +18,7 @@ module Locations (
|
||||||
gitAnnexBadLocation,
|
gitAnnexBadLocation,
|
||||||
gitAnnexUnusedLog,
|
gitAnnexUnusedLog,
|
||||||
gitAnnexJournalDir,
|
gitAnnexJournalDir,
|
||||||
|
gitAnnexJournalLock,
|
||||||
isLinkToAnnex,
|
isLinkToAnnex,
|
||||||
hashDirMixed,
|
hashDirMixed,
|
||||||
hashDirLower,
|
hashDirLower,
|
||||||
|
@ -109,6 +110,10 @@ gitAnnexUnusedLog prefix r = gitAnnexDir r </> (prefix ++ "unused")
|
||||||
gitAnnexJournalDir :: Git.Repo -> FilePath
|
gitAnnexJournalDir :: Git.Repo -> FilePath
|
||||||
gitAnnexJournalDir r = addTrailingPathSeparator $ gitAnnexDir r </> "journal"
|
gitAnnexJournalDir r = addTrailingPathSeparator $ gitAnnexDir r </> "journal"
|
||||||
|
|
||||||
|
{- Lock file for the journal. -}
|
||||||
|
gitAnnexJournalLock :: Git.Repo -> FilePath
|
||||||
|
gitAnnexJournalLock r = gitAnnexDir r </> "journal.lck"
|
||||||
|
|
||||||
{- Checks a symlink target to see if it appears to point to annexed content. -}
|
{- Checks a symlink target to see if it appears to point to annexed content. -}
|
||||||
isLinkToAnnex :: FilePath -> Bool
|
isLinkToAnnex :: FilePath -> Bool
|
||||||
isLinkToAnnex s = ("/.git/" ++ objectDir) `isInfixOf` s
|
isLinkToAnnex s = ("/.git/" ++ objectDir) `isInfixOf` s
|
||||||
|
|
1
debian/changelog
vendored
1
debian/changelog
vendored
|
@ -6,6 +6,7 @@ git-annex (3.20110929) UNRELEASED; urgency=low
|
||||||
* When displaying a list of repositories, show git remote names
|
* When displaying a list of repositories, show git remote names
|
||||||
in addition to their descriptions.
|
in addition to their descriptions.
|
||||||
* Contain the zombie hordes.
|
* Contain the zombie hordes.
|
||||||
|
* Add locking to avoid races when changing the git-annex branch.
|
||||||
|
|
||||||
-- Joey Hess <joeyh@debian.org> Thu, 29 Sep 2011 18:58:53 -0400
|
-- Joey Hess <joeyh@debian.org> Thu, 29 Sep 2011 18:58:53 -0400
|
||||||
|
|
||||||
|
|
|
@ -49,3 +49,5 @@ Make Branch.change transactional, so it takes a lock, reads a file,
|
||||||
applies a function to it, and writes the changed file.
|
applies a function to it, and writes the changed file.
|
||||||
|
|
||||||
Make Branch.update hold the same lock.
|
Make Branch.update hold the same lock.
|
||||||
|
|
||||||
|
> [[Done]].
|
||||||
|
|
Loading…
Reference in a new issue