9828f45d85
This solves the problem of sameas remotes trampling over per-remote state. Used for: * per-remote state, of course * per-remote metadata, also of course * per-remote content identifiers, because two remote implementations could in theory generate the same content identifier for two different peices of content While chunk logs are per-remote data, they don't use this, because the number and size of chunks stored is a common property across sameas remotes. External special remote had a complication, where it was theoretically possible for a remote to send SETSTATE or GETSTATE during INITREMOTE or EXPORTSUPPORTED. Since the uuid of the remote is typically generate in Remote.setup, it would only be possible to pass a Maybe RemoteStateHandle into it, and it would otherwise have to construct its own. Rather than go that route, I decided to send an ERROR in this case. It seems unlikely that any existing external special remote will be affected. They would have to make up a git-annex key, and set state for some reason during INITREMOTE. I can imagine such a hack, but it doesn't seem worth complicating the code in such an ugly way to support it. Unfortunately, both TestRemote and Annex.Import needed the Remote to have a new field added that holds its RemoteStateHandle.
46 lines
1.3 KiB
Haskell
46 lines
1.3 KiB
Haskell
{- Remote state logs.
|
|
-
|
|
- Copyright 2014, 2019 Joey Hess <id@joeyh.name>
|
|
-
|
|
- Licensed under the GNU AGPL version 3 or higher.
|
|
-}
|
|
|
|
module Logs.RemoteState (
|
|
getRemoteState,
|
|
setRemoteState,
|
|
) where
|
|
|
|
import Annex.Common
|
|
import Types.RemoteState
|
|
import Logs
|
|
import Logs.UUIDBased
|
|
import qualified Annex.Branch
|
|
import qualified Annex
|
|
|
|
import qualified Data.Map as M
|
|
import qualified Data.ByteString.Lazy as L
|
|
import qualified Data.Attoparsec.ByteString.Lazy as A
|
|
import Data.ByteString.Builder
|
|
|
|
type RemoteState = String
|
|
|
|
setRemoteState :: RemoteStateHandle -> Key -> RemoteState -> Annex ()
|
|
setRemoteState (RemoteStateHandle u) k s = do
|
|
c <- liftIO currentVectorClock
|
|
config <- Annex.getGitConfig
|
|
Annex.Branch.change (remoteStateLogFile config k) $
|
|
buildRemoteState . changeLog c u s . parseRemoteState
|
|
|
|
buildRemoteState :: Log RemoteState -> Builder
|
|
buildRemoteState = buildLogNew (byteString . encodeBS)
|
|
|
|
getRemoteState :: RemoteStateHandle -> Key -> Annex (Maybe RemoteState)
|
|
getRemoteState (RemoteStateHandle u) k = do
|
|
config <- Annex.getGitConfig
|
|
extract . parseRemoteState
|
|
<$> Annex.Branch.get (remoteStateLogFile config k)
|
|
where
|
|
extract m = value <$> M.lookup u m
|
|
|
|
parseRemoteState :: L.ByteString -> Log RemoteState
|
|
parseRemoteState = parseLogNew (decodeBS <$> A.takeByteString)
|