display scanning message whenever reconcileStaged has enough files to chew on
authorJoey Hess <joeyh@joeyh.name>
Tue, 8 Jun 2021 16:48:30 +0000 (12:48 -0400)
committerJoey Hess <joeyh@joeyh.name>
Tue, 8 Jun 2021 16:48:30 +0000 (12:48 -0400)
Clear visible progress bar first.

Removed showSideActionAfter because it can't be used in reconcileStaged
(import loop). Instead, it counts the number of files it
processes and displays it after it's seen a sufficient to know it's
taking a while.

Sponsored-by: Dartmouth College's Datalad project
Annex/Concurrent.hs
Annex/WorkTree.hs
Database/Keys.hs
Messages.hs
Messages/Progress.hs
Messages/Serialized.hs
Types/Messages.hs
Utility/Metered.hs
doc/todo/display_when_reconcileStaged_is_taking_a_long_time.mdwn

index cb22b6a4639ab9e8c74805105347bbff4868a987..1701120da29efe8bb2473770c9271f5c4594bf79 100644 (file)
@@ -100,23 +100,3 @@ mergeState st = do
                uncurry addCleanupAction
        Annex.Queue.mergeFrom st'
        changeState $ \s -> s { errcounter = errcounter s + errcounter st' }
-
-{- Display a message, only when the action runs for a long enough
- - amount of time.
- - 
- - The action should not display any other messages, progress, etc;
- - if it did there could be some scrambling of the display since the
- - message display could happen at the same time as other output,
- - or after it.
- -}
-showSideActionAfter :: Microseconds -> String -> Annex a -> Annex a
-showSideActionAfter t m a = do
-       waiter <- liftIO $ async $ unboundDelay t
-       let display = liftIO (waitCatch waiter) >>= \case
-               Left _ -> return ()
-               Right _ -> showSideAction m
-       displayer <- liftIO . async =<< forkState display
-       let cleanup = do
-               liftIO $ cancel waiter
-               join (liftIO (wait displayer))
-       a `finally` cleanup
index 33d90948729d448e0da1d0733a5aba6f11985d64..9a3dd50777ef63a18e2b46d7d6e4f90375c1c466 100644 (file)
@@ -15,8 +15,6 @@ import Annex.Content
 import Annex.ReplaceFile
 import Annex.CurrentBranch
 import Annex.InodeSentinal
-import Annex.Concurrent
-import Utility.ThreadScheduler
 import Utility.InodeCache
 import Git.FilePath
 import Git.CatFile
@@ -81,7 +79,7 @@ ifAnnexed file yes no = maybe no yes =<< lookupKey file
  - as-is.
  -}
 scanAnnexedFiles :: Bool -> Annex ()
-scanAnnexedFiles initscan = showSideActionAfter oneSecond "scanning for annexed files" $ do
+scanAnnexedFiles initscan = do
        -- This gets the keys database populated with all annexed files,
        -- by running Database.Keys.reconcileStaged.
        Database.Keys.runWriter (const noop)
index 3c0e3bede3480e14dbf7c585dec9eed5a6da6e36..6cbfecda14a03e0bdec33eb516c0154567cab7d9 100644 (file)
@@ -7,6 +7,7 @@
 
 {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE BangPatterns #-}
 
 module Database.Keys (
        DbHandle,
@@ -403,7 +404,7 @@ reconcileStaged qh = do
                                proct <- liftIO $ async $
                                        procthread mdreader catfeeder
                                                `finally` void catcloser
-                               dbchanged <- dbwriter False catreader
+                               dbchanged <- dbwriter False largediff catreader
                                -- Flush database changes now
                                -- so other processes can see them.
                                when dbchanged $
@@ -420,8 +421,27 @@ reconcileStaged qh = do
                        Just _ -> procthread mdreader catfeeder
                        Nothing -> return ()
 
-               dbwriter dbchanged catreader = liftIO catreader >>= \case
+               dbwriter dbchanged catreader = liftIO catreader >>= \case
                        Just (ka, content) -> do
                                changed <- ka (parseLinkTargetOrPointerLazy =<< content)
-                               dbwriter (dbchanged || changed) catreader
+                               !n' <- countdownToMessage n
+                               dbwriter (dbchanged || changed) n' catreader
                        Nothing -> return dbchanged
+
+       -- When the diff is large, the scan can take a while,
+       -- so let the user know what's going on.
+       countdownToMessage n
+               | n < 1 = return 0
+               | n == 1 = do
+                       showSideAction "scanning for annexed files"
+                       return 0
+               | otherwise = return (pred n)
+
+       -- How large is large? Too large and there will be a long
+       -- delay before the message is shown; too short and the message
+       -- will clutter things up unncessarily. It's uncommon for 1000
+       -- files to change in the index, and processing that many files
+       -- takes less than half a second, so that seems about right.
+       largediff :: Int
+       largediff = 1000
+
index 81c96a764f7a6f6f7a11f2ab47a28e816726673c..563bd7e815483cc84da26fd2bf7099169c056b50 100644 (file)
@@ -124,12 +124,14 @@ showSideAction m = Annex.getState Annex.output >>= go
   where
        go st
                | sideActionBlock st == StartBlock = do
-                       p
+                       go' st
                        let st' = st { sideActionBlock = InBlock }
                        Annex.changeState $ \s -> s { Annex.output = st' }
                | sideActionBlock st == InBlock = return ()
-               | otherwise = p
-       p = outputMessage JSON.none $ encodeBS' $ "(" ++ m ++ "...)\n"
+               | otherwise = go' st
+       go' st = do
+               liftIO $ clearProgressMeter st
+               outputMessage JSON.none $ encodeBS' $ "(" ++ m ++ "...)\n"
                        
 showStoringStateAction :: Annex ()
 showStoringStateAction = showSideAction "recording state in git"
index da60716e64712035c755cb459b0690dfc61fb1a0..397aebbb37e517c13f9689bf7795d2faf7ccba4e 100644 (file)
@@ -11,6 +11,7 @@
 module Messages.Progress where
 
 import Common
+import qualified Annex
 import Messages
 import Utility.Metered
 import Types
@@ -66,7 +67,7 @@ instance MeterSize KeySizer where
 
 {- Shows a progress meter while performing an action.
  - The action is passed the meter and a callback to use to update the meter.
- --}
+ -}
 metered
        :: MeterSize sizer
        => Maybe MeterUpdate
@@ -75,28 +76,38 @@ metered
        -> Annex a
 metered othermeter sizer a = withMessageState $ \st -> do
        sz <- getMeterSize sizer
-       metered' st othermeter sz showOutput a
+       metered' st setclear othermeter sz showOutput a
+  where
+       setclear c = Annex.changeState $ \st -> st
+               { Annex.output = (Annex.output st) { clearProgressMeter = c } }
 
 metered'
        :: (Monad m, MonadIO m, MonadMask m)
        => MessageState
+       -> (IO () -> m ())
+       -- ^ This should set clearProgressMeter when progress meters
+       -- are being displayed; not needed when outputType is not
+       -- NormalOutput.
        -> Maybe MeterUpdate
        -> Maybe TotalSize
        -> m ()
        -- ^ this should run showOutput
        -> (Meter -> MeterUpdate -> m a)
        -> m a
-metered' st othermeter msize showoutput a = go st
+metered' st setclear othermeter msize showoutput a = go st
   where
        go (MessageState { outputType = QuietOutput }) = nometer
        go (MessageState { outputType = NormalOutput, concurrentOutputEnabled = False }) = do
                showoutput
                meter <- liftIO $ mkMeter msize $ 
                        displayMeterHandle stdout bandwidthMeter
+               let clear = clearMeterHandle meter stdout
+               setclear clear
                m <- liftIO $ rateLimitMeterUpdate consoleratelimit meter $
                        updateMeter meter
                r <- a meter (combinemeter m)
-               liftIO $ clearMeterHandle meter stdout
+               setclear noop
+               liftIO clear
                return r
        go (MessageState { outputType = NormalOutput, concurrentOutputEnabled = True }) =
                withProgressRegion st $ \r -> do
@@ -149,7 +160,7 @@ metered' st othermeter msize showoutput a = go st
        jsonratelimit = 0.1
 
        minratelimit = min consoleratelimit jsonratelimit
-
+               
 {- Poll file size to display meter. -}
 meteredFile :: FilePath -> Maybe MeterUpdate -> Key -> Annex a -> Annex a
 meteredFile file combinemeterupdate key a = 
index ff2517a901bed29422c73c07d0e4b0260b4b0bd9..bf1d09578a5bb004c89ef7b182f3cdd4f9298289 100644 (file)
@@ -65,9 +65,10 @@ relaySerializedOutput getso sendsor meterreport runannex = go Nothing
                        loop st
                Left BeginProgressMeter -> do
                        ost <- runannex (Annex.getState Annex.output)
+                       let setclear = const noop
                        -- Display a progress meter while running, until
                        -- the meter ends or a final value is returned.
-                       metered' ost Nothing Nothing (runannex showOutput) 
+                       metered' ost setclear Nothing Nothing (runannex showOutput) 
                                (\meter meterupdate -> loop (Just (meter, meterupdate)))
                                >>= \case
                                        Right r -> return (Right r)
index 593207be350ed5186f135e4e885b4278d1ef52bb..e80dc86d63f09b69657a586f286622a6d0ab116b 100644 (file)
@@ -47,6 +47,7 @@ data MessageState = MessageState
        , consoleRegionErrFlag :: Bool
        , jsonBuffer :: Maybe Aeson.Object
        , promptLock :: MVar () -- left full when not prompting
+       , clearProgressMeter :: IO ()
        }
 
 newMessageState :: IO MessageState
@@ -60,6 +61,7 @@ newMessageState = do
                , consoleRegionErrFlag = False
                , jsonBuffer = Nothing
                , promptLock = promptlock
+               , clearProgressMeter = return ()
                }
 
 -- | When communicating with a child process over a pipe while it is
index 4683c13d6d59b609d3c3ae20ff62483a001230c6..a7c9c37d7f2a8892b904888a7c54824d79efe025 100644 (file)
@@ -425,7 +425,8 @@ displayMeterHandle h rendermeter v msize old new = do
                hPutStr h ('\r':s ++ padding)
                hFlush h
 
--- | Clear meter displayed by displayMeterHandle.
+-- | Clear meter displayed by displayMeterHandle. May be called before
+-- outputting something else, followed by more calls to displayMeterHandle.
 clearMeterHandle :: Meter -> Handle -> IO ()
 clearMeterHandle (Meter _ _ v _) h = do
        olds <- readMVar v
index 20b645d6e5d54d6871a145f9d9286a0cd26d2bcf..e89aa7b084e8487e8a44d6aee31b6bdd06717366 100644 (file)
@@ -26,6 +26,8 @@ with the progress display in view:
        (scanning annexed files...)
        add newfile ok
 
+> [[done]] --[[Joey]]
+
 It might also be possible to make reconcileStaged run a less expensive
 scan in this case, eg the scan it did before
 [[!commit 428c91606b434512d1986622e751c795edf4df44]]. In this case, it