Mercurial > hg
comparison mercurial/changegroup.py @ 38891:205c98e2f1ba
changegroup: rename "revlog" variables
"revlog" shadows the module import. But more importantly, changegroup
generation should be storage agnostic and not assume the existence
of revlogs. Let's rename the thing providing revision storage to
"store" to reflect this ideal property.
Differential Revision: https://phab.mercurial-scm.org/D4073
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Thu, 02 Aug 2018 17:05:11 -0700 |
parents | d706c77449f9 |
children | eb022ce9e505 |
comparison
equal
deleted
inserted
replaced
38890:d706c77449f9 | 38891:205c98e2f1ba |
---|---|
555 | 555 |
556 def fileheader(self, fname): | 556 def fileheader(self, fname): |
557 return chunkheader(len(fname)) + fname | 557 return chunkheader(len(fname)) + fname |
558 | 558 |
559 # Extracted both for clarity and for overriding in extensions. | 559 # Extracted both for clarity and for overriding in extensions. |
560 def _sortgroup(self, revlog, nodelist, lookup): | 560 def _sortgroup(self, store, nodelist, lookup): |
561 """Sort nodes for change group and turn them into revnums.""" | 561 """Sort nodes for change group and turn them into revnums.""" |
562 # Ellipses serving mode. | 562 # Ellipses serving mode. |
563 # | 563 # |
564 # In a perfect world, we'd generate better ellipsis-ified graphs | 564 # In a perfect world, we'd generate better ellipsis-ified graphs |
565 # for non-changelog revlogs. In practice, we haven't started doing | 565 # for non-changelog revlogs. In practice, we haven't started doing |
575 # order that they're introduced in dramatis personae by the | 575 # order that they're introduced in dramatis personae by the |
576 # changelog, so what we do is we sort the non-changelog histories | 576 # changelog, so what we do is we sort the non-changelog histories |
577 # by the order in which they are used by the changelog. | 577 # by the order in which they are used by the changelog. |
578 if util.safehasattr(self, 'full_nodes') and self.clnode_to_rev: | 578 if util.safehasattr(self, 'full_nodes') and self.clnode_to_rev: |
579 key = lambda n: self.clnode_to_rev[lookup(n)] | 579 key = lambda n: self.clnode_to_rev[lookup(n)] |
580 return [revlog.rev(n) for n in sorted(nodelist, key=key)] | 580 return [store.rev(n) for n in sorted(nodelist, key=key)] |
581 | 581 |
582 # for generaldelta revlogs, we linearize the revs; this will both be | 582 # for generaldelta revlogs, we linearize the revs; this will both be |
583 # much quicker and generate a much smaller bundle | 583 # much quicker and generate a much smaller bundle |
584 if (revlog._generaldelta and self._reorder is None) or self._reorder: | 584 if (store._generaldelta and self._reorder is None) or self._reorder: |
585 dag = dagutil.revlogdag(revlog) | 585 dag = dagutil.revlogdag(store) |
586 return dag.linearize(set(revlog.rev(n) for n in nodelist)) | 586 return dag.linearize(set(store.rev(n) for n in nodelist)) |
587 else: | 587 else: |
588 return sorted([revlog.rev(n) for n in nodelist]) | 588 return sorted([store.rev(n) for n in nodelist]) |
589 | 589 |
590 def group(self, nodelist, revlog, lookup, units=None): | 590 def group(self, nodelist, store, lookup, units=None): |
591 """Calculate a delta group, yielding a sequence of changegroup chunks | 591 """Calculate a delta group, yielding a sequence of changegroup chunks |
592 (strings). | 592 (strings). |
593 | 593 |
594 Given a list of changeset revs, return a set of deltas and | 594 Given a list of changeset revs, return a set of deltas and |
595 metadata corresponding to nodes. The first delta is | 595 metadata corresponding to nodes. The first delta is |
604 # if we don't have any revisions touched by these changesets, bail | 604 # if we don't have any revisions touched by these changesets, bail |
605 if len(nodelist) == 0: | 605 if len(nodelist) == 0: |
606 yield self.close() | 606 yield self.close() |
607 return | 607 return |
608 | 608 |
609 revs = self._sortgroup(revlog, nodelist, lookup) | 609 revs = self._sortgroup(store, nodelist, lookup) |
610 | 610 |
611 # add the parent of the first rev | 611 # add the parent of the first rev |
612 p = revlog.parentrevs(revs[0])[0] | 612 p = store.parentrevs(revs[0])[0] |
613 revs.insert(0, p) | 613 revs.insert(0, p) |
614 | 614 |
615 # build deltas | 615 # build deltas |
616 progress = None | 616 progress = None |
617 if units is not None: | 617 if units is not None: |
619 total=(len(revs) - 1)) | 619 total=(len(revs) - 1)) |
620 for r in pycompat.xrange(len(revs) - 1): | 620 for r in pycompat.xrange(len(revs) - 1): |
621 if progress: | 621 if progress: |
622 progress.update(r + 1) | 622 progress.update(r + 1) |
623 prev, curr = revs[r], revs[r + 1] | 623 prev, curr = revs[r], revs[r + 1] |
624 linknode = lookup(revlog.node(curr)) | 624 linknode = lookup(store.node(curr)) |
625 for c in self.revchunk(revlog, curr, prev, linknode): | 625 for c in self.revchunk(store, curr, prev, linknode): |
626 yield c | 626 yield c |
627 | 627 |
628 if progress: | 628 if progress: |
629 progress.complete() | 629 progress.complete() |
630 yield self.close() | 630 yield self.close() |
631 | 631 |
632 # filter any nodes that claim to be part of the known set | 632 # filter any nodes that claim to be part of the known set |
633 def prune(self, revlog, missing, commonrevs): | 633 def prune(self, store, missing, commonrevs): |
634 # TODO this violates storage abstraction for manifests. | 634 # TODO this violates storage abstraction for manifests. |
635 if isinstance(revlog, manifest.manifestrevlog): | 635 if isinstance(store, manifest.manifestrevlog): |
636 if not self._filematcher.visitdir(revlog._dir[:-1] or '.'): | 636 if not self._filematcher.visitdir(store._dir[:-1] or '.'): |
637 return [] | 637 return [] |
638 | 638 |
639 rr, rl = revlog.rev, revlog.linkrev | 639 rr, rl = store.rev, store.linkrev |
640 return [n for n in missing if rl(rr(n)) not in commonrevs] | 640 return [n for n in missing if rl(rr(n)) not in commonrevs] |
641 | 641 |
642 def _packmanifests(self, dir, mfnodes, lookuplinknode): | 642 def _packmanifests(self, dir, mfnodes, lookuplinknode): |
643 """Pack flat manifests into a changegroup stream.""" | 643 """Pack flat manifests into a changegroup stream.""" |
644 assert not dir | 644 assert not dir |
904 size += len(chunk) | 904 size += len(chunk) |
905 yield chunk | 905 yield chunk |
906 self._verbosenote(_('%8.i %s\n') % (size, fname)) | 906 self._verbosenote(_('%8.i %s\n') % (size, fname)) |
907 progress.complete() | 907 progress.complete() |
908 | 908 |
909 def deltaparent(self, revlog, rev, p1, p2, prev): | 909 def deltaparent(self, store, rev, p1, p2, prev): |
910 if not revlog.candelta(prev, rev): | 910 if not store.candelta(prev, rev): |
911 raise error.ProgrammingError('cg1 should not be used in this case') | 911 raise error.ProgrammingError('cg1 should not be used in this case') |
912 return prev | 912 return prev |
913 | 913 |
914 def revchunk(self, revlog, rev, prev, linknode): | 914 def revchunk(self, store, rev, prev, linknode): |
915 if util.safehasattr(self, 'full_nodes'): | 915 if util.safehasattr(self, 'full_nodes'): |
916 fn = self._revchunknarrow | 916 fn = self._revchunknarrow |
917 else: | 917 else: |
918 fn = self._revchunknormal | 918 fn = self._revchunknormal |
919 | 919 |
920 return fn(revlog, rev, prev, linknode) | 920 return fn(store, rev, prev, linknode) |
921 | 921 |
922 def _revchunknormal(self, revlog, rev, prev, linknode): | 922 def _revchunknormal(self, store, rev, prev, linknode): |
923 node = revlog.node(rev) | 923 node = store.node(rev) |
924 p1, p2 = revlog.parentrevs(rev) | 924 p1, p2 = store.parentrevs(rev) |
925 base = self.deltaparent(revlog, rev, p1, p2, prev) | 925 base = self.deltaparent(store, rev, p1, p2, prev) |
926 | 926 |
927 prefix = '' | 927 prefix = '' |
928 if revlog.iscensored(base) or revlog.iscensored(rev): | 928 if store.iscensored(base) or store.iscensored(rev): |
929 try: | 929 try: |
930 delta = revlog.revision(node, raw=True) | 930 delta = store.revision(node, raw=True) |
931 except error.CensoredNodeError as e: | 931 except error.CensoredNodeError as e: |
932 delta = e.tombstone | 932 delta = e.tombstone |
933 if base == nullrev: | 933 if base == nullrev: |
934 prefix = mdiff.trivialdiffheader(len(delta)) | 934 prefix = mdiff.trivialdiffheader(len(delta)) |
935 else: | 935 else: |
936 baselen = revlog.rawsize(base) | 936 baselen = store.rawsize(base) |
937 prefix = mdiff.replacediffheader(baselen, len(delta)) | 937 prefix = mdiff.replacediffheader(baselen, len(delta)) |
938 elif base == nullrev: | 938 elif base == nullrev: |
939 delta = revlog.revision(node, raw=True) | 939 delta = store.revision(node, raw=True) |
940 prefix = mdiff.trivialdiffheader(len(delta)) | 940 prefix = mdiff.trivialdiffheader(len(delta)) |
941 else: | 941 else: |
942 delta = revlog.revdiff(base, rev) | 942 delta = store.revdiff(base, rev) |
943 p1n, p2n = revlog.parents(node) | 943 p1n, p2n = store.parents(node) |
944 basenode = revlog.node(base) | 944 basenode = store.node(base) |
945 flags = revlog.flags(rev) | 945 flags = store.flags(rev) |
946 meta = self.builddeltaheader(node, p1n, p2n, basenode, linknode, flags) | 946 meta = self.builddeltaheader(node, p1n, p2n, basenode, linknode, flags) |
947 meta += prefix | 947 meta += prefix |
948 l = len(meta) + len(delta) | 948 l = len(meta) + len(delta) |
949 yield chunkheader(l) | 949 yield chunkheader(l) |
950 yield meta | 950 yield meta |
951 yield delta | 951 yield delta |
952 | 952 |
953 def _revchunknarrow(self, revlog, rev, prev, linknode): | 953 def _revchunknarrow(self, store, rev, prev, linknode): |
954 # build up some mapping information that's useful later. See | 954 # build up some mapping information that's useful later. See |
955 # the local() nested function below. | 955 # the local() nested function below. |
956 if not self.changelog_done: | 956 if not self.changelog_done: |
957 self.clnode_to_rev[linknode] = rev | 957 self.clnode_to_rev[linknode] = rev |
958 linkrev = rev | 958 linkrev = rev |
962 self.clrev_to_localrev[linkrev] = rev | 962 self.clrev_to_localrev[linkrev] = rev |
963 | 963 |
964 # This is a node to send in full, because the changeset it | 964 # This is a node to send in full, because the changeset it |
965 # corresponds to was a full changeset. | 965 # corresponds to was a full changeset. |
966 if linknode in self.full_nodes: | 966 if linknode in self.full_nodes: |
967 for x in self._revchunknormal(revlog, rev, prev, linknode): | 967 for x in self._revchunknormal(store, rev, prev, linknode): |
968 yield x | 968 yield x |
969 return | 969 return |
970 | 970 |
971 # At this point, a node can either be one we should skip or an | 971 # At this point, a node can either be one we should skip or an |
972 # ellipsis. If it's not an ellipsis, bail immediately. | 972 # ellipsis. If it's not an ellipsis, bail immediately. |
992 # have a parent that is already on the client, and we | 992 # have a parent that is already on the client, and we |
993 # need to store some extra mapping information so that | 993 # need to store some extra mapping information so that |
994 # our contained ellipsis nodes will be able to resolve | 994 # our contained ellipsis nodes will be able to resolve |
995 # their parents. | 995 # their parents. |
996 if clrev not in self.clrev_to_localrev: | 996 if clrev not in self.clrev_to_localrev: |
997 clnode = revlog.node(clrev) | 997 clnode = store.node(clrev) |
998 self.clnode_to_rev[clnode] = clrev | 998 self.clnode_to_rev[clnode] = clrev |
999 return clrev | 999 return clrev |
1000 | 1000 |
1001 # Walk the ellipsis-ized changelog breadth-first looking for a | 1001 # Walk the ellipsis-ized changelog breadth-first looking for a |
1002 # change that has been linked from the current revlog. | 1002 # change that has been linked from the current revlog. |
1032 # thorough) cases in our testsuite, but I would be | 1032 # thorough) cases in our testsuite, but I would be |
1033 # somewhat unsurprised to find a case in the wild | 1033 # somewhat unsurprised to find a case in the wild |
1034 # where this breaks down a bit. That said, I don't | 1034 # where this breaks down a bit. That said, I don't |
1035 # know if it would hurt anything. | 1035 # know if it would hurt anything. |
1036 for i in pycompat.xrange(rev, 0, -1): | 1036 for i in pycompat.xrange(rev, 0, -1): |
1037 if revlog.linkrev(i) == clrev: | 1037 if store.linkrev(i) == clrev: |
1038 return i | 1038 return i |
1039 # We failed to resolve a parent for this node, so | 1039 # We failed to resolve a parent for this node, so |
1040 # we crash the changegroup construction. | 1040 # we crash the changegroup construction. |
1041 raise error.Abort( | 1041 raise error.Abort( |
1042 'unable to resolve parent while packing %r %r' | 1042 'unable to resolve parent while packing %r %r' |
1043 ' for changeset %r' % (revlog.indexfile, rev, clrev)) | 1043 ' for changeset %r' % (store.indexfile, rev, clrev)) |
1044 | 1044 |
1045 return nullrev | 1045 return nullrev |
1046 | 1046 |
1047 if not linkparents or ( | 1047 if not linkparents or ( |
1048 revlog.parentrevs(rev) == (nullrev, nullrev)): | 1048 store.parentrevs(rev) == (nullrev, nullrev)): |
1049 p1, p2 = nullrev, nullrev | 1049 p1, p2 = nullrev, nullrev |
1050 elif len(linkparents) == 1: | 1050 elif len(linkparents) == 1: |
1051 p1, = sorted(local(p) for p in linkparents) | 1051 p1, = sorted(local(p) for p in linkparents) |
1052 p2 = nullrev | 1052 p2 = nullrev |
1053 else: | 1053 else: |
1054 p1, p2 = sorted(local(p) for p in linkparents) | 1054 p1, p2 = sorted(local(p) for p in linkparents) |
1055 n = revlog.node(rev) | 1055 n = store.node(rev) |
1056 | 1056 |
1057 yield ellipsisdata( | 1057 yield ellipsisdata( |
1058 self, rev, revlog, p1, p2, revlog.revision(n), linknode) | 1058 self, rev, store, p1, p2, store.revision(n), linknode) |
1059 | 1059 |
1060 def builddeltaheader(self, node, p1n, p2n, basenode, linknode, flags): | 1060 def builddeltaheader(self, node, p1n, p2n, basenode, linknode, flags): |
1061 # do nothing with basenode, it is implicitly the previous one in HG10 | 1061 # do nothing with basenode, it is implicitly the previous one in HG10 |
1062 # do nothing with flags, it is implicitly 0 for cg1 and cg2 | 1062 # do nothing with flags, it is implicitly 0 for cg1 and cg2 |
1063 return struct.pack(self.deltaheader, node, p1n, p2n, linknode) | 1063 return struct.pack(self.deltaheader, node, p1n, p2n, linknode) |
1074 # Since generaldelta is directly supported by cg2, reordering | 1074 # Since generaldelta is directly supported by cg2, reordering |
1075 # generally doesn't help, so we disable it by default (treating | 1075 # generally doesn't help, so we disable it by default (treating |
1076 # bundle.reorder=auto just like bundle.reorder=False). | 1076 # bundle.reorder=auto just like bundle.reorder=False). |
1077 self._reorder = False | 1077 self._reorder = False |
1078 | 1078 |
1079 def deltaparent(self, revlog, rev, p1, p2, prev): | 1079 def deltaparent(self, store, rev, p1, p2, prev): |
1080 # Narrow ellipses mode. | 1080 # Narrow ellipses mode. |
1081 if util.safehasattr(self, 'full_nodes'): | 1081 if util.safehasattr(self, 'full_nodes'): |
1082 # TODO: send better deltas when in narrow mode. | 1082 # TODO: send better deltas when in narrow mode. |
1083 # | 1083 # |
1084 # changegroup.group() loops over revisions to send, | 1084 # changegroup.group() loops over revisions to send, |
1090 # significantly smarter about delta bases. This is | 1090 # significantly smarter about delta bases. This is |
1091 # slightly tricky because this same code has to work for | 1091 # slightly tricky because this same code has to work for |
1092 # all revlogs, and we don't have the linkrev/linknode here. | 1092 # all revlogs, and we don't have the linkrev/linknode here. |
1093 return p1 | 1093 return p1 |
1094 | 1094 |
1095 dp = revlog.deltaparent(rev) | 1095 dp = store.deltaparent(rev) |
1096 if dp == nullrev and revlog.storedeltachains: | 1096 if dp == nullrev and store.storedeltachains: |
1097 # Avoid sending full revisions when delta parent is null. Pick prev | 1097 # Avoid sending full revisions when delta parent is null. Pick prev |
1098 # in that case. It's tempting to pick p1 in this case, as p1 will | 1098 # in that case. It's tempting to pick p1 in this case, as p1 will |
1099 # be smaller in the common case. However, computing a delta against | 1099 # be smaller in the common case. However, computing a delta against |
1100 # p1 may require resolving the raw text of p1, which could be | 1100 # p1 may require resolving the raw text of p1, which could be |
1101 # expensive. The revlog caches should have prev cached, meaning | 1101 # expensive. The revlog caches should have prev cached, meaning |
1109 elif dp not in (p1, p2, prev): | 1109 elif dp not in (p1, p2, prev): |
1110 # Pick prev when we can't be sure remote has the base revision. | 1110 # Pick prev when we can't be sure remote has the base revision. |
1111 return prev | 1111 return prev |
1112 else: | 1112 else: |
1113 base = dp | 1113 base = dp |
1114 if base != nullrev and not revlog.candelta(base, rev): | 1114 if base != nullrev and not store.candelta(base, rev): |
1115 base = nullrev | 1115 base = nullrev |
1116 return base | 1116 return base |
1117 | 1117 |
1118 def builddeltaheader(self, node, p1n, p2n, basenode, linknode, flags): | 1118 def builddeltaheader(self, node, p1n, p2n, basenode, linknode, flags): |
1119 # Do nothing with flags, it is implicitly 0 in cg1 and cg2 | 1119 # Do nothing with flags, it is implicitly 0 in cg1 and cg2 |