basic incremental fsck now working
This commit is contained in:
parent
6885b2deda
commit
e855cffa1b
1 changed files with 75 additions and 42 deletions
117
Command/Fsck.hs
117
Command/Fsck.hs
|
@ -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
|
||||||
withFlag incrementalOption $ \incremental ->
|
, withIncremental $ \i -> withBarePresentKeys $ startBare i
|
||||||
withFilesInGit $ whenAnnexed $
|
|
||||||
start from $ case (startincremental, incremental) of
|
|
||||||
(False, False) -> NonIncremental
|
|
||||||
(True, _) -> StartIncremental
|
|
||||||
(False, True) -> ContIncremental
|
|
||||||
, withBarePresentKeys startBare
|
|
||||||
]
|
]
|
||||||
|
|
||||||
data Incremental = StartIncremental | ContIncremental | NonIncremental
|
withIncremental :: (Incremental -> CommandSeek) -> CommandSeek
|
||||||
deriving (Eq)
|
withIncremental a = withFlag startIncrementalOption $ \startincremental ->
|
||||||
|
withFlag incrementalOption $ \incremental ->
|
||||||
|
a $ case (startincremental, incremental) of
|
||||||
|
(False, False) -> NonIncremental
|
||||||
|
(True, _) -> StartIncremental
|
||||||
|
(False, True) -> ContIncremental
|
||||||
|
|
||||||
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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue