avoid taking journal lock unnecessarily
This commit is contained in:
parent
d357556141
commit
2636ea79c3
1 changed files with 84 additions and 89 deletions
173
Branch.hs
173
Branch.hs
|
@ -18,14 +18,13 @@ module Branch (
|
||||||
name
|
name
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Control.Monad (unless, liftM)
|
import Control.Monad (unless, when, liftM, filterM)
|
||||||
import Control.Monad.State (liftIO)
|
import Control.Monad.State (liftIO)
|
||||||
import Control.Applicative ((<$>))
|
import Control.Applicative ((<$>))
|
||||||
import System.FilePath
|
import System.FilePath
|
||||||
import System.Directory
|
import System.Directory
|
||||||
import Data.String.Utils
|
import Data.String.Utils
|
||||||
import System.Cmd.Utils
|
import System.Cmd.Utils
|
||||||
import Data.Maybe
|
|
||||||
import System.IO
|
import System.IO
|
||||||
import System.IO.Binary
|
import System.IO.Binary
|
||||||
import System.Posix.Process
|
import System.Posix.Process
|
||||||
|
@ -131,8 +130,10 @@ create = unlessM hasBranch $ do
|
||||||
|
|
||||||
{- Stages the journal, and commits staged changes to the branch. -}
|
{- Stages the journal, and commits staged changes to the branch. -}
|
||||||
commit :: String -> Annex ()
|
commit :: String -> Annex ()
|
||||||
commit message = lockJournal $
|
commit message = do
|
||||||
whenM stageJournalFiles $ do
|
fs <- getJournalFiles
|
||||||
|
when (not $ null fs) $ lockJournal $ do
|
||||||
|
stageJournalFiles fs
|
||||||
g <- Annex.gitRepo
|
g <- Annex.gitRepo
|
||||||
withIndex $ liftIO $ Git.commit g message fullname [fullname]
|
withIndex $ liftIO $ Git.commit g message fullname [fullname]
|
||||||
|
|
||||||
|
@ -141,25 +142,54 @@ commit message = lockJournal $
|
||||||
update :: Annex ()
|
update :: Annex ()
|
||||||
update = do
|
update = do
|
||||||
state <- getState
|
state <- getState
|
||||||
unless (branchUpdated state) $ withIndex $ lockJournal $ do
|
unless (branchUpdated state) $ do
|
||||||
{- Since branches get merged into the index, it's important to
|
-- check what needs updating before taking the lock
|
||||||
- first stage the journal into the index. Otherwise, any
|
fs <- getJournalFiles
|
||||||
- changes in the journal would later get staged, and might
|
refs <- filterM checkref =<< siblingBranches
|
||||||
- overwrite changes made during the merge.
|
unless (null fs && null refs) $ withIndex $ lockJournal $ do
|
||||||
-
|
{- Before refs are merged into the index, it's
|
||||||
- It would be cleaner to handle the merge by updating the
|
- important to first stage the journal into the
|
||||||
- journal, not the index, with changes from the branches.
|
- index. Otherwise, any changes in the journal
|
||||||
-}
|
- would later get staged, and might overwrite
|
||||||
staged <- stageJournalFiles
|
- changes made during the merge.
|
||||||
|
-
|
||||||
refs <- siblingBranches
|
- It would be cleaner to handle the merge by
|
||||||
updated <- catMaybes <$> mapM updateRef refs
|
- updating the journal, not the index, with changes
|
||||||
g <- Annex.gitRepo
|
- from the branches.
|
||||||
unless (null updated && not staged) $ liftIO $
|
-}
|
||||||
Git.commit g "update" fullname (fullname:updated)
|
unless (null fs) $ stageJournalFiles fs
|
||||||
|
mapM_ mergeref refs
|
||||||
Annex.changeState $ \s -> s { Annex.branchstate = state { branchUpdated = True } }
|
g <- Annex.gitRepo
|
||||||
invalidateCache
|
liftIO $ Git.commit g "update" fullname (fullname:refs)
|
||||||
|
Annex.changeState $ \s -> s { Annex.branchstate = state { branchUpdated = True } }
|
||||||
|
invalidateCache
|
||||||
|
where
|
||||||
|
checkref ref = do
|
||||||
|
g <- Annex.gitRepo
|
||||||
|
-- checking with log to see if there have been changes
|
||||||
|
-- is less expensive than always merging
|
||||||
|
diffs <- liftIO $ Git.pipeRead g [
|
||||||
|
Param "log",
|
||||||
|
Param (name++".."++ref),
|
||||||
|
Params "--oneline -n1"
|
||||||
|
]
|
||||||
|
return $ not $ L.null diffs
|
||||||
|
mergeref ref = do
|
||||||
|
showSideAction $ "merging " ++
|
||||||
|
Git.refDescribe ref ++ " into " ++ name
|
||||||
|
{- By passing only one ref, it is actually
|
||||||
|
- merged into the index, preserving any
|
||||||
|
- changes that may already be staged.
|
||||||
|
-
|
||||||
|
- However, any changes in the git-annex
|
||||||
|
- branch that are *not* reflected in the
|
||||||
|
- index will be removed. So, documentation
|
||||||
|
- advises users not to directly modify the
|
||||||
|
- branch.
|
||||||
|
-}
|
||||||
|
g <- Annex.gitRepo
|
||||||
|
liftIO $ Git.UnionMerge.merge g [ref]
|
||||||
|
return $ Just ref
|
||||||
|
|
||||||
{- Checks if a git ref exists. -}
|
{- Checks if a git ref exists. -}
|
||||||
refExists :: GitRef -> Annex Bool
|
refExists :: GitRef -> Annex Bool
|
||||||
|
@ -188,35 +218,6 @@ siblingBranches = do
|
||||||
r <- liftIO $ Git.pipeRead g [Param "show-ref", Param name]
|
r <- liftIO $ Git.pipeRead g [Param "show-ref", Param name]
|
||||||
return $ map (last . words . L.unpack) (L.lines r)
|
return $ map (last . words . L.unpack) (L.lines r)
|
||||||
|
|
||||||
{- Ensures that a given ref has been merged into the index. -}
|
|
||||||
updateRef :: GitRef -> Annex (Maybe String)
|
|
||||||
updateRef ref
|
|
||||||
| ref == fullname = return Nothing
|
|
||||||
| otherwise = do
|
|
||||||
g <- Annex.gitRepo
|
|
||||||
-- checking with log to see if there have been changes
|
|
||||||
-- is less expensive than always merging
|
|
||||||
diffs <- liftIO $ Git.pipeRead g [
|
|
||||||
Param "log",
|
|
||||||
Param (name++".."++ref),
|
|
||||||
Params "--oneline -n1"
|
|
||||||
]
|
|
||||||
if L.null diffs
|
|
||||||
then return Nothing
|
|
||||||
else do
|
|
||||||
showSideAction $ "merging " ++ Git.refDescribe ref ++ " into " ++ name
|
|
||||||
-- By passing only one ref, it is actually
|
|
||||||
-- merged into the index, preserving any
|
|
||||||
-- changes that may already be staged.
|
|
||||||
--
|
|
||||||
-- However, any changes in the git-annex
|
|
||||||
-- branch that are *not* reflected in the
|
|
||||||
-- index will be removed. So, documentation
|
|
||||||
-- advises users not to directly modify the
|
|
||||||
-- branch.
|
|
||||||
liftIO $ Git.UnionMerge.merge g [ref]
|
|
||||||
return $ Just ref
|
|
||||||
|
|
||||||
{- Applies a function to modifiy the content of a file. -}
|
{- Applies a function to modifiy the content of a file. -}
|
||||||
change :: FilePath -> (String -> String) -> Annex ()
|
change :: FilePath -> (String -> String) -> Annex ()
|
||||||
change file a = lockJournal $ get file >>= return . a >>= set file
|
change file a = lockJournal $ get file >>= return . a >>= set file
|
||||||
|
@ -253,7 +254,7 @@ files = withIndexUpdate $ do
|
||||||
g <- Annex.gitRepo
|
g <- Annex.gitRepo
|
||||||
bfiles <- liftIO $ Git.pipeNullSplit g
|
bfiles <- liftIO $ Git.pipeNullSplit g
|
||||||
[Params "ls-tree --name-only -r -z", Param fullname]
|
[Params "ls-tree --name-only -r -z", Param fullname]
|
||||||
jfiles <- getJournalFiles
|
jfiles <- getJournalledFiles
|
||||||
return $ jfiles ++ bfiles
|
return $ jfiles ++ bfiles
|
||||||
|
|
||||||
{- Records content for a file in the branch to the journal.
|
{- Records content for a file in the branch to the journal.
|
||||||
|
@ -282,49 +283,43 @@ getJournalFile file = do
|
||||||
liftIO $ catch (liftM Just . readFileStrict $ journalFile g file)
|
liftIO $ catch (liftM Just . readFileStrict $ journalFile g file)
|
||||||
(const $ return Nothing)
|
(const $ return Nothing)
|
||||||
|
|
||||||
{- List of journal files. -}
|
{- List of files that have updated content in the journal. -}
|
||||||
getJournalFiles :: Annex [FilePath]
|
getJournalledFiles :: Annex [FilePath]
|
||||||
getJournalFiles = map fileJournal <$> getJournalFilesRaw
|
getJournalledFiles = map fileJournal <$> getJournalFiles
|
||||||
|
|
||||||
getJournalFilesRaw :: Annex [FilePath]
|
{- List of existing journal files. -}
|
||||||
getJournalFilesRaw = do
|
getJournalFiles :: Annex [FilePath]
|
||||||
|
getJournalFiles = do
|
||||||
g <- Annex.gitRepo
|
g <- Annex.gitRepo
|
||||||
fs <- liftIO $ catch (getDirectoryContents $ gitAnnexJournalDir g)
|
fs <- liftIO $ catch (getDirectoryContents $ gitAnnexJournalDir g)
|
||||||
(const $ return [])
|
(const $ return [])
|
||||||
return $ filter (`notElem` [".", ".."]) fs
|
return $ filter (`notElem` [".", ".."]) fs
|
||||||
|
|
||||||
{- Stages all journal files into the index, and returns True if the index
|
{- Stages the specified journalfiles. -}
|
||||||
- was modified. -}
|
stageJournalFiles :: [FilePath] -> Annex ()
|
||||||
stageJournalFiles :: Annex Bool
|
stageJournalFiles fs = do
|
||||||
stageJournalFiles = do
|
g <- Annex.gitRepo
|
||||||
l <- getJournalFilesRaw
|
withIndex $ liftIO $ do
|
||||||
if null l
|
let dir = gitAnnexJournalDir g
|
||||||
then return False
|
let paths = map (dir </>) fs
|
||||||
else do
|
-- inject all the journal files directly into git
|
||||||
g <- Annex.gitRepo
|
-- in one quick command
|
||||||
withIndex $ liftIO $ stage g l
|
(pid, fromh, toh) <- hPipeBoth "git" $ toCommand $
|
||||||
return True
|
Git.gitCommandLine g [Param "hash-object", Param "-w", Param "--stdin-paths"]
|
||||||
where
|
_ <- forkProcess $ do
|
||||||
stage g fs = do
|
hPutStr toh $ unlines paths
|
||||||
let dir = gitAnnexJournalDir g
|
|
||||||
let paths = map (dir </>) fs
|
|
||||||
-- inject all the journal files directly into git
|
|
||||||
-- in one quick command
|
|
||||||
(pid, fromh, toh) <- hPipeBoth "git" $ toCommand $
|
|
||||||
Git.gitCommandLine g [Param "hash-object", Param "-w", Param "--stdin-paths"]
|
|
||||||
_ <- forkProcess $ do
|
|
||||||
hPutStr toh $ unlines paths
|
|
||||||
hClose toh
|
|
||||||
exitSuccess
|
|
||||||
hClose toh
|
hClose toh
|
||||||
s <- hGetContents fromh
|
exitSuccess
|
||||||
-- update the index, also in just one command
|
hClose toh
|
||||||
Git.UnionMerge.update_index g $
|
s <- hGetContents fromh
|
||||||
index_lines (lines s) $ map fileJournal fs
|
-- update the index, also in just one command
|
||||||
hClose fromh
|
Git.UnionMerge.update_index g $
|
||||||
forceSuccess pid
|
index_lines (lines s) $ map fileJournal fs
|
||||||
mapM_ removeFile paths
|
hClose fromh
|
||||||
index_lines shas fs = map genline $ zip shas fs
|
forceSuccess pid
|
||||||
|
mapM_ removeFile paths
|
||||||
|
where
|
||||||
|
index_lines shas = map genline . zip shas
|
||||||
genline (sha, file) = Git.UnionMerge.update_index_line sha file
|
genline (sha, file) = Git.UnionMerge.update_index_line sha file
|
||||||
|
|
||||||
{- Produces a filename to use in the journal for a file on the branch.
|
{- Produces a filename to use in the journal for a file on the branch.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue