[PATCH 1 of 3 RFC] wireproto: implement an ancestors command
Gregory Szorc
gregory.szorc at gmail.com
Thu Nov 20 18:05:42 UTC 2014
# HG changeset patch
# User Gregory Szorc <gregory.szorc at gmail.com>
# Date 1416503184 28800
# Thu Nov 20 09:06:24 2014 -0800
# Node ID b2b2b245c345fa788b46f71022024e17086d4f45
# Parent e63941631a3f61b3323dbcc2545689b1eb34e308
wireproto: implement an ancestors command
THIS PATCH IS UNTESTED AND IS MEANT FOR CONSIDERATION ONLY.
As will be demonstrated in subsequent patches, allowing clients to
obtain all known ancestors of a node provides an alternate and possibly
more efficient mechanism to perform discovery.
This patch introduces an "ancestors" wire protocol command that does
what it's name implies: it sends ancestors of a specified commit down
to the client.
diff --git a/mercurial/wireproto.py b/mercurial/wireproto.py
--- a/mercurial/wireproto.py
+++ b/mercurial/wireproto.py
@@ -8,9 +8,9 @@
import urllib, tempfile, os, sys
from i18n import _
from node import bin, hex
import changegroup as changegroupmod, bundle2, pushkey as pushkeymod
-import peer, error, encoding, util, store, exchange
+import peer, error, encoding, util, store, exchange, ancestors
class abstractserverproto(object):
"""abstract class that summarizes the protocol API
@@ -254,8 +254,27 @@ class wirepeer(peer.peerrepository):
except ValueError:
self._abort(error.ResponseError(_("unexpected response:"), d))
@batchable
+ def ancestors(self, nodes, limit=None):
+ f = future()
+ args = {'nodes': encodelist(nodes)}
+ if limit:
+ args['limit'] = limit
+ yield args, f
+ d = f.value
+ try:
+ lines = d.split('\n')
+ if lines[0][0] == '0':
+ msg = _("unknown node: %s") % lines[0][2:]
+ self._abort(error.responseError(msg))
+ elif lines[0] != '1':
+ raise ValueError()
+ yield [bin(node) for node in lines[1:]]
+ except IndexError, ValueError:
+ self._abort(error.ResponseError(_("unexpected response:"), d))
+
+ @batchable
def branchmap(self):
f = future()
yield {}, f
d = f.value
@@ -584,9 +603,9 @@ def branches(repo, proto, nodes):
return "".join(r)
wireprotocaps = ['lookup', 'changegroupsubset', 'branchmap', 'pushkey',
- 'known', 'getbundle', 'unbundlehash', 'batch']
+ 'known', 'getbundle', 'unbundlehash', 'batch', 'ancestors']
def _capabilities(repo, proto):
"""return a list of capabilities for a repo
@@ -700,8 +719,39 @@ def lookup(repo, proto, key):
@wireprotocommand('known', 'nodes *')
def known(repo, proto, nodes, others):
return ''.join(b and "1" or "0" for b in repo.known(decodelist(nodes)))
+ at wireprotocommand('ancestors', 'nodes limit')
+def ancestors(repo, proto, nodes, limit=None):
+ """Obtain ancestors for a list of nodes.
+
+ The client sends a list of nodes and an optional response node limit.
+ The server responds by sending all known ancestors in reverse topological
+ order up to the limit.
+
+ The server imposes a default limit in case the argument is omitted.
+ """
+ try:
+ revs = [repo[node].rev() for node in decodelist(nodes)]
+ except error.LookupError, e:
+ return '0 %s\n' % e.name
+
+ if limit is None:
+ # 800 is about 32KB.
+ limit = repo.ui.configint('wireproto', 'ancestorslimit', 800)
+
+ lazyancestor = ancestors.lazyancestors(repo.changelog.parentrevs, revs)
+ lines = ['1']
+ count = 0
+ for rev in lazyincestors:
+ lines.append(repo[rev].hex())
+
+ count += 1
+ if limit and count >= limit:
+ break
+
+ return '\n'.join(lines)
+
@wireprotocommand('pushkey', 'namespace key old new')
def pushkey(repo, proto, namespace, key, old, new):
# compatibility with pre-1.8 clients which were accidentally
# sending raw binary nodes rather than utf-8-encoded hex
More information about the Mercurial-devel
mailing list