586 if self._repo.ui.verbose and not self._repo.ui.debugflag: |
586 if self._repo.ui.verbose and not self._repo.ui.debugflag: |
587 self._verbosenote = self._repo.ui.note |
587 self._verbosenote = self._repo.ui.note |
588 else: |
588 else: |
589 self._verbosenote = lambda s: None |
589 self._verbosenote = lambda s: None |
590 |
590 |
591 # TODO the functionality keyed off of this should probably be |
|
592 # controlled via arguments to group() that influence behavior. |
|
593 self._changelogdone = False |
|
594 |
|
595 # Maps CL revs to per-revlog revisions. Cleared in close() at |
591 # Maps CL revs to per-revlog revisions. Cleared in close() at |
596 # the end of each group. |
592 # the end of each group. |
597 self._clrevtolocalrev = {} |
593 self._clrevtolocalrev = {} |
598 self._nextclrevtolocalrev = {} |
594 self._nextclrevtolocalrev = {} |
599 |
595 |
612 |
608 |
613 def _fileheader(self, fname): |
609 def _fileheader(self, fname): |
614 return chunkheader(len(fname)) + fname |
610 return chunkheader(len(fname)) + fname |
615 |
611 |
616 # Extracted both for clarity and for overriding in extensions. |
612 # Extracted both for clarity and for overriding in extensions. |
617 def _sortgroup(self, store, nodelist, lookup): |
613 def _sortgroup(self, store, ischangelog, nodelist, lookup): |
618 """Sort nodes for change group and turn them into revnums.""" |
614 """Sort nodes for change group and turn them into revnums.""" |
619 # Ellipses serving mode. |
615 # Ellipses serving mode. |
620 # |
616 # |
621 # In a perfect world, we'd generate better ellipsis-ified graphs |
617 # In a perfect world, we'd generate better ellipsis-ified graphs |
622 # for non-changelog revlogs. In practice, we haven't started doing |
618 # for non-changelog revlogs. In practice, we haven't started doing |
630 # The one invariant we *know* holds is that the new (potentially |
626 # The one invariant we *know* holds is that the new (potentially |
631 # bogus) DAG shape will be valid if we order the nodes in the |
627 # bogus) DAG shape will be valid if we order the nodes in the |
632 # order that they're introduced in dramatis personae by the |
628 # order that they're introduced in dramatis personae by the |
633 # changelog, so what we do is we sort the non-changelog histories |
629 # changelog, so what we do is we sort the non-changelog histories |
634 # by the order in which they are used by the changelog. |
630 # by the order in which they are used by the changelog. |
635 if self._ellipses and self._changelogdone: |
631 if self._ellipses and not ischangelog: |
636 key = lambda n: self._clnodetorev[lookup(n)] |
632 key = lambda n: self._clnodetorev[lookup(n)] |
637 return [store.rev(n) for n in sorted(nodelist, key=key)] |
633 return [store.rev(n) for n in sorted(nodelist, key=key)] |
638 |
634 |
639 # for generaldelta revlogs, we linearize the revs; this will both be |
635 # for generaldelta revlogs, we linearize the revs; this will both be |
640 # much quicker and generate a much smaller bundle |
636 # much quicker and generate a much smaller bundle |
642 dag = dagutil.revlogdag(store) |
638 dag = dagutil.revlogdag(store) |
643 return dag.linearize(set(store.rev(n) for n in nodelist)) |
639 return dag.linearize(set(store.rev(n) for n in nodelist)) |
644 else: |
640 else: |
645 return sorted([store.rev(n) for n in nodelist]) |
641 return sorted([store.rev(n) for n in nodelist]) |
646 |
642 |
647 def group(self, nodelist, store, lookup, units=None): |
643 def group(self, nodelist, store, ischangelog, lookup, units=None): |
648 """Calculate a delta group, yielding a sequence of changegroup chunks |
644 """Calculate a delta group, yielding a sequence of changegroup chunks |
649 (strings). |
645 (strings). |
650 |
646 |
651 Given a list of changeset revs, return a set of deltas and |
647 Given a list of changeset revs, return a set of deltas and |
652 metadata corresponding to nodes. The first delta is |
648 metadata corresponding to nodes. The first delta is |
661 # if we don't have any revisions touched by these changesets, bail |
657 # if we don't have any revisions touched by these changesets, bail |
662 if len(nodelist) == 0: |
658 if len(nodelist) == 0: |
663 yield self._close() |
659 yield self._close() |
664 return |
660 return |
665 |
661 |
666 revs = self._sortgroup(store, nodelist, lookup) |
662 revs = self._sortgroup(store, ischangelog, nodelist, lookup) |
667 |
663 |
668 # add the parent of the first rev |
664 # add the parent of the first rev |
669 p = store.parentrevs(revs[0])[0] |
665 p = store.parentrevs(revs[0])[0] |
670 revs.insert(0, p) |
666 revs.insert(0, p) |
671 |
667 |
677 for r in pycompat.xrange(len(revs) - 1): |
673 for r in pycompat.xrange(len(revs) - 1): |
678 if progress: |
674 if progress: |
679 progress.update(r + 1) |
675 progress.update(r + 1) |
680 prev, curr = revs[r], revs[r + 1] |
676 prev, curr = revs[r], revs[r + 1] |
681 linknode = lookup(store.node(curr)) |
677 linknode = lookup(store.node(curr)) |
682 for c in self._revchunk(store, curr, prev, linknode): |
678 for c in self._revchunk(store, ischangelog, curr, prev, linknode): |
683 yield c |
679 yield c |
684 |
680 |
685 if progress: |
681 if progress: |
686 progress.complete() |
682 progress.complete() |
687 yield self._close() |
683 yield self._close() |
707 assert self.version == b'03' |
703 assert self.version == b'03' |
708 yield self._fileheader(dir) |
704 yield self._fileheader(dir) |
709 |
705 |
710 # TODO violates storage abstractions by assuming revlogs. |
706 # TODO violates storage abstractions by assuming revlogs. |
711 dirlog = self._repo.manifestlog._revlog.dirlog(dir) |
707 dirlog = self._repo.manifestlog._revlog.dirlog(dir) |
712 for chunk in self.group(mfnodes, dirlog, lookuplinknode, |
708 for chunk in self.group(mfnodes, dirlog, False, lookuplinknode, |
713 units=_('manifests')): |
709 units=_('manifests')): |
714 yield chunk |
710 yield chunk |
715 |
711 |
716 def generate(self, commonrevs, clnodes, fastpathlinkrev, source): |
712 def generate(self, commonrevs, clnodes, fastpathlinkrev, source): |
717 """Yield a sequence of changegroup byte chunks.""" |
713 """Yield a sequence of changegroup byte chunks.""" |
859 'clrevorder': clrevorder, |
853 'clrevorder': clrevorder, |
860 'mfs': mfs, |
854 'mfs': mfs, |
861 'changedfiles': changedfiles, |
855 'changedfiles': changedfiles, |
862 } |
856 } |
863 |
857 |
864 gen = self.group(nodes, cl, lookupcl, units=_('changesets')) |
858 gen = self.group(nodes, cl, True, lookupcl, units=_('changesets')) |
865 |
859 |
866 return state, gen |
860 return state, gen |
867 |
861 |
868 def generatemanifests(self, commonrevs, clrevorder, fastpathlinkrev, mfs, |
862 def generatemanifests(self, commonrevs, clrevorder, fastpathlinkrev, mfs, |
869 fnodes, source): |
863 fnodes, source): |
988 if filenodes: |
982 if filenodes: |
989 progress.update(i + 1, item=fname) |
983 progress.update(i + 1, item=fname) |
990 h = self._fileheader(fname) |
984 h = self._fileheader(fname) |
991 size = len(h) |
985 size = len(h) |
992 yield h |
986 yield h |
993 for chunk in self.group(filenodes, filerevlog, lookupfilelog): |
987 for chunk in self.group(filenodes, filerevlog, False, |
|
988 lookupfilelog): |
994 size += len(chunk) |
989 size += len(chunk) |
995 yield chunk |
990 yield chunk |
996 self._verbosenote(_('%8.i %s\n') % (size, fname)) |
991 self._verbosenote(_('%8.i %s\n') % (size, fname)) |
997 progress.complete() |
992 progress.complete() |
998 |
993 |
999 def _revchunk(self, store, rev, prev, linknode): |
994 def _revchunk(self, store, ischangelog, rev, prev, linknode): |
1000 if self._ellipses: |
995 if self._ellipses: |
1001 fn = self._revisiondeltanarrow |
996 fn = self._revisiondeltanarrow |
1002 else: |
997 else: |
1003 fn = self._revisiondeltanormal |
998 fn = self._revisiondeltanormal |
1004 |
999 |
1005 delta = fn(store, rev, prev, linknode) |
1000 delta = fn(store, ischangelog, rev, prev, linknode) |
1006 if not delta: |
1001 if not delta: |
1007 return |
1002 return |
1008 |
1003 |
1009 meta = self._builddeltaheader(delta) |
1004 meta = self._builddeltaheader(delta) |
1010 l = len(meta) + sum(len(x) for x in delta.deltachunks) |
1005 l = len(meta) + sum(len(x) for x in delta.deltachunks) |
1012 yield chunkheader(l) |
1007 yield chunkheader(l) |
1013 yield meta |
1008 yield meta |
1014 for x in delta.deltachunks: |
1009 for x in delta.deltachunks: |
1015 yield x |
1010 yield x |
1016 |
1011 |
1017 def _revisiondeltanormal(self, store, rev, prev, linknode): |
1012 def _revisiondeltanormal(self, store, ischangelog, rev, prev, linknode): |
1018 node = store.node(rev) |
1013 node = store.node(rev) |
1019 p1, p2 = store.parentrevs(rev) |
1014 p1, p2 = store.parentrevs(rev) |
1020 base = self._deltaparentfn(store, rev, p1, p2, prev) |
1015 base = self._deltaparentfn(store, rev, p1, p2, prev) |
1021 |
1016 |
1022 prefix = '' |
1017 prefix = '' |
1045 linknode=linknode, |
1040 linknode=linknode, |
1046 flags=store.flags(rev), |
1041 flags=store.flags(rev), |
1047 deltachunks=(prefix, delta), |
1042 deltachunks=(prefix, delta), |
1048 ) |
1043 ) |
1049 |
1044 |
1050 def _revisiondeltanarrow(self, store, rev, prev, linknode): |
1045 def _revisiondeltanarrow(self, store, ischangelog, rev, prev, linknode): |
1051 # build up some mapping information that's useful later. See |
1046 # build up some mapping information that's useful later. See |
1052 # the local() nested function below. |
1047 # the local() nested function below. |
1053 if not self._changelogdone: |
1048 if ischangelog: |
1054 self._clnodetorev[linknode] = rev |
1049 self._clnodetorev[linknode] = rev |
1055 linkrev = rev |
1050 linkrev = rev |
1056 self._clrevtolocalrev[linkrev] = rev |
1051 self._clrevtolocalrev[linkrev] = rev |
1057 else: |
1052 else: |
1058 linkrev = self._clnodetorev[linknode] |
1053 linkrev = self._clnodetorev[linknode] |
1059 self._clrevtolocalrev[linkrev] = rev |
1054 self._clrevtolocalrev[linkrev] = rev |
1060 |
1055 |
1061 # This is a node to send in full, because the changeset it |
1056 # This is a node to send in full, because the changeset it |
1062 # corresponds to was a full changeset. |
1057 # corresponds to was a full changeset. |
1063 if linknode in self._fullnodes: |
1058 if linknode in self._fullnodes: |
1064 return self._revisiondeltanormal(store, rev, prev, linknode) |
1059 return self._revisiondeltanormal(store, ischangelog, rev, prev, |
|
1060 linknode) |
1065 |
1061 |
1066 # At this point, a node can either be one we should skip or an |
1062 # At this point, a node can either be one we should skip or an |
1067 # ellipsis. If it's not an ellipsis, bail immediately. |
1063 # ellipsis. If it's not an ellipsis, bail immediately. |
1068 if linkrev not in self._precomputedellipsis: |
1064 if linkrev not in self._precomputedellipsis: |
1069 return |
1065 return |
1080 mappings as needed. |
1076 mappings as needed. |
1081 """ |
1077 """ |
1082 if clrev == nullrev: |
1078 if clrev == nullrev: |
1083 return nullrev |
1079 return nullrev |
1084 |
1080 |
1085 if not self._changelogdone: |
1081 if ischangelog: |
1086 # If we're doing the changelog, it's possible that we |
1082 # If we're doing the changelog, it's possible that we |
1087 # have a parent that is already on the client, and we |
1083 # have a parent that is already on the client, and we |
1088 # need to store some extra mapping information so that |
1084 # need to store some extra mapping information so that |
1089 # our contained ellipsis nodes will be able to resolve |
1085 # our contained ellipsis nodes will be able to resolve |
1090 # their parents. |
1086 # their parents. |