Fix git-annex branch data loss that could occur after git-annex forget --drop-dead

Added getStaged, to get the versions of git-annex branch files staged in its
index, and use during transitions so the result of merging sibling branches
is used.

The catFileStop in performTransitionsLocked is absolutely necessary,
without that the bug still occurred, because git cat-file was already
running and was looking at the old index file.

Note that getLocal still has cat-file look at the git-annex branch, not the
index. It might be faster if it looked at the index, but probably only
marginally so, and I've not benchmarked it to see if it's faster at all. I
didn't want to change unrelated behavior as part of this bug fix. And as
the need for catFileStop shows, using the index file has added
complications.

Anyway, it still seems fine for getLocal to look at the git-annex branch,
because normally the index file is updated just before the git-annex branch
is committed, and so they'll contain the same information. It's only during
a transition that the two diverge.

This commit was sponsored by Paul Walmsley in honor of Mark Phillips.
This commit is contained in:
Joey Hess 2018-08-06 17:22:12 -04:00
parent b221cc0434
commit 4c918437ab
No known key found for this signature in database
GPG key ID: DB12DB0FF05F8F38
5 changed files with 63 additions and 6 deletions

View file

@ -223,10 +223,15 @@ getLocal :: FilePath -> Annex String
getLocal file = go =<< getJournalFileStale file
where
go (Just journalcontent) = return journalcontent
go Nothing = getRaw file
go Nothing = getRef fullname file
getRaw :: FilePath -> Annex String
getRaw = getRef fullname
{- Gets the content of a file as staged in the branch's index. -}
getStaged :: FilePath -> Annex String
getStaged = getRef indexref
where
-- This makes git cat-file be run with ":file",
-- so it looks at the index.
indexref = Ref ""
getHistorical :: RefDate -> FilePath -> Annex String
getHistorical date file =
@ -533,6 +538,10 @@ performTransitionsLocked jl ts neednewlocalbranch transitionedrefs = do
-- update the git-annex branch, while it usually holds changes
-- for the head branch. Flush any such changes.
Annex.Queue.flush
-- Stop any running git cat-files, to ensure that the
-- getStaged calls below use the current index, and not some older
-- one.
catFileStop
withIndex $ do
prepareModifyIndex jl
run $ mapMaybe getTransitionCalculator tlist
@ -557,15 +566,15 @@ performTransitionsLocked jl ts neednewlocalbranch transitionedrefs = do
- to hold changes to every file in the branch at once.)
-
- When a file in the branch is changed by transition code,
- that value is remembered and fed into the code for subsequent
- its new content is remembered and fed into the code for subsequent
- transitions.
-}
run [] = noop
run changers = do
trustmap <- calcTrustMap <$> getRaw trustLog
trustmap <- calcTrustMap <$> getStaged trustLog
fs <- branchFiles
forM_ fs $ \f -> do
content <- getRaw f
content <- getStaged f
apply changers f content trustmap
apply [] _ _ _ = return ()
apply (changer:rest) file content trustmap =