REMOVE-BEFORE and GETTIMESTAMP

Only implemented server side, not used client side yet.

And not yet implemented for proxies/clusters, for which there's a build
warning about unhandled cases.

This is P2P protocol version 3. Probably will be the only change in that
version..

Added a dependency on clock to access a monotonic clock.
On i386-ancient, that is at version 0.2.0.0.
This commit is contained in:
Joey Hess 2024-07-03 16:59:22 -04:00
parent 665d3d66a5
commit 543c610a31
No known key found for this signature in database
GPG key ID: DB12DB0FF05F8F38
9 changed files with 159 additions and 27 deletions

View file

@ -56,7 +56,7 @@ defaultProtocolVersion :: ProtocolVersion
defaultProtocolVersion = ProtocolVersion 0
maxProtocolVersion :: ProtocolVersion
maxProtocolVersion = ProtocolVersion 2
maxProtocolVersion = ProtocolVersion 3
newtype ProtoAssociatedFile = ProtoAssociatedFile AssociatedFile
deriving (Show)
@ -71,6 +71,9 @@ data Validity = Valid | Invalid
newtype Bypass = Bypass (S.Set UUID)
deriving (Show, Monoid, Semigroup)
newtype MonotonicTimestamp = MonotonicTimestamp Integer
deriving (Show, Eq, Ord)
-- | Messages in the protocol. The peer that makes the connection
-- always initiates requests, and the other peer makes responses to them.
data Message
@ -86,6 +89,8 @@ data Message
| LOCKCONTENT Key
| UNLOCKCONTENT
| REMOVE Key
| REMOVE_BEFORE MonotonicTimestamp Key
| GETTIMESTAMP
| GET Offset ProtoAssociatedFile Key
| PUT ProtoAssociatedFile Key
| PUT_FROM Offset
@ -98,6 +103,7 @@ data Message
| BYPASS Bypass
| DATA Len -- followed by bytes of data
| VALIDITY Validity
| TIMESTAMP MonotonicTimestamp
| ERROR String
deriving (Show)
@ -114,6 +120,8 @@ instance Proto.Sendable Message where
formatMessage (LOCKCONTENT key) = ["LOCKCONTENT", Proto.serialize key]
formatMessage UNLOCKCONTENT = ["UNLOCKCONTENT"]
formatMessage (REMOVE key) = ["REMOVE", Proto.serialize key]
formatMessage (REMOVE_BEFORE ts key) = ["REMOVE-BEFORE", Proto.serialize ts, Proto.serialize key]
formatMessage GETTIMESTAMP = ["GETTIMESTAMP"]
formatMessage (GET offset af key) = ["GET", Proto.serialize offset, Proto.serialize af, Proto.serialize key]
formatMessage (PUT af key) = ["PUT", Proto.serialize af, Proto.serialize key]
formatMessage (PUT_FROM offset) = ["PUT-FROM", Proto.serialize offset]
@ -124,9 +132,10 @@ instance Proto.Sendable Message where
formatMessage FAILURE = ["FAILURE"]
formatMessage (FAILURE_PLUS uuids) = ("FAILURE-PLUS":map Proto.serialize uuids)
formatMessage (BYPASS (Bypass uuids)) = ("BYPASS":map Proto.serialize (S.toList uuids))
formatMessage (DATA len) = ["DATA", Proto.serialize len]
formatMessage (VALIDITY Valid) = ["VALID"]
formatMessage (VALIDITY Invalid) = ["INVALID"]
formatMessage (DATA len) = ["DATA", Proto.serialize len]
formatMessage (TIMESTAMP ts) = ["TIMESTAMP", Proto.serialize ts]
formatMessage (ERROR err) = ["ERROR", Proto.serialize err]
instance Proto.Receivable Message where
@ -142,6 +151,8 @@ instance Proto.Receivable Message where
parseCommand "LOCKCONTENT" = Proto.parse1 LOCKCONTENT
parseCommand "UNLOCKCONTENT" = Proto.parse0 UNLOCKCONTENT
parseCommand "REMOVE" = Proto.parse1 REMOVE
parseCommand "REMOVE-BEFORE" = Proto.parse2 REMOVE_BEFORE
parseCommand "GETTIMESTAMP" = Proto.parse0 GETTIMESTAMP
parseCommand "GET" = Proto.parse3 GET
parseCommand "PUT" = Proto.parse2 PUT
parseCommand "PUT-FROM" = Proto.parse1 PUT_FROM
@ -153,9 +164,10 @@ instance Proto.Receivable Message where
parseCommand "FAILURE-PLUS" = Proto.parseList FAILURE_PLUS
parseCommand "BYPASS" = Proto.parseList (BYPASS . Bypass . S.fromList)
parseCommand "DATA" = Proto.parse1 DATA
parseCommand "ERROR" = Proto.parse1 ERROR
parseCommand "VALID" = Proto.parse0 (VALIDITY Valid)
parseCommand "INVALID" = Proto.parse0 (VALIDITY Invalid)
parseCommand "TIMESTAMP" = Proto.parse1 TIMESTAMP
parseCommand "ERROR" = Proto.parse1 ERROR
parseCommand _ = Proto.parseFail
instance Proto.Serializable ProtocolVersion where
@ -170,6 +182,10 @@ instance Proto.Serializable Len where
serialize (Len n) = show n
deserialize = Len <$$> readish
instance Proto.Serializable MonotonicTimestamp where
serialize (MonotonicTimestamp n) = show n
deserialize = MonotonicTimestamp <$$> readish
instance Proto.Serializable Service where
serialize UploadPack = "git-upload-pack"
serialize ReceivePack = "git-receive-pack"
@ -249,6 +265,7 @@ data NetF c
| SetProtocolVersion ProtocolVersion c
--- ^ Called when a new protocol version has been negotiated.
| GetProtocolVersion (ProtocolVersion -> c)
| GetMonotonicTimestamp (MonotonicTimestamp -> c)
deriving (Functor)
type Net = Free NetF
@ -294,9 +311,11 @@ data LocalF c
| SetPresent Key UUID c
| CheckContentPresent Key (Bool -> c)
-- ^ Checks if the whole content of the key is locally present.
| RemoveContent Key (Bool -> c)
| RemoveContent Key (Maybe MonotonicTimestamp) (Bool -> c)
-- ^ If the content is not present, still succeeds.
-- May fail if not enough copies to safely drop, etc.
-- After locking the content for removal, checks if it's later
-- than the MonotonicTimestamp, and fails.
| TryLockContent Key (Bool -> Proto ()) c
-- ^ Try to lock the content of a key, preventing it
-- from being deleted, while running the provided protocol
@ -488,13 +507,13 @@ serveAuthed servermode myuuid = void $ serverLoop handler
sendSuccess =<< local (checkContentPresent key)
return ServerContinue
handler (REMOVE key) =
checkREMOVEServerMode servermode $ \case
Nothing -> do
sendSuccess =<< local (removeContent key)
return ServerContinue
Just notallowed -> do
notallowed
return ServerContinue
handleremove key Nothing
handler (REMOVE_BEFORE ts key) =
handleremove key (Just ts)
handler GETTIMESTAMP = do
ts <- net getMonotonicTimestamp
net $ sendMessage $ TIMESTAMP ts
return ServerContinue
handler (PUT (ProtoAssociatedFile af) key) =
checkPUTServerMode servermode $ \case
Nothing -> handleput af key
@ -536,6 +555,15 @@ serveAuthed servermode myuuid = void $ serverLoop handler
when (observeBool v) $
local $ setPresent key myuuid
return ServerContinue
handleremove key mts =
checkREMOVEServerMode servermode $ \case
Nothing -> do
sendSuccess =<< local (removeContent key mts)
return ServerContinue
Just notallowed -> do
notallowed
return ServerContinue
sendReadOnlyError :: Proto ()
sendReadOnlyError = net $ sendMessage $