D4484: exchangev2: fetch and apply phases data

indygreg (Gregory Szorc) phabricator at mercurial-scm.org
Wed Sep 5 16:23:18 UTC 2018


indygreg created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  Now that the server supports emitting phases data, we can request it
  and apply it on the client.
  
  Because we may receive phases-only updates from the server, we no
  longer conditionally perform the "changesetdata" command depending
  on whether there are revisions to fetch. In the previous wire
  protocol, this case would result in us falling back to performing
  "listkeys" commands to look up phases, bookmarks, etc data. But
  since "changesetdata" is smart enough to handle metadata only
  fetches, we can keep things consistent.
  
  It's worth noting that because of the unified approach to changeset
  data retrieval, phase handling code in wire proto v2 exchange is
  drastically simpler. Contrast with all the code in exchange.py
  dealing with all the variations for obtaining phases data.

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  mercurial/exchangev2.py
  tests/test-wireproto-exchangev2.t

CHANGE DETAILS

diff --git a/tests/test-wireproto-exchangev2.t b/tests/test-wireproto-exchangev2.t
--- a/tests/test-wireproto-exchangev2.t
+++ b/tests/test-wireproto-exchangev2.t
@@ -55,6 +55,7 @@
   sending command changesetdata: {
     'fields': set([
       'parents',
+      'phase',
       'revision'
     ]),
     'noderange': [
@@ -66,7 +67,7 @@
     ]
   }
   received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
-  received frame(size=809; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
+  received frame(size=871; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
   received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
   add changeset 3390ef850073
   add changeset 4432d83626e8
@@ -87,11 +88,11 @@
        4       4 caa2a465451d e96ae20f4188 000000000000
 
   $ hg -R client-simple log -G -T '{rev} {node} {phase}\n'
-  o  4 caa2a465451dd1facda0f5b12312c355584188a1 public
+  o  4 caa2a465451dd1facda0f5b12312c355584188a1 draft
   |
-  o  3 e96ae20f4188487b9ae4ef3941c27c81143146e5 public
+  o  3 e96ae20f4188487b9ae4ef3941c27c81143146e5 draft
   |
-  | o  2 cd2534766bece138c7c1afdc6825302f0f62d81f public
+  | o  2 cd2534766bece138c7c1afdc6825302f0f62d81f draft
   | |
   | o  1 4432d83626e8a98655f062ec1f2a43b07f7fbbb0 public
   |/
@@ -126,6 +127,7 @@
   sending command changesetdata: {
     'fields': set([
       'parents',
+      'phase',
       'revision'
     ]),
     'noderange': [
@@ -136,7 +138,7 @@
     ]
   }
   received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
-  received frame(size=327; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
+  received frame(size=353; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
   received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
   add changeset 3390ef850073
   add changeset 4432d83626e8
@@ -177,6 +179,7 @@
   sending command changesetdata: {
     'fields': set([
       'parents',
+      'phase',
       'revision'
     ]),
     'noderange': [
@@ -190,7 +193,7 @@
     ]
   }
   received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
-  received frame(size=495; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
+  received frame(size=571; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
   received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
   add changeset cd2534766bec
   add changeset e96ae20f4188
@@ -200,11 +203,71 @@
   (run 'hg update' to get a working copy)
 
   $ hg log -G -T '{rev} {node} {phase}\n'
+  o  4 caa2a465451dd1facda0f5b12312c355584188a1 draft
+  |
+  o  3 e96ae20f4188487b9ae4ef3941c27c81143146e5 draft
+  |
+  | o  2 cd2534766bece138c7c1afdc6825302f0f62d81f draft
+  | |
+  | o  1 4432d83626e8a98655f062ec1f2a43b07f7fbbb0 public
+  |/
+  o  0 3390ef850073fbc2f0dfff2244342c8e9229013a public
+  
+
+Phase-only update works
+
+  $ hg -R ../server-simple phase --public -r caa2a465451dd
+  $ hg --debug pull
+  pulling from http://localhost:$HGPORT/
+  using http://localhost:$HGPORT/
+  sending capabilities command
+  query 1; heads
+  sending 2 commands
+  sending command heads: {}
+  sending command known: {
+    'nodes': [
+      '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f',
+      '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1'
+    ]
+  }
+  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=3; request=3; stream=2; streamflags=; type=command-response; flags=continuation)
+  received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos)
+  searching for changes
+  all remote heads known locally
+  sending 1 commands
+  sending command changesetdata: {
+    'fields': set([
+      'parents',
+      'phase',
+      'revision'
+    ]),
+    'noderange': [
+      [
+        '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1',
+        '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f'
+      ],
+      [
+        '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1',
+        '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f'
+      ]
+    ]
+  }
+  received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
+  received frame(size=92; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
+  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
+  2 local changesets published
+  (run 'hg update' to get a working copy)
+
+  $ hg log -G -T '{rev} {node} {phase}\n'
   o  4 caa2a465451dd1facda0f5b12312c355584188a1 public
   |
   o  3 e96ae20f4188487b9ae4ef3941c27c81143146e5 public
   |
-  | o  2 cd2534766bece138c7c1afdc6825302f0f62d81f public
+  | o  2 cd2534766bece138c7c1afdc6825302f0f62d81f draft
   | |
   | o  1 4432d83626e8a98655f062ec1f2a43b07f7fbbb0 public
   |/
diff --git a/mercurial/exchangev2.py b/mercurial/exchangev2.py
--- a/mercurial/exchangev2.py
+++ b/mercurial/exchangev2.py
@@ -16,6 +16,7 @@
 )
 from . import (
     mdiff,
+    phases,
     pycompat,
     setdiscovery,
 )
@@ -30,8 +31,25 @@
     common, fetch, remoteheads = _pullchangesetdiscovery(
         repo, remote, pullop.heads, abortwhenunrelated=pullop.force)
 
+    # And fetch the data.
     pullheads = pullop.heads or remoteheads
-    _fetchchangesets(repo, tr, remote, common, fetch, pullheads)
+    csetres = _fetchchangesets(repo, tr, remote, common, fetch, pullheads)
+
+    # New revisions are written to the changelog. But all other updates
+    # are deferred. Do those now.
+
+    # Ensure all new changesets are draft by default. If the repo is
+    # publishing, the phase will be adjusted by the loop below.
+    if csetres['added']:
+        phases.registernew(repo, tr, phases.draft, csetres['added'])
+
+    # And adjust the phase of all changesets accordingly.
+    for phase in phases.phasenames:
+        if phase == b'secret' or not csetres['nodesbyphase'][phase]:
+            continue
+
+        phases.advanceboundary(repo, tr, phases.phasenames.index(phase),
+                               csetres['nodesbyphase'][phase])
 
 def _pullchangesetdiscovery(repo, remote, heads, abortwhenunrelated=True):
     """Determine which changesets need to be pulled."""
@@ -65,18 +83,15 @@
     return common, fetch, remoteheads
 
 def _fetchchangesets(repo, tr, remote, common, fetch, remoteheads):
-    if not fetch:
-        return
-
     # TODO consider adding a step here where we obtain the DAG shape first
     # (or ask the server to slice changesets into chunks for us) so that
     # we can perform multiple fetches in batches. This will facilitate
     # resuming interrupted clones, higher server-side cache hit rates due
     # to smaller segments, etc.
     with remote.commandexecutor() as e:
         objs = e.callcommand(b'changesetdata', {
             b'noderange': [sorted(common), sorted(remoteheads)],
-            b'fields': {b'parents', b'revision'},
+            b'fields': {b'parents', b'phase', b'revision'},
         }).result()
 
         # The context manager waits on all response data when exiting. So
@@ -108,15 +123,28 @@
     def onchangeset(cl, node):
         progress.increment()
 
+    nodesbyphase = {phase: set() for phase in phases.phasenames}
+
     # addgroup() expects a 7-tuple describing revisions. This normalizes
     # the wire data to that format.
+    #
+    # This loop also aggregates non-revision metadata, such as phase
+    # data.
     def iterrevisions():
         for cset in objs:
-            assert b'revisionsize' in cset
+            node = cset[b'node']
+
+            if b'phase' in cset:
+                nodesbyphase[cset[b'phase']].add(node)
+
+            # Some entries might only be metadata only updates.
+            if b'revisionsize' not in cset:
+                continue
+
             data = next(objs)
 
             yield (
-                cset[b'node'],
+                node,
                 cset[b'parents'][0],
                 cset[b'parents'][1],
                 # Linknode is always itself for changesets.
@@ -135,4 +163,5 @@
 
     return {
         'added': added,
+        'nodesbyphase': nodesbyphase,
     }



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


More information about the Mercurial-devel mailing list