refactoring

This is groundwork for using git-annex transferkeys to run transfers,
in order to allow stalled transfers to be interrupted and retried.

The new upload and download are closer to what git-annex transferkeys
does, so the plan is to make them use it.

Then things that were left using upload' and download' won't recover
from stalls. Notably, that includes import and export. But
at least get/move/copy will be able to. (Also the assistant hopefully,
but not yet.)

This commit was sponsored by Jake Vosloo on Patreon.
This commit is contained in:
Joey Hess 2020-12-07 14:44:21 -04:00
parent a0e1650a15
commit 4c47568876
No known key found for this signature in database
GPG key ID: DB12DB0FF05F8F38
11 changed files with 58 additions and 46 deletions

View file

@ -6,6 +6,8 @@
-} -}
module Annex.Action ( module Annex.Action (
action,
verifiedAction,
startup, startup,
shutdown, shutdown,
stopCoProcesses, stopCoProcesses,
@ -21,6 +23,22 @@ import Annex.CheckAttr
import Annex.HashObject import Annex.HashObject
import Annex.CheckIgnore import Annex.CheckIgnore
{- Runs an action that may throw exceptions, catching and displaying them. -}
action :: Annex () -> Annex Bool
action a = tryNonAsync a >>= \case
Right () -> return True
Left e -> do
warning (show e)
return False
verifiedAction :: Annex Verification -> Annex (Bool, Verification)
verifiedAction a = tryNonAsync a >>= \case
Right v -> return (True, v)
Left e -> do
warning (show e)
return (False, UnVerified)
{- Actions to perform each time ran. -} {- Actions to perform each time ran. -}
startup :: Annex () startup :: Annex ()
startup = return () startup = return ()

View file

@ -466,7 +466,7 @@ importKeys remote importtreeconfig importcontent importablecontents = do
return (Just (k', ok)) return (Just (k', ok))
checkDiskSpaceToGet k Nothing $ checkDiskSpaceToGet k Nothing $
notifyTransfer Download af $ notifyTransfer Download af $
download (Remote.uuid remote) k af stdRetry $ \p' -> download' (Remote.uuid remote) k af stdRetry $ \p' ->
withTmp k $ downloader p' withTmp k $ downloader p'
-- The file is small, so is added to git, so while importing -- The file is small, so is added to git, so while importing
@ -520,7 +520,7 @@ importKeys remote importtreeconfig importcontent importablecontents = do
return Nothing return Nothing
checkDiskSpaceToGet tmpkey Nothing $ checkDiskSpaceToGet tmpkey Nothing $
notifyTransfer Download af $ notifyTransfer Download af $
download (Remote.uuid remote) tmpkey af stdRetry $ \p -> download' (Remote.uuid remote) tmpkey af stdRetry $ \p ->
withTmp tmpkey $ \tmpfile -> withTmp tmpkey $ \tmpfile ->
metered (Just p) tmpkey $ metered (Just p) tmpkey $
const (rundownload tmpfile) const (rundownload tmpfile)

View file

@ -10,8 +10,10 @@
module Annex.Transfer ( module Annex.Transfer (
module X, module X,
upload, upload,
upload',
alwaysUpload, alwaysUpload,
download, download,
download',
runTransfer, runTransfer,
alwaysRunTransfer, alwaysRunTransfer,
noRetry, noRetry,
@ -24,7 +26,9 @@ import qualified Annex
import Logs.Transfer as X import Logs.Transfer as X
import Types.Transfer as X import Types.Transfer as X
import Annex.Notification as X import Annex.Notification as X
import Annex.Content
import Annex.Perms import Annex.Perms
import Annex.Action
import Utility.Metered import Utility.Metered
import Utility.ThreadScheduler import Utility.ThreadScheduler
import Annex.LockPool import Annex.LockPool
@ -42,16 +46,28 @@ import qualified Data.Map.Strict as M
import qualified System.FilePath.ByteString as P import qualified System.FilePath.ByteString as P
import Data.Ord import Data.Ord
upload :: Observable v => UUID -> Key -> AssociatedFile -> RetryDecider -> (MeterUpdate -> Annex v) -> NotifyWitness -> Annex v upload :: Remote -> Key -> AssociatedFile -> RetryDecider -> NotifyWitness -> Annex Bool
upload u key f d a _witness = guardHaveUUID u $ upload r key f d = upload' (Remote.uuid r) key f d $
action . Remote.storeKey r key f
upload' :: Observable v => UUID -> Key -> AssociatedFile -> RetryDecider -> (MeterUpdate -> Annex v) -> NotifyWitness -> Annex v
upload' u key f d a _witness = guardHaveUUID u $
runTransfer (Transfer Upload u (fromKey id key)) f d a runTransfer (Transfer Upload u (fromKey id key)) f d a
alwaysUpload :: Observable v => UUID -> Key -> AssociatedFile -> RetryDecider -> (MeterUpdate -> Annex v) -> NotifyWitness -> Annex v alwaysUpload :: Observable v => UUID -> Key -> AssociatedFile -> RetryDecider -> (MeterUpdate -> Annex v) -> NotifyWitness -> Annex v
alwaysUpload u key f d a _witness = guardHaveUUID u $ alwaysUpload u key f d a _witness = guardHaveUUID u $
alwaysRunTransfer (Transfer Upload u (fromKey id key)) f d a alwaysRunTransfer (Transfer Upload u (fromKey id key)) f d a
download :: Observable v => UUID -> Key -> AssociatedFile -> RetryDecider -> (MeterUpdate -> Annex v) -> NotifyWitness -> Annex v download :: Remote -> Key -> AssociatedFile -> RetryDecider -> NotifyWitness -> Annex Bool
download u key f d a _witness = guardHaveUUID u $ download r key f d witness =
getViaTmp (Remote.retrievalSecurityPolicy r) (RemoteVerify r) key f $ \dest ->
download' (Remote.uuid r) key f d (go dest) witness
where
go dest p = verifiedAction $
Remote.retrieveKeyFile r key f (fromRawFilePath dest) p
download' :: Observable v => UUID -> Key -> AssociatedFile -> RetryDecider -> (MeterUpdate -> Annex v) -> NotifyWitness -> Annex v
download' u key f d a _witness = guardHaveUUID u $
runTransfer (Transfer Download u (fromKey id key)) f d a runTransfer (Transfer Download u (fromKey id key)) f d a
guardHaveUUID :: Observable v => UUID -> Annex v -> Annex v guardHaveUUID :: Observable v => UUID -> Annex v -> Annex v
@ -81,7 +97,7 @@ alwaysRunTransfer :: Observable v => Transfer -> AssociatedFile -> RetryDecider
alwaysRunTransfer = runTransfer' True alwaysRunTransfer = runTransfer' True
runTransfer' :: Observable v => Bool -> Transfer -> AssociatedFile -> RetryDecider -> (MeterUpdate -> Annex v) -> Annex v runTransfer' :: Observable v => Bool -> Transfer -> AssociatedFile -> RetryDecider -> (MeterUpdate -> Annex v) -> Annex v
runTransfer' ignorelock t afile retrydecider transferaction = enteringStage TransferStage $ debugLocks $ checkSecureHashes t $ do runTransfer' ignorelock t afile retrydecider transferaction = enteringStage TransferStage $ debugLocks $ preCheckSecureHashes t $ do
info <- liftIO $ startTransferInfo afile info <- liftIO $ startTransferInfo afile
(meter, tfile, createtfile, metervar) <- mkProgressUpdater t info (meter, tfile, createtfile, metervar) <- mkProgressUpdater t info
mode <- annexFileMode mode <- annexFileMode
@ -180,8 +196,8 @@ runTransfer' ignorelock t afile retrydecider transferaction = enteringStage Tran
- still contains content using an insecure hash, remotes will likewise - still contains content using an insecure hash, remotes will likewise
- tend to be configured to reject it, so Upload is also prevented. - tend to be configured to reject it, so Upload is also prevented.
-} -}
checkSecureHashes :: Observable v => Transfer -> Annex v -> Annex v preCheckSecureHashes :: Observable v => Transfer -> Annex v -> Annex v
checkSecureHashes t a = ifM (isCryptographicallySecure (transferKey t)) preCheckSecureHashes t a = ifM (isCryptographicallySecure (transferKey t))
( a ( a
, ifM (annexSecureHashesOnly <$> Annex.getGitConfig) , ifM (annexSecureHashesOnly <$> Annex.getGitConfig)
( do ( do

View file

@ -332,7 +332,7 @@ downloadWeb addunlockedmatcher o url urlinfo file =
let cleanuptmp = pruneTmpWorkDirBefore tmp (liftIO . removeWhenExistsWith R.removeLink) let cleanuptmp = pruneTmpWorkDirBefore tmp (liftIO . removeWhenExistsWith R.removeLink)
showNote "using youtube-dl" showNote "using youtube-dl"
Transfer.notifyTransfer Transfer.Download url $ Transfer.notifyTransfer Transfer.Download url $
Transfer.download webUUID mediakey (AssociatedFile Nothing) Transfer.noRetry $ \p -> Transfer.download' webUUID mediakey (AssociatedFile Nothing) Transfer.noRetry $ \p ->
youtubeDl url (fromRawFilePath workdir) p >>= \case youtubeDl url (fromRawFilePath workdir) p >>= \case
Right (Just mediafile) -> do Right (Just mediafile) -> do
cleanuptmp cleanuptmp
@ -396,7 +396,7 @@ downloadWith' downloader dummykey u url afile =
checkDiskSpaceToGet dummykey Nothing $ do checkDiskSpaceToGet dummykey Nothing $ do
tmp <- fromRepo $ gitAnnexTmpObjectLocation dummykey tmp <- fromRepo $ gitAnnexTmpObjectLocation dummykey
ok <- Transfer.notifyTransfer Transfer.Download url $ ok <- Transfer.notifyTransfer Transfer.Download url $
Transfer.download u dummykey afile Transfer.stdRetry $ \p -> do Transfer.download' u dummykey afile Transfer.stdRetry $ \p -> do
createAnnexDirectory (parentDir tmp) createAnnexDirectory (parentDir tmp)
downloader (fromRawFilePath tmp) p downloader (fromRawFilePath tmp) p
if ok if ok

View file

@ -283,7 +283,7 @@ performExport r db ek af contentsha loc allfilledvar = do
sent <- tryNonAsync $ case ek of sent <- tryNonAsync $ case ek of
AnnexKey k -> ifM (inAnnex k) AnnexKey k -> ifM (inAnnex k)
( notifyTransfer Upload af $ ( notifyTransfer Upload af $
upload (uuid r) k af stdRetry $ \pm -> do upload' (uuid r) k af stdRetry $ \pm -> do
let rollback = void $ let rollback = void $
performUnexport r db [ek] loc performUnexport r db [ek] loc
sendAnnex k rollback $ \f -> sendAnnex k rollback $ \f ->

View file

@ -9,7 +9,6 @@ module Command.Get where
import Command import Command
import qualified Remote import qualified Remote
import Annex.Content
import Annex.Transfer import Annex.Transfer
import Annex.NumCopies import Annex.NumCopies
import Annex.Wanted import Annex.Wanted
@ -114,10 +113,6 @@ getKey' key afile = dispatch
| Remote.hasKeyCheap r = | Remote.hasKeyCheap r =
either (const False) id <$> Remote.hasKey r key either (const False) id <$> Remote.hasKey r key
| otherwise = return True | otherwise = return True
docopy r witness = getViaTmp (Remote.retrievalSecurityPolicy r) (RemoteVerify r) key afile $ \dest -> docopy r witness = do
download (Remote.uuid r) key afile stdRetry showAction $ "from " ++ Remote.name r
(\p -> do download r key afile stdRetry witness
showAction $ "from " ++ Remote.name r
Remote.verifiedAction $
Remote.retrieveKeyFile r key afile (fromRawFilePath dest) p
) witness

View file

@ -142,8 +142,7 @@ toPerform dest removewhen key afile fastcheck isthere = do
Right False -> logMove srcuuid destuuid False key $ \deststartedwithcopy -> do Right False -> logMove srcuuid destuuid False key $ \deststartedwithcopy -> do
showAction $ "to " ++ Remote.name dest showAction $ "to " ++ Remote.name dest
ok <- notifyTransfer Upload afile $ ok <- notifyTransfer Upload afile $
upload (Remote.uuid dest) key afile stdRetry $ upload dest key afile stdRetry
Remote.action . Remote.storeKey dest key afile
if ok if ok
then finish deststartedwithcopy $ then finish deststartedwithcopy $
Remote.logStatus dest key InfoPresent Remote.logStatus dest key InfoPresent
@ -223,10 +222,8 @@ fromPerform src removewhen key afile = do
then dispatch removewhen deststartedwithcopy True then dispatch removewhen deststartedwithcopy True
else dispatch removewhen deststartedwithcopy =<< get else dispatch removewhen deststartedwithcopy =<< get
where where
get = notifyTransfer Download afile $ get = notifyTransfer Download afile $
download (Remote.uuid src) key afile stdRetry $ \p -> download src key afile stdRetry
getViaTmp (Remote.retrievalSecurityPolicy src) (RemoteVerify src) key afile $ \t ->
Remote.verifiedAction $ Remote.retrieveKeyFile src key afile (fromRawFilePath t) p
dispatch _ _ False = stop -- failed dispatch _ _ False = stop -- failed
dispatch RemoveNever _ True = next $ return True -- copy complete dispatch RemoveNever _ True = next $ return True -- copy complete

View file

@ -51,7 +51,7 @@ start o (_, key) = startingCustomOutput key $ case fromToOptions o of
toPerform :: Key -> AssociatedFile -> Remote -> CommandPerform toPerform :: Key -> AssociatedFile -> Remote -> CommandPerform
toPerform key file remote = go Upload file $ toPerform key file remote = go Upload file $
upload (uuid remote) key file stdRetry $ \p -> do upload' (uuid remote) key file stdRetry $ \p -> do
tryNonAsync (Remote.storeKey remote key file p) >>= \case tryNonAsync (Remote.storeKey remote key file p) >>= \case
Right () -> do Right () -> do
Remote.logStatus remote key InfoPresent Remote.logStatus remote key InfoPresent
@ -62,7 +62,7 @@ toPerform key file remote = go Upload file $
fromPerform :: Key -> AssociatedFile -> Remote -> CommandPerform fromPerform :: Key -> AssociatedFile -> Remote -> CommandPerform
fromPerform key file remote = go Upload file $ fromPerform key file remote = go Upload file $
download (uuid remote) key file stdRetry $ \p -> download' (uuid remote) key file stdRetry $ \p ->
getViaTmp (retrievalSecurityPolicy remote) (RemoteVerify remote) key file $ \t -> getViaTmp (retrievalSecurityPolicy remote) (RemoteVerify remote) key file $ \t ->
tryNonAsync (Remote.retrieveKeyFile remote key file (fromRawFilePath t) p) >>= \case tryNonAsync (Remote.retrieveKeyFile remote key file (fromRawFilePath t) p) >>= \case
Right v -> return (True, v) Right v -> return (True, v)

View file

@ -49,7 +49,7 @@ start = do
where where
runner (TransferRequest direction _ keydata file) remote runner (TransferRequest direction _ keydata file) remote
| direction == Upload = notifyTransfer direction file $ | direction == Upload = notifyTransfer direction file $
upload (Remote.uuid remote) key file stdRetry $ \p -> do upload' (Remote.uuid remote) key file stdRetry $ \p -> do
tryNonAsync (Remote.storeKey remote key file p) >>= \case tryNonAsync (Remote.storeKey remote key file p) >>= \case
Left e -> do Left e -> do
warning (show e) warning (show e)
@ -58,7 +58,7 @@ start = do
Remote.logStatus remote key InfoPresent Remote.logStatus remote key InfoPresent
return True return True
| otherwise = notifyTransfer direction file $ | otherwise = notifyTransfer direction file $
download (Remote.uuid remote) key file stdRetry $ \p -> download' (Remote.uuid remote) key file stdRetry $ \p ->
getViaTmp (Remote.retrievalSecurityPolicy remote) (RemoteVerify remote) key file $ \t -> do getViaTmp (Remote.retrievalSecurityPolicy remote) (RemoteVerify remote) key file $ \t -> do
r <- tryNonAsync (Remote.retrieveKeyFile remote key file (fromRawFilePath t) p) >>= \case r <- tryNonAsync (Remote.retrieveKeyFile remote key file (fromRawFilePath t) p) >>= \case
Left e -> do Left e -> do

View file

@ -75,7 +75,7 @@ runLocal runst runner a = case a of
let rsp = RetrievalAllKeysSecure let rsp = RetrievalAllKeysSecure
v <- tryNonAsync $ do v <- tryNonAsync $ do
let runtransfer ti = let runtransfer ti =
Right <$> transfer download k af (\p -> Right <$> transfer download' k af (\p ->
getViaTmp rsp DefaultVerify k af $ \tmp -> getViaTmp rsp DefaultVerify k af $ \tmp ->
storefile (fromRawFilePath tmp) o l getb validitycheck p ti) storefile (fromRawFilePath tmp) o l getb validitycheck p ti)
let fallback = return $ Left $ let fallback = return $ Left $

View file

@ -70,6 +70,7 @@ import Annex.Common
import Types.Remote import Types.Remote
import qualified Annex import qualified Annex
import Annex.UUID import Annex.UUID
import Annex.Action
import Logs.UUID import Logs.UUID
import Logs.Trust import Logs.Trust
import Logs.Location hiding (logStatus) import Logs.Location hiding (logStatus)
@ -82,21 +83,6 @@ import Config.DynamicConfig
import Git.Types (RemoteName, ConfigKey(..), fromConfigValue) import Git.Types (RemoteName, ConfigKey(..), fromConfigValue)
import Utility.Aeson import Utility.Aeson
{- Runs an action that may throw exceptions, catching and displaying them. -}
action :: Annex () -> Annex Bool
action a = tryNonAsync a >>= \case
Right () -> return True
Left e -> do
warning (show e)
return False
verifiedAction :: Annex Verification -> Annex (Bool, Verification)
verifiedAction a = tryNonAsync a >>= \case
Right v -> return (True, v)
Left e -> do
warning (show e)
return (False, UnVerified)
{- Map from UUIDs of Remotes to a calculated value. -} {- Map from UUIDs of Remotes to a calculated value. -}
remoteMap :: (Remote -> v) -> Annex (M.Map UUID v) remoteMap :: (Remote -> v) -> Annex (M.Map UUID v)
remoteMap mkv = remoteMap' mkv (pure . mkk) remoteMap mkv = remoteMap' mkv (pure . mkk)