summaryrefslogtreecommitdiff
path: root/Annex/Branch.hs
diff options
context:
space:
mode:
authorGravatar Joey Hess <joey@kitenet.net>2013-10-03 15:43:08 -0400
committerGravatar Joey Hess <joey@kitenet.net>2013-10-03 15:43:08 -0400
commiteb932d259c605cf58fda4a61d051c469ef4531bf (patch)
tree31ce69ef58676af83bcde226e14a6f99c958f604 /Annex/Branch.hs
parent01111895034873f6b65fcd2ebb86a95de4e6a9e8 (diff)
Automatically and safely detect and recover from dangling .git/annex/index.lock files, which would prevent git from committing to the git-annex branch, eg after a crash.
Diffstat (limited to 'Annex/Branch.hs')
-rw-r--r--Annex/Branch.hs54
1 files changed, 40 insertions, 14 deletions
diff --git a/Annex/Branch.hs b/Annex/Branch.hs
index 8c8aef7d6..c704cef87 100644
--- a/Annex/Branch.hs
+++ b/Annex/Branch.hs
@@ -137,7 +137,7 @@ updateTo pairs = do
- may still be updated if the branch has gotten ahead
- of the index. -}
then whenM (needUpdateIndex branchref) $ lockJournal $ \jl -> do
- forceUpdateIndex branchref
+ forceUpdateIndex jl branchref
{- When there are journalled changes
- as well as the branch being updated,
- a commit needs to be done. -}
@@ -160,14 +160,14 @@ updateTo pairs = do
<$> getLocal transitionsLog
unless (null branches) $ do
showSideAction merge_desc
- mergeIndex refs
+ mergeIndex jl refs
let commitrefs = nub $ fullname:refs
unlessM (handleTransitions jl localtransitions commitrefs) $ do
ff <- if dirty
then return False
else inRepo $ Git.Branch.fastForward fullname refs
if ff
- then updateIndex branchref
+ then updateIndex jl branchref
else commitBranch jl branchref merge_desc commitrefs
liftIO cleanjournal
@@ -240,7 +240,7 @@ commitBranch jl branchref message parents = do
commitBranch' jl branchref message parents
commitBranch' :: JournalLocked -> Git.Ref -> String -> [Git.Ref] -> Annex ()
commitBranch' jl branchref message parents = do
- updateIndex branchref
+ updateIndex jl branchref
committedref <- inRepo $ Git.Branch.commit message fullname parents
setIndexSha committedref
parentrefs <- commitparents <$> catObject committedref
@@ -264,7 +264,7 @@ commitBranch' jl branchref message parents = do
{- To recover from the race, union merge the lost refs
- into the index, and recommit on top of the bad commit. -}
fixrace committedref lostrefs = do
- mergeIndex lostrefs
+ mergeIndex jl lostrefs
commitBranch jl committedref racemessage [committedref]
racemessage = message ++ " (recovery from race)"
@@ -297,11 +297,27 @@ genIndex g = Git.UpdateIndex.streamUpdateIndex g
{- Merges the specified refs into the index.
- Any changes staged in the index will be preserved. -}
-mergeIndex :: [Git.Ref] -> Annex ()
-mergeIndex branches = do
+mergeIndex :: JournalLocked -> [Git.Ref] -> Annex ()
+mergeIndex jl branches = do
+ prepareModifyIndex jl
h <- catFileHandle
inRepo $ \g -> Git.UnionMerge.mergeIndex h g branches
+{- Removes any stale git lock file, to avoid git falling over when
+ - updating the index.
+ -
+ - Since all modifications of the index are performed inside this module,
+ - and only when the journal is locked, the fact that the journal has to be
+ - locked when this is called ensures that no other process is currently
+ - modifying the index. So any index.lock file must be stale, caused
+ - by git running when the system crashed, or the repository's disk was
+ - removed, etc.
+ -}
+prepareModifyIndex :: JournalLocked -> Annex ()
+prepareModifyIndex _jl = do
+ index <- fromRepo gitAnnexIndex
+ void $ liftIO $ tryIO $ removeFile $ index ++ ".lock"
+
{- Runs an action using the branch's index file. -}
withIndex :: Annex a -> Annex a
withIndex = withIndex' False
@@ -339,13 +355,13 @@ withIndex' bootstrapping a = do
- Compares the ref stored in the lock file with the current
- ref of the branch to see if an update is needed.
-}
-updateIndex :: Git.Ref -> Annex ()
-updateIndex branchref = whenM (needUpdateIndex branchref) $
- forceUpdateIndex branchref
+updateIndex :: JournalLocked -> Git.Ref -> Annex ()
+updateIndex jl branchref = whenM (needUpdateIndex branchref) $
+ forceUpdateIndex jl branchref
-forceUpdateIndex :: Git.Ref -> Annex ()
-forceUpdateIndex branchref = do
- withIndex $ mergeIndex [fullname]
+forceUpdateIndex :: JournalLocked -> Git.Ref -> Annex ()
+forceUpdateIndex jl branchref = do
+ withIndex $ mergeIndex jl [fullname]
setIndexSha branchref
{- Checks if the index needs to be updated. -}
@@ -366,9 +382,18 @@ setIndexSha ref = do
{- Stages the journal into the index and returns an action that will
- clean up the staged journal files, which should only be run once
- - the index has been committed to the branch. -}
+ - the index has been committed to the branch.
+ -
+ - Before staging, this removes any existing git index file lock.
+ - This is safe to do because stageJournal is the only thing that
+ - modifies this index file, and only one can run at a time, because
+ - the journal is locked. So any existing git index file lock must be
+ - stale, and the journal must contain any data that was in the process
+ - of being written to the index file when it crashed.
+ -}
stageJournal :: JournalLocked -> Annex (IO ())
stageJournal jl = withIndex $ do
+ prepareModifyIndex jl
g <- gitRepo
let dir = gitAnnexJournalDir g
fs <- getJournalFiles jl
@@ -448,6 +473,7 @@ performTransitionsLocked jl ts neednewlocalbranch transitionedrefs = do
-- for the head branch. Flush any such changes.
Annex.Queue.flush
withIndex $ do
+ prepareModifyIndex jl
run $ mapMaybe getTransitionCalculator $ transitionList ts
Annex.Queue.flush
if neednewlocalbranch