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 |
|
|
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