ActionGetWanted working

The sim is now basically working!
This commit is contained in:
Joey Hess 2024-09-11 10:32:04 -04:00
parent 07f54668c4
commit a387f40ffb
No known key found for this signature in database
GPG key ID: DB12DB0FF05F8F38
2 changed files with 114 additions and 65 deletions

View file

@ -23,6 +23,7 @@ import Annex.FileMatcher
import Annex.Init import Annex.Init
import Annex.Startup import Annex.Startup
import Annex.Link import Annex.Link
import Annex.Wanted
import Logs.Group import Logs.Group
import Logs.Trust import Logs.Trust
import Logs.PreferredContent import Logs.PreferredContent
@ -66,13 +67,14 @@ data SimState = SimState
, simMaxSize :: M.Map UUID MaxSize , simMaxSize :: M.Map UUID MaxSize
, simRebalance :: Bool , simRebalance :: Bool
, simGetExistingRepoByName :: GetExistingRepoByName , simGetExistingRepoByName :: GetExistingRepoByName
, simGetSimRepoPath :: GetSimRepoPath
, simHistory :: [SimCommand] , simHistory :: [SimCommand]
, simVectorClock :: VectorClock , simVectorClock :: VectorClock
} }
deriving (Show) deriving (Show)
emptySimState :: StdGen -> GetExistingRepoByName -> SimState emptySimState :: StdGen -> GetExistingRepoByName -> GetSimRepoPath -> SimState
emptySimState rng repobyname = SimState emptySimState rng repobyname getpath = SimState
{ simRepos = mempty { simRepos = mempty
, simRepoList = mempty , simRepoList = mempty
, simRepoState = mempty , simRepoState = mempty
@ -89,6 +91,7 @@ emptySimState rng repobyname = SimState
, simMaxSize = mempty , simMaxSize = mempty
, simRebalance = False , simRebalance = False
, simGetExistingRepoByName = repobyname , simGetExistingRepoByName = repobyname
, simGetSimRepoPath = getpath
, simHistory = [] , simHistory = []
, simVectorClock = VectorClock 0 , simVectorClock = VectorClock 0
} }
@ -99,9 +102,7 @@ data SimRepoState = SimRepoState
, simIsSpecialRemote :: Bool , simIsSpecialRemote :: Bool
, simRepo :: Maybe SimRepo , simRepo :: Maybe SimRepo
} }
deriving (Show)
instance Show SimRepoState where
show _ = "SimRepoState"
data LocationState = LocationState VectorClock Bool data LocationState = LocationState VectorClock Bool
deriving (Eq, Show) deriving (Eq, Show)
@ -113,9 +114,18 @@ newerLocationState :: LocationState -> LocationState -> LocationState
newerLocationState l1@(LocationState vc1 _) l2@(LocationState vc2 _) newerLocationState l1@(LocationState vc1 _) l2@(LocationState vc2 _)
| vc1 > vc2 = l1 | vc1 > vc2 = l1
| otherwise = l2 | otherwise = l2
setPresentKey :: UUID -> Key -> RepoName -> SimState -> SimState
setPresentKey u k repo st = st
{ simRepoState = case M.lookup repo (simRepoState st) of
Just rst -> M.insert repo
(setPresentKey' (simVectorClock st) u k rst)
(simRepoState st)
Nothing -> error "no simRepoState in setPresentKey"
}
setPresentKey :: VectorClock -> UUID -> Key -> SimRepoState -> SimRepoState setPresentKey' :: VectorClock -> UUID -> Key -> SimRepoState -> SimRepoState
setPresentKey vc u k rst = rst setPresentKey' vc u k rst = rst
{ simLocations = { simLocations =
M.insertWith (M.unionWith newerLocationState) k M.insertWith (M.unionWith newerLocationState) k
(M.singleton u (LocationState vc True)) (M.singleton u (LocationState vc True))
@ -132,6 +142,9 @@ getSimLocations' = M.keysSet . M.filter present
where where
present (LocationState _ b) = b present (LocationState _ b) = b
addHistory :: SimState -> SimCommand -> SimState
addHistory st c = st { simHistory = c : simHistory st }
newtype RepoName = RepoName { fromRepoName :: String } newtype RepoName = RepoName { fromRepoName :: String }
deriving (Show, Eq, Ord) deriving (Show, Eq, Ord)
@ -148,12 +161,12 @@ data SimCommand
| CommandConnect RepoName RemoteName | CommandConnect RepoName RemoteName
| CommandDisconnect RepoName RemoteName | CommandDisconnect RepoName RemoteName
| CommandAddTree RepoName PreferredContentExpression | CommandAddTree RepoName PreferredContentExpression
| CommandAdd FilePath ByteSize RepoName | CommandAdd RawFilePath ByteSize RepoName
| CommandStep Int | CommandStep Int
| CommandAction RepoName SimAction | CommandAction RepoName SimAction
| CommandSeed Int | CommandSeed Int
| CommandPresent RepoName FilePath | CommandPresent RepoName RawFilePath
| CommandNotPresent RepoName FilePath | CommandNotPresent RepoName RawFilePath
| CommandNumCopies Int | CommandNumCopies Int
| CommandMinCopies Int | CommandMinCopies Int
| CommandTrustLevel RepoName String | CommandTrustLevel RepoName String
@ -195,9 +208,8 @@ applySimCommand
-> SimState -> SimState
-> Either String (Either (Annex SimState) SimState) -> Either String (Either (Annex SimState) SimState)
applySimCommand c st = applySimCommand c st =
applySimCommand' c $ st applySimCommand' c $ flip addHistory c $ st
{ simHistory = c : simHistory st { simVectorClock =
, simVectorClock =
let (VectorClock c) = simVectorClock st let (VectorClock c) = simVectorClock st
in VectorClock (succ c) in VectorClock (succ c)
} }
@ -243,13 +255,8 @@ applySimCommand' (CommandAddTree repo expr) st =
error "TODO" -- XXX error "TODO" -- XXX
applySimCommand' (CommandAdd file sz repo) st = checkKnownRepo repo st $ \u -> applySimCommand' (CommandAdd file sz repo) st = checkKnownRepo repo st $ \u ->
let (k, st') = genSimKey sz st let (k, st') = genSimKey sz st
in Right $ Right $ st' in Right $ Right $ setPresentKey u k repo $ st'
{ simFiles = M.insert (toRawFilePath file) k (simFiles st') { simFiles = M.insert file k (simFiles st')
, simRepoState = case M.lookup repo (simRepoState st') of
Just rst -> M.insert repo
(setPresentKey (simVectorClock st) u k rst)
(simRepoState st')
Nothing -> error "no simRepoState in applySimCommand CommandAdd"
} }
applySimCommand' (CommandStep _) _ = error "applySimCommand' CommandStep" applySimCommand' (CommandStep _) _ = error "applySimCommand' CommandStep"
applySimCommand' (CommandAction repo act) st = applySimCommand' (CommandAction repo act) st =
@ -259,30 +266,32 @@ applySimCommand' (CommandSeed rngseed) st = Right $ Right $ st
{ simRng = mkStdGen rngseed { simRng = mkStdGen rngseed
} }
applySimCommand' (CommandPresent repo file) st = checkKnownRepo repo st $ \u -> applySimCommand' (CommandPresent repo file) st = checkKnownRepo repo st $ \u ->
case (M.lookup (toRawFilePath file) (simFiles st), M.lookup repo (simRepoState st)) of case (M.lookup file (simFiles st), M.lookup repo (simRepoState st)) of
(Just k, Just rst) (Just k, Just rst)
| u `S.member` getSimLocations rst k -> | u `S.member` getSimLocations rst k ->
Right $ Right st Right $ Right st
| otherwise -> missing | otherwise -> missing
(Just _, Nothing) -> missing (Just _, Nothing) -> missing
(Nothing, _) -> Left $ "Expected " ++ file (Nothing, _) -> Left $ "Expected " ++ fromRawFilePath file
++ " to be present in " ++ fromRepoName repo ++ " to be present in " ++ fromRepoName repo
++ ", but the simulation does not include that file." ++ ", but the simulation does not include that file."
where where
missing = Left $ "Expected " ++ file ++ " to be present in " missing = Left $ "Expected " ++ fromRawFilePath file
++ " to be present in "
++ fromRepoName repo ++ ", but it is not." ++ fromRepoName repo ++ ", but it is not."
applySimCommand' (CommandNotPresent repo file) st = checkKnownRepo repo st $ \u -> applySimCommand' (CommandNotPresent repo file) st = checkKnownRepo repo st $ \u ->
case (M.lookup (toRawFilePath file) (simFiles st), M.lookup repo (simRepoState st)) of case (M.lookup file (simFiles st), M.lookup repo (simRepoState st)) of
(Just k, Just rst) (Just k, Just rst)
| u `S.notMember` getSimLocations rst k -> | u `S.notMember` getSimLocations rst k ->
Right $ Right st Right $ Right st
| otherwise -> present | otherwise -> present
(Just _, Nothing) -> present (Just _, Nothing) -> present
(Nothing, _) -> Left $ "Expected " ++ file (Nothing, _) -> Left $ "Expected " ++ fromRawFilePath file
++ " to not be present in " ++ fromRepoName repo ++ " to not be present in " ++ fromRepoName repo
++ ", but the simulation does not include that file." ++ ", but the simulation does not include that file."
where where
present = Left $ "Expected " ++ file ++ " not to be present in " present = Left $ "Expected " ++ fromRawFilePath file
++ " not to be present in "
++ fromRepoName repo ++ ", but it is present." ++ fromRepoName repo ++ ", but it is present."
applySimCommand' (CommandNumCopies n) st = Right $ Right $ st applySimCommand' (CommandNumCopies n) st = Right $ Right $ st
{ simNumCopies = configuredNumCopies n { simNumCopies = configuredNumCopies n
@ -336,7 +345,28 @@ applySimAction
-> Either String (Either (Annex SimState) SimState) -> Either String (Either (Annex SimState) SimState)
applySimAction r u (ActionPull remote) st = undefined applySimAction r u (ActionPull remote) st = undefined
applySimAction r u (ActionPush remote) st = undefined applySimAction r u (ActionPush remote) st = undefined
applySimAction r u (ActionGetWanted remote) st = undefined applySimAction r u (ActionGetWanted remote) st =
checkKnownRemote remote r u st $ \remoteu ->
Right $ Left $ liftIO $
runSimRepo r st $ \rst ->
let l = M.toList $
M.filter (knowninremote remoteu rst) $
simFiles st
in go l st
where
go [] st' = return st'
go ((f, k):rest) st' = do
ifM (wantGet NoLiveUpdate False (Just k) af)
( go rest $ setPresentKey u k r $
addHistory st' $ CommandPresent r f
, go rest st'
)
where
af = AssociatedFile $ Just f
knowninremote remoteu rst k =
remoteu `S.member` getSimLocations rst k
applySimAction r u (ActionDropUnwanted Nothing) st = undefined applySimAction r u (ActionDropUnwanted Nothing) st = undefined
applySimAction r u (ActionDropUnwanted (Just remote)) st = undefined applySimAction r u (ActionDropUnwanted (Just remote)) st = undefined
applySimAction r u (ActionSendWanted remote) st = undefined applySimAction r u (ActionSendWanted remote) st = undefined
@ -387,7 +417,7 @@ checkKnownRemote remotename reponame u st a =
in if S.member remotename rs in if S.member remotename rs
then checkKnownRepo (remoteNameToRepoName remotename) st a then checkKnownRepo (remoteNameToRepoName remotename) st a
else Left $ "Repository " ++ fromRepoName reponame else Left $ "Repository " ++ fromRepoName reponame
++ " does not have a remote named \"" ++ " does not have a remote \""
++ fromRemoteName remotename ++ "\"." ++ fromRemoteName remotename ++ "\"."
checkValidPreferredContentExpression :: PreferredContentExpression -> v -> Either String v checkValidPreferredContentExpression :: PreferredContentExpression -> v -> Either String v
@ -463,6 +493,11 @@ newtype GetExistingRepoByName = GetExistingRepoByName
instance Show GetExistingRepoByName where instance Show GetExistingRepoByName where
show _ = "GetExistingRepoByName" show _ = "GetExistingRepoByName"
newtype GetSimRepoPath = GetSimRepoPath (UUID -> FilePath)
instance Show GetSimRepoPath where
show _ = "GetSimRepoPath"
data SimRepoConfig = SimRepoConfig data SimRepoConfig = SimRepoConfig
{ simRepoUUID :: UUID { simRepoUUID :: UUID
, simRepoIsSpecialRemote :: Bool , simRepoIsSpecialRemote :: Bool
@ -565,11 +600,12 @@ data SimRepo = SimRepo
, simRepoName :: RepoName , simRepoName :: RepoName
} }
{- Clones and updates SimRepos to reflect the SimState. -} instance Show SimRepo where
updateSimRepos :: Repo -> (UUID -> FilePath) -> SimState -> IO SimState show _ = "SimRepo"
updateSimRepos parent getdest st = do
st' <- updateSimRepoStates st {- Inits and updates SimRepos to reflect the SimState. -}
cloneNewSimRepos parent getdest st' updateSimRepos :: SimState -> IO SimState
updateSimRepos st = updateSimRepoStates st >>= initNewSimRepos
updateSimRepoStates :: SimState -> IO SimState updateSimRepoStates :: SimState -> IO SimState
updateSimRepoStates st = go st (M.toList $ simRepoState st) updateSimRepoStates st = go st (M.toList $ simRepoState st)
@ -586,15 +622,15 @@ updateSimRepoStates st = go st (M.toList $ simRepoState st)
go st'' rest go st'' rest
Nothing -> go st' rest Nothing -> go st' rest
cloneNewSimRepos :: Repo -> (UUID -> FilePath) -> SimState -> IO SimState initNewSimRepos :: SimState -> IO SimState
cloneNewSimRepos parent getdest = \st -> go st (M.toList $ simRepoState st) initNewSimRepos = \st -> go st (M.toList $ simRepoState st)
where where
go st [] = return st go st [] = return st
go st ((reponame, rst):rest) = go st ((reponame, rst):rest) =
case (simRepo rst, M.lookup reponame (simRepos st)) of case (simRepo rst, M.lookup reponame (simRepos st)) of
(Nothing, Just u) -> do (Nothing, Just u) -> do
sr <- cloneSimRepo reponame u parent let GetSimRepoPath getdest = simGetSimRepoPath st
(getdest u) st sr <- initSimRepo reponame u (getdest u) st
let rst' = rst { simRepo = Just sr } let rst' = rst { simRepo = Just sr }
let st' = st let st' = st
{ simRepoState = M.insert reponame rst' { simRepoState = M.insert reponame rst'
@ -603,33 +639,21 @@ cloneNewSimRepos parent getdest = \st -> go st (M.toList $ simRepoState st)
go st' rest go st' rest
_ -> go st rest _ -> go st rest
cloneSimRepo :: RepoName -> UUID -> Repo -> FilePath -> SimState -> IO SimRepo initSimRepo :: RepoName -> UUID -> FilePath -> SimState -> IO SimRepo
cloneSimRepo simreponame u parent dest st = do initSimRepo simreponame u dest st = do
cloned <- boolSystem "git" inited <- boolSystem "git"
[ Param "clone" [ Param "init"
, Param "--shared"
, Param "--quiet" , Param "--quiet"
-- Avoid overhead of checking out the working tree.
, Param "--no-checkout"
-- Make sure the origin gets that name.
, Param "--origin", Param "origin"
, File (fromRawFilePath (repoPath parent))
, File dest , File dest
] ]
unless cloned $ unless inited $
giveup "git clone failed" giveup "git init failed"
simrepo <- Git.Construct.fromPath (toRawFilePath dest) simrepo <- Git.Construct.fromPath (toRawFilePath dest)
ast <- Annex.new simrepo ast <- Annex.new simrepo
((), ast') <- Annex.run ast $ doQuietAction $ do ((), ast') <- Annex.run ast $ doQuietAction $ do
-- Disconnect simulated repository from origin, so its
-- git-annex branch is not used, and also to prevent any
-- accidental foot shooting pushes to it.
inRepo $ Git.Remote.Remove.remove "origin"
storeUUID u storeUUID u
-- Prevent merging this simulated git-annex branch with -- Prevent merging this simulated git-annex branch with
-- any real one. Writing to the git-annex branch here also -- any real one.
-- avoids checkSharedClone enabling the shared clone
-- setting, which is not wanted here.
recordDifferences simulationDifferences u recordDifferences simulationDifferences u
let desc = simulatedRepositoryDescription simreponame let desc = simulatedRepositoryDescription simreponame
initialize startupAnnex (Just desc) Nothing initialize startupAnnex (Just desc) Nothing
@ -639,6 +663,7 @@ cloneSimRepo simreponame u parent dest st = do
, simRepoCurrState = emptySimState , simRepoCurrState = emptySimState
(simRng st) (simRng st)
(simGetExistingRepoByName st) (simGetExistingRepoByName st)
(simGetSimRepoPath st)
, simRepoName = simreponame , simRepoName = simreponame
} }
@ -649,6 +674,26 @@ simulatedRepositoryDescription simreponame =
simulationDifferences :: Differences simulationDifferences :: Differences
simulationDifferences = mkDifferences $ S.singleton Simulation simulationDifferences = mkDifferences $ S.singleton Simulation
runSimRepo :: RepoName -> SimState -> (SimRepoState -> Annex SimState) -> IO SimState
runSimRepo reponame st a = do
st' <- updateSimRepos st
case M.lookup reponame (simRepoState st') of
Just rst -> case simRepo rst of
Just sr -> do
(st'', strd) <- Annex.run (simRepoAnnex sr) $
doQuietAction (a rst)
let sr' = sr
{ simRepoAnnex = strd
}
return $ st''
{ simRepoState = M.adjust
(\rst' -> rst' { simRepo = Just sr' })
(simRepoName sr)
(simRepoState st'')
}
Nothing -> error $ "runSimRepo simRepo not set for " ++ fromRepoName reponame
Nothing -> error $ "runSimRepo simRepoState not found for " ++ fromRepoName reponame
updateSimRepoState :: SimState -> SimRepo -> IO SimRepo updateSimRepoState :: SimState -> SimRepo -> IO SimRepo
updateSimRepoState newst sr = do updateSimRepoState newst sr = do
((), (ast, ard)) <- Annex.run (simRepoAnnex sr) $ doQuietAction $ do ((), (ast, ard)) <- Annex.run (simRepoAnnex sr) $ doQuietAction $ do
@ -693,9 +738,9 @@ updateSimRepoState newst sr = do
, removeDiff = const . flip recordMaxSize (MaxSize 0) , removeDiff = const . flip recordMaxSize (MaxSize 0)
} }
updateField oldst newst getlocations $ DiffUpdate updateField oldst newst getlocations $ DiffUpdate
{ replaceDiff = \k oldls newls -> do { replaceDiff = \k newls oldls -> do
let olds = getSimLocations' oldls
let news = getSimLocations' newls let news = getSimLocations' newls
let olds = getSimLocations' oldls
setlocations InfoPresent k setlocations InfoPresent k
(S.difference news olds) (S.difference news olds)
setlocations InfoMissing k setlocations InfoMissing k
@ -730,7 +775,8 @@ updateSimRepoState newst sr = do
getlocations = maybe mempty simLocations getlocations = maybe mempty simLocations
. M.lookup (simRepoName sr) . M.lookup (simRepoName sr)
. simRepoState . simRepoState
setlocations s k = mapM_ (\l -> logChange NoLiveUpdate k l s) setlocations s k =
mapM_ (\l -> logChange NoLiveUpdate k l s)
data DiffUpdate a b m = DiffUpdate data DiffUpdate a b m = DiffUpdate
{ replaceDiff :: a -> b -> b -> m () { replaceDiff :: a -> b -> b -> m ()

View file

@ -5,11 +5,12 @@
- Licensed under the GNU AGPL version 3 or higher. - Licensed under the GNU AGPL version 3 or higher.
-} -}
{-# LANGUAGE OverloadedStrings #-}
module Command.Sim where module Command.Sim where
import Command import Command
import Annex.Sim import Annex.Sim
import qualified Annex
import Utility.Tmp.Dir import Utility.Tmp.Dir
import System.Random import System.Random
@ -23,16 +24,18 @@ seek :: CmdParams -> CommandSeek
seek _ = do seek _ = do
rng <- initStdGen rng <- initStdGen
repobyname <- mkGetExistingRepoByName repobyname <- mkGetExistingRepoByName
r <- Annex.gitRepo
withTmpDir "sim" $ \tmpdir -> do withTmpDir "sim" $ \tmpdir -> do
let st = emptySimState rng repobyname let getpath = GetSimRepoPath $ \u -> tmpdir </> fromUUID u
let st = emptySimState rng repobyname getpath
st' <- runSimCommand (CommandInit (RepoName "foo")) st st' <- runSimCommand (CommandInit (RepoName "foo")) st
>>= runSimCommand (CommandTrustLevel (RepoName "foo") "trusted") >>= runSimCommand (CommandTrustLevel (RepoName "foo") "trusted")
>>= runSimCommand (CommandUse (RepoName "bar") "here") >>= runSimCommand (CommandUse (RepoName "bar") "here")
>>= runSimCommand (CommandConnect (RepoName "foo") (RemoteName "bar")) >>= runSimCommand (CommandConnect (RepoName "foo") (RemoteName "bar"))
>>= runSimCommand (CommandAdd "foo" 100000 (RepoName "foo")) >>= runSimCommand (CommandConnect (RepoName "bar") (RemoteName "foo"))
let simdir = \u -> tmpdir </> fromUUID u >>= runSimCommand (CommandAdd "bigfile" 1000000 (RepoName "foo"))
st'' <- liftIO $ updateSimRepos r simdir st' >>= runSimCommand (CommandAction (RepoName "bar") (ActionGitPull (RemoteName "foo")))
>>= runSimCommand (CommandAction (RepoName "bar") (ActionGetWanted (RemoteName "foo")))
st'' <- liftIO $ updateSimRepos st'
liftIO $ print tmpdir liftIO $ print tmpdir
_ <- liftIO $ getLine _ <- liftIO $ getLine
return () return ()