Mercurial > hg
comparison mercurial/changegroup.py @ 38904:cdb9bc216771
changegroup: declare shallow flag in constructor
Thus begins the process of better formalizing ellipses and shallow
changegroup generation mode so it is tracked by cgpacker at
construction time instead of bolted on after the fact by a
wrapper function.
Differential Revision: https://phab.mercurial-scm.org/D4086
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Fri, 03 Aug 2018 12:57:11 -0700 |
parents | 68e490ed640e |
children | 379d90327861 |
comparison
equal
deleted
inserted
replaced
38903:68e490ed640e | 38904:cdb9bc216771 |
---|---|
520 deltachunks = attr.ib() | 520 deltachunks = attr.ib() |
521 | 521 |
522 class cgpacker(object): | 522 class cgpacker(object): |
523 def __init__(self, repo, filematcher, version, allowreorder, | 523 def __init__(self, repo, filematcher, version, allowreorder, |
524 useprevdelta, builddeltaheader, manifestsend, | 524 useprevdelta, builddeltaheader, manifestsend, |
525 sendtreemanifests, bundlecaps=None): | 525 sendtreemanifests, bundlecaps=None, shallow=False): |
526 """Given a source repo, construct a bundler. | 526 """Given a source repo, construct a bundler. |
527 | 527 |
528 filematcher is a matcher that matches on files to include in the | 528 filematcher is a matcher that matches on files to include in the |
529 changegroup. Used to facilitate sparse changegroups. | 529 changegroup. Used to facilitate sparse changegroups. |
530 | 530 |
544 | 544 |
545 bundlecaps is optional and can be used to specify the set of | 545 bundlecaps is optional and can be used to specify the set of |
546 capabilities which can be used to build the bundle. While bundlecaps is | 546 capabilities which can be used to build the bundle. While bundlecaps is |
547 unused in core Mercurial, extensions rely on this feature to communicate | 547 unused in core Mercurial, extensions rely on this feature to communicate |
548 capabilities to customize the changegroup packer. | 548 capabilities to customize the changegroup packer. |
549 | |
550 shallow indicates whether shallow data might be sent. The packer may | |
551 need to pack file contents not introduced by the changes being packed. | |
549 """ | 552 """ |
550 assert filematcher | 553 assert filematcher |
551 self._filematcher = filematcher | 554 self._filematcher = filematcher |
552 | 555 |
553 self.version = version | 556 self.version = version |
558 | 561 |
559 # Set of capabilities we can use to build the bundle. | 562 # Set of capabilities we can use to build the bundle. |
560 if bundlecaps is None: | 563 if bundlecaps is None: |
561 bundlecaps = set() | 564 bundlecaps = set() |
562 self._bundlecaps = bundlecaps | 565 self._bundlecaps = bundlecaps |
566 self._isshallow = shallow | |
563 | 567 |
564 # experimental config: bundle.reorder | 568 # experimental config: bundle.reorder |
565 reorder = repo.ui.config('bundle', 'reorder') | 569 reorder = repo.ui.config('bundle', 'reorder') |
566 if reorder == 'auto': | 570 if reorder == 'auto': |
567 self._reorder = allowreorder | 571 self._reorder = allowreorder |
734 # parents) | 738 # parents) |
735 self._next_clrev_to_localrev.setdefault(cl.rev(x), | 739 self._next_clrev_to_localrev.setdefault(cl.rev(x), |
736 mfrevlog.rev(n)) | 740 mfrevlog.rev(n)) |
737 # We can't trust the changed files list in the changeset if the | 741 # We can't trust the changed files list in the changeset if the |
738 # client requested a shallow clone. | 742 # client requested a shallow clone. |
739 if self._is_shallow: | 743 if self._isshallow: |
740 changedfiles.update(mfl[c[0]].read().keys()) | 744 changedfiles.update(mfl[c[0]].read().keys()) |
741 else: | 745 else: |
742 changedfiles.update(c[3]) | 746 changedfiles.update(c[3]) |
743 else: | 747 else: |
744 | 748 |
784 fastpathlinkrev, mfs, fnodes, source): | 788 fastpathlinkrev, mfs, fnodes, source): |
785 yield chunk | 789 yield chunk |
786 | 790 |
787 if ellipsesmode: | 791 if ellipsesmode: |
788 mfdicts = None | 792 mfdicts = None |
789 if self._is_shallow: | 793 if self._isshallow: |
790 mfdicts = [(self._repo.manifestlog[n].read(), lr) | 794 mfdicts = [(self._repo.manifestlog[n].read(), lr) |
791 for (n, lr) in mfs.iteritems()] | 795 for (n, lr) in mfs.iteritems()] |
792 | 796 |
793 mfs.clear() | 797 mfs.clear() |
794 clrevs = set(cl.rev(x) for x in clnodes) | 798 clrevs = set(cl.rev(x) for x in clnodes) |
890 | 894 |
891 # The 'source' parameter is useful for extensions | 895 # The 'source' parameter is useful for extensions |
892 def generatefiles(self, changedfiles, linknodes, commonrevs, source): | 896 def generatefiles(self, changedfiles, linknodes, commonrevs, source): |
893 changedfiles = list(filter(self._filematcher, changedfiles)) | 897 changedfiles = list(filter(self._filematcher, changedfiles)) |
894 | 898 |
895 if getattr(self, '_is_shallow', False): | 899 if self._isshallow: |
896 # See comment in generate() for why this sadness is a thing. | 900 # See comment in generate() for why this sadness is a thing. |
897 mfdicts = self._mfdicts | 901 mfdicts = self._mfdicts |
898 del self._mfdicts | 902 del self._mfdicts |
899 # In a shallow clone, the linknodes callback needs to also include | 903 # In a shallow clone, the linknodes callback needs to also include |
900 # those file nodes that are in the manifests we sent but weren't | 904 # those file nodes that are in the manifests we sent but weren't |
1169 linknode=linknode, | 1173 linknode=linknode, |
1170 flags=flags, | 1174 flags=flags, |
1171 deltachunks=(diffheader, data), | 1175 deltachunks=(diffheader, data), |
1172 ) | 1176 ) |
1173 | 1177 |
1174 def _makecg1packer(repo, filematcher, bundlecaps): | 1178 def _makecg1packer(repo, filematcher, bundlecaps, shallow=False): |
1175 builddeltaheader = lambda d: _CHANGEGROUPV1_DELTA_HEADER.pack( | 1179 builddeltaheader = lambda d: _CHANGEGROUPV1_DELTA_HEADER.pack( |
1176 d.node, d.p1node, d.p2node, d.linknode) | 1180 d.node, d.p1node, d.p2node, d.linknode) |
1177 | 1181 |
1178 return cgpacker(repo, filematcher, b'01', | 1182 return cgpacker(repo, filematcher, b'01', |
1179 useprevdelta=True, | 1183 useprevdelta=True, |
1180 allowreorder=None, | 1184 allowreorder=None, |
1181 builddeltaheader=builddeltaheader, | 1185 builddeltaheader=builddeltaheader, |
1182 manifestsend=b'', | 1186 manifestsend=b'', |
1183 sendtreemanifests=False, | 1187 sendtreemanifests=False, |
1184 bundlecaps=bundlecaps) | 1188 bundlecaps=bundlecaps, |
1185 | 1189 shallow=shallow) |
1186 def _makecg2packer(repo, filematcher, bundlecaps): | 1190 |
1191 def _makecg2packer(repo, filematcher, bundlecaps, shallow=False): | |
1187 builddeltaheader = lambda d: _CHANGEGROUPV2_DELTA_HEADER.pack( | 1192 builddeltaheader = lambda d: _CHANGEGROUPV2_DELTA_HEADER.pack( |
1188 d.node, d.p1node, d.p2node, d.basenode, d.linknode) | 1193 d.node, d.p1node, d.p2node, d.basenode, d.linknode) |
1189 | 1194 |
1190 # Since generaldelta is directly supported by cg2, reordering | 1195 # Since generaldelta is directly supported by cg2, reordering |
1191 # generally doesn't help, so we disable it by default (treating | 1196 # generally doesn't help, so we disable it by default (treating |
1194 useprevdelta=False, | 1199 useprevdelta=False, |
1195 allowreorder=False, | 1200 allowreorder=False, |
1196 builddeltaheader=builddeltaheader, | 1201 builddeltaheader=builddeltaheader, |
1197 manifestsend=b'', | 1202 manifestsend=b'', |
1198 sendtreemanifests=False, | 1203 sendtreemanifests=False, |
1199 bundlecaps=bundlecaps) | 1204 bundlecaps=bundlecaps, |
1200 | 1205 shallow=shallow) |
1201 def _makecg3packer(repo, filematcher, bundlecaps): | 1206 |
1207 def _makecg3packer(repo, filematcher, bundlecaps, shallow=False): | |
1202 builddeltaheader = lambda d: _CHANGEGROUPV3_DELTA_HEADER.pack( | 1208 builddeltaheader = lambda d: _CHANGEGROUPV3_DELTA_HEADER.pack( |
1203 d.node, d.p1node, d.p2node, d.basenode, d.linknode, d.flags) | 1209 d.node, d.p1node, d.p2node, d.basenode, d.linknode, d.flags) |
1204 | 1210 |
1205 return cgpacker(repo, filematcher, b'03', | 1211 return cgpacker(repo, filematcher, b'03', |
1206 useprevdelta=False, | 1212 useprevdelta=False, |
1207 allowreorder=False, | 1213 allowreorder=False, |
1208 builddeltaheader=builddeltaheader, | 1214 builddeltaheader=builddeltaheader, |
1209 manifestsend=closechunk(), | 1215 manifestsend=closechunk(), |
1210 sendtreemanifests=True, | 1216 sendtreemanifests=True, |
1211 bundlecaps=bundlecaps) | 1217 bundlecaps=bundlecaps, |
1218 shallow=shallow) | |
1212 | 1219 |
1213 _packermap = {'01': (_makecg1packer, cg1unpacker), | 1220 _packermap = {'01': (_makecg1packer, cg1unpacker), |
1214 # cg2 adds support for exchanging generaldelta | 1221 # cg2 adds support for exchanging generaldelta |
1215 '02': (_makecg2packer, cg2unpacker), | 1222 '02': (_makecg2packer, cg2unpacker), |
1216 # cg3 adds support for exchanging revlog flags and treemanifests | 1223 # cg3 adds support for exchanging revlog flags and treemanifests |
1266 if 'generaldelta' in repo.requirements: | 1273 if 'generaldelta' in repo.requirements: |
1267 versions.discard('01') | 1274 versions.discard('01') |
1268 assert versions | 1275 assert versions |
1269 return min(versions) | 1276 return min(versions) |
1270 | 1277 |
1271 def getbundler(version, repo, bundlecaps=None, filematcher=None): | 1278 def getbundler(version, repo, bundlecaps=None, filematcher=None, |
1279 shallow=False): | |
1272 assert version in supportedoutgoingversions(repo) | 1280 assert version in supportedoutgoingversions(repo) |
1273 | 1281 |
1274 if filematcher is None: | 1282 if filematcher is None: |
1275 filematcher = matchmod.alwaysmatcher(repo.root, '') | 1283 filematcher = matchmod.alwaysmatcher(repo.root, '') |
1276 | 1284 |
1282 # filter those out. | 1290 # filter those out. |
1283 filematcher = matchmod.intersectmatchers(repo.narrowmatch(), | 1291 filematcher = matchmod.intersectmatchers(repo.narrowmatch(), |
1284 filematcher) | 1292 filematcher) |
1285 | 1293 |
1286 fn = _packermap[version][0] | 1294 fn = _packermap[version][0] |
1287 return fn(repo, filematcher, bundlecaps) | 1295 return fn(repo, filematcher, bundlecaps, shallow=shallow) |
1288 | 1296 |
1289 def getunbundler(version, fh, alg, extras=None): | 1297 def getunbundler(version, fh, alg, extras=None): |
1290 return _packermap[version][1](fh, alg, extras=extras) | 1298 return _packermap[version][1](fh, alg, extras=extras) |
1291 | 1299 |
1292 def _changegroupinfo(repo, nodes, source): | 1300 def _changegroupinfo(repo, nodes, source): |
1377 # We wrap cg1packer.revchunk, using a side channel to pass | 1385 # We wrap cg1packer.revchunk, using a side channel to pass |
1378 # relevant_nodes into that area. Then if linknode isn't in the | 1386 # relevant_nodes into that area. Then if linknode isn't in the |
1379 # set, we know we have an ellipsis node and we should defer | 1387 # set, we know we have an ellipsis node and we should defer |
1380 # sending that node's data. We override close() to detect | 1388 # sending that node's data. We override close() to detect |
1381 # pending ellipsis nodes and flush them. | 1389 # pending ellipsis nodes and flush them. |
1382 packer = getbundler(version, repo, filematcher=match) | 1390 packer = getbundler(version, repo, filematcher=match, |
1391 shallow=depth is not None) | |
1383 # Give the packer the list of nodes which should not be | 1392 # Give the packer the list of nodes which should not be |
1384 # ellipsis nodes. We store this rather than the set of nodes | 1393 # ellipsis nodes. We store this rather than the set of nodes |
1385 # that should be an ellipsis because for very large histories | 1394 # that should be an ellipsis because for very large histories |
1386 # we expect this to be significantly smaller. | 1395 # we expect this to be significantly smaller. |
1387 packer._full_nodes = relevant_nodes | 1396 packer._full_nodes = relevant_nodes |
1393 packer._next_clrev_to_localrev = {} | 1402 packer._next_clrev_to_localrev = {} |
1394 # Maps changelog nodes to changelog revs. Filled in once | 1403 # Maps changelog nodes to changelog revs. Filled in once |
1395 # during changelog stage and then left unmodified. | 1404 # during changelog stage and then left unmodified. |
1396 packer._clnode_to_rev = {} | 1405 packer._clnode_to_rev = {} |
1397 packer._changelog_done = False | 1406 packer._changelog_done = False |
1398 # If true, informs the packer that it is serving shallow content and might | |
1399 # need to pack file contents not introduced by the changes being packed. | |
1400 packer._is_shallow = depth is not None | |
1401 | 1407 |
1402 return packer.generate(common, visitnodes, False, source) | 1408 return packer.generate(common, visitnodes, False, source) |