upgrade: Handle upgrade to v6 when the repository already contains v6 unlocked files whose content is already present.

Closes https://github.com/datalad/datalad/issues/1020

The use of runWriter in scanUnlockedFiles broke due to this change;
it failed with blocked indefinitely in mvar, because the database write
handle was taken while linkFromAnnex needed to also write to it (to update
the inode cache). So, switched to using a separate runWriter for each call
to addAssociatedFileFast. A little less efficient, but not greatly; the
writes should all still be cached.
This commit is contained in:
Joey Hess 2016-10-17 15:19:47 -04:00
parent 148bd0dbfd
commit 8e22114735
No known key found for this signature in database
GPG key ID: C910D9222512E3C7
4 changed files with 43 additions and 16 deletions

View file

@ -11,7 +11,10 @@ import Annex.Common
import Annex.Link import Annex.Link
import Annex.CatFile import Annex.CatFile
import Annex.Version import Annex.Version
import Annex.Content
import Annex.ReplaceFile
import Config import Config
import Git.FilePath
import qualified Git.Ref import qualified Git.Ref
import qualified Git.Branch import qualified Git.Branch
import qualified Git.LsTree import qualified Git.LsTree
@ -54,16 +57,19 @@ ifAnnexed file yes no = maybe no yes =<< lookupFile file
- This is expensive, and so normally the associated files are updated - This is expensive, and so normally the associated files are updated
- incrementally when changes are noticed. So, this only needs to be done - incrementally when changes are noticed. So, this only needs to be done
- when initializing/upgrading a v6 mode repository. - when initializing/upgrading a v6 mode repository.
-
- Also, the content for the unlocked file may already be present as
- an annex object. If so, make the unlocked file use that content.
-} -}
scanUnlockedFiles :: Annex () scanUnlockedFiles :: Annex ()
scanUnlockedFiles = whenM (isJust <$> inRepo Git.Branch.current) $ scanUnlockedFiles = whenM (isJust <$> inRepo Git.Branch.current) $ do
Database.Keys.runWriter $ \h -> do
showSideAction "scanning for unlocked files" showSideAction "scanning for unlocked files"
liftIO $ Database.Keys.SQL.dropAllAssociatedFiles h Database.Keys.runWriter $
liftIO . Database.Keys.SQL.dropAllAssociatedFiles
(l, cleanup) <- inRepo $ Git.LsTree.lsTree Git.Ref.headRef (l, cleanup) <- inRepo $ Git.LsTree.lsTree Git.Ref.headRef
forM_ l $ \i -> forM_ l $ \i ->
when (isregfile i) $ when (isregfile i) $
maybe noop (add h i) maybe noop (add i)
=<< catKey (Git.LsTree.sha i) =<< catKey (Git.LsTree.sha i)
liftIO $ void cleanup liftIO $ void cleanup
where where
@ -71,7 +77,17 @@ scanUnlockedFiles = whenM (isJust <$> inRepo Git.Branch.current) $
Just Git.Types.FileBlob -> True Just Git.Types.FileBlob -> True
Just Git.Types.ExecutableBlob -> True Just Git.Types.ExecutableBlob -> True
_ -> False _ -> False
add h i k = liftIO $ Database.Keys.SQL.addAssociatedFileFast add i k = do
(toIKey k) let tf = Git.LsTree.file i
(Git.LsTree.file i) Database.Keys.runWriter $
h liftIO . Database.Keys.SQL.addAssociatedFileFast (toIKey k) tf
whenM (inAnnex k) $ do
f <- fromRepo $ fromTopFilePath tf
destmode <- liftIO $ catchMaybeIO $ fileMode <$> getFileStatus f
replaceFile f $ \tmp -> do
r <- linkFromAnnex k tmp destmode
case r of
LinkAnnexOk -> return ()
LinkAnnexNoop -> return ()
LinkAnnexFailed -> liftIO $
writePointerFile tmp k destmode

View file

@ -2,6 +2,8 @@ git-annex (6.20161013) UNRELEASED; urgency=medium
* lock, smudge: Fix edge cases where data loss could occur in v6 mode * lock, smudge: Fix edge cases where data loss could occur in v6 mode
when the keys database was not populated. when the keys database was not populated.
* upgrade: Handle upgrade to v6 when the repository already contains
v6 unlocked files whose content is already present.
-- Joey Hess <id@joeyh.name> Mon, 17 Oct 2016 12:46:54 -0400 -- Joey Hess <id@joeyh.name> Mon, 17 Oct 2016 12:46:54 -0400

View file

@ -56,7 +56,7 @@ performNew dest key = do
case r of case r of
LinkAnnexOk -> return () LinkAnnexOk -> return ()
LinkAnnexNoop -> return () LinkAnnexNoop -> return ()
_ -> error "unlock failed" LinkAnnexFailed -> error "unlock failed"
, liftIO $ writePointerFile tmp key destmode , liftIO $ writePointerFile tmp key destmode
) )
next $ cleanupNew dest key destmode next $ cleanupNew dest key destmode

View file

@ -35,4 +35,13 @@ $> ./v6-push.sh 6 2>&1 | grep '>>>'
> >
> I am not sure yet why the keys database lacked an entry for the file; > I am not sure yet why the keys database lacked an entry for the file;
> perhaps something to do with it being a v6 unlocked file in a v5 > perhaps something to do with it being a v6 unlocked file in a v5
> repository. --[[Joey]] > repository.
>
> Ok.. Seems that cloning to a v5 repository, and then copying/getting
> objects into it, and then upgrading to v6 reproduces the problem with the
> keys database. The inode cache does not get populated for unlocked files
> on upgrade. Also, unlocked files stay as pointer files even when their
> content is present in annex/objects. Fixed the upgrade process to handle
> this case.
>
> [[fixed|done]]] --[[Joey]]