From b17f5da6c94b8047ed08af684f4a9f8786d68ddb Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Thu, 8 Oct 2015 18:11:39 -0400 Subject: [PATCH] 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. --- Annex/NumCopies.hs | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/Annex/NumCopies.hs b/Annex/NumCopies.hs index 6b534591e9..6368554019 100644 --- a/Annex/NumCopies.hs +++ b/Annex/NumCopies.hs @@ -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"