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, shallow=False): |
525 sendtreemanifests, bundlecaps=None, shallow=False, |
|
526 ellipsisroots=None): |
526 """Given a source repo, construct a bundler. |
527 """Given a source repo, construct a bundler. |
527 |
528 |
528 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 |
529 changegroup. Used to facilitate sparse changegroups. |
530 changegroup. Used to facilitate sparse changegroups. |
530 |
531 |
562 # Set of capabilities we can use to build the bundle. |
563 # Set of capabilities we can use to build the bundle. |
563 if bundlecaps is None: |
564 if bundlecaps is None: |
564 bundlecaps = set() |
565 bundlecaps = set() |
565 self._bundlecaps = bundlecaps |
566 self._bundlecaps = bundlecaps |
566 self._isshallow = shallow |
567 self._isshallow = shallow |
|
568 |
|
569 # Maps ellipsis revs to their roots at the changelog level. |
|
570 self._precomputedellipsis = ellipsisroots |
567 |
571 |
568 # experimental config: bundle.reorder |
572 # experimental config: bundle.reorder |
569 reorder = repo.ui.config('bundle', 'reorder') |
573 reorder = repo.ui.config('bundle', 'reorder') |
570 if reorder == 'auto': |
574 if reorder == 'auto': |
571 self._reorder = allowreorder |
575 self._reorder = allowreorder |
738 # Only update mfs if x is going to be sent. Otherwise we |
742 # Only update mfs if x is going to be sent. Otherwise we |
739 # end up with bogus linkrevs specified for manifests and |
743 # end up with bogus linkrevs specified for manifests and |
740 # we skip some manifest nodes that we should otherwise |
744 # we skip some manifest nodes that we should otherwise |
741 # have sent. |
745 # have sent. |
742 if (x in self._full_nodes |
746 if (x in self._full_nodes |
743 or cl.rev(x) in self._precomputed_ellipsis): |
747 or cl.rev(x) in self._precomputedellipsis): |
744 n = c[0] |
748 n = c[0] |
745 # Record the first changeset introducing this manifest |
749 # Record the first changeset introducing this manifest |
746 # version. |
750 # version. |
747 mfs.setdefault(n, x) |
751 mfs.setdefault(n, x) |
748 # Set this narrow-specific dict so we have the lowest |
752 # Set this narrow-specific dict so we have the lowest |
1084 if linknode in self._full_nodes: |
1088 if linknode in self._full_nodes: |
1085 return self._revisiondeltanormal(store, rev, prev, linknode) |
1089 return self._revisiondeltanormal(store, rev, prev, linknode) |
1086 |
1090 |
1087 # At this point, a node can either be one we should skip or an |
1091 # At this point, a node can either be one we should skip or an |
1088 # ellipsis. If it's not an ellipsis, bail immediately. |
1092 # ellipsis. If it's not an ellipsis, bail immediately. |
1089 if linkrev not in self._precomputed_ellipsis: |
1093 if linkrev not in self._precomputedellipsis: |
1090 return |
1094 return |
1091 |
1095 |
1092 linkparents = self._precomputed_ellipsis[linkrev] |
1096 linkparents = self._precomputedellipsis[linkrev] |
1093 def local(clrev): |
1097 def local(clrev): |
1094 """Turn a changelog revnum into a local revnum. |
1098 """Turn a changelog revnum into a local revnum. |
1095 |
1099 |
1096 The ellipsis dag is stored as revnums on the changelog, |
1100 The ellipsis dag is stored as revnums on the changelog, |
1097 but when we're producing ellipsis entries for |
1101 but when we're producing ellipsis entries for |
1131 if p in self._clrevtolocalrev: |
1135 if p in self._clrevtolocalrev: |
1132 return self._clrevtolocalrev[p] |
1136 return self._clrevtolocalrev[p] |
1133 elif p in self._full_nodes: |
1137 elif p in self._full_nodes: |
1134 walk.extend([pp for pp in self._repo.changelog.parentrevs(p) |
1138 walk.extend([pp for pp in self._repo.changelog.parentrevs(p) |
1135 if pp != nullrev]) |
1139 if pp != nullrev]) |
1136 elif p in self._precomputed_ellipsis: |
1140 elif p in self._precomputedellipsis: |
1137 walk.extend([pp for pp in self._precomputed_ellipsis[p] |
1141 walk.extend([pp for pp in self._precomputedellipsis[p] |
1138 if pp != nullrev]) |
1142 if pp != nullrev]) |
1139 else: |
1143 else: |
1140 # In this case, we've got an ellipsis with parents |
1144 # In this case, we've got an ellipsis with parents |
1141 # outside the current bundle (likely an |
1145 # outside the current bundle (likely an |
1142 # incremental pull). We "know" that we can use the |
1146 # incremental pull). We "know" that we can use the |
1186 linknode=linknode, |
1190 linknode=linknode, |
1187 flags=flags, |
1191 flags=flags, |
1188 deltachunks=(diffheader, data), |
1192 deltachunks=(diffheader, data), |
1189 ) |
1193 ) |
1190 |
1194 |
1191 def _makecg1packer(repo, filematcher, bundlecaps, shallow=False): |
1195 def _makecg1packer(repo, filematcher, bundlecaps, shallow=False, |
|
1196 ellipsisroots=None): |
1192 builddeltaheader = lambda d: _CHANGEGROUPV1_DELTA_HEADER.pack( |
1197 builddeltaheader = lambda d: _CHANGEGROUPV1_DELTA_HEADER.pack( |
1193 d.node, d.p1node, d.p2node, d.linknode) |
1198 d.node, d.p1node, d.p2node, d.linknode) |
1194 |
1199 |
1195 return cgpacker(repo, filematcher, b'01', |
1200 return cgpacker(repo, filematcher, b'01', |
1196 useprevdelta=True, |
1201 useprevdelta=True, |
1197 allowreorder=None, |
1202 allowreorder=None, |
1198 builddeltaheader=builddeltaheader, |
1203 builddeltaheader=builddeltaheader, |
1199 manifestsend=b'', |
1204 manifestsend=b'', |
1200 sendtreemanifests=False, |
1205 sendtreemanifests=False, |
1201 bundlecaps=bundlecaps, |
1206 bundlecaps=bundlecaps, |
1202 shallow=shallow) |
1207 shallow=shallow, |
1203 |
1208 ellipsisroots=ellipsisroots) |
1204 def _makecg2packer(repo, filematcher, bundlecaps, shallow=False): |
1209 |
|
1210 def _makecg2packer(repo, filematcher, bundlecaps, shallow=False, |
|
1211 ellipsisroots=None): |
1205 builddeltaheader = lambda d: _CHANGEGROUPV2_DELTA_HEADER.pack( |
1212 builddeltaheader = lambda d: _CHANGEGROUPV2_DELTA_HEADER.pack( |
1206 d.node, d.p1node, d.p2node, d.basenode, d.linknode) |
1213 d.node, d.p1node, d.p2node, d.basenode, d.linknode) |
1207 |
1214 |
1208 # Since generaldelta is directly supported by cg2, reordering |
1215 # Since generaldelta is directly supported by cg2, reordering |
1209 # generally doesn't help, so we disable it by default (treating |
1216 # generally doesn't help, so we disable it by default (treating |
1213 allowreorder=False, |
1220 allowreorder=False, |
1214 builddeltaheader=builddeltaheader, |
1221 builddeltaheader=builddeltaheader, |
1215 manifestsend=b'', |
1222 manifestsend=b'', |
1216 sendtreemanifests=False, |
1223 sendtreemanifests=False, |
1217 bundlecaps=bundlecaps, |
1224 bundlecaps=bundlecaps, |
1218 shallow=shallow) |
1225 shallow=shallow, |
1219 |
1226 ellipsisroots=ellipsisroots) |
1220 def _makecg3packer(repo, filematcher, bundlecaps, shallow=False): |
1227 |
|
1228 def _makecg3packer(repo, filematcher, bundlecaps, shallow=False, |
|
1229 ellipsisroots=None): |
1221 builddeltaheader = lambda d: _CHANGEGROUPV3_DELTA_HEADER.pack( |
1230 builddeltaheader = lambda d: _CHANGEGROUPV3_DELTA_HEADER.pack( |
1222 d.node, d.p1node, d.p2node, d.basenode, d.linknode, d.flags) |
1231 d.node, d.p1node, d.p2node, d.basenode, d.linknode, d.flags) |
1223 |
1232 |
1224 return cgpacker(repo, filematcher, b'03', |
1233 return cgpacker(repo, filematcher, b'03', |
1225 useprevdelta=False, |
1234 useprevdelta=False, |
1226 allowreorder=False, |
1235 allowreorder=False, |
1227 builddeltaheader=builddeltaheader, |
1236 builddeltaheader=builddeltaheader, |
1228 manifestsend=closechunk(), |
1237 manifestsend=closechunk(), |
1229 sendtreemanifests=True, |
1238 sendtreemanifests=True, |
1230 bundlecaps=bundlecaps, |
1239 bundlecaps=bundlecaps, |
1231 shallow=shallow) |
1240 shallow=shallow, |
|
1241 ellipsisroots=ellipsisroots) |
1232 |
1242 |
1233 _packermap = {'01': (_makecg1packer, cg1unpacker), |
1243 _packermap = {'01': (_makecg1packer, cg1unpacker), |
1234 # cg2 adds support for exchanging generaldelta |
1244 # cg2 adds support for exchanging generaldelta |
1235 '02': (_makecg2packer, cg2unpacker), |
1245 '02': (_makecg2packer, cg2unpacker), |
1236 # cg3 adds support for exchanging revlog flags and treemanifests |
1246 # cg3 adds support for exchanging revlog flags and treemanifests |
1287 versions.discard('01') |
1297 versions.discard('01') |
1288 assert versions |
1298 assert versions |
1289 return min(versions) |
1299 return min(versions) |
1290 |
1300 |
1291 def getbundler(version, repo, bundlecaps=None, filematcher=None, |
1301 def getbundler(version, repo, bundlecaps=None, filematcher=None, |
1292 shallow=False): |
1302 shallow=False, ellipsisroots=None): |
1293 assert version in supportedoutgoingversions(repo) |
1303 assert version in supportedoutgoingversions(repo) |
1294 |
1304 |
1295 if filematcher is None: |
1305 if filematcher is None: |
1296 filematcher = matchmod.alwaysmatcher(repo.root, '') |
1306 filematcher = matchmod.alwaysmatcher(repo.root, '') |
1297 |
1307 |
1303 # filter those out. |
1313 # filter those out. |
1304 filematcher = matchmod.intersectmatchers(repo.narrowmatch(), |
1314 filematcher = matchmod.intersectmatchers(repo.narrowmatch(), |
1305 filematcher) |
1315 filematcher) |
1306 |
1316 |
1307 fn = _packermap[version][0] |
1317 fn = _packermap[version][0] |
1308 return fn(repo, filematcher, bundlecaps, shallow=shallow) |
1318 return fn(repo, filematcher, bundlecaps, shallow=shallow, |
|
1319 ellipsisroots=ellipsisroots) |
1309 |
1320 |
1310 def getunbundler(version, fh, alg, extras=None): |
1321 def getunbundler(version, fh, alg, extras=None): |
1311 return _packermap[version][1](fh, alg, extras=extras) |
1322 return _packermap[version][1](fh, alg, extras=extras) |
1312 |
1323 |
1313 def _changegroupinfo(repo, nodes, source): |
1324 def _changegroupinfo(repo, nodes, source): |
1399 # relevant_nodes into that area. Then if linknode isn't in the |
1410 # relevant_nodes into that area. Then if linknode isn't in the |
1400 # set, we know we have an ellipsis node and we should defer |
1411 # set, we know we have an ellipsis node and we should defer |
1401 # sending that node's data. We override close() to detect |
1412 # sending that node's data. We override close() to detect |
1402 # pending ellipsis nodes and flush them. |
1413 # pending ellipsis nodes and flush them. |
1403 packer = getbundler(version, repo, filematcher=match, |
1414 packer = getbundler(version, repo, filematcher=match, |
1404 shallow=depth is not None) |
1415 shallow=depth is not None, |
|
1416 ellipsisroots=ellipsisroots) |
1405 # Give the packer the list of nodes which should not be |
1417 # Give the packer the list of nodes which should not be |
1406 # ellipsis nodes. We store this rather than the set of nodes |
1418 # ellipsis nodes. We store this rather than the set of nodes |
1407 # that should be an ellipsis because for very large histories |
1419 # that should be an ellipsis because for very large histories |
1408 # we expect this to be significantly smaller. |
1420 # we expect this to be significantly smaller. |
1409 packer._full_nodes = relevant_nodes |
1421 packer._full_nodes = relevant_nodes |
1410 # Maps ellipsis revs to their roots at the changelog level. |
|
1411 packer._precomputed_ellipsis = ellipsisroots |
|
1412 |
1422 |
1413 return packer.generate(common, visitnodes, False, source) |
1423 return packer.generate(common, visitnodes, False, source) |