mozext: obtain pushlog data via wire protocol (bug 1236618); r?nalexander draft
authorGregory Szorc <gps@mozilla.com>
Tue, 19 Jan 2016 18:37:55 -0800
changeset 6854 7019858949920060816f62290c069f1e01f5d2c8
parent 6853 c9fa762f8d85e0a108a1e62b35b8d27066f500b1
push id534
push usergszorc@mozilla.com
push dateWed, 20 Jan 2016 02:38:38 +0000
reviewersnalexander
bugs1236618
mozext: obtain pushlog data via wire protocol (bug 1236618); r?nalexander It is faster to obtain the pushlog via the wire protocol via an already established TCP connection than to fetch it via multiple HTTP requests from the Mercurial JSON web API. Before: ~20.3s After: ~13.3s This does create some duplicate pushlog fetch code. And `hg pushlogsync` doesn't use the new API. But progress is progress. We should probably clone the tracking bug to track doing this more robustly.
hgext/mozext/__init__.py
--- a/hgext/mozext/__init__.py
+++ b/hgext/mozext/__init__.py
@@ -289,16 +289,17 @@ from mercurial.i18n import _
 from mercurial.error import (
     ParseError,
     RepoError,
 )
 from mercurial.localrepo import (
     repofilecache,
 )
 from mercurial.node import (
+    bin,
     hex,
     short,
 )
 from mercurial import (
     commands,
     cmdutil,
     demandimport,
     encoding,
@@ -393,18 +394,48 @@ def exchangepullpushlog(orig, pullop):
         return res
 
     repo = pullop.repo
 
     tree = resolve_uri_to_tree(pullop.remote.url())
     if not tree or not repo.changetracker or tree == "try":
         return res
 
-    repo.ui.status('fetching pushlog\n')
-    repo.changetracker.load_pushlog(tree)
+    lastpushid = repo.changetracker.last_push_id(tree)
+    fetchfrom = lastpushid + 1 if lastpushid is not None else 0
+
+    lines = pullop.remote._call('pushlog', firstpush=str(fetchfrom))
+    lines = iter(lines.splitlines())
+
+    statusline = lines.next()
+    if statusline[0] == '0':
+        raise error.Abort('remote error fetching pushlog: %s' % lines.next())
+    elif statusline != '1':
+        raise error.Abort('error fetching pushlog: unexpected response: %s\n' %
+            statusline)
+
+    pushes = []
+    for line in lines:
+        pushid, who, when, nodes = line.split(' ', 3)
+        nodes = [bin(n) for n in nodes.split()]
+
+        # Verify incoming changesets are known and stop processing when we see
+        # an unknown changeset. This can happen when we're pulling a former
+        # head instead of all changesets.
+        try:
+            [repo[n] for n in nodes]
+        except error.RepoLookupError:
+            repo.ui.warn('received pushlog entry for unknown changeset; ignoring\n')
+            break
+
+        pushes.append((int(pushid), who, int(when), nodes))
+
+    if pushes:
+        repo.changetracker.add_pushes(tree, pushes)
+        repo.ui.status('added %d pushes\n' % len(pushes))
 
     return res
 
 def critique(ui, repo, entire=False, node=None, **kwargs):
     """Perform a critique of a changeset."""
     demandimport.disable()
 
     from flake8.engine import get_style_guide