summaryrefslogtreecommitdiff
path: root/Annex
diff options
context:
space:
mode:
authorGravatar Joey Hess <joey@kitenet.net>2014-07-09 15:07:53 -0400
committerGravatar Joey Hess <joey@kitenet.net>2014-07-09 15:08:19 -0400
commit79de0bb85e576b20117ce867ed76aab74815098d (patch)
tree1610a43fd5cc605aa0b537e67341ac73536b3742 /Annex
parent32a2bf7d2050f8d639e41645069d745f7b7d56a3 (diff)
prospective fix for bad_merge_commit_deleting_all_files
Assuming my analysis of a race is correct. In any case, this certianly closes a race..
Diffstat (limited to 'Annex')
-rw-r--r--Annex/Direct.hs35
1 files changed, 30 insertions, 5 deletions
diff --git a/Annex/Direct.hs b/Annex/Direct.hs
index 356354aa9..c41f9cf49 100644
--- a/Annex/Direct.hs
+++ b/Annex/Direct.hs
@@ -5,6 +5,8 @@
- Licensed under the GNU GPL version 3 or higher.
-}
+{-# LANGUAGE CPP #-}
+
module Annex.Direct where
import Common.Annex
@@ -150,13 +152,16 @@ addDirect file cache = do
- directory, and the merge is staged into a copy of the index.
- Then the work tree is updated to reflect the merge, and
- finally, the merge is committed and the real index updated.
+ -
+ - A lock file is used to avoid races with any other caller of mergeDirect.
+ -
+ - To avoid other git processes from making change to the index while our
+ - merge is in progress, the index lock file is used as the temp index
+ - file. This is the same as what git does when updating the index
+ - normally.
-}
mergeDirect :: Maybe Git.Ref -> Maybe Git.Ref -> Git.Branch -> Annex Bool -> Git.Branch.CommitMode -> Annex Bool
-mergeDirect startbranch oldref branch resolvemerge commitmode = do
- -- Use the index lock file as the temp index file.
- -- This is actually what git does when updating the index,
- -- and so it will prevent other git processes from making
- -- any changes to the index while our merge is in progress.
+mergeDirect startbranch oldref branch resolvemerge commitmode = lockMerge $ do
reali <- fromRepo indexFile
tmpi <- fromRepo indexFileLock
liftIO $ copyFile reali tmpi
@@ -174,9 +179,29 @@ mergeDirect startbranch oldref branch resolvemerge commitmode = do
else resolvemerge
mergeDirectCleanup d (fromMaybe Git.Sha.emptyTree oldref)
mergeDirectCommit merged startbranch branch commitmode
+
liftIO $ rename tmpi reali
+
return r
+lockMerge :: Annex a -> Annex a
+lockMerge a = do
+ lockfile <- fromRepo gitAnnexMergeLock
+ createAnnexDirectory $ takeDirectory lockfile
+ mode <- annexFileMode
+ bracketIO (lock lockfile mode) unlock (const a)
+ where
+#ifndef mingw32_HOST_OS
+ lock lockfile mode = do
+ l <- noUmask mode $ createFile lockfile mode
+ waitToSetLock l (WriteLock, AbsoluteSeek, 0, 0)
+ return l
+ unlock = closeFd
+#else
+ lock lockfile _mode = waitToLock $ lockExclusive lockfile
+ unlock = dropLock
+#endif
+
{- Stage a merge into the index, avoiding changing HEAD or the current
- branch. -}
stageMerge :: FilePath -> Git.Branch -> Git.Branch.CommitMode -> Annex Bool