comparison mercurial/changegroup.py @ 38909:1af339c22aeb

changegroup: move fullnodes into cgpacker And with this change, the narrow packer no longer defines any addition attributes on packer instances! Differential Revision: https://phab.mercurial-scm.org/D4091
author Gregory Szorc <gregory.szorc@gmail.com>
date Fri, 03 Aug 2018 13:43:55 -0700
parents 1469584ad5fe
children 245c58952298
comparison
equal deleted inserted replaced
38908:1469584ad5fe 38909:1af339c22aeb
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, ellipses=False, 525 sendtreemanifests, bundlecaps=None, ellipses=False,
526 shallow=False, ellipsisroots=None): 526 shallow=False, ellipsisroots=None, fullnodes=None):
527 """Given a source repo, construct a bundler. 527 """Given a source repo, construct a bundler.
528 528
529 filematcher is a matcher that matches on files to include in the 529 filematcher is a matcher that matches on files to include in the
530 changegroup. Used to facilitate sparse changegroups. 530 changegroup. Used to facilitate sparse changegroups.
531 531
550 unused in core Mercurial, extensions rely on this feature to communicate 550 unused in core Mercurial, extensions rely on this feature to communicate
551 capabilities to customize the changegroup packer. 551 capabilities to customize the changegroup packer.
552 552
553 shallow indicates whether shallow data might be sent. The packer may 553 shallow indicates whether shallow data might be sent. The packer may
554 need to pack file contents not introduced by the changes being packed. 554 need to pack file contents not introduced by the changes being packed.
555
556 fullnodes is the list of nodes which should not be ellipsis nodes. We
557 store this rather than the set of nodes that should be ellipsis because
558 for very large histories we expect this to be significantly smaller.
555 """ 559 """
556 assert filematcher 560 assert filematcher
557 self._filematcher = filematcher 561 self._filematcher = filematcher
558 562
559 self.version = version 563 self.version = version
566 # Set of capabilities we can use to build the bundle. 570 # Set of capabilities we can use to build the bundle.
567 if bundlecaps is None: 571 if bundlecaps is None:
568 bundlecaps = set() 572 bundlecaps = set()
569 self._bundlecaps = bundlecaps 573 self._bundlecaps = bundlecaps
570 self._isshallow = shallow 574 self._isshallow = shallow
575 self._fullnodes = fullnodes
571 576
572 # Maps ellipsis revs to their roots at the changelog level. 577 # Maps ellipsis revs to their roots at the changelog level.
573 self._precomputedellipsis = ellipsisroots 578 self._precomputedellipsis = ellipsisroots
574 579
575 # experimental config: bundle.reorder 580 # experimental config: bundle.reorder
742 if self._ellipses: 747 if self._ellipses:
743 # Only update mfs if x is going to be sent. Otherwise we 748 # Only update mfs if x is going to be sent. Otherwise we
744 # end up with bogus linkrevs specified for manifests and 749 # end up with bogus linkrevs specified for manifests and
745 # we skip some manifest nodes that we should otherwise 750 # we skip some manifest nodes that we should otherwise
746 # have sent. 751 # have sent.
747 if (x in self._full_nodes 752 if (x in self._fullnodes
748 or cl.rev(x) in self._precomputedellipsis): 753 or cl.rev(x) in self._precomputedellipsis):
749 n = c[0] 754 n = c[0]
750 # Record the first changeset introducing this manifest 755 # Record the first changeset introducing this manifest
751 # version. 756 # version.
752 mfs.setdefault(n, x) 757 mfs.setdefault(n, x)
1084 linkrev = self._clnodetorev[linknode] 1089 linkrev = self._clnodetorev[linknode]
1085 self._clrevtolocalrev[linkrev] = rev 1090 self._clrevtolocalrev[linkrev] = rev
1086 1091
1087 # This is a node to send in full, because the changeset it 1092 # This is a node to send in full, because the changeset it
1088 # corresponds to was a full changeset. 1093 # corresponds to was a full changeset.
1089 if linknode in self._full_nodes: 1094 if linknode in self._fullnodes:
1090 return self._revisiondeltanormal(store, rev, prev, linknode) 1095 return self._revisiondeltanormal(store, rev, prev, linknode)
1091 1096
1092 # At this point, a node can either be one we should skip or an 1097 # At this point, a node can either be one we should skip or an
1093 # ellipsis. If it's not an ellipsis, bail immediately. 1098 # ellipsis. If it's not an ellipsis, bail immediately.
1094 if linkrev not in self._precomputedellipsis: 1099 if linkrev not in self._precomputedellipsis:
1133 while walk: 1138 while walk:
1134 p = walk[0] 1139 p = walk[0]
1135 walk = walk[1:] 1140 walk = walk[1:]
1136 if p in self._clrevtolocalrev: 1141 if p in self._clrevtolocalrev:
1137 return self._clrevtolocalrev[p] 1142 return self._clrevtolocalrev[p]
1138 elif p in self._full_nodes: 1143 elif p in self._fullnodes:
1139 walk.extend([pp for pp in self._repo.changelog.parentrevs(p) 1144 walk.extend([pp for pp in self._repo.changelog.parentrevs(p)
1140 if pp != nullrev]) 1145 if pp != nullrev])
1141 elif p in self._precomputedellipsis: 1146 elif p in self._precomputedellipsis:
1142 walk.extend([pp for pp in self._precomputedellipsis[p] 1147 walk.extend([pp for pp in self._precomputedellipsis[p]
1143 if pp != nullrev]) 1148 if pp != nullrev])
1192 flags=flags, 1197 flags=flags,
1193 deltachunks=(diffheader, data), 1198 deltachunks=(diffheader, data),
1194 ) 1199 )
1195 1200
1196 def _makecg1packer(repo, filematcher, bundlecaps, ellipses=False, 1201 def _makecg1packer(repo, filematcher, bundlecaps, ellipses=False,
1197 shallow=False, ellipsisroots=None): 1202 shallow=False, ellipsisroots=None, fullnodes=None):
1198 builddeltaheader = lambda d: _CHANGEGROUPV1_DELTA_HEADER.pack( 1203 builddeltaheader = lambda d: _CHANGEGROUPV1_DELTA_HEADER.pack(
1199 d.node, d.p1node, d.p2node, d.linknode) 1204 d.node, d.p1node, d.p2node, d.linknode)
1200 1205
1201 return cgpacker(repo, filematcher, b'01', 1206 return cgpacker(repo, filematcher, b'01',
1202 useprevdelta=True, 1207 useprevdelta=True,
1205 manifestsend=b'', 1210 manifestsend=b'',
1206 sendtreemanifests=False, 1211 sendtreemanifests=False,
1207 bundlecaps=bundlecaps, 1212 bundlecaps=bundlecaps,
1208 ellipses=ellipses, 1213 ellipses=ellipses,
1209 shallow=shallow, 1214 shallow=shallow,
1210 ellipsisroots=ellipsisroots) 1215 ellipsisroots=ellipsisroots,
1216 fullnodes=fullnodes)
1211 1217
1212 def _makecg2packer(repo, filematcher, bundlecaps, ellipses=False, 1218 def _makecg2packer(repo, filematcher, bundlecaps, ellipses=False,
1213 shallow=False, ellipsisroots=None): 1219 shallow=False, ellipsisroots=None, fullnodes=None):
1214 builddeltaheader = lambda d: _CHANGEGROUPV2_DELTA_HEADER.pack( 1220 builddeltaheader = lambda d: _CHANGEGROUPV2_DELTA_HEADER.pack(
1215 d.node, d.p1node, d.p2node, d.basenode, d.linknode) 1221 d.node, d.p1node, d.p2node, d.basenode, d.linknode)
1216 1222
1217 # Since generaldelta is directly supported by cg2, reordering 1223 # Since generaldelta is directly supported by cg2, reordering
1218 # generally doesn't help, so we disable it by default (treating 1224 # generally doesn't help, so we disable it by default (treating
1224 manifestsend=b'', 1230 manifestsend=b'',
1225 sendtreemanifests=False, 1231 sendtreemanifests=False,
1226 bundlecaps=bundlecaps, 1232 bundlecaps=bundlecaps,
1227 ellipses=ellipses, 1233 ellipses=ellipses,
1228 shallow=shallow, 1234 shallow=shallow,
1229 ellipsisroots=ellipsisroots) 1235 ellipsisroots=ellipsisroots,
1236 fullnodes=fullnodes)
1230 1237
1231 def _makecg3packer(repo, filematcher, bundlecaps, ellipses=False, 1238 def _makecg3packer(repo, filematcher, bundlecaps, ellipses=False,
1232 shallow=False, ellipsisroots=None): 1239 shallow=False, ellipsisroots=None, fullnodes=None):
1233 builddeltaheader = lambda d: _CHANGEGROUPV3_DELTA_HEADER.pack( 1240 builddeltaheader = lambda d: _CHANGEGROUPV3_DELTA_HEADER.pack(
1234 d.node, d.p1node, d.p2node, d.basenode, d.linknode, d.flags) 1241 d.node, d.p1node, d.p2node, d.basenode, d.linknode, d.flags)
1235 1242
1236 return cgpacker(repo, filematcher, b'03', 1243 return cgpacker(repo, filematcher, b'03',
1237 useprevdelta=False, 1244 useprevdelta=False,
1240 manifestsend=closechunk(), 1247 manifestsend=closechunk(),
1241 sendtreemanifests=True, 1248 sendtreemanifests=True,
1242 bundlecaps=bundlecaps, 1249 bundlecaps=bundlecaps,
1243 ellipses=ellipses, 1250 ellipses=ellipses,
1244 shallow=shallow, 1251 shallow=shallow,
1245 ellipsisroots=ellipsisroots) 1252 ellipsisroots=ellipsisroots,
1253 fullnodes=fullnodes)
1246 1254
1247 _packermap = {'01': (_makecg1packer, cg1unpacker), 1255 _packermap = {'01': (_makecg1packer, cg1unpacker),
1248 # cg2 adds support for exchanging generaldelta 1256 # cg2 adds support for exchanging generaldelta
1249 '02': (_makecg2packer, cg2unpacker), 1257 '02': (_makecg2packer, cg2unpacker),
1250 # cg3 adds support for exchanging revlog flags and treemanifests 1258 # cg3 adds support for exchanging revlog flags and treemanifests
1301 versions.discard('01') 1309 versions.discard('01')
1302 assert versions 1310 assert versions
1303 return min(versions) 1311 return min(versions)
1304 1312
1305 def getbundler(version, repo, bundlecaps=None, filematcher=None, 1313 def getbundler(version, repo, bundlecaps=None, filematcher=None,
1306 ellipses=False, shallow=False, ellipsisroots=None): 1314 ellipses=False, shallow=False, ellipsisroots=None,
1315 fullnodes=None):
1307 assert version in supportedoutgoingversions(repo) 1316 assert version in supportedoutgoingversions(repo)
1308 1317
1309 if filematcher is None: 1318 if filematcher is None:
1310 filematcher = matchmod.alwaysmatcher(repo.root, '') 1319 filematcher = matchmod.alwaysmatcher(repo.root, '')
1311 1320
1323 filematcher = matchmod.intersectmatchers(repo.narrowmatch(), 1332 filematcher = matchmod.intersectmatchers(repo.narrowmatch(),
1324 filematcher) 1333 filematcher)
1325 1334
1326 fn = _packermap[version][0] 1335 fn = _packermap[version][0]
1327 return fn(repo, filematcher, bundlecaps, ellipses=ellipses, 1336 return fn(repo, filematcher, bundlecaps, ellipses=ellipses,
1328 shallow=shallow, ellipsisroots=ellipsisroots) 1337 shallow=shallow, ellipsisroots=ellipsisroots,
1338 fullnodes=fullnodes)
1329 1339
1330 def getunbundler(version, fh, alg, extras=None): 1340 def getunbundler(version, fh, alg, extras=None):
1331 return _packermap[version][1](fh, alg, extras=extras) 1341 return _packermap[version][1](fh, alg, extras=extras)
1332 1342
1333 def _changegroupinfo(repo, nodes, source): 1343 def _changegroupinfo(repo, nodes, source):
1417 # sending that node's data. We override close() to detect 1427 # sending that node's data. We override close() to detect
1418 # pending ellipsis nodes and flush them. 1428 # pending ellipsis nodes and flush them.
1419 packer = getbundler(version, repo, filematcher=match, 1429 packer = getbundler(version, repo, filematcher=match,
1420 ellipses=True, 1430 ellipses=True,
1421 shallow=depth is not None, 1431 shallow=depth is not None,
1422 ellipsisroots=ellipsisroots) 1432 ellipsisroots=ellipsisroots,
1423 # Give the packer the list of nodes which should not be 1433 fullnodes=relevant_nodes)
1424 # ellipsis nodes. We store this rather than the set of nodes
1425 # that should be an ellipsis because for very large histories
1426 # we expect this to be significantly smaller.
1427 packer._full_nodes = relevant_nodes
1428 1434
1429 return packer.generate(common, visitnodes, False, source) 1435 return packer.generate(common, visitnodes, False, source)