basic incremental fsck now working

This commit is contained in:
Joey Hess 2012-09-25 15:06:33 -04:00
parent 6885b2deda
commit e855cffa1b

View file

@ -51,29 +51,29 @@ options = [fromOption, startIncrementalOption, incrementalOption]
seek :: [CommandSeek] seek :: [CommandSeek]
seek = seek =
[ withField fromOption Remote.byName $ \from -> [ withField fromOption Remote.byName $ \from ->
withFlag startIncrementalOption $ \startincremental -> withIncremental $ \i -> withFilesInGit $ whenAnnexed $ start from i
, withIncremental $ \i -> withBarePresentKeys $ startBare i
]
withIncremental :: (Incremental -> CommandSeek) -> CommandSeek
withIncremental a = withFlag startIncrementalOption $ \startincremental ->
withFlag incrementalOption $ \incremental -> withFlag incrementalOption $ \incremental ->
withFilesInGit $ whenAnnexed $ a $ case (startincremental, incremental) of
start from $ case (startincremental, incremental) of
(False, False) -> NonIncremental (False, False) -> NonIncremental
(True, _) -> StartIncremental (True, _) -> StartIncremental
(False, True) -> ContIncremental (False, True) -> ContIncremental
, withBarePresentKeys startBare
]
data Incremental = StartIncremental | ContIncremental | NonIncremental
deriving (Eq)
start :: Maybe Remote -> Incremental -> FilePath -> (Key, Backend) -> CommandStart start :: Maybe Remote -> Incremental -> FilePath -> (Key, Backend) -> CommandStart
start from inc file (key, backend) = do start from inc file (key, backend) = do
numcopies <- numCopies file numcopies <- numCopies file
showStart "fsck" file
case from of case from of
Nothing -> next $ perform inc key file backend numcopies Nothing -> go $ perform key file backend numcopies
Just r -> next $ performRemote inc key file backend numcopies r Just r -> go $ performRemote key file backend numcopies r
where
go = runFsck inc file key
perform :: Incremental -> Key -> FilePath -> Backend -> Maybe Int -> CommandPerform perform :: Key -> FilePath -> Backend -> Maybe Int -> Annex Bool
perform inc key file backend numcopies = check perform key file backend numcopies = check
-- order matters -- order matters
[ fixLink key file [ fixLink key file
, verifyLocationLog key file , verifyLocationLog key file
@ -84,13 +84,13 @@ perform inc key file backend numcopies = check
{- To fsck a remote, the content is retrieved to a tmp file, {- To fsck a remote, the content is retrieved to a tmp file,
- and checked locally. -} - and checked locally. -}
performRemote :: Incremental -> Key -> FilePath -> Backend -> Maybe Int -> Remote -> CommandPerform performRemote :: Key -> FilePath -> Backend -> Maybe Int -> Remote -> Annex Bool
performRemote inc key file backend numcopies remote = performRemote key file backend numcopies remote =
dispatch =<< Remote.hasKey remote key dispatch =<< Remote.hasKey remote key
where where
dispatch (Left err) = do dispatch (Left err) = do
showNote err showNote err
stop return False
dispatch (Right True) = withtmp $ \tmpfile -> dispatch (Right True) = withtmp $ \tmpfile ->
ifM (getfile tmpfile) ifM (getfile tmpfile)
( go True (Just tmpfile) ( go True (Just tmpfile)
@ -130,30 +130,23 @@ withBarePresentKeys a params = isBareRepo >>= go
error "fsck should be run without parameters in a bare repository" error "fsck should be run without parameters in a bare repository"
map a <$> loggedKeys map a <$> loggedKeys
startBare :: Key -> CommandStart startBare :: Incremental -> Key -> CommandStart
startBare key = case Backend.maybeLookupBackendName (Types.Key.keyBackendName key) of startBare inc key = case Backend.maybeLookupBackendName (Types.Key.keyBackendName key) of
Nothing -> stop Nothing -> stop
Just backend -> do Just backend -> runFsck inc (key2file key) key $ performBare key backend
showStart "fsck" (key2file key)
next $ performBare key backend
{- Note that numcopies cannot be checked in a bare repository, because {- Note that numcopies cannot be checked in a bare repository, because
- getting the numcopies value requires a working copy with .gitattributes - getting the numcopies value requires a working copy with .gitattributes
- files. -} - files. -}
performBare :: Key -> Backend -> CommandPerform performBare :: Key -> Backend -> Annex Bool
performBare key backend = check performBare key backend = check
[ verifyLocationLog key (key2file key) [ verifyLocationLog key (key2file key)
, checkKeySize key , checkKeySize key
, checkBackend backend key , checkBackend backend key
] ]
check :: [Annex Bool] -> CommandPerform check :: [Annex Bool] -> Annex Bool
check = sequence >=> dispatch check cs = all id <$> sequence cs
where
dispatch vs
| all (== True) vs = next $ return True
| otherwise = stop
{- Checks that the file's symlink points correctly to the content. -} {- Checks that the file's symlink points correctly to the content. -}
fixLink :: Key -> FilePath -> Annex Bool fixLink :: Key -> FilePath -> Annex Bool
@ -323,7 +316,37 @@ badContentRemote remote key = do
return $ (if ok then "dropped from " else "failed to drop from ") return $ (if ok then "dropped from " else "failed to drop from ")
++ Remote.name remote ++ Remote.name remote
{- To record the time that an annexed file was last fscked, without data Incremental = StartIncremental | ContIncremental | NonIncremental
deriving (Eq)
runFsck :: Incremental -> FilePath -> Key -> Annex Bool -> CommandStart
runFsck inc file key a = do
starttime <- getstart
ifM (needFsck inc starttime key)
( do
showStart "fsck" file
next $ do
ok <- a
when ok $
recordFsckTime key
next $ return ok
, stop
)
where
getstart
| inc == StartIncremental = Just <$> recordStartTime
| inc == ContIncremental = getStartTime
| otherwise = return Nothing
{- Check if a key needs to be fscked, with support for incremental fscks. -}
needFsck :: Incremental -> Maybe EpochTime -> Key -> Annex Bool
needFsck ContIncremental Nothing _ = return True
needFsck ContIncremental starttime key = do
fscktime <- getFsckTime key
return $ fscktime < starttime
needFsck _ _ _ = return True
{- To record the time that a key was last fscked, without
- modifying its mtime, we set the timestamp of its parent directory. - modifying its mtime, we set the timestamp of its parent directory.
- Each annexed file is the only thing in its directory, so this is fine. - Each annexed file is the only thing in its directory, so this is fine.
- -
@ -332,31 +355,41 @@ badContentRemote remote key = do
- we can reuse this permission bit.) - we can reuse this permission bit.)
- -
- Note that this relies on the parent directory being deleted when a file - Note that this relies on the parent directory being deleted when a file
- is dropped. That way, if it's later added back, the fsck metadata - is dropped. That way, if it's later added back, the fsck record
- won't still be present. - won't still be present.
-} -}
updateMetadata :: Key -> Annex Bool recordFsckTime :: Key -> Annex ()
updateMetadata key = do recordFsckTime key = do
file <- inRepo $ gitAnnexLocation key parent <- parentDir <$> inRepo (gitAnnexLocation key)
let parent = parentDir file liftIO $ void $ tryIO $ do
liftIO $ touchFile parent touchFile parent
liftIO $ setSticky parent setSticky parent
return True
{- Records the start time of an interactive fsck. getFsckTime :: Key -> Annex (Maybe EpochTime)
getFsckTime key = do
parent <- parentDir <$> inRepo (gitAnnexLocation key)
liftIO $ catchDefaultIO Nothing $ do
s <- getFileStatus parent
return $ if isSticky $ fileMode s
then Just $ modificationTime s
else Nothing
{- Records the start time of an interactive fsck, also returning it.
- -
- To guard against time stamp damange (for example, if an annex directory - To guard against time stamp damange (for example, if an annex directory
- is copied without -a), the fsckstate file contains a time that should - is copied without -a), the fsckstate file contains a time that should
- be identical to its modification time. -} - be identical to its modification time. -}
recordStartTime :: Annex () recordStartTime :: Annex (EpochTime)
recordStartTime = do recordStartTime = do
f <- fromRepo gitAnnexFsckState f <- fromRepo gitAnnexFsckState
createAnnexDirectory $ parentDir f
liftIO $ do liftIO $ do
nukeFile f nukeFile f
h <- openFile f WriteMode h <- openFile f WriteMode
t <- modificationTime <$> getFileStatus f t <- modificationTime <$> getFileStatus f
hPutStr h $ showTime $ realToFrac t hPutStr h $ showTime $ realToFrac t
hClose h hClose h
return t
where where
showTime :: POSIXTime -> String showTime :: POSIXTime -> String
showTime = show showTime = show