D4895: narrow: when widening, don't include manifests the client already has

martinvonz (Martin von Zweigbergk) phabricator at mercurial-scm.org
Thu Oct 18 07:03:51 EDT 2018


This revision was automatically updated to reflect the committed changes.
Closed by commit rHG89cba88e95ed: narrow: when widening, don't include manifests the client already has (authored by martinvonz, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D4895?vs=12217&id=12237

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

AFFECTED FILES
  hgext/narrow/narrowbundle2.py
  hgext/narrow/narrowwirepeer.py
  mercurial/bundle2.py
  mercurial/changegroup.py
  mercurial/exchange.py

CHANGE DETAILS

diff --git a/mercurial/exchange.py b/mercurial/exchange.py
--- a/mercurial/exchange.py
+++ b/mercurial/exchange.py
@@ -2153,14 +2153,12 @@
     if kwargs.get(r'narrow', False):
         include = sorted(filter(bool, kwargs.get(r'includepats', [])))
         exclude = sorted(filter(bool, kwargs.get(r'excludepats', [])))
-        filematcher = narrowspec.match(repo.root, include=include,
-                                       exclude=exclude)
+        matcher = narrowspec.match(repo.root, include=include, exclude=exclude)
     else:
-        filematcher = None
+        matcher = None
 
     cgstream = changegroup.makestream(repo, outgoing, version, source,
-                                      bundlecaps=bundlecaps,
-                                      filematcher=filematcher)
+                                      bundlecaps=bundlecaps, matcher=matcher)
 
     part = bundler.newpart('changegroup', data=cgstream)
     if cgversions:
diff --git a/mercurial/changegroup.py b/mercurial/changegroup.py
--- a/mercurial/changegroup.py
+++ b/mercurial/changegroup.py
@@ -727,14 +727,17 @@
         progress.complete()
 
 class cgpacker(object):
-    def __init__(self, repo, filematcher, version,
+    def __init__(self, repo, oldmatcher, matcher, version,
                  builddeltaheader, manifestsend,
                  forcedeltaparentprev=False,
                  bundlecaps=None, ellipses=False,
                  shallow=False, ellipsisroots=None, fullnodes=None):
         """Given a source repo, construct a bundler.
 
-        filematcher is a matcher that matches on files to include in the
+        oldmatcher is a matcher that matches on files the client already has.
+        These will not be included in the changegroup.
+
+        matcher is a matcher that matches on files to include in the
         changegroup. Used to facilitate sparse changegroups.
 
         forcedeltaparentprev indicates whether delta parents must be against
@@ -761,8 +764,10 @@
         ellipsis because for very large histories we expect this to be
         significantly smaller.
         """
-        assert filematcher
-        self._filematcher = filematcher
+        assert oldmatcher
+        assert matcher
+        self._oldmatcher = oldmatcher
+        self._matcher = matcher
 
         self.version = version
         self._forcedeltaparentprev = forcedeltaparentprev
@@ -1027,7 +1032,7 @@
             tree, nodes = tmfnodes.popitem()
             store = mfl.getstorage(tree)
 
-            if not self._filematcher.visitdir(store.tree[:-1] or '.'):
+            if not self._matcher.visitdir(store.tree[:-1] or '.'):
                 # No nodes to send because this directory is out of
                 # the client's view of the repository (probably
                 # because of narrow clones).
@@ -1051,7 +1056,16 @@
                 fullclnodes=self._fullclnodes,
                 precomputedellipsis=self._precomputedellipsis)
 
-            yield tree, deltas
+            if not self._oldmatcher.visitdir(store.tree[:-1] or '.'):
+                yield tree, deltas
+            else:
+                # 'deltas' is a generator and we need to consume it even if
+                # we are not going to send it because a side-effect is that
+                # it updates tmdnodes (via lookupfn)
+                for d in deltas:
+                    pass
+                if not tree:
+                    yield tree, []
 
     def _prunemanifests(self, store, nodes, commonrevs):
         # This is split out as a separate method to allow filtering
@@ -1066,7 +1080,8 @@
     # The 'source' parameter is useful for extensions
     def generatefiles(self, changedfiles, commonrevs, source,
                       mfdicts, fastpathlinkrev, fnodes, clrevs):
-        changedfiles = list(filter(self._filematcher, changedfiles))
+        changedfiles = [f for f in changedfiles
+                        if self._matcher(f) and not self._oldmatcher(f)]
 
         if not fastpathlinkrev:
             def normallinknodes(unused, fname):
@@ -1151,12 +1166,13 @@
 
         progress.complete()
 
-def _makecg1packer(repo, filematcher, bundlecaps, ellipses=False,
-                   shallow=False, ellipsisroots=None, fullnodes=None):
+def _makecg1packer(repo, oldmatcher, matcher, bundlecaps,
+                   ellipses=False, shallow=False, ellipsisroots=None,
+                   fullnodes=None):
     builddeltaheader = lambda d: _CHANGEGROUPV1_DELTA_HEADER.pack(
         d.node, d.p1node, d.p2node, d.linknode)
 
-    return cgpacker(repo, filematcher, b'01',
+    return cgpacker(repo, oldmatcher, matcher, b'01',
                     builddeltaheader=builddeltaheader,
                     manifestsend=b'',
                     forcedeltaparentprev=True,
@@ -1166,26 +1182,28 @@
                     ellipsisroots=ellipsisroots,
                     fullnodes=fullnodes)
 
-def _makecg2packer(repo, filematcher, bundlecaps, ellipses=False,
-                   shallow=False, ellipsisroots=None, fullnodes=None):
+def _makecg2packer(repo, oldmatcher, matcher, bundlecaps,
+                   ellipses=False, shallow=False, ellipsisroots=None,
+                   fullnodes=None):
     builddeltaheader = lambda d: _CHANGEGROUPV2_DELTA_HEADER.pack(
         d.node, d.p1node, d.p2node, d.basenode, d.linknode)
 
-    return cgpacker(repo, filematcher, b'02',
+    return cgpacker(repo, oldmatcher, matcher, b'02',
                     builddeltaheader=builddeltaheader,
                     manifestsend=b'',
                     bundlecaps=bundlecaps,
                     ellipses=ellipses,
                     shallow=shallow,
                     ellipsisroots=ellipsisroots,
                     fullnodes=fullnodes)
 
-def _makecg3packer(repo, filematcher, bundlecaps, ellipses=False,
-                   shallow=False, ellipsisroots=None, fullnodes=None):
+def _makecg3packer(repo, oldmatcher, matcher, bundlecaps,
+                   ellipses=False, shallow=False, ellipsisroots=None,
+                   fullnodes=None):
     builddeltaheader = lambda d: _CHANGEGROUPV3_DELTA_HEADER.pack(
         d.node, d.p1node, d.p2node, d.basenode, d.linknode, d.flags)
 
-    return cgpacker(repo, filematcher, b'03',
+    return cgpacker(repo, oldmatcher, matcher, b'03',
                     builddeltaheader=builddeltaheader,
                     manifestsend=closechunk(),
                     bundlecaps=bundlecaps,
@@ -1252,15 +1270,17 @@
     assert versions
     return min(versions)
 
-def getbundler(version, repo, bundlecaps=None, filematcher=None,
-               ellipses=False, shallow=False, ellipsisroots=None,
-               fullnodes=None):
+def getbundler(version, repo, bundlecaps=None, oldmatcher=None,
+               matcher=None, ellipses=False, shallow=False,
+               ellipsisroots=None, fullnodes=None):
     assert version in supportedoutgoingversions(repo)
 
-    if filematcher is None:
-        filematcher = matchmod.alwaysmatcher(repo.root, '')
+    if matcher is None:
+        matcher = matchmod.alwaysmatcher(repo.root, '')
+    if oldmatcher is None:
+        oldmatcher = matchmod.nevermatcher(repo.root, '')
 
-    if version == '01' and not filematcher.always():
+    if version == '01' and not matcher.always():
         raise error.ProgrammingError('version 01 changegroups do not support '
                                      'sparse file matchers')
 
@@ -1271,10 +1291,10 @@
 
     # Requested files could include files not in the local store. So
     # filter those out.
-    filematcher = repo.narrowmatch(filematcher)
+    matcher = repo.narrowmatch(matcher)
 
     fn = _packermap[version][0]
-    return fn(repo, filematcher, bundlecaps, ellipses=ellipses,
+    return fn(repo, oldmatcher, matcher, bundlecaps, ellipses=ellipses,
               shallow=shallow, ellipsisroots=ellipsisroots,
               fullnodes=fullnodes)
 
@@ -1297,9 +1317,9 @@
                         {'clcount': len(outgoing.missing) })
 
 def makestream(repo, outgoing, version, source, fastpath=False,
-               bundlecaps=None, filematcher=None):
+               bundlecaps=None, matcher=None):
     bundler = getbundler(version, repo, bundlecaps=bundlecaps,
-                         filematcher=filematcher)
+                         matcher=matcher)
 
     repo = repo.unfiltered()
     commonrevs = outgoing.common
diff --git a/mercurial/bundle2.py b/mercurial/bundle2.py
--- a/mercurial/bundle2.py
+++ b/mercurial/bundle2.py
@@ -2278,12 +2278,13 @@
     streamclone.applybundlev2(repo, part, filecount, bytecount,
                               requirements)
 
-def widen_bundle(repo, diffmatcher, common, known, cgversion, ellipses):
+def widen_bundle(repo, oldmatcher, newmatcher, common, known, cgversion,
+                 ellipses):
     """generates bundle2 for widening a narrow clone
 
     repo is the localrepository instance
-    diffmatcher is a differencemacther of '(newincludes, newexcludes) -
-    (oldincludes, oldexcludes)'
+    oldmatcher matches what the client already has
+    newmatcher matches what the client needs (including what it already has)
     common is set of common heads between server and client
     known is a set of revs known on the client side (used in ellipses)
     cgversion is the changegroup version to send
@@ -2300,7 +2301,8 @@
         # XXX: we should only send the filelogs (and treemanifest). user
         # already has the changelog and manifest
         packer = changegroup.getbundler(cgversion, repo,
-                                        filematcher=diffmatcher,
+                                        oldmatcher=oldmatcher,
+                                        matcher=newmatcher,
                                         fullnodes=commonnodes)
         cgdata = packer.generate(set([nodemod.nullid]), list(commonnodes),
                                  False, 'narrow_widen', changelog=False)
diff --git a/hgext/narrow/narrowwirepeer.py b/hgext/narrow/narrowwirepeer.py
--- a/hgext/narrow/narrowwirepeer.py
+++ b/hgext/narrow/narrowwirepeer.py
@@ -82,9 +82,8 @@
                                     exclude=newexcludes)
         oldmatch = narrowspec.match(repo.root, include=oldincludes,
                                     exclude=oldexcludes)
-        diffmatch = matchmod.differencematcher(newmatch, oldmatch)
 
-        bundler = bundle2.widen_bundle(repo, diffmatch, common, known,
+        bundler = bundle2.widen_bundle(repo, oldmatch, newmatch, common, known,
                                              cgversion, ellipses)
     except error.Abort as exc:
         bundler = bundle2.bundle20(repo.ui)
diff --git a/hgext/narrow/narrowbundle2.py b/hgext/narrow/narrowbundle2.py
--- a/hgext/narrow/narrowbundle2.py
+++ b/hgext/narrow/narrowbundle2.py
@@ -117,7 +117,7 @@
             repo, set(), common, known, newmatch)
         if newvisit:
             packer = changegroup.getbundler(version, repo,
-                                            filematcher=newmatch,
+                                            matcher=newmatch,
                                             ellipses=True,
                                             shallow=depth is not None,
                                             ellipsisroots=newellipsis,
@@ -135,7 +135,7 @@
     repo.ui.debug('Found %d relevant revs\n' % len(relevant_nodes))
     if visitnodes:
         packer = changegroup.getbundler(version, repo,
-                                        filematcher=newmatch,
+                                        matcher=newmatch,
                                         ellipses=True,
                                         shallow=depth is not None,
                                         ellipsisroots=ellipsisroots,



To: martinvonz, durin42, #hg-reviewers, pulkit
Cc: pulkit, mercurial-devel


More information about the Mercurial-devel mailing list