##// END OF EJS Templates
exchangev2: fetch file revisions...
exchangev2: fetch file revisions Now that the server has an API for fetching file data, we can call into it to fetch file revisions. The implementation is relatively straightforward: we examine the manifests that we fetched and find all new file revisions referenced by them. We build up a mapping from file path to file nodes to manifest node. (The mapping to first manifest node allows us to map back to first changelog node/revision, which is used for the linkrev.) Once that map is built up, we iterate over it in a deterministic manner and fetch and store file data. The code is very similar to manifest fetching. So similar that we could probably extract the common bits into a generic function. With file data retrieval implemented, `hg clone` and `hg pull` are effectively feature complete, at least as far as the completeness of data transfer for essential repository data (changesets, manifests, files, phases, and bookmarks). We're still missing support for obsolescence markers, the hgtags fnodes cache, and the branchmap cache. But these are non-essential for the moment (and will be implemented later). This is a good point to assess the state of exchangev2 in terms of performance. I ran a local `hg clone` for the mozilla-unified repository using both version 1 and version 2 of the wire protocols and exchange methods. This is effectively comparing the performance of the wire protocol overhead and "getbundle" versus domain-specific commands. Wire protocol version 2 doesn't have compression implemented yet. So I tested version 1 with `server.compressionengines=none` to remove compression overhead from the equation. server before: user 220.420+0.000 sys 14.420+0.000 after: user 321.980+0.000 sys 18.990+0.000 client before: real 561.650 secs (user 497.670+0.000 sys 28.160+0.000) after: real 1226.260 secs (user 944.240+0.000 sys 354.150+0.000) We have substantial regressions on both client and server. This is obviously not desirable. I'm aware of some reasons: * Lack of hgtagsfnodes transfer (contributes significant CPU to client). * Lack of branch cache transfer (contributes significant CPU to client). * Little to no profiling / optimization performed on wire protocol version 2 code. * There appears to be a memory leak on the client and that is likely causing swapping on my machine. * Using multiple threads on the client may be counter-productive because Python. * We're not compressing on the server. * We're tracking file nodes on the client via manifest diffing rather than using linkrev shortcuts on the server. I'm pretty confident that most of these issues are addressable. But even if we can't get wire protocol version 2 on performance parity with "getbundle," I still think it is important to have the set of low level data-specific retrieval commands that we have implemented so far. This is because the existence of such commands allows flexibility in how clients access server data. Differential Revision: https://phab.mercurial-scm.org/D4491

File last commit:

r37823:8c8b6d13 stable
r39676:039bf1ed default
Show More
bundle2.txt
677 lines | 19.2 KiB | text/plain | TextLexer
Bundle2 refers to a data format that is used for both on-disk storage
and over-the-wire transfer of repository data and state.
The data format allows the capture of multiple components of
repository data. Contrast with the initial bundle format, which
only captured *changegroup* data (and couldn't store bookmarks,
phases, etc).
Bundle2 is used for:
* Transferring data from a repository (e.g. as part of an ``hg clone``
or ``hg pull`` operation).
* Transferring data to a repository (e.g. as part of an ``hg push``
operation).
* Storing data on disk (e.g. the result of an ``hg bundle``
operation).
* Transferring the results of a repository operation (e.g. the
reply to an ``hg push`` operation).
At its highest level, a bundle2 payload is a stream that begins
with some metadata and consists of a series of *parts*, with each
part describing repository data or state or the result of an
operation. New bundle2 parts are introduced over time when there is
a need to capture a new form of data. A *capabilities* mechanism
exists to allow peers to understand which bundle2 parts the other
understands.
Stream Format
=============
A bundle2 payload consists of a magic string (``HG20``) followed by
stream level parameters, followed by any number of payload *parts*.
It may help to think of the stream level parameters as *headers* and the
payload parts as the *body*.
Stream Level Parameters
-----------------------
Following the magic string is data that defines parameters applicable to the
entire payload.
Stream level parameters begin with a 32-bit unsigned big-endian integer.
The value of this integer defines the number of bytes of stream level
parameters that follow.
The *N* bytes of raw data contains a space separated list of parameters.
Each parameter consists of a required name and an optional value.
Parameters have the form ``<name>`` or ``<name>=<value>``.
Both the parameter name and value are URL quoted.
Names MUST start with a letter. If the first letter is lower case, the
parameter is advisory and can safely be ignored. If the first letter
is upper case, the parameter is mandatory and the handler MUST stop if
it is unable to process it.
Stream level parameters apply to the entire bundle2 payload. Lower-level
options should go into a bundle2 part instead.
The following stream level parameters are defined:
Compression
Compression format of payload data. ``GZ`` denotes zlib. ``BZ``
denotes bzip2. ``ZS`` denotes zstandard.
When defined, all bytes after the stream level parameters are
compressed using the compression format defined by this parameter.
If this parameter isn't present, data is raw/uncompressed.
This parameter MUST be mandatory because attempting to consume
streams without knowing how to decode the underlying bytes will
result in errors.
Payload Part
------------
Following the stream level parameters are 0 or more payload parts. Each
payload part consists of a header and a body.
The payload part header consists of a 32-bit unsigned big-endian integer
defining the number of bytes in the header that follow. The special
value ``0`` indicates the end of the bundle2 stream.
The binary format of the part header is as follows:
* 8-bit unsigned size of the part name
* N-bytes alphanumeric part name
* 32-bit unsigned big-endian part ID
* N bytes part parameter data
The *part name* identifies the type of the part. A part name with an
UPPERCASE letter is mandatory. Otherwise, the part is advisory. A
consumer should abort if it encounters a mandatory part it doesn't know
how to process. See the sections below for each defined part type.
The *part ID* is a unique identifier within the bundle used to refer to a
specific part. It should be unique within the bundle2 payload.
Part parameter data consists of:
* 1 byte number of mandatory parameters
* 1 byte number of advisory parameters
* 2 * N bytes of sizes of parameter key and values
* N * M blobs of values for parameter key and values
Following the 2 bytes of mandatory and advisory parameter counts are
2-tuples of bytes of the sizes of each parameter. e.g.
(<key size>, <value size>).
Following that are the raw values, without padding. Mandatory parameters
come first, followed by advisory parameters.
Each parameter's key MUST be unique within the part.
Following the part parameter data is the part payload. The part payload
consists of a series of framed chunks. The frame header is a 32-bit
big-endian integer defining the size of the chunk. The N bytes of raw
payload data follows.
The part payload consists of 0 or more chunks.
A chunk with size ``0`` denotes the end of the part payload. Therefore,
there will always be at least 1 32-bit integer following the payload
part header.
A chunk size of ``-1`` is used to signal an *interrupt*. If such a chunk
size is seen, the stream processor should process the next bytes as a new
payload part. After this payload part, processing of the original,
interrupted part should resume.
Capabilities
============
Bundle2 is a dynamic format that can evolve over time. For example,
when a new repository data concept is invented, a new bundle2 part
is typically invented to hold that data. In addition, parts performing
similar functionality may come into existence if there is a better
mechanism for performing certain functionality.
Because the bundle2 format evolves over time, peers need to understand
what bundle2 features the other can understand. The *capabilities*
mechanism is how those features are expressed.
Bundle2 capabilities are logically expressed as a dictionary of
string key-value pairs where the keys are strings and the values
are lists of strings.
Capabilities are encoded for exchange between peers. The encoded
capabilities blob consists of a newline (``\n``) delimited list of
entries. Each entry has the form ``<key>`` or ``<key>=<value>``,
depending if the capability has a value.
The capability name is URL quoted (``%XX`` encoding of URL unsafe
characters).
The value, if present, is formed by URL quoting each value in
the capability list and concatenating the result with a comma (``,``).
For example, the capabilities ``novaluekey`` and ``listvaluekey``
with values ``value 1`` and ``value 2``. This would be encoded as:
listvaluekey=value%201,value%202\nnovaluekey
The sections below detail the defined bundle2 capabilities.
HG20
----
Denotes that the peer supports the bundle2 data format.
bookmarks
---------
Denotes that the peer supports the ``bookmarks`` part.
Peers should not issue mandatory ``bookmarks`` parts unless this
capability is present.
changegroup
-----------
Denotes which versions of the *changegroup* format the peer can
receive. Values include ``01``, ``02``, and ``03``.
The peer should not generate changegroup data for a version not
specified by this capability.
checkheads
----------
Denotes which forms of heads checking the peer supports.
If ``related`` is in the value, then the peer supports the ``check:heads``
part and the peer is capable of detecting race conditions when applying
changelog data.
digests
-------
Denotes which hashing formats the peer supports.
Values are names of hashing function. Values include ``md5``, ``sha1``,
and ``sha512``.
error
-----
Denotes which ``error:`` parts the peer supports.
Value is a list of strings of ``error:`` part names. Valid values
include ``abort``, ``unsupportecontent``, ``pushraced``, and ``pushkey``.
Peers should not issue an ``error:`` part unless the type of that
part is listed as supported by this capability.
listkeys
--------
Denotes that the peer supports the ``listkeys`` part.
hgtagsfnodes
------------
Denotes that the peer supports the ``hgtagsfnodes`` part.
obsmarkers
----------
Denotes that the peer supports the ``obsmarker`` part and which versions
of the obsolescence data format it can receive. Values are strings like
``V<N>``. e.g. ``V1``.
phases
------
Denotes that the peer supports the ``phases`` part.
pushback
--------
Denotes that the peer supports sending/receiving bundle2 data in response
to a bundle2 request.
This capability is typically used by servers that employ server-side
rewriting of pushed repository data. For example, a server may wish to
automatically rebase pushed changesets. When this capability is present,
the server can send a bundle2 response containing the rewritten changeset
data and the client will apply it.
pushkey
-------
Denotes that the peer supports the ``puskey`` part.
remote-changegroup
------------------
Denotes that the peer supports the ``remote-changegroup`` part and
which protocols it can use to fetch remote changegroup data.
Values are protocol names. e.g. ``http`` and ``https``.
stream
------
Denotes that the peer supports ``stream*`` parts in order to support
*stream clone*.
Values are which ``stream*`` parts the peer supports. ``v2`` denotes
support for the ``stream2`` part.
Bundle2 Part Types
==================
The sections below detail the various bundle2 part types.
bookmarks
---------
The ``bookmarks`` part holds bookmarks information.
This part has no parameters.
The payload consists of entries defining bookmarks. Each entry consists of:
* 20 bytes binary changeset node.
* 2 bytes big endian short defining bookmark name length.
* N bytes defining bookmark name.
Receivers typically update bookmarks to match the state specified in
this part.
changegroup
-----------
The ``changegroup`` part contains *changegroup* data (changelog, manifestlog,
and filelog revision data).
The following part parameters are defined for this part.
version
Changegroup version string. e.g. ``01``, ``02``, and ``03``. This parameter
determines how to interpret the changegroup data within the part.
nbchanges
The number of changesets in this changegroup. This parameter can be used
to aid in the display of progress bars, etc during part application.
treemanifest
Whether the changegroup contains tree manifests.
targetphase
The target phase of changesets in this part. Value is an integer of
the target phase.
The payload of this part is raw changegroup data. See
:hg:`help internals.changegroups` for the format of changegroup data.
check:bookmarks
---------------
The ``check:bookmarks`` part is inserted into a bundle as a means for the
receiver to validate that the sender's known state of bookmarks matches
the receiver's.
This part has no parameters.
The payload is a binary stream of bookmark data. Each entry in the stream
consists of:
* 20 bytes binary node that bookmark is associated with
* 2 bytes unsigned short defining length of bookmark name
* N bytes containing the bookmark name
If all bits in the node value are ``1``, then this signifies a missing
bookmark.
When the receiver encounters this part, for each bookmark in the part
payload, it should validate that the current bookmark state matches
the specified state. If it doesn't, then the receiver should take
appropriate action. (In the case of pushes, this mismatch signifies
a race condition and the receiver should consider rejecting the push.)
check:heads
-----------
The ``check:heads`` part is a means to validate that the sender's state
of DAG heads matches the receiver's.
This part has no parameters.
The body of this part is an array of 20 byte binary nodes representing
changeset heads.
Receivers should compare the set of heads defined in this part to the
current set of repo heads and take action if there is a mismatch in that
set.
Note that this part applies to *all* heads in the repo.
check:phases
------------
The ``check:phases`` part validates that the sender's state of phase
boundaries matches the receiver's.
This part has no parameters.
The payload consists of an array of 24 byte entries. Each entry is
a big endian 32-bit integer defining the phase integer and 20 byte
binary node value.
For each changeset defined in this part, the receiver should validate
that its current phase matches the phase defined in this part. The
receiver should take appropriate action if a mismatch occurs.
check:updated-heads
-------------------
The ``check:updated-heads`` part validates that the sender's state of
DAG heads updated by this bundle matches the receiver's.
This type is nearly identical to ``check:heads`` except the heads
in the payload are only a subset of heads in the repository. The
receiver should validate that all nodes specified by the sender are
branch heads and take appropriate action if not.
error:abort
-----------
The ``error:abort`` part conveys a fatal error.
The following part parameters are defined:
message
The string content of the error message.
hint
Supplemental string giving a hint on how to fix the problem.
error:pushkey
-------------
The ``error:pushkey`` part conveys an error in the *pushkey* protocol.
The following part parameters are defined:
namespace
The pushkey domain that exhibited the error.
key
The key whose update failed.
new
The value we tried to set the key to.
old
The old value of the key (as supplied by the client).
ret
The integer result code for the pushkey request.
in-reply-to
Part ID that triggered this error.
This part is generated if there was an error applying *pushkey* data.
Pushkey data includes bookmarks, phases, and obsolescence markers.
error:pushraced
---------------
The ``error:pushraced`` part conveys that an error occurred and
the likely cause is losing a race with another pusher.
The following part parameters are defined:
message
String error message.
This part is typically emitted when a receiver examining ``check:*``
parts encountered inconsistency between incoming state and local state.
The likely cause of that inconsistency is another repository change
operation (often another client performing an ``hg push``).
error:unsupportedcontent
------------------------
The ``error:unsupportedcontent`` part conveys that a bundle2 receiver
encountered a part or content it was not able to handle.
The following part parameters are defined:
parttype
The name of the part that triggered this error.
params
``\0`` delimited list of parameters.
hgtagsfnodes
------------
The ``hgtagsfnodes`` type defines file nodes for the ``.hgtags`` file
for various changesets.
This part has no parameters.
The payload is an array of pairs of 20 byte binary nodes. The first node
is a changeset node. The second node is the ``.hgtags`` file node.
Resolving tags requires resolving the ``.hgtags`` file node for changesets.
On large repositories, this can be expensive. Repositories cache the
mapping of changeset to ``.hgtags`` file node on disk as a performance
optimization. This part allows that cached data to be transferred alongside
changeset data.
Receivers should update their ``.hgtags`` cache file node mappings with
the incoming data.
listkeys
--------
The ``listkeys`` part holds content for a *pushkey* namespace.
The following part parameters are defined:
namespace
The pushkey domain this data belongs to.
The part payload contains a newline (``\n``) delimited list of
tab (``\t``) delimited key-value pairs defining entries in this pushkey
namespace.
obsmarkers
----------
The ``obsmarkers`` part defines obsolescence markers.
This part has no parameters.
The payload consists of obsolescence markers using the on-disk markers
format. The first byte defines the version format.
The receiver should apply the obsolescence markers defined in this
part. A ``reply:obsmarkers`` part should be sent to the sender, if possible.
output
------
The ``output`` part is used to display output on the receiver.
This part has no parameters.
The payload consists of raw data to be printed on the receiver.
phase-heads
-----------
The ``phase-heads`` part defines phase boundaries.
This part has no parameters.
The payload consists of an array of 24 byte entries. Each entry is
a big endian 32-bit integer defining the phase integer and 20 byte
binary node value.
pushkey
-------
The ``pushkey`` part communicates an intent to perform a ``pushkey``
request.
The following part parameters are defined:
namespace
The pushkey domain to operate on.
key
The key within the pushkey namespace that is being changed.
old
The old value for the key being changed.
new
The new value for the key being changed.
This part has no payload.
The receiver should perform a pushkey operation as described by this
part's parameters.
If the pushey operation fails, a ``reply:pushkey`` part should be sent
back to the sender, if possible. The ``in-reply-to`` part parameter
should reference the source part.
pushvars
--------
The ``pushvars`` part defines environment variables that should be
set when processing this bundle2 payload.
The part's advisory parameters define environment variables.
There is no part payload.
When received, part parameters are prefixed with ``USERVAR_`` and the
resulting variables are defined in the hooks context for the current
bundle2 application. This part provides a mechanism for senders to
inject extra state into the hook execution environment on the receiver.
remote-changegroup
------------------
The ``remote-changegroup`` part defines an external location of a bundle
to apply. This part can be used by servers to serve pre-generated bundles
hosted at arbitrary URLs.
The following part parameters are defined:
url
The URL of the remote bundle.
size
The size in bytes of the remote bundle.
digests
A space separated list of the digest types provided in additional
part parameters.
digest:<type>
The hexadecimal representation of the digest (hash) of the remote bundle.
There is no payload for this part type.
When encountered, clients should attempt to fetch the URL being advertised
and read and apply it as a bundle.
The ``size`` and ``digest:<type>`` parameters should be used to validate
that the downloaded bundle matches what was advertised. If a mismatch occurs,
the client should abort.
reply:changegroup
-----------------
The ``reply:changegroup`` part conveys the results of application of a
``changegroup`` part.
The following part parameters are defined:
return
Integer return code from changegroup application.
in-reply-to
Part ID of part this reply is in response to.
reply:obsmarkers
----------------
The ``reply:obsmarkers`` part conveys the results of applying an
``obsmarkers`` part.
The following part parameters are defined:
new
The integer number of new markers that were applied.
in-reply-to
The part ID that this part is in reply to.
reply:pushkey
-------------
The ``reply:pushkey`` part conveys the result of a *pushkey* operation.
The following part parameters are defined:
return
Integer result code from pushkey operation.
in-reply-to
Part ID that triggered this pushkey operation.
This part has no payload.
replycaps
---------
The ``replycaps`` part notifies the receiver that a reply bundle should
be created.
This part has no parameters.
The payload consists of a bundle2 capabilities blob.
stream2
-------
The ``stream2`` part contains *streaming clone* version 2 data.
The following part parameters are defined:
requirements
URL quoted repository requirements string. Requirements are delimited by a
command (``,``).
filecount
The total number of files being transferred in the payload.
bytecount
The total size of file content being transferred in the payload.
The payload consists of raw stream clone version 2 data.
The ``filecount`` and ``bytecount`` parameters can be used for progress and
reporting purposes. The values may not be exact.