fix deadlock
authorJoey Hess <joeyh@joeyh.name>
Mon, 24 May 2021 19:31:06 +0000 (15:31 -0400)
committerJoey Hess <joeyh@joeyh.name>
Mon, 24 May 2021 20:19:26 +0000 (16:19 -0400)
git-annex test hung, at varying points depending
on when git decided to run the smudge clean filter.

Recent changes to reconcileStaged caused a deadlock, when git write-tree
for some reason decides to run the smudge clean filter. Which tries
to open the keys db, and blocks waiting for the lock file that its
grandparent has locked.

I don't know why git write-tree does that. It's supposed to only write a
tree from the index which needs no smudge/clean filtering.

I've verified that, in a situation where git write-tree runs the clean
filter, disabling the filter results in a tree being written that
contains the annex link, not eg, the worktree file content. So it seems
safe to disable the clean filter, but also this seems likely to be
working around a bug in git because it seems it is running the clean
filter in a situation where the object has already been cleaned.

Sponsored-by: Dartmouth College's Datalad project
Database/Keys.hs

index 6a3b43cb548eeaf110307ed1b0746d9cc6e58c29..842b53f1d1415977e6e8aa12335d3acc2d169263 100644 (file)
@@ -237,8 +237,6 @@ reconcileStaged qh = do
   where
        lastindexref = Ref "refs/annex/last-index"
 
-       getindextree = inRepo writeTreeQuiet
-
        readindexcache indexcache = liftIO $ maybe Nothing readInodeCache
                <$> catchMaybeIO (readFile indexcache)
 
@@ -272,9 +270,17 @@ reconcileStaged qh = do
                when changed $
                        liftIO $ H.flushDbQueue qh
        
+       -- Avoid running smudge clean filter, which would block trying to
+       -- access the locked database. git write-tree sometimes calls it,
+       -- even though it is not adding work tree files to the index,
+       -- and so the filter cannot have an effect on the contents of the
+       -- index or on the tree that gets written from it.
+       getindextree = inRepo $ \r -> writeTreeQuiet $ r
+               { gitGlobalOpts = gitGlobalOpts r ++ bypassSmudgeConfig }
+       
        diff old new =
-               -- Avoid running smudge or clean filters, since we want the
-               -- raw output, and they would block trying to access the
+               -- Avoid running smudge clean filter, since we want the
+               -- raw output, and it would block trying to access the
                -- locked database. The --raw normally avoids git diff
                -- running them, but older versions of git need this.
                bypassSmudgeConfig ++