require 1 locked copy while dropping from local or a remote

See doc/bugs/concurrent_drop--from_presence_checking_failures.mdwn for
discussion about why 1 locked copy is all we can require, and how this
fixes concurrent dropping bugs.

Note that, since nothing yet generates a VerifiedCopyLock yet, this commit
breaks dropping temporarily.
This commit is contained in:
Joey Hess 2015-10-08 18:11:39 -04:00
parent c75c79864d
commit b17f5da6c9
Failed to extract signature

View file

@ -108,7 +108,11 @@ verifyEnoughCopies nolocmsg key need skip preverified tocheck =
notEnoughCopies key need have (skip++missing) bad nolocmsg
return False
helper bad missing have (r:rs)
| NumCopies (length have) >= need = return True
| verifiedEnoughCopies need have = do
stillhave <- liftIO $ filterM checkVerifiedCopy have
if verifiedEnoughCopies need stillhave
then return True
else helper bad missing stillhave (r:rs)
| any (== u) (map toUUID have) = helper bad missing have rs
| otherwise = do
haskey <- Remote.hasKey r key
@ -119,6 +123,26 @@ verifyEnoughCopies nolocmsg key need skip preverified tocheck =
where
u = Remote.uuid r
{- Check whether enough verification has been done of copies to allow
- dropping content safely.
-
- Unless numcopies is 0, at least one VerifiedCopyLock is required.
- This prevents races between concurrent drops from dropping the last
- copy, no matter what.
-
- The other N-1 copies can be less strong verifications. While those
- are subject to concurrent drop races, and so could be dropped
- all at once, causing numcopies to be violated, this is the best that can
- be done without requiring all special remotes to support locking.
-}
verifiedEnoughCopies :: NumCopies -> [VerifiedCopy] -> Bool
verifiedEnoughCopies (NumCopies n) l
| n == 0 = True
| otherwise = length l >= n && any islock l
where
islock (VerifiedCopyLock _) = True
islock _ = False
notEnoughCopies :: Key -> NumCopies -> [VerifiedCopy] -> [UUID] -> [Remote] -> String -> Annex ()
notEnoughCopies key need have skip bad nolocmsg = do
showNote "unsafe"