comparison mercurial/changegroup.py @ 39001:a6e1ff40e335

changegroup: pass clrevtolocalrev to each group clrevtolocalrev is a per-changegroup group mapping revisions to aid with shallow clone. Back when this functionality was implemented in an extension, this dict was added to the packer instance so monkeypatched functions could reference it there. Now that this code is part of core, we can pass the dict to each consumer properly so it doesn't have to live on the cgpacker instance. This commit does that. Differential Revision: https://phab.mercurial-scm.org/D4193
author Gregory Szorc <gregory.szorc@gmail.com>
date Tue, 07 Aug 2018 14:52:00 -0700
parents 4cff37564006
children eb8a0139ace3
comparison
equal deleted inserted replaced
39000:4cff37564006 39001:a6e1ff40e335
656 if self._repo.ui.verbose and not self._repo.ui.debugflag: 656 if self._repo.ui.verbose and not self._repo.ui.debugflag:
657 self._verbosenote = self._repo.ui.note 657 self._verbosenote = self._repo.ui.note
658 else: 658 else:
659 self._verbosenote = lambda s: None 659 self._verbosenote = lambda s: None
660 660
661 # Maps CL revs to per-revlog revisions. Cleared in close() at
662 # the end of each group.
663 self._clrevtolocalrev = {}
664
665 def _close(self): 661 def _close(self):
666 # Ellipses serving mode.
667 self._clrevtolocalrev.clear()
668
669 return closechunk() 662 return closechunk()
670 663
671 def group(self, revs, store, ischangelog, lookup, units=None): 664 def group(self, revs, store, ischangelog, lookup, units=None,
665 clrevtolocalrev=None):
672 """Calculate a delta group, yielding a sequence of changegroup chunks 666 """Calculate a delta group, yielding a sequence of changegroup chunks
673 (strings). 667 (strings).
674 668
675 Given a list of changeset revs, return a set of deltas and 669 Given a list of changeset revs, return a set of deltas and
676 metadata corresponding to nodes. The first delta is 670 metadata corresponding to nodes. The first delta is
704 prev, curr = revs[r], revs[r + 1] 698 prev, curr = revs[r], revs[r + 1]
705 linknode = lookup(store.node(curr)) 699 linknode = lookup(store.node(curr))
706 700
707 if self._ellipses: 701 if self._ellipses:
708 linkrev = cl.rev(linknode) 702 linkrev = cl.rev(linknode)
709 self._clrevtolocalrev[linkrev] = curr 703 clrevtolocalrev[linkrev] = curr
710 704
711 # This is a node to send in full, because the changeset it 705 # This is a node to send in full, because the changeset it
712 # corresponds to was a full changeset. 706 # corresponds to was a full changeset.
713 if linknode in self._fullclnodes: 707 if linknode in self._fullclnodes:
714 delta = _revisiondeltanormal(store, curr, prev, linknode, 708 delta = _revisiondeltanormal(store, curr, prev, linknode,
715 self._deltaparentfn) 709 self._deltaparentfn)
716 elif linkrev not in self._precomputedellipsis: 710 elif linkrev not in self._precomputedellipsis:
717 delta = None 711 delta = None
718 else: 712 else:
719 delta = self._revisiondeltanarrow(store, ischangelog, 713 delta = self._revisiondeltanarrow(store, ischangelog,
720 curr, linkrev, linknode) 714 curr, linkrev, linknode,
715 clrevtolocalrev)
721 else: 716 else:
722 delta = _revisiondeltanormal(store, curr, prev, linknode, 717 delta = _revisiondeltanormal(store, curr, prev, linknode,
723 self._deltaparentfn) 718 self._deltaparentfn)
724 719
725 if not delta: 720 if not delta:
744 return [] 739 return []
745 740
746 rr, rl = store.rev, store.linkrev 741 rr, rl = store.rev, store.linkrev
747 return [n for n in missing if rl(rr(n)) not in commonrevs] 742 return [n for n in missing if rl(rr(n)) not in commonrevs]
748 743
749 def _packmanifests(self, dir, dirlog, revs, lookuplinknode): 744 def _packmanifests(self, dir, dirlog, revs, lookuplinknode,
745 clrevtolocalrev):
750 """Pack manifests into a changegroup stream. 746 """Pack manifests into a changegroup stream.
751 747
752 Encodes the directory name in the output so multiple manifests 748 Encodes the directory name in the output so multiple manifests
753 can be sent. Multiple manifests is not supported by cg1 and cg2. 749 can be sent. Multiple manifests is not supported by cg1 and cg2.
754 """ 750 """
755 if dir: 751 if dir:
756 assert self.version == b'03' 752 assert self.version == b'03'
757 yield _fileheader(dir) 753 yield _fileheader(dir)
758 754
759 for chunk in self.group(revs, dirlog, False, lookuplinknode, 755 for chunk in self.group(revs, dirlog, False, lookuplinknode,
760 units=_('manifests')): 756 units=_('manifests'),
757 clrevtolocalrev=clrevtolocalrev):
761 yield chunk 758 yield chunk
762 759
763 def generate(self, commonrevs, clnodes, fastpathlinkrev, source): 760 def generate(self, commonrevs, clnodes, fastpathlinkrev, source):
764 """Yield a sequence of changegroup byte chunks.""" 761 """Yield a sequence of changegroup byte chunks."""
765 762
777 self._verbosenote(_('%8.i (changelog)\n') % size) 774 self._verbosenote(_('%8.i (changelog)\n') % size)
778 775
779 clrevorder = clstate['clrevorder'] 776 clrevorder = clstate['clrevorder']
780 mfs = clstate['mfs'] 777 mfs = clstate['mfs']
781 changedfiles = clstate['changedfiles'] 778 changedfiles = clstate['changedfiles']
782
783 if self._ellipses:
784 self._clrevtolocalrev = clstate['clrevtomanifestrev']
785 779
786 # We need to make sure that the linkrev in the changegroup refers to 780 # We need to make sure that the linkrev in the changegroup refers to
787 # the first changeset that introduced the manifest or file revision. 781 # the first changeset that introduced the manifest or file revision.
788 # The fastpath is usually safer than the slowpath, because the filelogs 782 # The fastpath is usually safer than the slowpath, because the filelogs
789 # are walked in revlog order. 783 # are walked in revlog order.
806 'treemanifest' not in repo.requirements) 800 'treemanifest' not in repo.requirements)
807 801
808 fnodes = {} # needed file nodes 802 fnodes = {} # needed file nodes
809 803
810 for chunk in self.generatemanifests(commonrevs, clrevorder, 804 for chunk in self.generatemanifests(commonrevs, clrevorder,
811 fastpathlinkrev, mfs, fnodes, source): 805 fastpathlinkrev, mfs, fnodes, source,
806 clstate['clrevtomanifestrev']):
812 yield chunk 807 yield chunk
813 808
814 mfdicts = None 809 mfdicts = None
815 if self._ellipses and self._isshallow: 810 if self._ellipses and self._isshallow:
816 mfdicts = [(self._repo.manifestlog[n].read(), lr) 811 mfdicts = [(self._repo.manifestlog[n].read(), lr)
893 'mfs': mfs, 888 'mfs': mfs,
894 'changedfiles': changedfiles, 889 'changedfiles': changedfiles,
895 'clrevtomanifestrev': clrevtomanifestrev, 890 'clrevtomanifestrev': clrevtomanifestrev,
896 } 891 }
897 892
898 gen = self.group(revs, cl, True, lookupcl, units=_('changesets')) 893 gen = self.group(revs, cl, True, lookupcl, units=_('changesets'),
894 clrevtolocalrev={})
899 895
900 return state, gen 896 return state, gen
901 897
902 def generatemanifests(self, commonrevs, clrevorder, fastpathlinkrev, mfs, 898 def generatemanifests(self, commonrevs, clrevorder, fastpathlinkrev, mfs,
903 fnodes, source): 899 fnodes, source, clrevtolocalrev):
904 """Returns an iterator of changegroup chunks containing manifests. 900 """Returns an iterator of changegroup chunks containing manifests.
905 901
906 `source` is unused here, but is used by extensions like remotefilelog to 902 `source` is unused here, but is used by extensions like remotefilelog to
907 change what is sent based in pulls vs pushes, etc. 903 change what is sent based in pulls vs pushes, etc.
908 """ 904 """
967 lookupfn) 963 lookupfn)
968 else: 964 else:
969 revs = _sortnodesnormal(store, prunednodes, 965 revs = _sortnodesnormal(store, prunednodes,
970 self._reorder) 966 self._reorder)
971 967
972 for x in self._packmanifests(dir, store, revs, lookupfn): 968 for x in self._packmanifests(dir, store, revs, lookupfn,
969 clrevtolocalrev):
973 size += len(x) 970 size += len(x)
974 yield x 971 yield x
975 self._verbosenote(_('%8.i (manifests)\n') % size) 972 self._verbosenote(_('%8.i (manifests)\n') % size)
976 yield self._manifestsend 973 yield self._manifestsend
977 974
990 flinkrev = store.linkrev 987 flinkrev = store.linkrev
991 fnode = store.node 988 fnode = store.node
992 revs = ((r, flinkrev(r)) for r in store) 989 revs = ((r, flinkrev(r)) for r in store)
993 return dict((fnode(r), cln(lr)) 990 return dict((fnode(r), cln(lr))
994 for r, lr in revs if lr in clrevs) 991 for r, lr in revs if lr in clrevs)
992
993 clrevtolocalrev = {}
995 994
996 if self._isshallow: 995 if self._isshallow:
997 # In a shallow clone, the linknodes callback needs to also include 996 # In a shallow clone, the linknodes callback needs to also include
998 # those file nodes that are in the manifests we sent but weren't 997 # those file nodes that are in the manifests we sent but weren't
999 # introduced by those manifests. 998 # introduced by those manifests.
1005 # TODO have caller pass in appropriate function. 1004 # TODO have caller pass in appropriate function.
1006 def linknodes(flog, fname): 1005 def linknodes(flog, fname):
1007 for c in commonctxs: 1006 for c in commonctxs:
1008 try: 1007 try:
1009 fnode = c.filenode(fname) 1008 fnode = c.filenode(fname)
1010 self._clrevtolocalrev[c.rev()] = flog.rev(fnode) 1009 clrevtolocalrev[c.rev()] = flog.rev(fnode)
1011 except error.ManifestLookupError: 1010 except error.ManifestLookupError:
1012 pass 1011 pass
1013 links = normallinknodes(flog, fname) 1012 links = normallinknodes(flog, fname)
1014 if len(links) != len(mfdicts): 1013 if len(links) != len(mfdicts):
1015 for mf, lr in mfdicts: 1014 for mf, lr in mfdicts:
1030 filerevlog = repo.file(fname) 1029 filerevlog = repo.file(fname)
1031 if not filerevlog: 1030 if not filerevlog:
1032 raise error.Abort(_("empty or missing file data for %s") % 1031 raise error.Abort(_("empty or missing file data for %s") %
1033 fname) 1032 fname)
1034 1033
1034 clrevtolocalrev.clear()
1035
1035 linkrevnodes = linknodes(filerevlog, fname) 1036 linkrevnodes = linknodes(filerevlog, fname)
1036 # Lookup for filenodes, we collected the linkrev nodes above in the 1037 # Lookup for filenodes, we collected the linkrev nodes above in the
1037 # fastpath case and with lookupmf in the slowpath case. 1038 # fastpath case and with lookupmf in the slowpath case.
1038 def lookupfilelog(x): 1039 def lookupfilelog(x):
1039 return linkrevnodes[x] 1040 return linkrevnodes[x]
1049 1050
1050 progress.update(i + 1, item=fname) 1051 progress.update(i + 1, item=fname)
1051 h = _fileheader(fname) 1052 h = _fileheader(fname)
1052 size = len(h) 1053 size = len(h)
1053 yield h 1054 yield h
1054 for chunk in self.group(revs, filerevlog, False, lookupfilelog): 1055 for chunk in self.group(revs, filerevlog, False, lookupfilelog,
1056 clrevtolocalrev=clrevtolocalrev):
1055 size += len(chunk) 1057 size += len(chunk)
1056 yield chunk 1058 yield chunk
1057 self._verbosenote(_('%8.i %s\n') % (size, fname)) 1059 self._verbosenote(_('%8.i %s\n') % (size, fname))
1058 progress.complete() 1060 progress.complete()
1059 1061
1060 def _revisiondeltanarrow(self, store, ischangelog, rev, linkrev, linknode): 1062 def _revisiondeltanarrow(self, store, ischangelog, rev, linkrev, linknode,
1063 clrevtolocalrev):
1061 linkparents = self._precomputedellipsis[linkrev] 1064 linkparents = self._precomputedellipsis[linkrev]
1062 def local(clrev): 1065 def local(clrev):
1063 """Turn a changelog revnum into a local revnum. 1066 """Turn a changelog revnum into a local revnum.
1064 1067
1065 The ellipsis dag is stored as revnums on the changelog, 1068 The ellipsis dag is stored as revnums on the changelog,
1087 # nodes even after ellipsis-izing. 1090 # nodes even after ellipsis-izing.
1088 walk = [clrev] 1091 walk = [clrev]
1089 while walk: 1092 while walk:
1090 p = walk[0] 1093 p = walk[0]
1091 walk = walk[1:] 1094 walk = walk[1:]
1092 if p in self._clrevtolocalrev: 1095 if p in clrevtolocalrev:
1093 return self._clrevtolocalrev[p] 1096 return clrevtolocalrev[p]
1094 elif p in self._fullclnodes: 1097 elif p in self._fullclnodes:
1095 walk.extend([pp for pp in self._repo.changelog.parentrevs(p) 1098 walk.extend([pp for pp in self._repo.changelog.parentrevs(p)
1096 if pp != nullrev]) 1099 if pp != nullrev])
1097 elif p in self._precomputedellipsis: 1100 elif p in self._precomputedellipsis:
1098 walk.extend([pp for pp in self._precomputedellipsis[p] 1101 walk.extend([pp for pp in self._precomputedellipsis[p]