Mercurial > hg
comparison mercurial/changegroup.py @ 38886:66cf046ef60f
changegroup: move revchunk() from narrow
The monkeypatched revchunk for ellipses serving is a
completely independent implementation. We model it as such
in the changegroup code. revchunk() is now a simple proxy
function.
Again, I wish we had better APIs here. Especially since this
narrow code is part of cg1packer and cg1packer can't be used
with narrow. Class inheritance is wonky. And I will definitely
be making changes to changegroup code for delta generation.
As part of the code move, `node.nullrev` was replaced by
`nullrev`. And a reference to `orig` was replaced to call
`self._revchunknormal` directly.
Differential Revision: https://phab.mercurial-scm.org/D4063
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Thu, 02 Aug 2018 09:53:22 -0700 |
parents | 5839a170357d |
children | 75d6139e69f9 |
comparison
equal
deleted
inserted
replaced
38885:5839a170357d | 38886:66cf046ef60f |
---|---|
800 if not revlog.candelta(prev, rev): | 800 if not revlog.candelta(prev, rev): |
801 raise error.ProgrammingError('cg1 should not be used in this case') | 801 raise error.ProgrammingError('cg1 should not be used in this case') |
802 return prev | 802 return prev |
803 | 803 |
804 def revchunk(self, revlog, rev, prev, linknode): | 804 def revchunk(self, revlog, rev, prev, linknode): |
805 if util.safehasattr(self, 'full_nodes'): | |
806 fn = self._revchunknarrow | |
807 else: | |
808 fn = self._revchunknormal | |
809 | |
810 return fn(revlog, rev, prev, linknode) | |
811 | |
812 def _revchunknormal(self, revlog, rev, prev, linknode): | |
805 node = revlog.node(rev) | 813 node = revlog.node(rev) |
806 p1, p2 = revlog.parentrevs(rev) | 814 p1, p2 = revlog.parentrevs(rev) |
807 base = self.deltaparent(revlog, rev, p1, p2, prev) | 815 base = self.deltaparent(revlog, rev, p1, p2, prev) |
808 | 816 |
809 prefix = '' | 817 prefix = '' |
829 meta += prefix | 837 meta += prefix |
830 l = len(meta) + len(delta) | 838 l = len(meta) + len(delta) |
831 yield chunkheader(l) | 839 yield chunkheader(l) |
832 yield meta | 840 yield meta |
833 yield delta | 841 yield delta |
842 | |
843 def _revchunknarrow(self, revlog, rev, prev, linknode): | |
844 # build up some mapping information that's useful later. See | |
845 # the local() nested function below. | |
846 if not self.changelog_done: | |
847 self.clnode_to_rev[linknode] = rev | |
848 linkrev = rev | |
849 self.clrev_to_localrev[linkrev] = rev | |
850 else: | |
851 linkrev = self.clnode_to_rev[linknode] | |
852 self.clrev_to_localrev[linkrev] = rev | |
853 | |
854 # This is a node to send in full, because the changeset it | |
855 # corresponds to was a full changeset. | |
856 if linknode in self.full_nodes: | |
857 for x in self._revchunknormal(revlog, rev, prev, linknode): | |
858 yield x | |
859 return | |
860 | |
861 # At this point, a node can either be one we should skip or an | |
862 # ellipsis. If it's not an ellipsis, bail immediately. | |
863 if linkrev not in self.precomputed_ellipsis: | |
864 return | |
865 | |
866 linkparents = self.precomputed_ellipsis[linkrev] | |
867 def local(clrev): | |
868 """Turn a changelog revnum into a local revnum. | |
869 | |
870 The ellipsis dag is stored as revnums on the changelog, | |
871 but when we're producing ellipsis entries for | |
872 non-changelog revlogs, we need to turn those numbers into | |
873 something local. This does that for us, and during the | |
874 changelog sending phase will also expand the stored | |
875 mappings as needed. | |
876 """ | |
877 if clrev == nullrev: | |
878 return nullrev | |
879 | |
880 if not self.changelog_done: | |
881 # If we're doing the changelog, it's possible that we | |
882 # have a parent that is already on the client, and we | |
883 # need to store some extra mapping information so that | |
884 # our contained ellipsis nodes will be able to resolve | |
885 # their parents. | |
886 if clrev not in self.clrev_to_localrev: | |
887 clnode = revlog.node(clrev) | |
888 self.clnode_to_rev[clnode] = clrev | |
889 return clrev | |
890 | |
891 # Walk the ellipsis-ized changelog breadth-first looking for a | |
892 # change that has been linked from the current revlog. | |
893 # | |
894 # For a flat manifest revlog only a single step should be necessary | |
895 # as all relevant changelog entries are relevant to the flat | |
896 # manifest. | |
897 # | |
898 # For a filelog or tree manifest dirlog however not every changelog | |
899 # entry will have been relevant, so we need to skip some changelog | |
900 # nodes even after ellipsis-izing. | |
901 walk = [clrev] | |
902 while walk: | |
903 p = walk[0] | |
904 walk = walk[1:] | |
905 if p in self.clrev_to_localrev: | |
906 return self.clrev_to_localrev[p] | |
907 elif p in self.full_nodes: | |
908 walk.extend([pp for pp in self._repo.changelog.parentrevs(p) | |
909 if pp != nullrev]) | |
910 elif p in self.precomputed_ellipsis: | |
911 walk.extend([pp for pp in self.precomputed_ellipsis[p] | |
912 if pp != nullrev]) | |
913 else: | |
914 # In this case, we've got an ellipsis with parents | |
915 # outside the current bundle (likely an | |
916 # incremental pull). We "know" that we can use the | |
917 # value of this same revlog at whatever revision | |
918 # is pointed to by linknode. "Know" is in scare | |
919 # quotes because I haven't done enough examination | |
920 # of edge cases to convince myself this is really | |
921 # a fact - it works for all the (admittedly | |
922 # thorough) cases in our testsuite, but I would be | |
923 # somewhat unsurprised to find a case in the wild | |
924 # where this breaks down a bit. That said, I don't | |
925 # know if it would hurt anything. | |
926 for i in pycompat.xrange(rev, 0, -1): | |
927 if revlog.linkrev(i) == clrev: | |
928 return i | |
929 # We failed to resolve a parent for this node, so | |
930 # we crash the changegroup construction. | |
931 raise error.Abort( | |
932 'unable to resolve parent while packing %r %r' | |
933 ' for changeset %r' % (revlog.indexfile, rev, clrev)) | |
934 | |
935 return nullrev | |
936 | |
937 if not linkparents or ( | |
938 revlog.parentrevs(rev) == (nullrev, nullrev)): | |
939 p1, p2 = nullrev, nullrev | |
940 elif len(linkparents) == 1: | |
941 p1, = sorted(local(p) for p in linkparents) | |
942 p2 = nullrev | |
943 else: | |
944 p1, p2 = sorted(local(p) for p in linkparents) | |
945 n = revlog.node(rev) | |
946 | |
947 yield ellipsisdata( | |
948 self, rev, revlog, p1, p2, revlog.revision(n), linknode) | |
949 | |
834 def builddeltaheader(self, node, p1n, p2n, basenode, linknode, flags): | 950 def builddeltaheader(self, node, p1n, p2n, basenode, linknode, flags): |
835 # do nothing with basenode, it is implicitly the previous one in HG10 | 951 # do nothing with basenode, it is implicitly the previous one in HG10 |
836 # do nothing with flags, it is implicitly 0 for cg1 and cg2 | 952 # do nothing with flags, it is implicitly 0 for cg1 and cg2 |
837 return struct.pack(self.deltaheader, node, p1n, p2n, linknode) | 953 return struct.pack(self.deltaheader, node, p1n, p2n, linknode) |
838 | 954 |