Patchwork [1,of,3,RFC] wireproto: implement an ancestors command

login
register
mail settings
Submitter Gregory Szorc
Date Nov. 20, 2014, 6:05 p.m.
Message ID <b2b2b245c345fa788b46.1416506742@3.1.168.192.in-addr.arpa>
Download mbox | patch
Permalink /patch/6810/
State Deferred
Headers show

Comments

Gregory Szorc - Nov. 20, 2014, 6:05 p.m.
# HG changeset patch
# User Gregory Szorc <gregory.szorc@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.

Patch

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)))
 
+@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