add download progress polling thread

This commit is contained in:
Joey Hess 2012-08-28 14:04:28 -04:00
parent 9ea389ee2f
commit 7024a973b2
3 changed files with 80 additions and 13 deletions

View file

@ -39,30 +39,32 @@
- and maintains the DaemonStatus currentTransfers map. - and maintains the DaemonStatus currentTransfers map.
- (This uses inotify on .git/annex/transfer/, so there are - (This uses inotify on .git/annex/transfer/, so there are
- additional inotify threads associated with it, too.) - additional inotify threads associated with it, too.)
- Thread 10: Transferrer - Thread 10: TransferPoller
- Polls to determine how much of each ongoing transfer is complete.
- Thread 11: Transferrer
- Waits for Transfers to be queued and does them. - Waits for Transfers to be queued and does them.
- Thread 11: StatusLogger - Thread 12: StatusLogger
- Wakes up periodically and records the daemon's status to disk. - Wakes up periodically and records the daemon's status to disk.
- Thread 12: SanityChecker - Thread 13: SanityChecker
- Wakes up periodically (rarely) and does sanity checks. - Wakes up periodically (rarely) and does sanity checks.
- Thread 13: MountWatcher - Thread 14: MountWatcher
- Either uses dbus to watch for drive mount events, or, when - Either uses dbus to watch for drive mount events, or, when
- there's no dbus, polls to find newly mounted filesystems. - there's no dbus, polls to find newly mounted filesystems.
- Once a filesystem that contains a remote is mounted, updates - Once a filesystem that contains a remote is mounted, updates
- state about that remote, pulls from it, and queues a push to it, - state about that remote, pulls from it, and queues a push to it,
- as well as an update, and queues it onto the - as well as an update, and queues it onto the
- ConnectedRemoteChan - ConnectedRemoteChan
- Thread 13: NetWatcher - Thread 15: NetWatcher
- Deals with network connection interruptions, which would cause - Deals with network connection interruptions, which would cause
- transfers to fail, and can be recovered from by waiting for a - transfers to fail, and can be recovered from by waiting for a
- network connection, and syncing with all network remotes. - network connection, and syncing with all network remotes.
- Uses dbus to watch for network connections, or when dbus - Uses dbus to watch for network connections, or when dbus
- cannot be used, assumes there's been one every 30 minutes. - cannot be used, assumes there's been one every 30 minutes.
- Thread 15: TransferScanner - Thread 16: TransferScanner
- Does potentially expensive checks to find data that needs to be - Does potentially expensive checks to find data that needs to be
- transferred from or to remotes, and queues Transfers. - transferred from or to remotes, and queues Transfers.
- Uses the ScanRemotes map. - Uses the ScanRemotes map.
- Thread 16: WebApp - Thread 17: WebApp
- Spawns more threads as necessary to handle clients. - Spawns more threads as necessary to handle clients.
- Displays the DaemonStatus. - Displays the DaemonStatus.
- -
@ -118,6 +120,7 @@ import Assistant.Threads.SanityChecker
import Assistant.Threads.MountWatcher import Assistant.Threads.MountWatcher
import Assistant.Threads.NetWatcher import Assistant.Threads.NetWatcher
import Assistant.Threads.TransferScanner import Assistant.Threads.TransferScanner
import Assistant.Threads.TransferPoller
#ifdef WITH_WEBAPP #ifdef WITH_WEBAPP
import Assistant.Threads.WebApp import Assistant.Threads.WebApp
#else #else
@ -168,6 +171,7 @@ startAssistant assistant daemonize webappwaiter = do
, assist $ pushRetryThread st dstatus pushmap , assist $ pushRetryThread st dstatus pushmap
, assist $ mergeThread st , assist $ mergeThread st
, assist $ transferWatcherThread st dstatus , assist $ transferWatcherThread st dstatus
, assist $ transferPollerThread st dstatus
, assist $ transfererThread st dstatus transferqueue transferslots , assist $ transfererThread st dstatus transferqueue transferslots
, assist $ daemonStatusThread st dstatus , assist $ daemonStatusThread st dstatus
, assist $ sanityCheckerThread st dstatus transferqueue changechan , assist $ sanityCheckerThread st dstatus transferqueue changechan

View file

@ -0,0 +1,49 @@
{- git-annex assistant transfer polling thread
-
- Copyright 2012 Joey Hess <joey@kitenet.net>
-
- Licensed under the GNU GPL version 3 or higher.
-}
module Assistant.Threads.TransferPoller where
import Assistant.Common
import Assistant.ThreadedMonad
import Assistant.DaemonStatus
import Logs.Transfer
import Utility.NotificationBroadcaster
import Control.Concurrent
import qualified Data.Map as M
thisThread :: ThreadName
thisThread = "TransferPoller"
{- This thread polls the status of ongoing transfers, determining how much
- of each transfer is complete. -}
transferPollerThread :: ThreadState -> DaemonStatusHandle -> IO ()
transferPollerThread st dstatus = do
g <- runThreadState st $ fromRepo id
tn <- newNotificationHandle =<<
transferNotifier <$> getDaemonStatus dstatus
forever $ do
threadDelay 500000 -- 0.5 seconds
ts <- currentTransfers <$> getDaemonStatus dstatus
if M.null ts
then waitNotification tn -- block until transfers running
else mapM_ (poll g) $ M.toList ts
where
poll g (t, info)
{- Downloads are polled by checking the size of the
- temp file being used for the transfer. -}
| transferDirection t == Download = do
let f = gitAnnexTmpLocation (transferKey t) g
sz <- catchMaybeIO $
fromIntegral . fileSize
<$> getFileStatus f
when (bytesComplete info /= sz && isJust sz) $ do
putStrLn $ "download size " ++ show sz
updateTransferInfo dstatus t info
{ bytesComplete = sz }
{- can't poll uploads -}
| otherwise = noop

View file

@ -5,10 +5,24 @@ for it, in the terminal.
Something better is needed for the [[webapp]]. There needs to be a Something better is needed for the [[webapp]]. There needs to be a
way for the web app to know what the current progress is of all transfers. way for the web app to know what the current progress is of all transfers.
To get this info for downloads, git-annex can watch the file as it arrives
and use its size.
TODO: What about uploads? Will i have to parse rsync's progresss output?
Feed it via a named pipe? Ugh. Check into librsync.
This is one of those potentially hidden but time consuming problems. This is one of those potentially hidden but time consuming problems.
## downloads
* Watch temp file as it's coming in and use its size.
This is the only option for some special remotes (ie, non-rsync).
Can either poll every .5 seconds or so to check file size, or
could use inotify. Implemented.
* Feed rsync output into a parser and parse out a progress value. Ugly,
failure prone, but potentially the least CPU-expensive option.
* Use librsync. Note: It's not wire-compatiable with the actual rsync
command.
* Set up a FIFO, have rsync read from or write to that, and the FIFO
feeder/reader then can update the transfer info. Generic enough to
work for most (all?) special remotes, but also the most expensive option,
involving another copy through memory of the whole file contents.
## uploads
Cannot use temp file, as we're not receiving it. Rsync progress parser,
librsync, and FIFO all work.