assistant: Notice on startup when the index file is corrupt, and auto-repair.

This commit is contained in:
Joey Hess 2013-11-13 14:27:17 -04:00
parent 5e7e0c7dc0
commit 13108b7196
5 changed files with 39 additions and 12 deletions

View file

@ -25,8 +25,10 @@ import Utility.Batch
import Utility.NotificationBroadcaster import Utility.NotificationBroadcaster
import Config import Config
import Utility.HumanTime import Utility.HumanTime
import Git.Repair
import Data.Time.Clock.POSIX import Data.Time.Clock.POSIX
import qualified Data.Set as S
{- This thread runs once at startup, and most other threads wait for it {- This thread runs once at startup, and most other threads wait for it
- to finish. (However, the webapp thread does not, to prevent the UI - to finish. (However, the webapp thread does not, to prevent the UI
@ -36,6 +38,16 @@ sanityCheckerStartupThread startupdelay = namedThreadUnchecked "SanityCheckerSta
{- Stale git locks can prevent commits from happening, etc. -} {- Stale git locks can prevent commits from happening, etc. -}
void $ repairStaleGitLocks =<< liftAnnex gitRepo void $ repairStaleGitLocks =<< liftAnnex gitRepo
{- A corrupt index file can prevent the assistant from working at
- all, so detect and repair. -}
unlessM (liftAnnex $ inRepo $ checkIndex S.empty) $ do
debug ["corrupt index found at startup; removing"]
liftAnnex $ inRepo nukeIndex
{- Normally the startup scan avoids re-staging files,
- but with the index deleted, everything needs to be
- restaged. -}
modifyDaemonStatus_ $ \s -> s { forceRestage = True }
{- If there's a startup delay, it's done here. -} {- If there's a startup delay, it's done here. -}
liftIO $ maybe noop (threadDelaySeconds . Seconds . fromIntegral . durationSeconds) startupdelay liftIO $ maybe noop (threadDelaySeconds . Seconds . fromIntegral . durationSeconds) startupdelay

View file

@ -200,6 +200,9 @@ onAdd matcher file filestatus
add matcher file add matcher file
| otherwise = noChange | otherwise = noChange
shouldRestage :: DaemonStatus -> Bool
shouldRestage ds = scanComplete ds || forceRestage ds
{- In direct mode, add events are received for both new files, and {- In direct mode, add events are received for both new files, and
- modified existing files. - modified existing files.
-} -}
@ -214,7 +217,7 @@ onAddDirect symlinkssupported matcher file fs = do
- really modified, but it might have - really modified, but it might have
- just been deleted and been put back, - just been deleted and been put back,
- so it symlink is restaged to make sure. -} - so it symlink is restaged to make sure. -}
( ifM (scanComplete <$> getDaemonStatus) ( ifM (shouldRestage <$> getDaemonStatus)
( do ( do
link <- liftAnnex $ inRepo $ gitAnnexLink file key link <- liftAnnex $ inRepo $ gitAnnexLink file key
addLink file link (Just key) addLink file link (Just key)
@ -286,7 +289,7 @@ onAddSymlink' linktarget mk isdirect file filestatus = go mk
- links too.) - links too.)
-} -}
ensurestaged (Just link) daemonstatus ensurestaged (Just link) daemonstatus
| scanComplete daemonstatus = addLink file link mk | shouldRestage daemonstatus = addLink file link mk
| otherwise = case filestatus of | otherwise = case filestatus of
Just s Just s
| not (afterLastDaemonRun (statusChangeTime s) daemonstatus) -> noChange | not (afterLastDaemonRun (statusChangeTime s) daemonstatus) -> noChange

View file

@ -28,6 +28,8 @@ data DaemonStatus = DaemonStatus
{ startedThreads :: M.Map ThreadName (Async (), IO ()) { startedThreads :: M.Map ThreadName (Async (), IO ())
-- False when the daemon is performing its startup scan -- False when the daemon is performing its startup scan
, scanComplete :: Bool , scanComplete :: Bool
-- True when all files should be restaged.
, forceRestage :: Bool
-- Time when a previous process of the daemon was running ok -- Time when a previous process of the daemon was running ok
, lastRunning :: Maybe POSIXTime , lastRunning :: Maybe POSIXTime
-- True when the daily sanity checker is running -- True when the daily sanity checker is running
@ -81,6 +83,7 @@ newDaemonStatus :: IO DaemonStatus
newDaemonStatus = DaemonStatus newDaemonStatus = DaemonStatus
<$> pure M.empty <$> pure M.empty
<*> pure False <*> pure False
<*> pure False
<*> pure Nothing <*> pure Nothing
<*> pure False <*> pure False
<*> pure Nothing <*> pure Nothing

View file

@ -13,6 +13,7 @@ module Git.Repair (
resetLocalBranches, resetLocalBranches,
removeTrackingBranches, removeTrackingBranches,
checkIndex, checkIndex,
nukeIndex,
emptyGoodCommits, emptyGoodCommits,
) where ) where
@ -368,15 +369,18 @@ verifyTree missing treesha r
else cleanup else cleanup
{- Checks that the index file only refers to objects that are not missing, {- Checks that the index file only refers to objects that are not missing,
- and is not itself corrupt. -} - and is not itself corrupt or missing. -}
checkIndex :: MissingObjects -> Repo -> IO Bool checkIndex :: MissingObjects -> Repo -> IO Bool
checkIndex missing r = do checkIndex missing r = ifM (doesFileExist (localGitDir r </> "index"))
( do
(bad, _good, cleanup) <- partitionIndex missing r (bad, _good, cleanup) <- partitionIndex missing r
if null bad if null bad
then cleanup then cleanup
else do else do
void cleanup void cleanup
return False return False
, return False
)
partitionIndex :: MissingObjects -> Repo -> IO ([LsFiles.StagedDetails], [LsFiles.StagedDetails], IO Bool) partitionIndex :: MissingObjects -> Repo -> IO ([LsFiles.StagedDetails], [LsFiles.StagedDetails], IO Bool)
partitionIndex missing r = do partitionIndex missing r = do
@ -396,7 +400,7 @@ rewriteIndex missing r
| otherwise = do | otherwise = do
(bad, good, cleanup) <- partitionIndex missing r (bad, good, cleanup) <- partitionIndex missing r
unless (null bad) $ do unless (null bad) $ do
nukeFile (localGitDir r </> "index") nukeIndex r
UpdateIndex.streamUpdateIndex r UpdateIndex.streamUpdateIndex r
=<< (catMaybes <$> mapM reinject good) =<< (catMaybes <$> mapM reinject good)
void cleanup void cleanup
@ -408,6 +412,9 @@ rewriteIndex missing r
UpdateIndex.stageFile sha blobtype file r UpdateIndex.stageFile sha blobtype file r
reinject _ = return Nothing reinject _ = return Nothing
nukeIndex :: Repo -> IO ()
nukeIndex r = nukeFile (localGitDir r </> "index")
newtype GoodCommits = GoodCommits (S.Set Sha) newtype GoodCommits = GoodCommits (S.Set Sha)
emptyGoodCommits :: GoodCommits emptyGoodCommits :: GoodCommits
@ -502,7 +509,7 @@ runRepairOf fsckresult forced referencerepo g = do
return (True, stillmissing, modifiedbranches) return (True, stillmissing, modifiedbranches)
corruptedindex = do corruptedindex = do
nukeFile (localGitDir g </> "index") nukeIndex g
putStrLn "Removed the corrupted index file. You should look at what files are present in your working tree and git add them back to the index when appropriate." putStrLn "Removed the corrupted index file. You should look at what files are present in your working tree and git add them back to the index when appropriate."
return (True, S.empty, []) return (True, S.empty, [])

2
debian/changelog vendored
View file

@ -27,6 +27,8 @@ git-annex (5.20131102) UNRELEASED; urgency=low
* Work around Android linker problem that had prevented git-annex from * Work around Android linker problem that had prevented git-annex from
running on Android 4.3 and 4.4. running on Android 4.3 and 4.4.
* repair: Handle case where index file is corrupt, but all objects are ok. * repair: Handle case where index file is corrupt, but all objects are ok.
* assistant: Notice on startup when the index file is corrupt, and
auto-repair.
-- Joey Hess <joeyh@debian.org> Wed, 06 Nov 2013 16:14:14 -0400 -- Joey Hess <joeyh@debian.org> Wed, 06 Nov 2013 16:14:14 -0400