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)) |