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:
parent
665d3d66a5
commit
543c610a31
9 changed files with 159 additions and 27 deletions
|
@ -2,6 +2,10 @@ git-annex (10.20240702) UNRELEASED; urgency=medium
|
||||||
|
|
||||||
* assistant: Fix a race condition that could cause a pointer file to
|
* assistant: Fix a race condition that could cause a pointer file to
|
||||||
get ingested into the annex.
|
get ingested into the annex.
|
||||||
|
* Avoid potential data loss in situations where git-annex-shell or
|
||||||
|
git-annex remotedaemon is killed while locking a key to prevent its
|
||||||
|
removal.
|
||||||
|
* Added a dependency on clock.
|
||||||
|
|
||||||
-- Joey Hess <id@joeyh.name> Tue, 02 Jul 2024 12:14:53 -0400
|
-- Joey Hess <id@joeyh.name> Tue, 02 Jul 2024 12:14:53 -0400
|
||||||
|
|
||||||
|
|
13
P2P/Annex.hs
13
P2P/Annex.hs
|
@ -110,15 +110,24 @@ runLocal runst runner a = case a of
|
||||||
case v of
|
case v of
|
||||||
Left e -> return $ Left $ ProtoFailureException e
|
Left e -> return $ Left $ ProtoFailureException e
|
||||||
Right result -> runner (next result)
|
Right result -> runner (next result)
|
||||||
RemoveContent k next -> do
|
RemoveContent k mts next -> do
|
||||||
let cleanup = do
|
let cleanup = do
|
||||||
logStatus k InfoMissing
|
logStatus k InfoMissing
|
||||||
return True
|
return True
|
||||||
|
let checkts = case mts of
|
||||||
|
Nothing -> return True
|
||||||
|
Just ts -> do
|
||||||
|
now <- liftIO getMonotonicTimestampIO
|
||||||
|
return (now < ts)
|
||||||
v <- tryNonAsync $
|
v <- tryNonAsync $
|
||||||
ifM (Annex.Content.inAnnex k)
|
ifM (Annex.Content.inAnnex k)
|
||||||
( lockContentForRemoval k cleanup $ \contentlock -> do
|
( lockContentForRemoval k cleanup $ \contentlock ->
|
||||||
|
ifM checkts
|
||||||
|
( do
|
||||||
removeAnnex contentlock
|
removeAnnex contentlock
|
||||||
cleanup
|
cleanup
|
||||||
|
, return False
|
||||||
|
)
|
||||||
, return True
|
, return True
|
||||||
)
|
)
|
||||||
case v of
|
case v of
|
||||||
|
|
12
P2P/IO.hs
12
P2P/IO.hs
|
@ -25,6 +25,7 @@ module P2P.IO
|
||||||
, describeProtoFailure
|
, describeProtoFailure
|
||||||
, runNetProto
|
, runNetProto
|
||||||
, runNet
|
, runNet
|
||||||
|
, getMonotonicTimestampIO
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Common
|
import Common
|
||||||
|
@ -53,6 +54,11 @@ import qualified Data.ByteString as B
|
||||||
import qualified Data.ByteString.Lazy as L
|
import qualified Data.ByteString.Lazy as L
|
||||||
import qualified Network.Socket as S
|
import qualified Network.Socket as S
|
||||||
import System.PosixCompat.Files (groupReadMode, groupWriteMode, otherReadMode, otherWriteMode)
|
import System.PosixCompat.Files (groupReadMode, groupWriteMode, otherReadMode, otherWriteMode)
|
||||||
|
#if MIN_VERSION_clock(0,3,0)
|
||||||
|
import qualified System.Clock as Clock
|
||||||
|
#else
|
||||||
|
import qualified System.Posix.Clock as Clock
|
||||||
|
#endif
|
||||||
|
|
||||||
-- Type of interpreters of the Proto free monad.
|
-- Type of interpreters of the Proto free monad.
|
||||||
type RunProto m = forall a. Proto a -> m (Either ProtoFailure a)
|
type RunProto m = forall a. Proto a -> m (Either ProtoFailure a)
|
||||||
|
@ -282,6 +288,8 @@ runNet runst conn runner f = case f of
|
||||||
runner next
|
runner next
|
||||||
GetProtocolVersion next ->
|
GetProtocolVersion next ->
|
||||||
liftIO (readTVarIO versiontvar) >>= runner . next
|
liftIO (readTVarIO versiontvar) >>= runner . next
|
||||||
|
GetMonotonicTimestamp next ->
|
||||||
|
liftIO getMonotonicTimestampIO >>= runner . next
|
||||||
where
|
where
|
||||||
-- This is only used for running Net actions when relaying,
|
-- This is only used for running Net actions when relaying,
|
||||||
-- so it's ok to use runNetProto, despite it not supporting
|
-- so it's ok to use runNetProto, despite it not supporting
|
||||||
|
@ -452,3 +460,7 @@ relayReader v hout = loop
|
||||||
else getsome (b:bs)
|
else getsome (b:bs)
|
||||||
|
|
||||||
chunk = 65536
|
chunk = 65536
|
||||||
|
|
||||||
|
getMonotonicTimestampIO :: IO MonotonicTimestamp
|
||||||
|
getMonotonicTimestampIO = (MonotonicTimestamp . fromIntegral . Clock.sec)
|
||||||
|
<$> Clock.getTime Clock.Monotonic
|
||||||
|
|
|
@ -56,7 +56,7 @@ defaultProtocolVersion :: ProtocolVersion
|
||||||
defaultProtocolVersion = ProtocolVersion 0
|
defaultProtocolVersion = ProtocolVersion 0
|
||||||
|
|
||||||
maxProtocolVersion :: ProtocolVersion
|
maxProtocolVersion :: ProtocolVersion
|
||||||
maxProtocolVersion = ProtocolVersion 2
|
maxProtocolVersion = ProtocolVersion 3
|
||||||
|
|
||||||
newtype ProtoAssociatedFile = ProtoAssociatedFile AssociatedFile
|
newtype ProtoAssociatedFile = ProtoAssociatedFile AssociatedFile
|
||||||
deriving (Show)
|
deriving (Show)
|
||||||
|
@ -71,6 +71,9 @@ data Validity = Valid | Invalid
|
||||||
newtype Bypass = Bypass (S.Set UUID)
|
newtype Bypass = Bypass (S.Set UUID)
|
||||||
deriving (Show, Monoid, Semigroup)
|
deriving (Show, Monoid, Semigroup)
|
||||||
|
|
||||||
|
newtype MonotonicTimestamp = MonotonicTimestamp Integer
|
||||||
|
deriving (Show, Eq, Ord)
|
||||||
|
|
||||||
-- | Messages in the protocol. The peer that makes the connection
|
-- | Messages in the protocol. The peer that makes the connection
|
||||||
-- always initiates requests, and the other peer makes responses to them.
|
-- always initiates requests, and the other peer makes responses to them.
|
||||||
data Message
|
data Message
|
||||||
|
@ -86,6 +89,8 @@ data Message
|
||||||
| LOCKCONTENT Key
|
| LOCKCONTENT Key
|
||||||
| UNLOCKCONTENT
|
| UNLOCKCONTENT
|
||||||
| REMOVE Key
|
| REMOVE Key
|
||||||
|
| REMOVE_BEFORE MonotonicTimestamp Key
|
||||||
|
| GETTIMESTAMP
|
||||||
| GET Offset ProtoAssociatedFile Key
|
| GET Offset ProtoAssociatedFile Key
|
||||||
| PUT ProtoAssociatedFile Key
|
| PUT ProtoAssociatedFile Key
|
||||||
| PUT_FROM Offset
|
| PUT_FROM Offset
|
||||||
|
@ -98,6 +103,7 @@ data Message
|
||||||
| BYPASS Bypass
|
| BYPASS Bypass
|
||||||
| DATA Len -- followed by bytes of data
|
| DATA Len -- followed by bytes of data
|
||||||
| VALIDITY Validity
|
| VALIDITY Validity
|
||||||
|
| TIMESTAMP MonotonicTimestamp
|
||||||
| ERROR String
|
| ERROR String
|
||||||
deriving (Show)
|
deriving (Show)
|
||||||
|
|
||||||
|
@ -114,6 +120,8 @@ instance Proto.Sendable Message where
|
||||||
formatMessage (LOCKCONTENT key) = ["LOCKCONTENT", Proto.serialize key]
|
formatMessage (LOCKCONTENT key) = ["LOCKCONTENT", Proto.serialize key]
|
||||||
formatMessage UNLOCKCONTENT = ["UNLOCKCONTENT"]
|
formatMessage UNLOCKCONTENT = ["UNLOCKCONTENT"]
|
||||||
formatMessage (REMOVE key) = ["REMOVE", Proto.serialize key]
|
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 (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 af key) = ["PUT", Proto.serialize af, Proto.serialize key]
|
||||||
formatMessage (PUT_FROM offset) = ["PUT-FROM", Proto.serialize offset]
|
formatMessage (PUT_FROM offset) = ["PUT-FROM", Proto.serialize offset]
|
||||||
|
@ -124,9 +132,10 @@ instance Proto.Sendable Message where
|
||||||
formatMessage FAILURE = ["FAILURE"]
|
formatMessage FAILURE = ["FAILURE"]
|
||||||
formatMessage (FAILURE_PLUS uuids) = ("FAILURE-PLUS":map Proto.serialize uuids)
|
formatMessage (FAILURE_PLUS uuids) = ("FAILURE-PLUS":map Proto.serialize uuids)
|
||||||
formatMessage (BYPASS (Bypass uuids)) = ("BYPASS":map Proto.serialize (S.toList 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 Valid) = ["VALID"]
|
||||||
formatMessage (VALIDITY Invalid) = ["INVALID"]
|
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]
|
formatMessage (ERROR err) = ["ERROR", Proto.serialize err]
|
||||||
|
|
||||||
instance Proto.Receivable Message where
|
instance Proto.Receivable Message where
|
||||||
|
@ -142,6 +151,8 @@ instance Proto.Receivable Message where
|
||||||
parseCommand "LOCKCONTENT" = Proto.parse1 LOCKCONTENT
|
parseCommand "LOCKCONTENT" = Proto.parse1 LOCKCONTENT
|
||||||
parseCommand "UNLOCKCONTENT" = Proto.parse0 UNLOCKCONTENT
|
parseCommand "UNLOCKCONTENT" = Proto.parse0 UNLOCKCONTENT
|
||||||
parseCommand "REMOVE" = Proto.parse1 REMOVE
|
parseCommand "REMOVE" = Proto.parse1 REMOVE
|
||||||
|
parseCommand "REMOVE-BEFORE" = Proto.parse2 REMOVE_BEFORE
|
||||||
|
parseCommand "GETTIMESTAMP" = Proto.parse0 GETTIMESTAMP
|
||||||
parseCommand "GET" = Proto.parse3 GET
|
parseCommand "GET" = Proto.parse3 GET
|
||||||
parseCommand "PUT" = Proto.parse2 PUT
|
parseCommand "PUT" = Proto.parse2 PUT
|
||||||
parseCommand "PUT-FROM" = Proto.parse1 PUT_FROM
|
parseCommand "PUT-FROM" = Proto.parse1 PUT_FROM
|
||||||
|
@ -153,9 +164,10 @@ instance Proto.Receivable Message where
|
||||||
parseCommand "FAILURE-PLUS" = Proto.parseList FAILURE_PLUS
|
parseCommand "FAILURE-PLUS" = Proto.parseList FAILURE_PLUS
|
||||||
parseCommand "BYPASS" = Proto.parseList (BYPASS . Bypass . S.fromList)
|
parseCommand "BYPASS" = Proto.parseList (BYPASS . Bypass . S.fromList)
|
||||||
parseCommand "DATA" = Proto.parse1 DATA
|
parseCommand "DATA" = Proto.parse1 DATA
|
||||||
parseCommand "ERROR" = Proto.parse1 ERROR
|
|
||||||
parseCommand "VALID" = Proto.parse0 (VALIDITY Valid)
|
parseCommand "VALID" = Proto.parse0 (VALIDITY Valid)
|
||||||
parseCommand "INVALID" = Proto.parse0 (VALIDITY Invalid)
|
parseCommand "INVALID" = Proto.parse0 (VALIDITY Invalid)
|
||||||
|
parseCommand "TIMESTAMP" = Proto.parse1 TIMESTAMP
|
||||||
|
parseCommand "ERROR" = Proto.parse1 ERROR
|
||||||
parseCommand _ = Proto.parseFail
|
parseCommand _ = Proto.parseFail
|
||||||
|
|
||||||
instance Proto.Serializable ProtocolVersion where
|
instance Proto.Serializable ProtocolVersion where
|
||||||
|
@ -170,6 +182,10 @@ instance Proto.Serializable Len where
|
||||||
serialize (Len n) = show n
|
serialize (Len n) = show n
|
||||||
deserialize = Len <$$> readish
|
deserialize = Len <$$> readish
|
||||||
|
|
||||||
|
instance Proto.Serializable MonotonicTimestamp where
|
||||||
|
serialize (MonotonicTimestamp n) = show n
|
||||||
|
deserialize = MonotonicTimestamp <$$> readish
|
||||||
|
|
||||||
instance Proto.Serializable Service where
|
instance Proto.Serializable Service where
|
||||||
serialize UploadPack = "git-upload-pack"
|
serialize UploadPack = "git-upload-pack"
|
||||||
serialize ReceivePack = "git-receive-pack"
|
serialize ReceivePack = "git-receive-pack"
|
||||||
|
@ -249,6 +265,7 @@ data NetF c
|
||||||
| SetProtocolVersion ProtocolVersion c
|
| SetProtocolVersion ProtocolVersion c
|
||||||
--- ^ Called when a new protocol version has been negotiated.
|
--- ^ Called when a new protocol version has been negotiated.
|
||||||
| GetProtocolVersion (ProtocolVersion -> c)
|
| GetProtocolVersion (ProtocolVersion -> c)
|
||||||
|
| GetMonotonicTimestamp (MonotonicTimestamp -> c)
|
||||||
deriving (Functor)
|
deriving (Functor)
|
||||||
|
|
||||||
type Net = Free NetF
|
type Net = Free NetF
|
||||||
|
@ -294,9 +311,11 @@ data LocalF c
|
||||||
| SetPresent Key UUID c
|
| SetPresent Key UUID c
|
||||||
| CheckContentPresent Key (Bool -> c)
|
| CheckContentPresent Key (Bool -> c)
|
||||||
-- ^ Checks if the whole content of the key is locally present.
|
-- ^ 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.
|
-- ^ If the content is not present, still succeeds.
|
||||||
-- May fail if not enough copies to safely drop, etc.
|
-- 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
|
| TryLockContent Key (Bool -> Proto ()) c
|
||||||
-- ^ Try to lock the content of a key, preventing it
|
-- ^ Try to lock the content of a key, preventing it
|
||||||
-- from being deleted, while running the provided protocol
|
-- from being deleted, while running the provided protocol
|
||||||
|
@ -488,12 +507,12 @@ serveAuthed servermode myuuid = void $ serverLoop handler
|
||||||
sendSuccess =<< local (checkContentPresent key)
|
sendSuccess =<< local (checkContentPresent key)
|
||||||
return ServerContinue
|
return ServerContinue
|
||||||
handler (REMOVE key) =
|
handler (REMOVE key) =
|
||||||
checkREMOVEServerMode servermode $ \case
|
handleremove key Nothing
|
||||||
Nothing -> do
|
handler (REMOVE_BEFORE ts key) =
|
||||||
sendSuccess =<< local (removeContent key)
|
handleremove key (Just ts)
|
||||||
return ServerContinue
|
handler GETTIMESTAMP = do
|
||||||
Just notallowed -> do
|
ts <- net getMonotonicTimestamp
|
||||||
notallowed
|
net $ sendMessage $ TIMESTAMP ts
|
||||||
return ServerContinue
|
return ServerContinue
|
||||||
handler (PUT (ProtoAssociatedFile af) key) =
|
handler (PUT (ProtoAssociatedFile af) key) =
|
||||||
checkPUTServerMode servermode $ \case
|
checkPUTServerMode servermode $ \case
|
||||||
|
@ -537,6 +556,15 @@ serveAuthed servermode myuuid = void $ serverLoop handler
|
||||||
local $ setPresent key myuuid
|
local $ setPresent key myuuid
|
||||||
return ServerContinue
|
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 :: Proto ()
|
||||||
sendReadOnlyError = net $ sendMessage $
|
sendReadOnlyError = net $ sendMessage $
|
||||||
ERROR "this repository is read-only; write access denied"
|
ERROR "this repository is read-only; write access denied"
|
||||||
|
|
1
debian/control
vendored
1
debian/control
vendored
|
@ -84,6 +84,7 @@ Build-Depends:
|
||||||
libghc-filepath-bytestring-dev,
|
libghc-filepath-bytestring-dev,
|
||||||
libghc-git-lfs-dev (>= 1.2.0),
|
libghc-git-lfs-dev (>= 1.2.0),
|
||||||
libghc-criterion-dev,
|
libghc-criterion-dev,
|
||||||
|
libghc-clock-dev,
|
||||||
lsof [linux-any],
|
lsof [linux-any],
|
||||||
ikiwiki,
|
ikiwiki,
|
||||||
libimage-magick-perl,
|
libimage-magick-perl,
|
||||||
|
|
|
@ -55,7 +55,7 @@ any authentication.
|
||||||
|
|
||||||
The client sends the highest protocol version it supports:
|
The client sends the highest protocol version it supports:
|
||||||
|
|
||||||
VERSION 2
|
VERSION 3
|
||||||
|
|
||||||
The server responds with the highest protocol version it supports
|
The server responds with the highest protocol version it supports
|
||||||
that is less than or equal to the version the client sent:
|
that is less than or equal to the version the client sent:
|
||||||
|
@ -134,6 +134,32 @@ In protocol version 2, the server can optionally reply with SUCCESS-PLUS
|
||||||
or FAILURE-PLUS. Each has a subsequent list of UUIDs of repositories
|
or FAILURE-PLUS. Each has a subsequent list of UUIDs of repositories
|
||||||
that the content was removed from.
|
that the content was removed from.
|
||||||
|
|
||||||
|
## Removing content before a specified time
|
||||||
|
|
||||||
|
This is only available in protocol version 3 and above.
|
||||||
|
|
||||||
|
To remove a key's content from the server, but only before a specified time,
|
||||||
|
the client sends:
|
||||||
|
|
||||||
|
REMOVE-BEFORE Timestamp Key
|
||||||
|
|
||||||
|
The server responds to the message in the same way as to REMOVE.
|
||||||
|
|
||||||
|
If the server receives the message at a time after the specified timestamp,
|
||||||
|
the remove must fail. This is used to avoid removing content after a point
|
||||||
|
in time where it is no longer locked in other repostitories.
|
||||||
|
|
||||||
|
## Getting a timestamp
|
||||||
|
|
||||||
|
This is only available in protocol version 3 and above.
|
||||||
|
|
||||||
|
To get the current timestamp from the server, the client sends:
|
||||||
|
|
||||||
|
GETTIMESTAMP
|
||||||
|
|
||||||
|
The server responds with TIMESTAMP followed by its current time, as a
|
||||||
|
number of seconds. Note that this uses a monotonic clock.
|
||||||
|
|
||||||
## Storing content on the server
|
## Storing content on the server
|
||||||
|
|
||||||
To store content on the server, the client sends:
|
To store content on the server, the client sends:
|
||||||
|
|
|
@ -24,14 +24,14 @@ may want git-annex to use HTTP in eg a LAN.
|
||||||
|
|
||||||
Each request in the protocol is versioned. The versions correspond
|
Each request in the protocol is versioned. The versions correspond
|
||||||
to P2P protocol versions, but for simplicity, the minimum version supported
|
to P2P protocol versions, but for simplicity, the minimum version supported
|
||||||
over HTTP is version 2. Every implementation of the HTTP protocol must
|
over HTTP is version 3. Every implementation of the HTTP protocol must
|
||||||
support version 2.
|
support version 3.
|
||||||
|
|
||||||
The protocol version comes before the request. Eg: `/git-annex/v2/put`
|
The protocol version comes before the request. Eg: `/git-annex/v3/put`
|
||||||
|
|
||||||
If the server does not support a particular protocol version, the
|
If the server does not support a particular protocol version, the
|
||||||
request will fail with a 404, and the client should fall back to an earlier
|
request will fail with a 404, and the client should fall back to an earlier
|
||||||
protocol version, eg version 2.
|
protocol version.
|
||||||
|
|
||||||
## common request parameters
|
## common request parameters
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ Checks if a key is currently present on the server.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
> POST /git-annex/v2/checkpresent?key=SHA1--foo&clientuuid=79a5a1f4-07e8-11ef-873d-97f93ca91925&serveruuid=ecf6d4ca-07e8-11ef-8990-9b8c1f696bf6 HTTP/1.1
|
> POST /git-annex/v3/checkpresent?key=SHA1--foo&clientuuid=79a5a1f4-07e8-11ef-873d-97f93ca91925&serveruuid=ecf6d4ca-07e8-11ef-8990-9b8c1f696bf6 HTTP/1.1
|
||||||
< SUCCESS
|
< SUCCESS
|
||||||
|
|
||||||
There is one required additional parameter, `key`.
|
There is one required additional parameter, `key`.
|
||||||
|
@ -99,13 +99,32 @@ or closes the websocket, the server unlocks the content.
|
||||||
XXX What happens if the connection times out? Will the client notice that
|
XXX What happens if the connection times out? Will the client notice that
|
||||||
in time? How does this work with P2P over ssh?
|
in time? How does this work with P2P over ssh?
|
||||||
|
|
||||||
|
### limit-remove
|
||||||
|
|
||||||
|
Limit the next requested removal of a key to occur within a specified
|
||||||
|
number of seconds.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
> POST /git-annex/v3/limit-remove?seconds=600&key=SHA1--foo&clientuuid=79a5a1f4-07e8-11ef-873d-97f93ca91925&serveruuid=ecf6d4ca-07e8-11ef-8990-9b8c1f696bf6 HTTP/1.1
|
||||||
|
< SUCCESS
|
||||||
|
|
||||||
|
There are two required additional parameters, `key` and `seconds`.
|
||||||
|
|
||||||
|
The body of the request is empty.
|
||||||
|
|
||||||
|
The server responds with "SUCCESS".
|
||||||
|
|
||||||
|
The server will check the next `remove` request, and if it's for the same key,
|
||||||
|
and more time has elapsed, it will refuse to remove the key's content.
|
||||||
|
|
||||||
### remove
|
### remove
|
||||||
|
|
||||||
Remove a key's content from the server.
|
Remove a key's content from the server.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
> POST /git-annex/v2/remove?key=SHA1--foo&clientuuid=79a5a1f4-07e8-11ef-873d-97f93ca91925&serveruuid=ecf6d4ca-07e8-11ef-8990-9b8c1f696bf6 HTTP/1.1
|
> POST /git-annex/v3/remove?key=SHA1--foo&clientuuid=79a5a1f4-07e8-11ef-873d-97f93ca91925&serveruuid=ecf6d4ca-07e8-11ef-8990-9b8c1f696bf6 HTTP/1.1
|
||||||
< SUCCESS
|
< SUCCESS
|
||||||
|
|
||||||
There is one required additional parameter, `key`.
|
There is one required additional parameter, `key`.
|
||||||
|
@ -125,13 +144,46 @@ If the server was prevented from trying to remove the key due to a policy
|
||||||
(eg due to being read-only or append-only, it will respond with "ERROR",
|
(eg due to being read-only or append-only, it will respond with "ERROR",
|
||||||
followed by a space and an error message.
|
followed by a space and an error message.
|
||||||
|
|
||||||
|
## remove-before
|
||||||
|
|
||||||
|
Remove a key's content from the server, but only before a specified time.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
> POST /git-annex/v3/remove-before?timestamp=4949292929&key=SHA1--foo&clientuuid=79a5a1f4-07e8-11ef-873d-97f93ca91925&serveruuid=ecf6d4ca-07e8-11ef-8990-9b8c1f696bf6 HTTP/1.1
|
||||||
|
< SUCCESS
|
||||||
|
|
||||||
|
This is the same as the `remove` request, but with an additional parameter,
|
||||||
|
`timestamp`.
|
||||||
|
|
||||||
|
If the server's clock is past the specified timestamp, the removal will
|
||||||
|
fail. This is used to avoid removing content after a point in time where it
|
||||||
|
is no longer locked in other repostitories.
|
||||||
|
|
||||||
|
## gettimestamp
|
||||||
|
|
||||||
|
Gets the current timestamp from the server.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
> POST /git-annex/v3/gettimestamp?clientuuid=79a5a1f4-07e8-11ef-873d-97f93ca91925&serveruuid=ecf6d4ca-07e8-11ef-8990-9b8c1f696bf6 HTTP/1.1
|
||||||
|
< TIMESTAMP 59459392
|
||||||
|
|
||||||
|
The body of the request is empty.
|
||||||
|
|
||||||
|
The server responds with "TIMESTAMP" followed by a space and the current
|
||||||
|
value of its monotonic clock, as a number of seconds.
|
||||||
|
|
||||||
|
Important: If multiple servers are serving this protocol for the same
|
||||||
|
repository, they MUST all use the same monotonic clock.
|
||||||
|
|
||||||
### put
|
### put
|
||||||
|
|
||||||
Store content on the server.
|
Store content on the server.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
> POST /git-annex/v2/put?key=SHA1--foo&associatedfile=bar&clientuuid=79a5a1f4-07e8-11ef-873d-97f93ca91925&serveruuid=ecf6d4ca-07e8-11ef-8990-9b8c1f696bf6 HTTP/1.1
|
> POST /git-annex/v3/put?key=SHA1--foo&associatedfile=bar&clientuuid=79a5a1f4-07e8-11ef-873d-97f93ca91925&serveruuid=ecf6d4ca-07e8-11ef-8990-9b8c1f696bf6 HTTP/1.1
|
||||||
> Content-Type: application/octet-stream
|
> Content-Type: application/octet-stream
|
||||||
> Content-Length: 4
|
> Content-Length: 4
|
||||||
> foo1
|
> foo1
|
||||||
|
@ -186,7 +238,7 @@ the `put` request failing.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
> POST /git-annex/v2/putoffset?key=SHA1--foo&clientuuid=79a5a1f4-07e8-11ef-873d-97f93ca91925&serveruuid=ecf6d4ca-07e8-11ef-8990-9b8c1f696bf6 HTTP/1.1
|
> POST /git-annex/v3/putoffset?key=SHA1--foo&clientuuid=79a5a1f4-07e8-11ef-873d-97f93ca91925&serveruuid=ecf6d4ca-07e8-11ef-8990-9b8c1f696bf6 HTTP/1.1
|
||||||
< 10
|
< 10
|
||||||
|
|
||||||
There is one required additional parameter, `key`.
|
There is one required additional parameter, `key`.
|
||||||
|
@ -211,7 +263,7 @@ Get content from the server.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
> POST /git-annex/v2/get?key=SHA1--foo&associatedfile=bar&clientuuid=79a5a1f4-07e8-11ef-873d-97f93ca91925&serveruuid=ecf6d4ca-07e8-11ef-8990-9b8c1f696bf6 HTTP/1.1
|
> POST /git-annex/v3/get?key=SHA1--foo&associatedfile=bar&clientuuid=79a5a1f4-07e8-11ef-873d-97f93ca91925&serveruuid=ecf6d4ca-07e8-11ef-8990-9b8c1f696bf6 HTTP/1.1
|
||||||
< Content-Type: application/octet-stream
|
< Content-Type: application/octet-stream
|
||||||
< Content-Length: 4
|
< Content-Length: 4
|
||||||
< foo1
|
< foo1
|
||||||
|
|
|
@ -111,4 +111,3 @@ out to each client, by calling GETTIMESTAMP again and applying the offsets
|
||||||
between the cluster's clock and each node's clock.
|
between the cluster's clock and each node's clock.
|
||||||
|
|
||||||
This approach would need to use a monotonic clock!
|
This approach would need to use a monotonic clock!
|
||||||
>>>>>>> master
|
|
||||||
|
|
|
@ -278,7 +278,8 @@ Executable git-annex
|
||||||
DAV (>= 1.0),
|
DAV (>= 1.0),
|
||||||
network (>= 3.0.0.0),
|
network (>= 3.0.0.0),
|
||||||
network-bsd,
|
network-bsd,
|
||||||
git-lfs (>= 1.2.0)
|
git-lfs (>= 1.2.0),
|
||||||
|
clock (>= 0.2.0.0)
|
||||||
CC-Options: -Wall
|
CC-Options: -Wall
|
||||||
GHC-Options: -Wall -fno-warn-tabs -Wincomplete-uni-patterns
|
GHC-Options: -Wall -fno-warn-tabs -Wincomplete-uni-patterns
|
||||||
Default-Language: Haskell2010
|
Default-Language: Haskell2010
|
||||||
|
|
Loading…
Reference in a new issue