summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Joey Hess <joeyh@joeyh.name>2015-10-09 13:07:03 -0400
committerGravatar Joey Hess <joeyh@joeyh.name>2015-10-09 13:12:58 -0400
commit8817fe6331ffc3d99bbf44af559f773af1a2ddd2 (patch)
tree21da807bf1ae9dda9714990b5d6c0dd961bd4ff6
parent7788d302397096c85fe70c35f2661d76a8d2f511 (diff)
content locking during drop working for local git remotes
Only ssh remotes lack locking now
-rw-r--r--Annex/NumCopies.hs38
-rw-r--r--Remote/Git.hs13
-rw-r--r--Types/NumCopies.hs2
-rw-r--r--Types/Remote.hs7
4 files changed, 52 insertions, 8 deletions
diff --git a/Annex/NumCopies.hs b/Annex/NumCopies.hs
index 7874fb0e9..be1db4be8 100644
--- a/Annex/NumCopies.hs
+++ b/Annex/NumCopies.hs
@@ -5,6 +5,8 @@
- Licensed under the GNU GPL version 3 or higher.
-}
+{-# LANGUAGE ScopedTypeVariables, DeriveDataTypeable #-}
+
module Annex.NumCopies (
module Types.NumCopies,
module Logs.NumCopies,
@@ -30,6 +32,10 @@ import qualified Types.Remote as Remote
import Annex.UUID
import Annex.Content
+import Control.Exception
+import qualified Control.Monad.Catch as M
+import Data.Typeable
+
defaultNumCopies :: NumCopies
defaultNumCopies = NumCopies 1
@@ -124,10 +130,31 @@ verifyEnoughCopiesToDrop nolocmsg key need skip preverified tocheck dropaction n
Right proof -> dropaction proof
Left stillhave -> helper bad missing stillhave (r:rs)
| 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
- Just lockcontent -> lockcontent key $ \v -> case v of
- Nothing -> fallback
- Just vc -> helper bad missing (vc : have) rs
where
fallback = do
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
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 need have skip bad nolocmsg = do
showNote "unsafe"
diff --git a/Remote/Git.hs b/Remote/Git.hs
index 725b302b8..9fa7158e5 100644
--- a/Remote/Git.hs
+++ b/Remote/Git.hs
@@ -53,6 +53,7 @@ import Annex.Path
import Creds
import Annex.CatFile
import Messages.Progress
+import Types.NumCopies
import Control.Concurrent
import Control.Concurrent.MSampleVar
@@ -142,7 +143,7 @@ gen r u c gc
, retrieveKeyFile = copyFromRemote new
, retrieveKeyFileCheap = copyFromRemoteCheap new
, removeKey = dropKey new
- , lockContent = Nothing
+ , lockContent = Just (lockKey new)
, checkPresent = inAnnex new
, checkPresentCheap = repoCheap r
, whereisKey = Nothing
@@ -359,6 +360,16 @@ dropKey r key
| Git.repoIsHttp (repo r) = error "dropping from http remote not supported"
| 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. -}
copyFromRemote :: Remote -> Key -> AssociatedFile -> FilePath -> MeterUpdate -> Annex (Bool, Verification)
copyFromRemote r key file dest p = parallelMetered (Just p) key file $
diff --git a/Types/NumCopies.hs b/Types/NumCopies.hs
index 23df6610a..476c33058 100644
--- a/Types/NumCopies.hs
+++ b/Types/NumCopies.hs
@@ -1,6 +1,6 @@
{- 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.
-}
diff --git a/Types/Remote.hs b/Types/Remote.hs
index 511a85afa..a39324163 100644
--- a/Types/Remote.hs
+++ b/Types/Remote.hs
@@ -78,10 +78,11 @@ data RemoteA a = Remote {
-- Removes a key's contents (succeeds if the contents are not present)
removeKey :: Key -> a Bool,
-- Uses locking to prevent removal of a key's contents,
- -- thus producing a VerifiedCopy.
- -- The action must be run whether or not the locking succeeds.
+ -- thus producing a VerifiedCopy, which is passed to the callback.
+ -- If unable to lock, does not run the callback, and throws an
+ -- error.
-- 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.
-- Throws an exception if the remote cannot be accessed.
checkPresent :: Key -> a Bool,