Mercurial > hg
changeset 39016:39b8277e2115
changegroup: differentiate between fulltext and diff based deltas
Previously, revisiondelta encoded a delta and an optional prefix
containing a delta header. The underlying code could populate
the delta with either a real delta or a fulltext revision.
Following the theme of wanting to defer serialization of revision
data to the changegroup format as long as possible, it seems
prudent for the revision delta instance to capture what type of
data is being represented. This could possibly allow us to
encode revision data differently in the future. But for the
short term, it makes the behavior of a revisiondelta more
explicit.
Differential Revision: https://phab.mercurial-scm.org/D4213
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Wed, 08 Aug 2018 16:01:26 -0700 |
parents | ad9eccedb379 |
children | ef3d3a2f9aa5 |
files | mercurial/changegroup.py |
diffstat | 1 files changed, 49 insertions(+), 20 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial/changegroup.py Wed Aug 08 15:28:22 2018 -0700 +++ b/mercurial/changegroup.py Wed Aug 08 16:01:26 2018 -0700 @@ -507,6 +507,8 @@ Captured data is sufficient to serialize the delta into multiple formats. + + ``revision`` and ``delta`` are mutually exclusive. """ # 20 byte node of this revision. node = attr.ib() @@ -519,17 +521,40 @@ linknode = attr.ib() # 2 bytes of flags to apply to revision data. flags = attr.ib() - # Iterable of chunks holding raw delta data. - deltachunks = attr.ib() + # Size of base revision this delta is against. May be None if + # basenode is nullid. + baserevisionsize = attr.ib() + # Raw fulltext revision data. + revision = attr.ib() + # Delta between the basenode and node. + delta = attr.ib() def _revisiondeltatochunks(delta, headerfn): """Serialize a revisiondelta to changegroup chunks.""" + + # The captured revision delta may be encoded as a delta against + # a base revision or as a full revision. The changegroup format + # requires that everything on the wire be deltas. So for full + # revisions, we need to invent a header that says to rewrite + # data. + + if delta.delta is not None: + prefix, data = b'', delta.delta + elif delta.basenode == nullid: + data = delta.revision + prefix = mdiff.trivialdiffheader(len(data)) + else: + data = delta.revision + prefix = mdiff.replacediffheader(delta.baserevisionsize, + len(data)) + meta = headerfn(delta) - l = len(meta) + sum(len(x) for x in delta.deltachunks) - yield chunkheader(l) + + yield chunkheader(len(meta) + len(prefix) + len(data)) yield meta - for x in delta.deltachunks: - yield x + if prefix: + yield prefix + yield data def _sortnodesnormal(store, nodes, reorder): """Sort nodes for changegroup generation and turn into revnums.""" @@ -568,22 +593,24 @@ p1, p2 = store.parentrevs(rev) base = deltaparentfn(store, rev, p1, p2, prev) - prefix = '' + revision = None + delta = None + baserevisionsize = None + if store.iscensored(base) or store.iscensored(rev): try: - delta = store.revision(node, raw=True) + revision = store.revision(node, raw=True) except error.CensoredNodeError as e: - delta = e.tombstone - if base == nullrev: - prefix = mdiff.trivialdiffheader(len(delta)) - else: - baselen = store.rawsize(base) - prefix = mdiff.replacediffheader(baselen, len(delta)) + revision = e.tombstone + + if base != nullrev: + baserevisionsize = store.rawsize(base) + elif base == nullrev: - delta = store.revision(node, raw=True) - prefix = mdiff.trivialdiffheader(len(delta)) + revision = store.revision(node, raw=True) else: delta = store.revdiff(base, rev) + p1n, p2n = store.parents(node) return revisiondelta( @@ -593,7 +620,9 @@ basenode=store.node(base), linknode=linknode, flags=store.flags(rev), - deltachunks=(prefix, delta), + baserevisionsize=baserevisionsize, + revision=revision, + delta=delta, ) def _revisiondeltanarrow(cl, store, ischangelog, rev, linkrev, @@ -677,8 +706,6 @@ flags |= revlog.REVIDX_ELLIPSIS # TODO: try and actually send deltas for ellipsis data blocks - data = store.revision(n) - diffheader = mdiff.trivialdiffheader(len(data)) return revisiondelta( node=n, @@ -687,7 +714,9 @@ basenode=nullid, linknode=linknode, flags=flags, - deltachunks=(diffheader, data), + baserevisionsize=None, + revision=store.revision(n), + delta=None, ) def deltagroup(repo, revs, store, ischangelog, lookup, deltaparentfn,