##// END OF EJS Templates
changegroup: factor changelog chunk generation into own function...
Gregory Szorc -
r39012:f7228c90 default
parent child Browse files
Show More
@@ -715,14 +715,100 b' class cgpacker(object):'
715 yield chunk
715 yield chunk
716
716
717 def generate(self, commonrevs, clnodes, fastpathlinkrev, source):
717 def generate(self, commonrevs, clnodes, fastpathlinkrev, source):
718 '''yield a sequence of changegroup chunks (strings)'''
718 """Yield a sequence of changegroup byte chunks."""
719
719 repo = self._repo
720 repo = self._repo
720 cl = repo.changelog
721 cl = repo.changelog
721
722
723 self._verbosenote(_('uncompressed size of bundle content:\n'))
724 size = 0
725
726 clstate, chunks = self._generatechangelog(cl, clnodes)
727 for chunk in chunks:
728 size += len(chunk)
729 yield chunk
730
731 self._verbosenote(_('%8.i (changelog)\n') % size)
732
733 clrevorder = clstate['clrevorder']
734 mfs = clstate['mfs']
735 changedfiles = clstate['changedfiles']
736
737 # We need to make sure that the linkrev in the changegroup refers to
738 # the first changeset that introduced the manifest or file revision.
739 # The fastpath is usually safer than the slowpath, because the filelogs
740 # are walked in revlog order.
741 #
742 # When taking the slowpath with reorder=None and the manifest revlog
743 # uses generaldelta, the manifest may be walked in the "wrong" order.
744 # Without 'clrevorder', we would get an incorrect linkrev (see fix in
745 # cc0ff93d0c0c).
746 #
747 # When taking the fastpath, we are only vulnerable to reordering
748 # of the changelog itself. The changelog never uses generaldelta, so
749 # it is only reordered when reorder=True. To handle this case, we
750 # simply take the slowpath, which already has the 'clrevorder' logic.
751 # This was also fixed in cc0ff93d0c0c.
752 fastpathlinkrev = fastpathlinkrev and not self._reorder
753 # Treemanifests don't work correctly with fastpathlinkrev
754 # either, because we don't discover which directory nodes to
755 # send along with files. This could probably be fixed.
756 fastpathlinkrev = fastpathlinkrev and (
757 'treemanifest' not in repo.requirements)
758
759 fnodes = {} # needed file nodes
760
761 for chunk in self.generatemanifests(commonrevs, clrevorder,
762 fastpathlinkrev, mfs, fnodes, source):
763 yield chunk
764
765 if self._ellipses:
766 mfdicts = None
767 if self._isshallow:
768 mfdicts = [(self._repo.manifestlog[n].read(), lr)
769 for (n, lr) in mfs.iteritems()]
770
771 mfs.clear()
772 clrevs = set(cl.rev(x) for x in clnodes)
773
774 if not fastpathlinkrev:
775 def linknodes(unused, fname):
776 return fnodes.get(fname, {})
777 else:
778 cln = cl.node
779 def linknodes(filerevlog, fname):
780 llr = filerevlog.linkrev
781 fln = filerevlog.node
782 revs = ((r, llr(r)) for r in filerevlog)
783 return dict((fln(r), cln(lr)) for r, lr in revs if lr in clrevs)
784
785 if self._ellipses:
786 # We need to pass the mfdicts variable down into
787 # generatefiles(), but more than one command might have
788 # wrapped generatefiles so we can't modify the function
789 # signature. Instead, we pass the data to ourselves using an
790 # instance attribute. I'm sorry.
791 self._mfdicts = mfdicts
792
793 for chunk in self.generatefiles(changedfiles, linknodes, commonrevs,
794 source):
795 yield chunk
796
797 yield self._close()
798
799 if clnodes:
800 repo.hook('outgoing', node=hex(clnodes[0]), source=source)
801
802 def _generatechangelog(self, cl, nodes):
803 """Generate data for changelog chunks.
804
805 Returns a 2-tuple of a dict containing state and an iterable of
806 byte chunks. The state will not be fully populated until the
807 chunk stream has been fully consumed.
808 """
722 clrevorder = {}
809 clrevorder = {}
723 mfs = {} # needed manifests
810 mfs = {} # needed manifests
724 fnodes = {} # needed file nodes
811 mfl = self._repo.manifestlog
725 mfl = repo.manifestlog
726 # TODO violates storage abstraction.
812 # TODO violates storage abstraction.
727 mfrevlog = mfl._revlog
813 mfrevlog = mfl._revlog
728 changedfiles = set()
814 changedfiles = set()
@@ -768,75 +854,15 b' class cgpacker(object):'
768
854
769 return x
855 return x
770
856
771 self._verbosenote(_('uncompressed size of bundle content:\n'))
857 state = {
772 size = 0
858 'clrevorder': clrevorder,
773 for chunk in self.group(clnodes, cl, lookupcl, units=_('changesets')):
859 'mfs': mfs,
774 size += len(chunk)
860 'changedfiles': changedfiles,
775 yield chunk
861 }
776 self._verbosenote(_('%8.i (changelog)\n') % size)
777
778 # We need to make sure that the linkrev in the changegroup refers to
779 # the first changeset that introduced the manifest or file revision.
780 # The fastpath is usually safer than the slowpath, because the filelogs
781 # are walked in revlog order.
782 #
783 # When taking the slowpath with reorder=None and the manifest revlog
784 # uses generaldelta, the manifest may be walked in the "wrong" order.
785 # Without 'clrevorder', we would get an incorrect linkrev (see fix in
786 # cc0ff93d0c0c).
787 #
788 # When taking the fastpath, we are only vulnerable to reordering
789 # of the changelog itself. The changelog never uses generaldelta, so
790 # it is only reordered when reorder=True. To handle this case, we
791 # simply take the slowpath, which already has the 'clrevorder' logic.
792 # This was also fixed in cc0ff93d0c0c.
793 fastpathlinkrev = fastpathlinkrev and not self._reorder
794 # Treemanifests don't work correctly with fastpathlinkrev
795 # either, because we don't discover which directory nodes to
796 # send along with files. This could probably be fixed.
797 fastpathlinkrev = fastpathlinkrev and (
798 'treemanifest' not in repo.requirements)
799
800 for chunk in self.generatemanifests(commonrevs, clrevorder,
801 fastpathlinkrev, mfs, fnodes, source):
802 yield chunk
803
862
804 if self._ellipses:
863 gen = self.group(nodes, cl, lookupcl, units=_('changesets'))
805 mfdicts = None
806 if self._isshallow:
807 mfdicts = [(self._repo.manifestlog[n].read(), lr)
808 for (n, lr) in mfs.iteritems()]
809
810 mfs.clear()
811 clrevs = set(cl.rev(x) for x in clnodes)
812
864
813 if not fastpathlinkrev:
865 return state, gen
814 def linknodes(unused, fname):
815 return fnodes.get(fname, {})
816 else:
817 cln = cl.node
818 def linknodes(filerevlog, fname):
819 llr = filerevlog.linkrev
820 fln = filerevlog.node
821 revs = ((r, llr(r)) for r in filerevlog)
822 return dict((fln(r), cln(lr)) for r, lr in revs if lr in clrevs)
823
824 if self._ellipses:
825 # We need to pass the mfdicts variable down into
826 # generatefiles(), but more than one command might have
827 # wrapped generatefiles so we can't modify the function
828 # signature. Instead, we pass the data to ourselves using an
829 # instance attribute. I'm sorry.
830 self._mfdicts = mfdicts
831
832 for chunk in self.generatefiles(changedfiles, linknodes, commonrevs,
833 source):
834 yield chunk
835
836 yield self._close()
837
838 if clnodes:
839 repo.hook('outgoing', node=hex(clnodes[0]), source=source)
840
866
841 def generatemanifests(self, commonrevs, clrevorder, fastpathlinkrev, mfs,
867 def generatemanifests(self, commonrevs, clrevorder, fastpathlinkrev, mfs,
842 fnodes, source):
868 fnodes, source):
General Comments 0
You need to be logged in to leave comments. Login now