content locking during drop working for local git remotes
Only ssh remotes lack locking now
This commit is contained in:
parent
ceb5819538
commit
4c6095b6f5
4 changed files with 52 additions and 8 deletions
|
@ -5,6 +5,8 @@
|
||||||
- Licensed under the GNU GPL version 3 or higher.
|
- Licensed under the GNU GPL version 3 or higher.
|
||||||
-}
|
-}
|
||||||
|
|
||||||
|
{-# LANGUAGE ScopedTypeVariables, DeriveDataTypeable #-}
|
||||||
|
|
||||||
module Annex.NumCopies (
|
module Annex.NumCopies (
|
||||||
module Types.NumCopies,
|
module Types.NumCopies,
|
||||||
module Logs.NumCopies,
|
module Logs.NumCopies,
|
||||||
|
@ -30,6 +32,10 @@ import qualified Types.Remote as Remote
|
||||||
import Annex.UUID
|
import Annex.UUID
|
||||||
import Annex.Content
|
import Annex.Content
|
||||||
|
|
||||||
|
import Control.Exception
|
||||||
|
import qualified Control.Monad.Catch as M
|
||||||
|
import Data.Typeable
|
||||||
|
|
||||||
defaultNumCopies :: NumCopies
|
defaultNumCopies :: NumCopies
|
||||||
defaultNumCopies = NumCopies 1
|
defaultNumCopies = NumCopies 1
|
||||||
|
|
||||||
|
@ -124,10 +130,31 @@ verifyEnoughCopiesToDrop nolocmsg key need skip preverified tocheck dropaction n
|
||||||
Right proof -> dropaction proof
|
Right proof -> dropaction proof
|
||||||
Left stillhave -> helper bad missing stillhave (r:rs)
|
Left stillhave -> helper bad missing stillhave (r:rs)
|
||||||
| otherwise = case Remote.lockContent r of
|
| otherwise = case Remote.lockContent r of
|
||||||
|
Just lockcontent -> do
|
||||||
|
-- The remote's lockContent will throw
|
||||||
|
-- an exception if it is unable to lock,
|
||||||
|
-- in which case the fallback should be
|
||||||
|
-- run.
|
||||||
|
--
|
||||||
|
-- On the other hand, the callback passed
|
||||||
|
-- to the lockContent could itself throw an
|
||||||
|
-- exception (ie, the eventual drop
|
||||||
|
-- action fails), and in this case we don't
|
||||||
|
-- want to use the fallback since part
|
||||||
|
-- of the drop action may have already been
|
||||||
|
-- performed.
|
||||||
|
--
|
||||||
|
-- Differentiate between these two sorts
|
||||||
|
-- of exceptions by using DropException.
|
||||||
|
let a = lockcontent key $ \vc ->
|
||||||
|
helper bad missing (vc : have) rs
|
||||||
|
`catchNonAsync` (throw . DropException)
|
||||||
|
a `M.catches`
|
||||||
|
[ M.Handler (\ (e :: AsyncException) -> throwM e)
|
||||||
|
, M.Handler (\ (DropException e') -> throwM e')
|
||||||
|
, M.Handler (\ (_e :: SomeException) -> fallback)
|
||||||
|
]
|
||||||
Nothing -> fallback
|
Nothing -> fallback
|
||||||
Just lockcontent -> lockcontent key $ \v -> case v of
|
|
||||||
Nothing -> fallback
|
|
||||||
Just vc -> helper bad missing (vc : have) rs
|
|
||||||
where
|
where
|
||||||
fallback = do
|
fallback = do
|
||||||
haskey <- Remote.hasKey r key
|
haskey <- Remote.hasKey r key
|
||||||
|
@ -136,6 +163,11 @@ verifyEnoughCopiesToDrop nolocmsg key need skip preverified tocheck dropaction n
|
||||||
Left _ -> helper (r:bad) missing have rs
|
Left _ -> helper (r:bad) missing have rs
|
||||||
Right False -> helper bad (Remote.uuid r:missing) have rs
|
Right False -> helper bad (Remote.uuid r:missing) have rs
|
||||||
|
|
||||||
|
data DropException = DropException SomeException
|
||||||
|
deriving (Typeable, Show)
|
||||||
|
|
||||||
|
instance Exception DropException
|
||||||
|
|
||||||
notEnoughCopies :: Key -> NumCopies -> [VerifiedCopy] -> [UUID] -> [Remote] -> String -> Annex ()
|
notEnoughCopies :: Key -> NumCopies -> [VerifiedCopy] -> [UUID] -> [Remote] -> String -> Annex ()
|
||||||
notEnoughCopies key need have skip bad nolocmsg = do
|
notEnoughCopies key need have skip bad nolocmsg = do
|
||||||
showNote "unsafe"
|
showNote "unsafe"
|
||||||
|
|
|
@ -53,6 +53,7 @@ import Annex.Path
|
||||||
import Creds
|
import Creds
|
||||||
import Annex.CatFile
|
import Annex.CatFile
|
||||||
import Messages.Progress
|
import Messages.Progress
|
||||||
|
import Types.NumCopies
|
||||||
|
|
||||||
import Control.Concurrent
|
import Control.Concurrent
|
||||||
import Control.Concurrent.MSampleVar
|
import Control.Concurrent.MSampleVar
|
||||||
|
@ -142,7 +143,7 @@ gen r u c gc
|
||||||
, retrieveKeyFile = copyFromRemote new
|
, retrieveKeyFile = copyFromRemote new
|
||||||
, retrieveKeyFileCheap = copyFromRemoteCheap new
|
, retrieveKeyFileCheap = copyFromRemoteCheap new
|
||||||
, removeKey = dropKey new
|
, removeKey = dropKey new
|
||||||
, lockContent = Nothing
|
, lockContent = Just (lockKey new)
|
||||||
, checkPresent = inAnnex new
|
, checkPresent = inAnnex new
|
||||||
, checkPresentCheap = repoCheap r
|
, checkPresentCheap = repoCheap r
|
||||||
, whereisKey = Nothing
|
, whereisKey = Nothing
|
||||||
|
@ -359,6 +360,16 @@ dropKey r key
|
||||||
| Git.repoIsHttp (repo r) = error "dropping from http remote not supported"
|
| Git.repoIsHttp (repo r) = error "dropping from http remote not supported"
|
||||||
| otherwise = commitOnCleanup r $ Ssh.dropKey (repo r) key
|
| otherwise = commitOnCleanup r $ Ssh.dropKey (repo r) key
|
||||||
|
|
||||||
|
lockKey :: Remote -> Key -> (VerifiedCopy -> Annex r) -> Annex r
|
||||||
|
lockKey r key a
|
||||||
|
| not $ Git.repoIsUrl (repo r) =
|
||||||
|
guardUsable (repo r) cantlock $
|
||||||
|
onLocal r $ Annex.Content.lockContentShared key a
|
||||||
|
| Git.repoIsHttp (repo r) = cantlock
|
||||||
|
| otherwise = error "TODO"
|
||||||
|
where
|
||||||
|
cantlock = error "can't lock content"
|
||||||
|
|
||||||
{- Tries to copy a key's content from a remote's annex to a file. -}
|
{- Tries to copy a key's content from a remote's annex to a file. -}
|
||||||
copyFromRemote :: Remote -> Key -> AssociatedFile -> FilePath -> MeterUpdate -> Annex (Bool, Verification)
|
copyFromRemote :: Remote -> Key -> AssociatedFile -> FilePath -> MeterUpdate -> Annex (Bool, Verification)
|
||||||
copyFromRemote r key file dest p = parallelMetered (Just p) key file $
|
copyFromRemote r key file dest p = parallelMetered (Just p) key file $
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{- git-annex numcopies types
|
{- git-annex numcopies types
|
||||||
-
|
-
|
||||||
- Copyright 2014 Joey Hess <id@joeyh.name>
|
- Copyright 2014-2015 Joey Hess <id@joeyh.name>
|
||||||
-
|
-
|
||||||
- Licensed under the GNU GPL version 3 or higher.
|
- Licensed under the GNU GPL version 3 or higher.
|
||||||
-}
|
-}
|
||||||
|
|
|
@ -78,10 +78,11 @@ data RemoteA a = Remote {
|
||||||
-- Removes a key's contents (succeeds if the contents are not present)
|
-- Removes a key's contents (succeeds if the contents are not present)
|
||||||
removeKey :: Key -> a Bool,
|
removeKey :: Key -> a Bool,
|
||||||
-- Uses locking to prevent removal of a key's contents,
|
-- Uses locking to prevent removal of a key's contents,
|
||||||
-- thus producing a VerifiedCopy.
|
-- thus producing a VerifiedCopy, which is passed to the callback.
|
||||||
-- The action must be run whether or not the locking succeeds.
|
-- If unable to lock, does not run the callback, and throws an
|
||||||
|
-- error.
|
||||||
-- This is optional; remotes do not have to support locking.
|
-- This is optional; remotes do not have to support locking.
|
||||||
lockContent :: forall r. Maybe (Key -> (Maybe VerifiedCopy -> a r) -> a r),
|
lockContent :: forall r. Maybe (Key -> (VerifiedCopy -> a r) -> a r),
|
||||||
-- Checks if a key is present in the remote.
|
-- Checks if a key is present in the remote.
|
||||||
-- Throws an exception if the remote cannot be accessed.
|
-- Throws an exception if the remote cannot be accessed.
|
||||||
checkPresent :: Key -> a Bool,
|
checkPresent :: Key -> a Bool,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue