mercurial/localrepo.py
changeset 13706 7beb9834d185
parent 13703 48d606d7192b
child 13707 296e78744d32
equal deleted inserted replaced
13705:73cfb7a5aa56 13706:7beb9834d185
  1437 
  1437 
  1438         Another wrinkle is doing the reverse, figuring out which changeset in
  1438         Another wrinkle is doing the reverse, figuring out which changeset in
  1439         the changegroup a particular filenode or manifestnode belongs to.
  1439         the changegroup a particular filenode or manifestnode belongs to.
  1440         """
  1440         """
  1441 
  1441 
  1442         # Set up some initial variables
       
  1443         # Make it easy to refer to self.changelog
       
  1444         cl = self.changelog
  1442         cl = self.changelog
       
  1443         mf = self.manifest
       
  1444         mfs = {} # needed manifests
       
  1445         fnodes = {} # needed file nodes
       
  1446 
  1445         # Compute the list of changesets in this changegroup.
  1447         # Compute the list of changesets in this changegroup.
  1446         # Some bases may turn out to be superfluous, and some heads may be
  1448         # Some bases may turn out to be superfluous, and some heads may be
  1447         # too.  nodesbetween will return the minimal set of bases and heads
  1449         # too.  nodesbetween will return the minimal set of bases and heads
  1448         # necessary to re-create the changegroup.
  1450         # necessary to re-create the changegroup.
  1449         if not bases:
  1451         if not bases:
  1450             bases = [nullid]
  1452             bases = [nullid]
  1451         msng_cl_lst, bases, heads = cl.nodesbetween(bases, heads)
  1453         csets, bases, heads = cl.nodesbetween(bases, heads)
  1452 
  1454 
  1453         # can we go through the fast path ?
  1455         # can we go through the fast path ?
  1454         heads.sort()
  1456         heads.sort()
  1455         allheads = self.heads()
  1457         allheads = self.heads()
  1456         allheads.sort()
  1458         allheads.sort()
  1457         if heads == allheads:
  1459         if heads == allheads:
  1458             return self._changegroup(msng_cl_lst, source)
  1460             return self._changegroup(csets, source)
  1459 
  1461 
  1460         # slow path
  1462         # slow path
  1461         self.hook('preoutgoing', throw=True, source=source)
  1463         self.hook('preoutgoing', throw=True, source=source)
  1462 
  1464         self.changegroupinfo(csets, source)
  1463         self.changegroupinfo(msng_cl_lst, source)
       
  1464 
  1465 
  1465         # We assume that all ancestors of bases are known
  1466         # We assume that all ancestors of bases are known
  1466         commonrevs = set(cl.ancestors(*[cl.rev(n) for n in bases]))
  1467         commonrevs = set(cl.ancestors(*[cl.rev(n) for n in bases]))
  1467 
       
  1468         # Make it easy to refer to self.manifest
       
  1469         mnfst = self.manifest
       
  1470         # We don't know which manifests are missing yet
       
  1471         msng_mnfst_set = {}
       
  1472         # Nor do we know which filenodes are missing.
       
  1473         msng_filenode_set = {}
       
  1474 
  1468 
  1475         # A changeset always belongs to itself, so the changenode lookup
  1469         # A changeset always belongs to itself, so the changenode lookup
  1476         # function for a changenode is identity.
  1470         # function for a changenode is identity.
  1477         def identity(x):
  1471         def identity(x):
  1478             return x
  1472             return x
  1485             # so we can include those in the changegroup too.
  1479             # so we can include those in the changegroup too.
  1486             #
  1480             #
  1487             # It also remembers which changenode each filenode belongs to.  It
  1481             # It also remembers which changenode each filenode belongs to.  It
  1488             # does this by assuming the a filenode belongs to the changenode
  1482             # does this by assuming the a filenode belongs to the changenode
  1489             # the first manifest that references it belongs to.
  1483             # the first manifest that references it belongs to.
  1490             def collect_msng_filenodes(mnfstnode):
  1484             def collect(mannode):
  1491                 r = mnfst.rev(mnfstnode)
  1485                 r = mf.rev(mannode)
  1492                 if mnfst.deltaparent(r) in mnfst.parentrevs(r):
  1486                 if mf.deltaparent(r) in mf.parentrevs(r):
  1493                     # If the previous rev is one of the parents,
  1487                     # If the previous rev is one of the parents,
  1494                     # we only need to see a diff.
  1488                     # we only need to see a diff.
  1495                     deltamf = mnfst.readdelta(mnfstnode)
  1489                     deltamf = mf.readdelta(mannode)
  1496                     # For each line in the delta
  1490                     # For each line in the delta
  1497                     for f, fnode in deltamf.iteritems():
  1491                     for f, fnode in deltamf.iteritems():
  1498                         # And if the file is in the list of files we care
  1492                         # And if the file is in the list of files we care
  1499                         # about.
  1493                         # about.
  1500                         if f in changedfiles:
  1494                         if f in changedfiles:
  1501                             # Get the changenode this manifest belongs to
  1495                             # Get the changenode this manifest belongs to
  1502                             clnode = msng_mnfst_set[mnfstnode]
  1496                             clnode = mfs[mannode]
  1503                             # Create the set of filenodes for the file if
  1497                             # Create the set of filenodes for the file if
  1504                             # there isn't one already.
  1498                             # there isn't one already.
  1505                             ndset = msng_filenode_set.setdefault(f, {})
  1499                             ndset = fnodes.setdefault(f, {})
  1506                             # And set the filenode's changelog node to the
  1500                             # And set the filenode's changelog node to the
  1507                             # manifest's if it hasn't been set already.
  1501                             # manifest's if it hasn't been set already.
  1508                             ndset.setdefault(fnode, clnode)
  1502                             ndset.setdefault(fnode, clnode)
  1509                 else:
  1503                 else:
  1510                     # Otherwise we need a full manifest.
  1504                     # Otherwise we need a full manifest.
  1511                     m = mnfst.read(mnfstnode)
  1505                     m = mf.read(mannode)
  1512                     # For every file in we care about.
  1506                     # For every file in we care about.
  1513                     for f in changedfiles:
  1507                     for f in changedfiles:
  1514                         fnode = m.get(f, None)
  1508                         fnode = m.get(f, None)
  1515                         # If it's in the manifest
  1509                         # If it's in the manifest
  1516                         if fnode is not None:
  1510                         if fnode is not None:
  1517                             # See comments above.
  1511                             # See comments above.
  1518                             clnode = msng_mnfst_set[mnfstnode]
  1512                             clnode = mfs[mannode]
  1519                             ndset = msng_filenode_set.setdefault(f, {})
  1513                             ndset = fnodes.setdefault(f, {})
  1520                             ndset.setdefault(fnode, clnode)
  1514                             ndset.setdefault(fnode, clnode)
  1521             return collect_msng_filenodes
  1515             return collect
  1522 
  1516 
  1523         # If we determine that a particular file or manifest node must be a
  1517         # If we determine that a particular file or manifest node must be a
  1524         # node that the recipient of the changegroup will already have, we can
  1518         # node that the recipient of the changegroup will already have, we can
  1525         # also assume the recipient will have all the parents.  This function
  1519         # also assume the recipient will have all the parents.  This function
  1526         # prunes them from the set of missing nodes.
  1520         # prunes them from the set of missing nodes.
  1541         # Now that we have all theses utility functions to help out and
  1535         # Now that we have all theses utility functions to help out and
  1542         # logically divide up the task, generate the group.
  1536         # logically divide up the task, generate the group.
  1543         def gengroup():
  1537         def gengroup():
  1544             # The set of changed files starts empty.
  1538             # The set of changed files starts empty.
  1545             changedfiles = set()
  1539             changedfiles = set()
  1546             collect = changegroup.collector(cl, msng_mnfst_set, changedfiles)
  1540             collect = changegroup.collector(cl, mfs, changedfiles)
  1547 
  1541 
  1548             # Create a changenode group generator that will call our functions
  1542             # Create a changenode group generator that will call our functions
  1549             # back to lookup the owning changenode and collect information.
  1543             # back to lookup the owning changenode and collect information.
  1550             group = cl.group(msng_cl_lst, identity, collect)
  1544             group = cl.group(csets, identity, collect)
  1551             for cnt, chnk in enumerate(group):
  1545             for cnt, chnk in enumerate(group):
  1552                 yield chnk
  1546                 yield chnk
  1553                 # revlog.group yields three entries per node, so
  1547                 # revlog.group yields three entries per node, so
  1554                 # dividing by 3 gives an approximation of how many
  1548                 # dividing by 3 gives an approximation of how many
  1555                 # nodes have been processed.
  1549                 # nodes have been processed.
  1556                 self.ui.progress(_('bundling'), cnt / 3,
  1550                 self.ui.progress(_('bundling'), cnt / 3,
  1557                                  unit=_('changesets'))
  1551                                  unit=_('changesets'))
  1558             changecount = cnt / 3
  1552             changecount = cnt / 3
  1559             self.ui.progress(_('bundling'), None)
  1553             self.ui.progress(_('bundling'), None)
  1560 
  1554 
  1561             prune(mnfst, msng_mnfst_set)
  1555             prune(mf, mfs)
  1562             msng_mnfst_lst = msng_mnfst_set.keys()
       
  1563             # Sort the manifestnodes by revision number.
       
  1564             msng_mnfst_lst.sort(key=mnfst.rev)
       
  1565             # Create a generator for the manifestnodes that calls our lookup
  1556             # Create a generator for the manifestnodes that calls our lookup
  1566             # and data collection functions back.
  1557             # and data collection functions back.
  1567             group = mnfst.group(msng_mnfst_lst,
  1558             group = mf.group(sorted(mfs, key=mf.rev),
  1568                                 lambda mnode: msng_mnfst_set[mnode],
  1559                              lambda mnode: mfs[mnode],
  1569                                 filenode_collector(changedfiles))
  1560                              filenode_collector(changedfiles))
  1570             efiles = {}
  1561             efiles = {}
  1571             for cnt, chnk in enumerate(group):
  1562             for cnt, chnk in enumerate(group):
  1572                 if cnt % 3 == 1:
  1563                 if cnt % 3 == 1:
  1573                     mnode = chnk[:20]
  1564                     mnode = chnk[:20]
  1574                     efiles.update(mnfst.readdelta(mnode))
  1565                     efiles.update(mf.readdelta(mnode))
  1575                 yield chnk
  1566                 yield chnk
  1576                 # see above comment for why we divide by 3
  1567                 # see above comment for why we divide by 3
  1577                 self.ui.progress(_('bundling'), cnt / 3,
  1568                 self.ui.progress(_('bundling'), cnt / 3,
  1578                                  unit=_('manifests'), total=changecount)
  1569                                  unit=_('manifests'), total=changecount)
  1579             self.ui.progress(_('bundling'), None)
  1570             self.ui.progress(_('bundling'), None)
  1580             efiles = len(efiles)
  1571             efiles = len(efiles)
  1581 
  1572 
  1582             # These are no longer needed, dereference and toss the memory for
  1573             mfs.clear()
  1583             # them.
       
  1584             msng_mnfst_lst = None
       
  1585             msng_mnfst_set.clear()
       
  1586 
  1574 
  1587             # Go through all our files in order sorted by name.
  1575             # Go through all our files in order sorted by name.
  1588             for idx, fname in enumerate(sorted(changedfiles)):
  1576             for idx, fname in enumerate(sorted(changedfiles)):
  1589                 filerevlog = self.file(fname)
  1577                 filerevlog = self.file(fname)
  1590                 if not len(filerevlog):
  1578                 if not len(filerevlog):
  1591                     raise util.Abort(_("empty or missing revlog for %s") % fname)
  1579                     raise util.Abort(_("empty or missing revlog for %s") % fname)
  1592                 # Toss out the filenodes that the recipient isn't really
  1580                 # Toss out the filenodes that the recipient isn't really
  1593                 # missing.
  1581                 # missing.
  1594                 missingfnodes = msng_filenode_set.pop(fname, {})
  1582                 missingfnodes = fnodes.pop(fname, {})
  1595                 prune(filerevlog, missingfnodes)
  1583                 prune(filerevlog, missingfnodes)
  1596                 # If any filenodes are left, generate the group for them,
  1584                 # If any filenodes are left, generate the group for them,
  1597                 # otherwise don't bother.
  1585                 # otherwise don't bother.
  1598                 if missingfnodes:
  1586                 if missingfnodes:
  1599                     yield changegroup.chunkheader(len(fname))
  1587                     yield changegroup.chunkheader(len(fname))
  1616                         yield chnk
  1604                         yield chnk
  1617             # Signal that no more groups are left.
  1605             # Signal that no more groups are left.
  1618             yield changegroup.closechunk()
  1606             yield changegroup.closechunk()
  1619             self.ui.progress(_('bundling'), None)
  1607             self.ui.progress(_('bundling'), None)
  1620 
  1608 
  1621             if msng_cl_lst:
  1609             if csets:
  1622                 self.hook('outgoing', node=hex(msng_cl_lst[0]), source=source)
  1610                 self.hook('outgoing', node=hex(csets[0]), source=source)
  1623 
  1611 
  1624         return changegroup.unbundle10(util.chunkbuffer(gengroup()), 'UN')
  1612         return changegroup.unbundle10(util.chunkbuffer(gengroup()), 'UN')
  1625 
  1613 
  1626     def changegroup(self, basenodes, source):
  1614     def changegroup(self, basenodes, source):
  1627         # to avoid a race we use changegroupsubset() (issue1320)
  1615         # to avoid a race we use changegroupsubset() (issue1320)