Mercurial > public > mercurial-scm > hg
comparison mercurial/revlog.py @ 39231:b41d023a412a
repository: establish API for emitting revision deltas
With our revision delta and revision delta request interfaces
defined, it is now time to define a method on storage interfaces
for using them.
So far, the only storage interface that is well-defined and used
is file storage. So that is the only interface we need to add a
method on.
We define an ``emitrevisiondeltas()`` method that takes an
iterable of ``irevisiondeltarequest``s and turns them into
``irevisiondelta`` instances.
changegroup._handlerevisiondeltarequest() and the looping logic
from changegroup.deltagroup() has effectively been moved to
revlog.emitrevisiondeltas().
Our filelog wrapper class proxies its emitrevisiondeltas() to
the internal revlog instance.
The simple store test extension used to verify sanity of storage
abstractions has also implemented emitrevisiondeltas() for
file storage and the test harness when run with this extension doesn't
seem to exhibit any regressions.
Rather than create a shared type to represent revision deltas,
each storage backend has its own type and the class name identifies
where the revision delta was derived from.
Differential Revision: https://phab.mercurial-scm.org/D4226
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Thu, 09 Aug 2018 16:02:14 -0700 |
parents | dbc5ead9f40f |
children | 0a5b20c107a6 |
comparison
equal
deleted
inserted
replaced
39230:b518d495a560 | 39231:b41d023a412a |
---|---|
43 ancestor, | 43 ancestor, |
44 error, | 44 error, |
45 mdiff, | 45 mdiff, |
46 policy, | 46 policy, |
47 pycompat, | 47 pycompat, |
48 repository, | |
48 templatefilters, | 49 templatefilters, |
49 util, | 50 util, |
50 ) | 51 ) |
51 from .utils import ( | 52 from .utils import ( |
53 interfaceutil, | |
52 stringutil, | 54 stringutil, |
53 ) | 55 ) |
54 | 56 |
55 parsers = policy.importmod(r'parsers') | 57 parsers = policy.importmod(r'parsers') |
56 | 58 |
818 p2 = attr.ib() | 820 p2 = attr.ib() |
819 btext = attr.ib() | 821 btext = attr.ib() |
820 textlen = attr.ib() | 822 textlen = attr.ib() |
821 cachedelta = attr.ib() | 823 cachedelta = attr.ib() |
822 flags = attr.ib() | 824 flags = attr.ib() |
825 | |
826 @interfaceutil.implementer(repository.irevisiondelta) | |
827 @attr.s(slots=True, frozen=True) | |
828 class revlogrevisiondelta(object): | |
829 node = attr.ib() | |
830 p1node = attr.ib() | |
831 p2node = attr.ib() | |
832 basenode = attr.ib() | |
833 linknode = attr.ib() | |
834 flags = attr.ib() | |
835 baserevisionsize = attr.ib() | |
836 revision = attr.ib() | |
837 delta = attr.ib() | |
823 | 838 |
824 # index v0: | 839 # index v0: |
825 # 4 bytes: offset | 840 # 4 bytes: offset |
826 # 4 bytes: compressed length | 841 # 4 bytes: compressed length |
827 # 4 bytes: base rev | 842 # 4 bytes: base rev |
2948 res = [self.indexfile] | 2963 res = [self.indexfile] |
2949 if not self._inline: | 2964 if not self._inline: |
2950 res.append(self.datafile) | 2965 res.append(self.datafile) |
2951 return res | 2966 return res |
2952 | 2967 |
2968 def emitrevisiondeltas(self, requests): | |
2969 frev = self.rev | |
2970 | |
2971 prevrev = None | |
2972 for request in requests: | |
2973 node = request.node | |
2974 rev = frev(node) | |
2975 | |
2976 if prevrev is None: | |
2977 prevrev = self.index[rev][5] | |
2978 | |
2979 # Requesting a full revision. | |
2980 if request.basenode == nullid: | |
2981 baserev = nullrev | |
2982 # Requesting an explicit revision. | |
2983 elif request.basenode is not None: | |
2984 baserev = frev(request.basenode) | |
2985 # Allowing us to choose. | |
2986 else: | |
2987 p1rev, p2rev = self.parentrevs(rev) | |
2988 deltaparentrev = self.deltaparent(rev) | |
2989 | |
2990 # Avoid sending full revisions when delta parent is null. Pick | |
2991 # prev in that case. It's tempting to pick p1 in this case, as | |
2992 # p1 will be smaller in the common case. However, computing a | |
2993 # delta against p1 may require resolving the raw text of p1, | |
2994 # which could be expensive. The revlog caches should have prev | |
2995 # cached, meaning less CPU for delta generation. There is | |
2996 # likely room to add a flag and/or config option to control this | |
2997 # behavior. | |
2998 if deltaparentrev == nullrev and self.storedeltachains: | |
2999 baserev = prevrev | |
3000 | |
3001 # Revlog is configured to use full snapshot for a reason. | |
3002 # Stick to full snapshot. | |
3003 elif deltaparentrev == nullrev: | |
3004 baserev = nullrev | |
3005 | |
3006 # Pick previous when we can't be sure the base is available | |
3007 # on consumer. | |
3008 elif deltaparentrev not in (p1rev, p2rev, prevrev): | |
3009 baserev = prevrev | |
3010 else: | |
3011 baserev = deltaparentrev | |
3012 | |
3013 if baserev != nullrev and not self.candelta(baserev, rev): | |
3014 baserev = nullrev | |
3015 | |
3016 revision = None | |
3017 delta = None | |
3018 baserevisionsize = None | |
3019 | |
3020 if self.iscensored(baserev) or self.iscensored(rev): | |
3021 try: | |
3022 revision = self.revision(node, raw=True) | |
3023 except error.CensoredNodeError as e: | |
3024 revision = e.tombstone | |
3025 | |
3026 if baserev != nullrev: | |
3027 baserevisionsize = self.rawsize(baserev) | |
3028 | |
3029 elif baserev == nullrev: | |
3030 revision = self.revision(node, raw=True) | |
3031 else: | |
3032 delta = self.revdiff(baserev, rev) | |
3033 | |
3034 extraflags = REVIDX_ELLIPSIS if request.ellipsis else 0 | |
3035 | |
3036 yield revlogrevisiondelta( | |
3037 node=node, | |
3038 p1node=request.p1node, | |
3039 p2node=request.p2node, | |
3040 linknode=request.linknode, | |
3041 basenode=self.node(baserev), | |
3042 flags=self.flags(rev) | extraflags, | |
3043 baserevisionsize=baserevisionsize, | |
3044 revision=revision, | |
3045 delta=delta) | |
3046 | |
3047 prevrev = rev | |
3048 | |
2953 DELTAREUSEALWAYS = 'always' | 3049 DELTAREUSEALWAYS = 'always' |
2954 DELTAREUSESAMEREVS = 'samerevs' | 3050 DELTAREUSESAMEREVS = 'samerevs' |
2955 DELTAREUSENEVER = 'never' | 3051 DELTAREUSENEVER = 'never' |
2956 | 3052 |
2957 DELTAREUSEFULLADD = 'fulladd' | 3053 DELTAREUSEFULLADD = 'fulladd' |