D4480: exchangev2: start to implement pull with wire protocol v2

indygreg (Gregory Szorc) phabricator at mercurial-scm.org
Fri Sep 14 23:16:43 EDT 2018


This revision was automatically updated to reflect the committed changes.
Closed by commit rHGa86d21e70b2b: exchangev2: start to implement pull with wire protocol v2 (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D4480?vs=10961&id=11058

REVISION DETAIL
  https://phab.mercurial-scm.org/D4480

AFFECTED FILES
  mercurial/exchange.py
  mercurial/exchangev2.py
  mercurial/httppeer.py
  tests/test-wireproto-exchangev2.t
  tests/wireprotohelpers.sh

CHANGE DETAILS

diff --git a/tests/wireprotohelpers.sh b/tests/wireprotohelpers.sh
--- a/tests/wireprotohelpers.sh
+++ b/tests/wireprotohelpers.sh
@@ -56,3 +56,10 @@
 web.api.http-v2 = true
 EOF
 }
+
+enablehttpv2client() {
+  cat >> $HGRCPATH << EOF
+[experimental]
+httppeer.advertise-v2 = true
+EOF
+}
diff --git a/tests/test-wireproto-exchangev2.t b/tests/test-wireproto-exchangev2.t
new file mode 100644
--- /dev/null
+++ b/tests/test-wireproto-exchangev2.t
@@ -0,0 +1,53 @@
+Tests for wire protocol version 2 exchange.
+Tests in this file should be folded into existing tests once protocol
+v2 has enough features that it can be enabled via #testcase in existing
+tests.
+
+  $ . $TESTDIR/wireprotohelpers.sh
+  $ enablehttpv2client
+
+  $ hg init server-simple
+  $ enablehttpv2 server-simple
+  $ cd server-simple
+  $ cat >> .hg/hgrc << EOF
+  > [phases]
+  > publish = false
+  > EOF
+  $ echo a0 > a
+  $ echo b0 > b
+  $ hg -q commit -A -m 'commit 0'
+
+  $ echo a1 > a
+  $ hg commit -m 'commit 1'
+  $ hg phase --public -r .
+  $ echo a2 > a
+  $ hg commit -m 'commit 2'
+
+  $ hg -q up -r 0
+  $ echo b1 > b
+  $ hg -q commit -m 'head 2 commit 1'
+  $ echo b2 > b
+  $ hg -q commit -m 'head 2 commit 2'
+
+  $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log
+  $ cat hg.pid > $DAEMON_PIDS
+
+  $ cd ..
+
+Test basic clone
+
+  $ hg --debug clone -U http://localhost:$HGPORT client-simple
+  using http://localhost:$HGPORT/
+  sending capabilities command
+  query 1; heads
+  sending 2 commands
+  sending command heads: {}
+  sending command known: {
+    'nodes': []
+  }
+  received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
+  received frame(size=43; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
+  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
+  received frame(size=11; request=3; stream=2; streamflags=; type=command-response; flags=continuation)
+  received frame(size=1; request=3; stream=2; streamflags=; type=command-response; flags=continuation)
+  received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos)
diff --git a/mercurial/httppeer.py b/mercurial/httppeer.py
--- a/mercurial/httppeer.py
+++ b/mercurial/httppeer.py
@@ -802,7 +802,8 @@
             return True
 
         # Other concepts.
-        if name in ('bundle2',):
+        # TODO remove exchangev2 once we have a command implemented.
+        if name in ('bundle2', 'exchangev2'):
             return True
 
         # Alias command-* to presence of command of that name.
diff --git a/mercurial/exchangev2.py b/mercurial/exchangev2.py
new file mode 100644
--- /dev/null
+++ b/mercurial/exchangev2.py
@@ -0,0 +1,55 @@
+# exchangev2.py - repository exchange for wire protocol version 2
+#
+# Copyright 2018 Gregory Szorc <gregory.szorc at gmail.com>
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+
+from __future__ import absolute_import
+
+from .node import (
+    nullid,
+)
+from . import (
+    setdiscovery,
+)
+
+def pull(pullop):
+    """Pull using wire protocol version 2."""
+    repo = pullop.repo
+    remote = pullop.remote
+
+    # Figure out what needs to be fetched.
+    common, fetch, remoteheads = _pullchangesetdiscovery(
+        repo, remote, pullop.heads, abortwhenunrelated=pullop.force)
+
+def _pullchangesetdiscovery(repo, remote, heads, abortwhenunrelated=True):
+    """Determine which changesets need to be pulled."""
+
+    if heads:
+        knownnode = repo.changelog.hasnode
+        if all(knownnode(head) for head in heads):
+            return heads, False, heads
+
+    # TODO wire protocol version 2 is capable of more efficient discovery
+    # than setdiscovery. Consider implementing something better.
+    common, fetch, remoteheads = setdiscovery.findcommonheads(
+        repo.ui, repo, remote, abortwhenunrelated=abortwhenunrelated)
+
+    common = set(common)
+    remoteheads = set(remoteheads)
+
+    # If a remote head is filtered locally, put it back in the common set.
+    # See the comment in exchange._pulldiscoverychangegroup() for more.
+
+    if fetch and remoteheads:
+        nodemap = repo.unfiltered().changelog.nodemap
+
+        common |= {head for head in remoteheads if head in nodemap}
+
+        if set(remoteheads).issubset(common):
+            fetch = []
+
+    common.discard(nullid)
+
+    return common, fetch, remoteheads
diff --git a/mercurial/exchange.py b/mercurial/exchange.py
--- a/mercurial/exchange.py
+++ b/mercurial/exchange.py
@@ -26,6 +26,7 @@
     changegroup,
     discovery,
     error,
+    exchangev2,
     lock as lockmod,
     logexchange,
     narrowspec,
@@ -1506,17 +1507,21 @@
 
     pullop.trmanager = transactionmanager(repo, 'pull', remote.url())
     with repo.wlock(), repo.lock(), pullop.trmanager:
-        # This should ideally be in _pullbundle2(). However, it needs to run
-        # before discovery to avoid extra work.
-        _maybeapplyclonebundle(pullop)
-        streamclone.maybeperformlegacystreamclone(pullop)
-        _pulldiscovery(pullop)
-        if pullop.canusebundle2:
-            _fullpullbundle2(repo, pullop)
-        _pullchangeset(pullop)
-        _pullphase(pullop)
-        _pullbookmarks(pullop)
-        _pullobsolete(pullop)
+        # Use the modern wire protocol, if available.
+        if remote.capable('exchangev2'):
+            exchangev2.pull(pullop)
+        else:
+            # This should ideally be in _pullbundle2(). However, it needs to run
+            # before discovery to avoid extra work.
+            _maybeapplyclonebundle(pullop)
+            streamclone.maybeperformlegacystreamclone(pullop)
+            _pulldiscovery(pullop)
+            if pullop.canusebundle2:
+                _fullpullbundle2(repo, pullop)
+            _pullchangeset(pullop)
+            _pullphase(pullop)
+            _pullbookmarks(pullop)
+            _pullobsolete(pullop)
 
     # storing remotenames
     if repo.ui.configbool('experimental', 'remotenames'):



To: indygreg, #hg-reviewers
Cc: durin42, mercurial-devel


More information about the Mercurial-devel mailing list