##// 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 715 yield chunk
716 716
717 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 720 repo = self._repo
720 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 809 clrevorder = {}
723 810 mfs = {} # needed manifests
724 fnodes = {} # needed file nodes
725 mfl = repo.manifestlog
811 mfl = self._repo.manifestlog
726 812 # TODO violates storage abstraction.
727 813 mfrevlog = mfl._revlog
728 814 changedfiles = set()
@@ -768,75 +854,15 b' class cgpacker(object):'
768 854
769 855 return x
770 856
771 self._verbosenote(_('uncompressed size of bundle content:\n'))
772 size = 0
773 for chunk in self.group(clnodes, cl, lookupcl, units=_('changesets')):
774 size += len(chunk)
775 yield chunk
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
857 state = {
858 'clrevorder': clrevorder,
859 'mfs': mfs,
860 'changedfiles': changedfiles,
861 }
803 862
804 if self._ellipses:
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)
863 gen = self.group(nodes, cl, lookupcl, units=_('changesets'))
812 864
813 if not fastpathlinkrev:
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)
865 return state, gen
840 866
841 867 def generatemanifests(self, commonrevs, clrevorder, fastpathlinkrev, mfs,
842 868 fnodes, source):
General Comments 0
You need to be logged in to leave comments. Login now