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