From 956694b88fff7bc151bad6196ed429e0db7b23cb Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sat, 26 Oct 2013 12:42:58 -0400 Subject: assistant: When autostarted, wait 5 seconds before running the startup scan, to avoid contending with the user's desktop login process. --- Assistant.hs | 7 +++-- Assistant/Threads/SanityChecker.hs | 21 +++++++------- Command/Assistant.hs | 41 +++++++++++++++++++-------- Command/Watch.hs | 9 +++--- Command/WebApp.hs | 4 +-- debian/changelog | 7 +++++ doc/bugs/Too_much_system_load_on_startup.mdwn | 4 +++ 7 files changed, 61 insertions(+), 32 deletions(-) diff --git a/Assistant.hs b/Assistant.hs index 8a0c574ab..5eeba818e 100644 --- a/Assistant.hs +++ b/Assistant.hs @@ -48,6 +48,7 @@ import Assistant.Types.UrlRenderer import qualified Utility.Daemon import Utility.LogFile import Utility.ThreadScheduler +import Utility.HumanTime import qualified Build.SysConfig as SysConfig import System.Log.Logger @@ -61,8 +62,8 @@ stopDaemon = liftIO . Utility.Daemon.stopDaemon =<< fromRepo gitAnnexPidFile - - startbrowser is passed the url and html shim file, as well as the original - stdout and stderr descriptors. -} -startDaemon :: Bool -> Bool -> Maybe HostName -> Maybe (Maybe Handle -> Maybe Handle -> String -> FilePath -> IO ()) -> Annex () -startDaemon assistant foreground listenhost startbrowser = do +startDaemon :: Bool -> Bool -> Maybe Duration -> Maybe HostName -> Maybe (Maybe Handle -> Maybe Handle -> String -> FilePath -> IO ()) -> Annex () +startDaemon assistant foreground startdelay listenhost startbrowser = do Annex.changeState $ \s -> s { Annex.daemon = True } pidfile <- fromRepo gitAnnexPidFile logfile <- fromRepo gitAnnexLogFile @@ -140,7 +141,7 @@ startDaemon assistant foreground listenhost startbrowser = do , watch $ watchThread -- must come last so that all threads that wait -- on it have already started waiting - , watch $ sanityCheckerStartupThread + , watch $ sanityCheckerStartupThread startdelay ] liftIO waitForTermination diff --git a/Assistant/Threads/SanityChecker.hs b/Assistant/Threads/SanityChecker.hs index b3aa9ddfd..d8ffa41f4 100644 --- a/Assistant/Threads/SanityChecker.hs +++ b/Assistant/Threads/SanityChecker.hs @@ -25,15 +25,22 @@ import Utility.NotificationBroadcaster import Config import qualified Git import qualified Utility.Lsof as Lsof +import Utility.HumanTime import Data.Time.Clock.POSIX {- 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 - being nonresponsive.) -} -sanityCheckerStartupThread :: NamedThread -sanityCheckerStartupThread = namedThreadUnchecked "SanityCheckerStartup" $ - startupCheck +sanityCheckerStartupThread :: Maybe Duration -> NamedThread +sanityCheckerStartupThread startupdelay = namedThreadUnchecked "SanityCheckerStartup" $ do + checkStaleGitLocks + + liftIO $ maybe noop (threadDelaySeconds . Seconds . fromIntegral . durationSeconds) startupdelay + + {- Notify other threads that the startup sanity check is done. -} + status <- getDaemonStatus + liftIO $ sendNotification $ startupSanityCheckNotifier status {- This thread wakes up hourly for inxepensive frequent sanity checks. -} sanityCheckerHourlyThread :: NamedThread @@ -80,14 +87,6 @@ waitForNextCheck = do oneDay - truncate (now - lastcheck) | otherwise = oneDay -startupCheck :: Assistant () -startupCheck = do - checkStaleGitLocks - - {- Notify other threads that the startup sanity check is done. -} - status <- getDaemonStatus - liftIO $ sendNotification $ startupSanityCheckNotifier status - {- It's important to stay out of the Annex monad as much as possible while - running potentially expensive parts of this check, since remaining in it - will block the watcher. -} diff --git a/Command/Assistant.hs b/Command/Assistant.hs index f65bed736..521a88571 100644 --- a/Command/Assistant.hs +++ b/Command/Assistant.hs @@ -14,43 +14,55 @@ import qualified Command.Watch import Init import Config.Files import qualified Build.SysConfig +import Utility.HumanTime import System.Environment def :: [Command] -def = [noRepo checkAutoStart $ dontCheck repoExists $ - withOptions [Command.Watch.foregroundOption, Command.Watch.stopOption, autoStartOption] $ +def = [noRepo checkAutoStart $ dontCheck repoExists $ withOptions options $ command "assistant" paramNothing seek SectionCommon "automatically handle changes"] +options :: [Option] +options = + [ Command.Watch.foregroundOption + , Command.Watch.stopOption + , autoStartOption + , startDelayOption + ] + autoStartOption :: Option autoStartOption = Option.flag [] "autostart" "start in known repositories" +startDelayOption :: Option +startDelayOption = Option.field [] "startdelay" paramNumber "delay before running startup scan" + seek :: [CommandSeek] seek = [withFlag Command.Watch.stopOption $ \stopdaemon -> withFlag Command.Watch.foregroundOption $ \foreground -> withFlag autoStartOption $ \autostart -> - withNothing $ start foreground stopdaemon autostart] + withField startDelayOption (pure . maybe Nothing parseDuration) $ \startdelay -> + withNothing $ start foreground stopdaemon autostart startdelay] -start :: Bool -> Bool -> Bool -> CommandStart -start foreground stopdaemon autostart +start :: Bool -> Bool -> Bool -> Maybe Duration -> CommandStart +start foreground stopdaemon autostart startdelay | autostart = do - liftIO autoStart + liftIO $ autoStart startdelay stop | otherwise = do ensureInitialized - Command.Watch.start True foreground stopdaemon + Command.Watch.start True foreground stopdaemon startdelay {- Run outside a git repository. Check to see if any parameter is - --autostart and enter autostart mode. -} checkAutoStart :: IO () checkAutoStart = ifM (elem "--autostart" <$> getArgs) - ( autoStart + ( autoStart Nothing , error "Not in a git repository." ) -autoStart :: IO () -autoStart = do +autoStart :: Maybe Duration -> IO () +autoStart startdelay = do dirs <- liftIO readAutoStartFile when (null dirs) $ do f <- autoStartFile @@ -67,5 +79,10 @@ autoStart = do go haveionice program dir = do setCurrentDirectory dir if haveionice - then boolSystem "ionice" [Param "-c3", Param program, Param "assistant"] - else boolSystem program [Param "assistant"] + then boolSystem "ionice" (Param "-c3" : Param program : baseparams) + else boolSystem program baseparams + where + baseparams = + [ Param "assistant" + , Param $ "--startdelay=" ++ fromDuration (fromMaybe (Duration 5) startdelay) + ] diff --git a/Command/Watch.hs b/Command/Watch.hs index c5fd1a8cd..0b34b0f84 100644 --- a/Command/Watch.hs +++ b/Command/Watch.hs @@ -11,6 +11,7 @@ import Common.Annex import Assistant import Command import Option +import Utility.HumanTime def :: [Command] def = [notBareRepo $ withOptions [foregroundOption, stopOption] $ @@ -19,7 +20,7 @@ def = [notBareRepo $ withOptions [foregroundOption, stopOption] $ seek :: [CommandSeek] seek = [withFlag stopOption $ \stopdaemon -> withFlag foregroundOption $ \foreground -> - withNothing $ start False foreground stopdaemon] + withNothing $ start False foreground stopdaemon Nothing] foregroundOption :: Option foregroundOption = Option.flag [] "foreground" "do not daemonize" @@ -27,9 +28,9 @@ foregroundOption = Option.flag [] "foreground" "do not daemonize" stopOption :: Option stopOption = Option.flag [] "stop" "stop daemon" -start :: Bool -> Bool -> Bool -> CommandStart -start assistant foreground stopdaemon = do +start :: Bool -> Bool -> Bool -> Maybe Duration -> CommandStart +start assistant foreground stopdaemon startdelay = do if stopdaemon then stopDaemon - else startDaemon assistant foreground Nothing Nothing -- does not return + else startDaemon assistant foreground startdelay Nothing Nothing -- does not return stop diff --git a/Command/WebApp.hs b/Command/WebApp.hs index 6577ce02b..88c1537d0 100644 --- a/Command/WebApp.hs +++ b/Command/WebApp.hs @@ -69,7 +69,7 @@ start' allowauto listenhost = do url <- liftIO . readFile =<< fromRepo gitAnnexUrlFile liftIO $ openBrowser browser f url Nothing Nothing - , startDaemon True True listenhost $ Just $ + , startDaemon True True Nothing listenhost $ Just $ \origout origerr url htmlshim -> if isJust listenhost then maybe noop (`hPutStrLn` url) origout @@ -155,7 +155,7 @@ firstRun listenhost = do _wait <- takeMVar v state <- Annex.new =<< Git.CurrentRepo.get Annex.eval state $ - startDaemon True True listenhost $ Just $ + startDaemon True True Nothing listenhost $ Just $ sendurlback v sendurlback v _origout _origerr url _htmlshim = do recordUrl url diff --git a/debian/changelog b/debian/changelog index a38466dd8..5c28b729a 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +git-annex (4.20131025) UNRELEASED; urgency=low + + * assistant: When autostarted, wait 5 seconds before running the startup + scan, to avoid contending with the user's desktop login process. + + -- Joey Hess Sat, 26 Oct 2013 12:11:48 -0400 + git-annex (4.20131024) unstable; urgency=low * webapp: Fix bug when adding a remote and git-remote-gcrypt diff --git a/doc/bugs/Too_much_system_load_on_startup.mdwn b/doc/bugs/Too_much_system_load_on_startup.mdwn index 9ee63f6d7..fc514ca73 100644 --- a/doc/bugs/Too_much_system_load_on_startup.mdwn +++ b/doc/bugs/Too_much_system_load_on_startup.mdwn @@ -18,3 +18,7 @@ to Exec=sleep 5 ionice -c 3 /usr/bin/git-annex assistant --autostart This delays the start of git-annex for 5 seconds, letting the desktop get started, and forces git-annex to yield IO to other programs -preventing it from slowing them down by forcing them to wait for disk access. Since this is a background daemon with potentially high IO usage, but no need for quick responsiveness, perhaps that would make a decent default? + +> Added 5 second delay to existing ionice. Provisionally [[done]], +> although it does occur to me that the startup scan could add some delays +> in between actions to run more as a batch job. --[[Joey]] -- cgit v1.2.3