Mercurial > public > mercurial-scm > hg
comparison mercurial/changegroup.py @ 39004:e11d07cc125c
changegroup: make _revisiondeltanarrow() a standalone function
It doesn't require any state on the packer. Everything impacting
behavior is passed in as a function. So split it out, just like
what was done for _revisiondeltanormal().
Differential Revision: https://phab.mercurial-scm.org/D4196
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Tue, 07 Aug 2018 15:10:38 -0700 |
parents | 58377518201c |
children | d56a6b78de3b |
comparison
equal
deleted
inserted
replaced
39003:58377518201c | 39004:e11d07cc125c |
---|---|
586 linknode=linknode, | 586 linknode=linknode, |
587 flags=store.flags(rev), | 587 flags=store.flags(rev), |
588 deltachunks=(prefix, delta), | 588 deltachunks=(prefix, delta), |
589 ) | 589 ) |
590 | 590 |
591 def _revisiondeltanarrow(cl, store, ischangelog, rev, linkrev, | |
592 linknode, clrevtolocalrev, fullclnodes, | |
593 precomputedellipsis): | |
594 linkparents = precomputedellipsis[linkrev] | |
595 def local(clrev): | |
596 """Turn a changelog revnum into a local revnum. | |
597 | |
598 The ellipsis dag is stored as revnums on the changelog, | |
599 but when we're producing ellipsis entries for | |
600 non-changelog revlogs, we need to turn those numbers into | |
601 something local. This does that for us, and during the | |
602 changelog sending phase will also expand the stored | |
603 mappings as needed. | |
604 """ | |
605 if clrev == nullrev: | |
606 return nullrev | |
607 | |
608 if ischangelog: | |
609 return clrev | |
610 | |
611 # Walk the ellipsis-ized changelog breadth-first looking for a | |
612 # change that has been linked from the current revlog. | |
613 # | |
614 # For a flat manifest revlog only a single step should be necessary | |
615 # as all relevant changelog entries are relevant to the flat | |
616 # manifest. | |
617 # | |
618 # For a filelog or tree manifest dirlog however not every changelog | |
619 # entry will have been relevant, so we need to skip some changelog | |
620 # nodes even after ellipsis-izing. | |
621 walk = [clrev] | |
622 while walk: | |
623 p = walk[0] | |
624 walk = walk[1:] | |
625 if p in clrevtolocalrev: | |
626 return clrevtolocalrev[p] | |
627 elif p in fullclnodes: | |
628 walk.extend([pp for pp in cl.parentrevs(p) | |
629 if pp != nullrev]) | |
630 elif p in precomputedellipsis: | |
631 walk.extend([pp for pp in precomputedellipsis[p] | |
632 if pp != nullrev]) | |
633 else: | |
634 # In this case, we've got an ellipsis with parents | |
635 # outside the current bundle (likely an | |
636 # incremental pull). We "know" that we can use the | |
637 # value of this same revlog at whatever revision | |
638 # is pointed to by linknode. "Know" is in scare | |
639 # quotes because I haven't done enough examination | |
640 # of edge cases to convince myself this is really | |
641 # a fact - it works for all the (admittedly | |
642 # thorough) cases in our testsuite, but I would be | |
643 # somewhat unsurprised to find a case in the wild | |
644 # where this breaks down a bit. That said, I don't | |
645 # know if it would hurt anything. | |
646 for i in pycompat.xrange(rev, 0, -1): | |
647 if store.linkrev(i) == clrev: | |
648 return i | |
649 # We failed to resolve a parent for this node, so | |
650 # we crash the changegroup construction. | |
651 raise error.Abort( | |
652 'unable to resolve parent while packing %r %r' | |
653 ' for changeset %r' % (store.indexfile, rev, clrev)) | |
654 | |
655 return nullrev | |
656 | |
657 if not linkparents or ( | |
658 store.parentrevs(rev) == (nullrev, nullrev)): | |
659 p1, p2 = nullrev, nullrev | |
660 elif len(linkparents) == 1: | |
661 p1, = sorted(local(p) for p in linkparents) | |
662 p2 = nullrev | |
663 else: | |
664 p1, p2 = sorted(local(p) for p in linkparents) | |
665 | |
666 n = store.node(rev) | |
667 p1n, p2n = store.node(p1), store.node(p2) | |
668 flags = store.flags(rev) | |
669 flags |= revlog.REVIDX_ELLIPSIS | |
670 | |
671 # TODO: try and actually send deltas for ellipsis data blocks | |
672 data = store.revision(n) | |
673 diffheader = mdiff.trivialdiffheader(len(data)) | |
674 | |
675 return revisiondelta( | |
676 node=n, | |
677 p1node=p1n, | |
678 p2node=p2n, | |
679 basenode=nullid, | |
680 linknode=linknode, | |
681 flags=flags, | |
682 deltachunks=(diffheader, data), | |
683 ) | |
684 | |
591 class cgpacker(object): | 685 class cgpacker(object): |
592 def __init__(self, repo, filematcher, version, allowreorder, | 686 def __init__(self, repo, filematcher, version, allowreorder, |
593 deltaparentfn, builddeltaheader, manifestsend, | 687 deltaparentfn, builddeltaheader, manifestsend, |
594 bundlecaps=None, ellipses=False, | 688 bundlecaps=None, ellipses=False, |
595 shallow=False, ellipsisroots=None, fullnodes=None): | 689 shallow=False, ellipsisroots=None, fullnodes=None): |
705 delta = _revisiondeltanormal(store, curr, prev, linknode, | 799 delta = _revisiondeltanormal(store, curr, prev, linknode, |
706 self._deltaparentfn) | 800 self._deltaparentfn) |
707 elif linkrev not in self._precomputedellipsis: | 801 elif linkrev not in self._precomputedellipsis: |
708 delta = None | 802 delta = None |
709 else: | 803 else: |
710 delta = self._revisiondeltanarrow( | 804 delta = _revisiondeltanarrow( |
711 cl, store, ischangelog, curr, linkrev, linknode, | 805 cl, store, ischangelog, curr, linkrev, linknode, |
712 clrevtolocalrev, self._fullclnodes, | 806 clrevtolocalrev, self._fullclnodes, |
713 self._precomputedellipsis) | 807 self._precomputedellipsis) |
714 else: | 808 else: |
715 delta = _revisiondeltanormal(store, curr, prev, linknode, | 809 delta = _revisiondeltanormal(store, curr, prev, linknode, |
1055 clrevtolocalrev=clrevtolocalrev): | 1149 clrevtolocalrev=clrevtolocalrev): |
1056 size += len(chunk) | 1150 size += len(chunk) |
1057 yield chunk | 1151 yield chunk |
1058 self._verbosenote(_('%8.i %s\n') % (size, fname)) | 1152 self._verbosenote(_('%8.i %s\n') % (size, fname)) |
1059 progress.complete() | 1153 progress.complete() |
1060 | |
1061 def _revisiondeltanarrow(self, cl, store, ischangelog, rev, linkrev, | |
1062 linknode, clrevtolocalrev, fullclnodes, | |
1063 precomputedellipsis): | |
1064 linkparents = precomputedellipsis[linkrev] | |
1065 def local(clrev): | |
1066 """Turn a changelog revnum into a local revnum. | |
1067 | |
1068 The ellipsis dag is stored as revnums on the changelog, | |
1069 but when we're producing ellipsis entries for | |
1070 non-changelog revlogs, we need to turn those numbers into | |
1071 something local. This does that for us, and during the | |
1072 changelog sending phase will also expand the stored | |
1073 mappings as needed. | |
1074 """ | |
1075 if clrev == nullrev: | |
1076 return nullrev | |
1077 | |
1078 if ischangelog: | |
1079 return clrev | |
1080 | |
1081 # Walk the ellipsis-ized changelog breadth-first looking for a | |
1082 # change that has been linked from the current revlog. | |
1083 # | |
1084 # For a flat manifest revlog only a single step should be necessary | |
1085 # as all relevant changelog entries are relevant to the flat | |
1086 # manifest. | |
1087 # | |
1088 # For a filelog or tree manifest dirlog however not every changelog | |
1089 # entry will have been relevant, so we need to skip some changelog | |
1090 # nodes even after ellipsis-izing. | |
1091 walk = [clrev] | |
1092 while walk: | |
1093 p = walk[0] | |
1094 walk = walk[1:] | |
1095 if p in clrevtolocalrev: | |
1096 return clrevtolocalrev[p] | |
1097 elif p in fullclnodes: | |
1098 walk.extend([pp for pp in cl.parentrevs(p) | |
1099 if pp != nullrev]) | |
1100 elif p in precomputedellipsis: | |
1101 walk.extend([pp for pp in precomputedellipsis[p] | |
1102 if pp != nullrev]) | |
1103 else: | |
1104 # In this case, we've got an ellipsis with parents | |
1105 # outside the current bundle (likely an | |
1106 # incremental pull). We "know" that we can use the | |
1107 # value of this same revlog at whatever revision | |
1108 # is pointed to by linknode. "Know" is in scare | |
1109 # quotes because I haven't done enough examination | |
1110 # of edge cases to convince myself this is really | |
1111 # a fact - it works for all the (admittedly | |
1112 # thorough) cases in our testsuite, but I would be | |
1113 # somewhat unsurprised to find a case in the wild | |
1114 # where this breaks down a bit. That said, I don't | |
1115 # know if it would hurt anything. | |
1116 for i in pycompat.xrange(rev, 0, -1): | |
1117 if store.linkrev(i) == clrev: | |
1118 return i | |
1119 # We failed to resolve a parent for this node, so | |
1120 # we crash the changegroup construction. | |
1121 raise error.Abort( | |
1122 'unable to resolve parent while packing %r %r' | |
1123 ' for changeset %r' % (store.indexfile, rev, clrev)) | |
1124 | |
1125 return nullrev | |
1126 | |
1127 if not linkparents or ( | |
1128 store.parentrevs(rev) == (nullrev, nullrev)): | |
1129 p1, p2 = nullrev, nullrev | |
1130 elif len(linkparents) == 1: | |
1131 p1, = sorted(local(p) for p in linkparents) | |
1132 p2 = nullrev | |
1133 else: | |
1134 p1, p2 = sorted(local(p) for p in linkparents) | |
1135 | |
1136 n = store.node(rev) | |
1137 p1n, p2n = store.node(p1), store.node(p2) | |
1138 flags = store.flags(rev) | |
1139 flags |= revlog.REVIDX_ELLIPSIS | |
1140 | |
1141 # TODO: try and actually send deltas for ellipsis data blocks | |
1142 data = store.revision(n) | |
1143 diffheader = mdiff.trivialdiffheader(len(data)) | |
1144 | |
1145 return revisiondelta( | |
1146 node=n, | |
1147 p1node=p1n, | |
1148 p2node=p2n, | |
1149 basenode=nullid, | |
1150 linknode=linknode, | |
1151 flags=flags, | |
1152 deltachunks=(diffheader, data), | |
1153 ) | |
1154 | 1154 |
1155 def _deltaparentprev(store, rev, p1, p2, prev): | 1155 def _deltaparentprev(store, rev, p1, p2, prev): |
1156 """Resolve a delta parent to the previous revision. | 1156 """Resolve a delta parent to the previous revision. |
1157 | 1157 |
1158 Used for version 1 changegroups, which don't support generaldelta. | 1158 Used for version 1 changegroups, which don't support generaldelta. |