mercurial/changegroup.py
changeset 46711 a41565bef69f
parent 46627 f4c325bf80fc
child 46712 e8c11a2c96c0
equal deleted inserted replaced
46710:4cd214c9948d 46711:a41565bef69f
    30     scmutil,
    30     scmutil,
    31     util,
    31     util,
    32 )
    32 )
    33 
    33 
    34 from .interfaces import repository
    34 from .interfaces import repository
       
    35 from .revlogutils import sidedata as sidedatamod
    35 
    36 
    36 _CHANGEGROUPV1_DELTA_HEADER = struct.Struct(b"20s20s20s20s")
    37 _CHANGEGROUPV1_DELTA_HEADER = struct.Struct(b"20s20s20s20s")
    37 _CHANGEGROUPV2_DELTA_HEADER = struct.Struct(b"20s20s20s20s20s")
    38 _CHANGEGROUPV2_DELTA_HEADER = struct.Struct(b"20s20s20s20s20s")
    38 _CHANGEGROUPV3_DELTA_HEADER = struct.Struct(b">20s20s20s20s20sH")
    39 _CHANGEGROUPV3_DELTA_HEADER = struct.Struct(b">20s20s20s20s20sH")
    39 
    40 
   200             return {}
   201             return {}
   201         headerdata = readexactly(self._stream, self.deltaheadersize)
   202         headerdata = readexactly(self._stream, self.deltaheadersize)
   202         header = self.deltaheader.unpack(headerdata)
   203         header = self.deltaheader.unpack(headerdata)
   203         delta = readexactly(self._stream, l - self.deltaheadersize)
   204         delta = readexactly(self._stream, l - self.deltaheadersize)
   204         node, p1, p2, deltabase, cs, flags = self._deltaheader(header, prevnode)
   205         node, p1, p2, deltabase, cs, flags = self._deltaheader(header, prevnode)
   205         return (node, p1, p2, cs, deltabase, delta, flags)
   206         # cg4 forward-compat
       
   207         sidedata = {}
       
   208         return (node, p1, p2, cs, deltabase, delta, flags, sidedata)
   206 
   209 
   207     def getchunks(self):
   210     def getchunks(self):
   208         """returns all the chunks contains in the bundle
   211         """returns all the chunks contains in the bundle
   209 
   212 
   210         Used when you need to forward the binary stream to a file or another
   213         Used when you need to forward the binary stream to a file or another
   548             d = chunkdata[b"filename"]
   551             d = chunkdata[b"filename"]
   549             repo.ui.debug(b"adding %s revisions\n" % d)
   552             repo.ui.debug(b"adding %s revisions\n" % d)
   550             deltas = self.deltaiter()
   553             deltas = self.deltaiter()
   551             if not repo.manifestlog.getstorage(d).addgroup(deltas, revmap, trp):
   554             if not repo.manifestlog.getstorage(d).addgroup(deltas, revmap, trp):
   552                 raise error.Abort(_(b"received dir revlog group is empty"))
   555                 raise error.Abort(_(b"received dir revlog group is empty"))
       
   556 
       
   557 
       
   558 class cg4unpacker(cg3unpacker):
       
   559     """Unpacker for cg4 streams.
       
   560 
       
   561     cg4 streams add support for exchanging sidedata.
       
   562     """
       
   563 
       
   564     version = b'04'
       
   565 
       
   566     def deltachunk(self, prevnode):
       
   567         res = super(cg4unpacker, self).deltachunk(prevnode)
       
   568         if not res:
       
   569             return res
       
   570 
       
   571         (node, p1, p2, cs, deltabase, delta, flags, _sidedata) = res
       
   572 
       
   573         sidedata_raw = getchunk(self._stream)
       
   574         sidedata = {}
       
   575         if len(sidedata_raw) > 0:
       
   576             sidedata = sidedatamod.deserialize_sidedata(sidedata_raw)
       
   577 
       
   578         return node, p1, p2, cs, deltabase, delta, flags, sidedata
   553 
   579 
   554 
   580 
   555 class headerlessfixup(object):
   581 class headerlessfixup(object):
   556     def __init__(self, fh, h):
   582     def __init__(self, fh, h):
   557         self._h = h
   583         self._h = h
   859         bundlecaps=None,
   885         bundlecaps=None,
   860         ellipses=False,
   886         ellipses=False,
   861         shallow=False,
   887         shallow=False,
   862         ellipsisroots=None,
   888         ellipsisroots=None,
   863         fullnodes=None,
   889         fullnodes=None,
       
   890         remote_sidedata=None,
   864     ):
   891     ):
   865         """Given a source repo, construct a bundler.
   892         """Given a source repo, construct a bundler.
   866 
   893 
   867         oldmatcher is a matcher that matches on files the client already has.
   894         oldmatcher is a matcher that matches on files the client already has.
   868         These will not be included in the changegroup.
   895         These will not be included in the changegroup.
   891 
   918 
   892         fullnodes is the set of changelog nodes which should not be ellipsis
   919         fullnodes is the set of changelog nodes which should not be ellipsis
   893         nodes. We store this rather than the set of nodes that should be
   920         nodes. We store this rather than the set of nodes that should be
   894         ellipsis because for very large histories we expect this to be
   921         ellipsis because for very large histories we expect this to be
   895         significantly smaller.
   922         significantly smaller.
       
   923 
       
   924         remote_sidedata is the set of sidedata categories wanted by the remote.
   896         """
   925         """
   897         assert oldmatcher
   926         assert oldmatcher
   898         assert matcher
   927         assert matcher
   899         self._oldmatcher = oldmatcher
   928         self._oldmatcher = oldmatcher
   900         self._matcher = matcher
   929         self._matcher = matcher
   986             clstate[b'clrevtomanifestrev'],
  1015             clstate[b'clrevtomanifestrev'],
   987         )
  1016         )
   988 
  1017 
   989         for tree, deltas in it:
  1018         for tree, deltas in it:
   990             if tree:
  1019             if tree:
   991                 assert self.version == b'03'
  1020                 assert self.version in (b'03', b'04')
   992                 chunk = _fileheader(tree)
  1021                 chunk = _fileheader(tree)
   993                 size += len(chunk)
  1022                 size += len(chunk)
   994                 yield chunk
  1023                 yield chunk
   995 
  1024 
   996             for delta in deltas:
  1025             for delta in deltas:
  1392     bundlecaps,
  1421     bundlecaps,
  1393     ellipses=False,
  1422     ellipses=False,
  1394     shallow=False,
  1423     shallow=False,
  1395     ellipsisroots=None,
  1424     ellipsisroots=None,
  1396     fullnodes=None,
  1425     fullnodes=None,
       
  1426     remote_sidedata=None,
  1397 ):
  1427 ):
  1398     builddeltaheader = lambda d: _CHANGEGROUPV1_DELTA_HEADER.pack(
  1428     builddeltaheader = lambda d: _CHANGEGROUPV1_DELTA_HEADER.pack(
  1399         d.node, d.p1node, d.p2node, d.linknode
  1429         d.node, d.p1node, d.p2node, d.linknode
  1400     )
  1430     )
  1401 
  1431 
  1422     bundlecaps,
  1452     bundlecaps,
  1423     ellipses=False,
  1453     ellipses=False,
  1424     shallow=False,
  1454     shallow=False,
  1425     ellipsisroots=None,
  1455     ellipsisroots=None,
  1426     fullnodes=None,
  1456     fullnodes=None,
       
  1457     remote_sidedata=None,
  1427 ):
  1458 ):
  1428     builddeltaheader = lambda d: _CHANGEGROUPV2_DELTA_HEADER.pack(
  1459     builddeltaheader = lambda d: _CHANGEGROUPV2_DELTA_HEADER.pack(
  1429         d.node, d.p1node, d.p2node, d.basenode, d.linknode
  1460         d.node, d.p1node, d.p2node, d.basenode, d.linknode
  1430     )
  1461     )
  1431 
  1462 
  1451     bundlecaps,
  1482     bundlecaps,
  1452     ellipses=False,
  1483     ellipses=False,
  1453     shallow=False,
  1484     shallow=False,
  1454     ellipsisroots=None,
  1485     ellipsisroots=None,
  1455     fullnodes=None,
  1486     fullnodes=None,
       
  1487     remote_sidedata=None,
  1456 ):
  1488 ):
  1457     builddeltaheader = lambda d: _CHANGEGROUPV3_DELTA_HEADER.pack(
  1489     builddeltaheader = lambda d: _CHANGEGROUPV3_DELTA_HEADER.pack(
  1458         d.node, d.p1node, d.p2node, d.basenode, d.linknode, d.flags
  1490         d.node, d.p1node, d.p2node, d.basenode, d.linknode, d.flags
  1459     )
  1491     )
  1460 
  1492 
  1471         ellipsisroots=ellipsisroots,
  1503         ellipsisroots=ellipsisroots,
  1472         fullnodes=fullnodes,
  1504         fullnodes=fullnodes,
  1473     )
  1505     )
  1474 
  1506 
  1475 
  1507 
       
  1508 def _makecg4packer(
       
  1509     repo,
       
  1510     oldmatcher,
       
  1511     matcher,
       
  1512     bundlecaps,
       
  1513     ellipses=False,
       
  1514     shallow=False,
       
  1515     ellipsisroots=None,
       
  1516     fullnodes=None,
       
  1517     remote_sidedata=None,
       
  1518 ):
       
  1519     # Same header func as cg3. Sidedata is in a separate chunk from the delta to
       
  1520     # differenciate "raw delta" and sidedata.
       
  1521     builddeltaheader = lambda d: _CHANGEGROUPV3_DELTA_HEADER.pack(
       
  1522         d.node, d.p1node, d.p2node, d.basenode, d.linknode, d.flags
       
  1523     )
       
  1524 
       
  1525     return cgpacker(
       
  1526         repo,
       
  1527         oldmatcher,
       
  1528         matcher,
       
  1529         b'04',
       
  1530         builddeltaheader=builddeltaheader,
       
  1531         manifestsend=closechunk(),
       
  1532         bundlecaps=bundlecaps,
       
  1533         ellipses=ellipses,
       
  1534         shallow=shallow,
       
  1535         ellipsisroots=ellipsisroots,
       
  1536         fullnodes=fullnodes,
       
  1537         remote_sidedata=remote_sidedata,
       
  1538     )
       
  1539 
       
  1540 
  1476 _packermap = {
  1541 _packermap = {
  1477     b'01': (_makecg1packer, cg1unpacker),
  1542     b'01': (_makecg1packer, cg1unpacker),
  1478     # cg2 adds support for exchanging generaldelta
  1543     # cg2 adds support for exchanging generaldelta
  1479     b'02': (_makecg2packer, cg2unpacker),
  1544     b'02': (_makecg2packer, cg2unpacker),
  1480     # cg3 adds support for exchanging revlog flags and treemanifests
  1545     # cg3 adds support for exchanging revlog flags and treemanifests
  1481     b'03': (_makecg3packer, cg3unpacker),
  1546     b'03': (_makecg3packer, cg3unpacker),
       
  1547     # ch4 adds support for exchanging sidedata
       
  1548     b'04': (_makecg4packer, cg4unpacker),
  1482 }
  1549 }
  1483 
  1550 
  1484 
  1551 
  1485 def allsupportedversions(repo):
  1552 def allsupportedversions(repo):
  1486     versions = set(_packermap.keys())
  1553     versions = set(_packermap.keys())
  1496         # contains both normal and tree manifest at the same time. so using
  1563         # contains both normal and tree manifest at the same time. so using
  1497         # older version to pull data is viable
  1564         # older version to pull data is viable
  1498         #
  1565         #
  1499         # (or even to push subset of history)
  1566         # (or even to push subset of history)
  1500         needv03 = True
  1567         needv03 = True
  1501     if b'exp-sidedata-flag' in repo.requirements:
  1568     has_revlogv2 = requirements.REVLOGV2_REQUIREMENT in repo.requirements
  1502         needv03 = True
  1569     if not has_revlogv2:
  1503         # don't attempt to use 01/02 until we do sidedata cleaning
  1570         versions.discard(b'04')
  1504         versions.discard(b'01')
       
  1505         versions.discard(b'02')
       
  1506     if not needv03:
  1571     if not needv03:
  1507         versions.discard(b'03')
  1572         versions.discard(b'03')
  1508     return versions
  1573     return versions
  1509 
  1574 
  1510 
  1575 
  1563     matcher=None,
  1628     matcher=None,
  1564     ellipses=False,
  1629     ellipses=False,
  1565     shallow=False,
  1630     shallow=False,
  1566     ellipsisroots=None,
  1631     ellipsisroots=None,
  1567     fullnodes=None,
  1632     fullnodes=None,
       
  1633     remote_sidedata=None,
  1568 ):
  1634 ):
  1569     assert version in supportedoutgoingversions(repo)
  1635     assert version in supportedoutgoingversions(repo)
  1570 
  1636 
  1571     if matcher is None:
  1637     if matcher is None:
  1572         matcher = matchmod.always()
  1638         matcher = matchmod.always()
  1599         bundlecaps,
  1665         bundlecaps,
  1600         ellipses=ellipses,
  1666         ellipses=ellipses,
  1601         shallow=shallow,
  1667         shallow=shallow,
  1602         ellipsisroots=ellipsisroots,
  1668         ellipsisroots=ellipsisroots,
  1603         fullnodes=fullnodes,
  1669         fullnodes=fullnodes,
       
  1670         remote_sidedata=remote_sidedata,
  1604     )
  1671     )
  1605 
  1672 
  1606 
  1673 
  1607 def getunbundler(version, fh, alg, extras=None):
  1674 def getunbundler(version, fh, alg, extras=None):
  1608     return _packermap[version][1](fh, alg, extras=extras)
  1675     return _packermap[version][1](fh, alg, extras=extras)
  1642     version,
  1709     version,
  1643     source,
  1710     source,
  1644     fastpath=False,
  1711     fastpath=False,
  1645     bundlecaps=None,
  1712     bundlecaps=None,
  1646     matcher=None,
  1713     matcher=None,
       
  1714     remote_sidedata=None,
  1647 ):
  1715 ):
  1648     bundler = getbundler(version, repo, bundlecaps=bundlecaps, matcher=matcher)
  1716     bundler = getbundler(
       
  1717         version,
       
  1718         repo,
       
  1719         bundlecaps=bundlecaps,
       
  1720         matcher=matcher,
       
  1721         remote_sidedata=remote_sidedata,
       
  1722     )
  1649 
  1723 
  1650     repo = repo.unfiltered()
  1724     repo = repo.unfiltered()
  1651     commonrevs = outgoing.common
  1725     commonrevs = outgoing.common
  1652     csets = outgoing.missing
  1726     csets = outgoing.missing
  1653     heads = outgoing.ancestorsof
  1727     heads = outgoing.ancestorsof