Mercurial > hg-stable
changeset 39869:7b752bf08435
wireprotov2server: port to emitrevisions()
We now have a proper storage API to request data on multiple
revisions. We can drop it into wire protocol version 2 with
minimal effort.
The new API handles pretty much everything we were doing manually to
build up the delta request. So we were able to delete a lot of code.
As a bonus, wireprotov2 code is no longer accessing some low-level
storage APIs. This includes the assumption that a node has an
associated numeric revision number! This should make it drastically
simpler to implement a server that doesn't have the concept of
revision numbers.
Differential Revision: https://phab.mercurial-scm.org/D4724
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Mon, 24 Sep 2018 09:48:02 -0700 |
parents | c73f9f345ec0 |
children | 31b7e8e7132e |
files | mercurial/wireprotov2server.py |
diffstat | 1 files changed, 26 insertions(+), 151 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial/wireprotov2server.py Fri Sep 21 14:54:59 2018 -0700 +++ b/mercurial/wireprotov2server.py Mon Sep 24 09:48:02 2018 -0700 @@ -12,11 +12,8 @@ from .node import ( hex, nullid, - nullrev, ) from . import ( - changegroup, - dagop, discovery, encoding, error, @@ -463,86 +460,6 @@ return proto.addcapabilities(repo, caps) -def builddeltarequests(store, nodes, haveparents): - """Build a series of revision delta requests against a backend store. - - Returns a list of revision numbers in the order they should be sent - and a list of ``irevisiondeltarequest`` instances to be made against - the backend store. - """ - # We sort and send nodes in DAG order because this is optimal for - # storage emission. - # TODO we may want a better storage API here - one where we can throw - # a list of nodes and delta preconditions over a figurative wall and - # have the storage backend figure it out for us. - revs = dagop.linearize({store.rev(n) for n in nodes}, store.parentrevs) - - requests = [] - seenrevs = set() - - for rev in revs: - node = store.node(rev) - parentnodes = store.parents(node) - parentrevs = [store.rev(n) for n in parentnodes] - deltabaserev = store.deltaparent(rev) - deltabasenode = store.node(deltabaserev) - - # The choice of whether to send a fulltext revision or a delta and - # what delta to send is governed by a few factors. - # - # To send a delta, we need to ensure the receiver is capable of - # decoding it. And that requires the receiver to have the base - # revision the delta is against. - # - # We can only guarantee the receiver has the base revision if - # a) we've already sent the revision as part of this group - # b) the receiver has indicated they already have the revision. - # And the mechanism for "b" is the client indicating they have - # parent revisions. So this means we can only send the delta if - # it is sent before or it is against a delta and the receiver says - # they have a parent. - - # We can send storage delta if it is against a revision we've sent - # in this group. - if deltabaserev != nullrev and deltabaserev in seenrevs: - basenode = deltabasenode - - # We can send storage delta if it is against a parent revision and - # the receiver indicates they have the parents. - elif (deltabaserev != nullrev and deltabaserev in parentrevs - and haveparents): - basenode = deltabasenode - - # Otherwise the storage delta isn't appropriate. Fall back to - # using another delta, if possible. - - # Use p1 if we've emitted it or receiver says they have it. - elif parentrevs[0] != nullrev and ( - parentrevs[0] in seenrevs or haveparents): - basenode = parentnodes[0] - - # Use p2 if we've emitted it or receiver says they have it. - elif parentrevs[1] != nullrev and ( - parentrevs[1] in seenrevs or haveparents): - basenode = parentnodes[1] - - # Nothing appropriate to delta against. Send the full revision. - else: - basenode = nullid - - requests.append(changegroup.revisiondeltarequest( - node=node, - p1node=parentnodes[0], - p2node=parentnodes[1], - # Receiver deals with linknode resolution. - linknode=nullid, - basenode=basenode, - )) - - seenrevs.add(rev) - - return revs, requests - def wireprotocommand(name, args=None, permission='push'): """Decorator to declare a wire protocol command. @@ -860,47 +777,33 @@ raise error.WireprotoCommandError('unknown file node: %s', (hex(node),)) - revs, requests = builddeltarequests(store, nodes, haveparents) + revisions = store.emitrevisions(nodes, + revisiondata=b'revision' in fields, + assumehaveparentrevisions=haveparents) yield { - b'totalitems': len(revs), + b'totalitems': len(nodes), } - if b'revision' in fields: - deltas = store.emitrevisiondeltas(requests) - else: - deltas = None - - for rev in revs: - node = store.node(rev) - - if deltas is not None: - delta = next(deltas) - else: - delta = None - + for revision in revisions: d = { - b'node': node, + b'node': revision.node, } if b'parents' in fields: - d[b'parents'] = store.parents(node) + d[b'parents'] = [revision.p1node, revision.p2node] followingmeta = [] followingdata = [] if b'revision' in fields: - assert delta is not None - assert delta.flags == 0 - assert d[b'node'] == delta.node - - if delta.revision is not None: - followingmeta.append((b'revision', len(delta.revision))) - followingdata.append(delta.revision) + if revision.revision is not None: + followingmeta.append((b'revision', len(revision.revision))) + followingdata.append(revision.revision) else: - d[b'deltabasenode'] = delta.basenode - followingmeta.append((b'delta', len(delta.delta))) - followingdata.append(delta.delta) + d[b'deltabasenode'] = revision.basenode + followingmeta.append((b'delta', len(revision.delta))) + followingdata.append(revision.delta) if followingmeta: d[b'fieldsfollowing'] = followingmeta @@ -910,13 +813,6 @@ for extra in followingdata: yield extra - if deltas is not None: - try: - next(deltas) - raise error.ProgrammingError('should not have more deltas') - except GeneratorExit: - pass - @wireprotocommand( 'heads', args={ @@ -1019,47 +915,33 @@ raise error.WireprotoCommandError( 'unknown node: %s', (node,)) - revs, requests = builddeltarequests(store, nodes, haveparents) + revisions = store.emitrevisions(nodes, + revisiondata=b'revision' in fields, + assumehaveparentrevisions=haveparents) yield { - b'totalitems': len(revs), + b'totalitems': len(nodes), } - if b'revision' in fields: - deltas = store.emitrevisiondeltas(requests) - else: - deltas = None - - for rev in revs: - node = store.node(rev) - - if deltas is not None: - delta = next(deltas) - else: - delta = None - + for revision in revisions: d = { - b'node': node, + b'node': revision.node, } if b'parents' in fields: - d[b'parents'] = store.parents(node) + d[b'parents'] = [revision.p1node, revision.p2node] followingmeta = [] followingdata = [] if b'revision' in fields: - assert delta is not None - assert delta.flags == 0 - assert d[b'node'] == delta.node - - if delta.revision is not None: - followingmeta.append((b'revision', len(delta.revision))) - followingdata.append(delta.revision) + if revision.revision is not None: + followingmeta.append((b'revision', len(revision.revision))) + followingdata.append(revision.revision) else: - d[b'deltabasenode'] = delta.basenode - followingmeta.append((b'delta', len(delta.delta))) - followingdata.append(delta.delta) + d[b'deltabasenode'] = revision.basenode + followingmeta.append((b'delta', len(revision.delta))) + followingdata.append(revision.delta) if followingmeta: d[b'fieldsfollowing'] = followingmeta @@ -1069,13 +951,6 @@ for extra in followingdata: yield extra - if deltas is not None: - try: - next(deltas) - raise error.ProgrammingError('should not have more deltas') - except GeneratorExit: - pass - @wireprotocommand( 'pushkey', args={