Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/revlog.py @ 35641:c41bb85c09ff
revlog: group revision info into a dedicated structure
author | Paul Morelle <paul.morelle@octobus.net> |
---|---|
date | Sun, 14 Jan 2018 13:04:26 -0800 |
parents | fa4278171add |
children | d99b07bc69fb |
comparison
equal
deleted
inserted
replaced
35640:fa4278171add | 35641:c41bb85c09ff |
---|---|
261 data = attr.ib() | 261 data = attr.ib() |
262 base = attr.ib() | 262 base = attr.ib() |
263 chainbase = attr.ib() | 263 chainbase = attr.ib() |
264 chainlen = attr.ib() | 264 chainlen = attr.ib() |
265 compresseddeltalen = attr.ib() | 265 compresseddeltalen = attr.ib() |
266 | |
267 @attr.s(slots=True, frozen=True) | |
268 class _revisioninfo(object): | |
269 """Information about a revision that allows building its fulltext | |
270 node: expected hash of the revision | |
271 p1, p2: parent revs of the revision | |
272 btext: built text cache consisting of a one-element list | |
273 cachedelta: (baserev, uncompressed_delta) or None | |
274 flags: flags associated to the revision storage | |
275 | |
276 One of btext[0] or cachedelta must be set. | |
277 """ | |
278 node = attr.ib() | |
279 p1 = attr.ib() | |
280 p2 = attr.ib() | |
281 btext = attr.ib() | |
282 cachedelta = attr.ib() | |
283 flags = attr.ib() | |
266 | 284 |
267 # index v0: | 285 # index v0: |
268 # 4 bytes: offset | 286 # 4 bytes: offset |
269 # 4 bytes: compressed length | 287 # 4 bytes: compressed length |
270 # 4 bytes: base rev | 288 # 4 bytes: base rev |
1892 if prev not in tested: | 1910 if prev not in tested: |
1893 # other approach failed try against prev to hopefully save us a | 1911 # other approach failed try against prev to hopefully save us a |
1894 # fulltext. | 1912 # fulltext. |
1895 yield (prev,) | 1913 yield (prev,) |
1896 | 1914 |
1897 def _buildtext(self, node, p1, p2, btext, cachedelta, fh, flags): | 1915 def _buildtext(self, revinfo, fh): |
1898 """Builds a fulltext version of a revision | 1916 """Builds a fulltext version of a revision |
1899 | 1917 |
1900 node: expected hash of the revision | 1918 revinfo: _revisioninfo instance that contains all needed info |
1901 p1, p2: parent revs of the revision | 1919 fh: file handle to either the .i or the .d revlog file, |
1902 btext: built text cache consisting of a one-element list | 1920 depending on whether it is inlined or not |
1903 cachedelta: (baserev, uncompressed_delta) or None | 1921 """ |
1904 fh: file handle to either the .i or the .d revlog file, | 1922 btext = revinfo.btext |
1905 depending on whether it is inlined or not | |
1906 flags: flags associated to the revision storage | |
1907 | |
1908 One of btext[0] or cachedelta must be set. | |
1909 """ | |
1910 if btext[0] is not None: | 1923 if btext[0] is not None: |
1911 return btext[0] | 1924 return btext[0] |
1925 | |
1926 cachedelta = revinfo.cachedelta | |
1927 flags = revinfo.flags | |
1928 node = revinfo.node | |
1929 | |
1912 baserev = cachedelta[0] | 1930 baserev = cachedelta[0] |
1913 delta = cachedelta[1] | 1931 delta = cachedelta[1] |
1914 # special case deltas which replace entire base; no need to decode | 1932 # special case deltas which replace entire base; no need to decode |
1915 # base revision. this neatly avoids censored bases, which throw when | 1933 # base revision. this neatly avoids censored bases, which throw when |
1916 # they're decoded. | 1934 # they're decoded. |
1924 | 1942 |
1925 try: | 1943 try: |
1926 res = self._processflags(btext[0], flags, 'read', raw=True) | 1944 res = self._processflags(btext[0], flags, 'read', raw=True) |
1927 btext[0], validatehash = res | 1945 btext[0], validatehash = res |
1928 if validatehash: | 1946 if validatehash: |
1929 self.checkhash(btext[0], node, p1=p1, p2=p2) | 1947 self.checkhash(btext[0], node, p1=revinfo.p1, p2=revinfo.p2) |
1930 if flags & REVIDX_ISCENSORED: | 1948 if flags & REVIDX_ISCENSORED: |
1931 raise RevlogError(_('node %s is not censored') % node) | 1949 raise RevlogError(_('node %s is not censored') % node) |
1932 except CensoredNodeError: | 1950 except CensoredNodeError: |
1933 # must pass the censored index flag to add censored revisions | 1951 # must pass the censored index flag to add censored revisions |
1934 if not flags & REVIDX_ISCENSORED: | 1952 if not flags & REVIDX_ISCENSORED: |
1935 raise | 1953 raise |
1936 return btext[0] | 1954 return btext[0] |
1937 | 1955 |
1938 def _builddeltadiff(self, base, node, p1, p2, btext, cachedelta, fh, flags): | 1956 def _builddeltadiff(self, base, revinfo, fh): |
1939 t = self._buildtext(node, p1, p2, btext, cachedelta, fh, flags) | 1957 t = self._buildtext(revinfo, fh) |
1940 if self.iscensored(base): | 1958 if self.iscensored(base): |
1941 # deltas based on a censored revision must replace the | 1959 # deltas based on a censored revision must replace the |
1942 # full content in one patch, so delta works everywhere | 1960 # full content in one patch, so delta works everywhere |
1943 header = mdiff.replacediffheader(self.rawsize(base), len(t)) | 1961 header = mdiff.replacediffheader(self.rawsize(base), len(t)) |
1944 delta = header + t | 1962 delta = header + t |
1946 ptext = self.revision(base, _df=fh, raw=True) | 1964 ptext = self.revision(base, _df=fh, raw=True) |
1947 delta = mdiff.textdiff(ptext, t) | 1965 delta = mdiff.textdiff(ptext, t) |
1948 | 1966 |
1949 return delta | 1967 return delta |
1950 | 1968 |
1951 def _builddeltainfo(self, node, base, p1, p2, btext, cachedelta, fh, flags): | 1969 def _builddeltainfo(self, revinfo, base, fh): |
1952 # can we use the cached delta? | 1970 # can we use the cached delta? |
1953 if cachedelta and cachedelta[0] == base: | 1971 if revinfo.cachedelta and revinfo.cachedelta[0] == base: |
1954 delta = cachedelta[1] | 1972 delta = revinfo.cachedelta[1] |
1955 else: | 1973 else: |
1956 delta = self._builddeltadiff(base, node, p1, p2, btext, cachedelta, | 1974 delta = self._builddeltadiff(base, revinfo, fh) |
1957 fh, flags) | |
1958 header, data = self.compress(delta) | 1975 header, data = self.compress(delta) |
1959 deltalen = len(header) + len(data) | 1976 deltalen = len(header) + len(data) |
1960 chainbase = self.chainbase(base) | 1977 chainbase = self.chainbase(base) |
1961 offset = self.end(len(self) - 1) | 1978 offset = self.end(len(self) - 1) |
1962 dist = deltalen + offset - self.start(chainbase) | 1979 dist = deltalen + offset - self.start(chainbase) |
2008 textlen = mdiff.patchedsize(self.rawsize(cachedelta[0]), | 2025 textlen = mdiff.patchedsize(self.rawsize(cachedelta[0]), |
2009 cachedelta[1]) | 2026 cachedelta[1]) |
2010 else: | 2027 else: |
2011 textlen = len(rawtext) | 2028 textlen = len(rawtext) |
2012 | 2029 |
2030 revinfo = _revisioninfo(node, p1, p2, btext, cachedelta, flags) | |
2013 for candidaterevs in self._getcandidaterevs(p1, p2, cachedelta): | 2031 for candidaterevs in self._getcandidaterevs(p1, p2, cachedelta): |
2014 nominateddeltas = [] | 2032 nominateddeltas = [] |
2015 for candidaterev in candidaterevs: | 2033 for candidaterev in candidaterevs: |
2016 candidatedelta = self._builddeltainfo(node, candidaterev, p1, | 2034 candidatedelta = self._builddeltainfo(revinfo, candidaterev, fh) |
2017 p2, btext, cachedelta, | |
2018 fh, flags) | |
2019 if self._isgooddeltainfo(candidatedelta, textlen): | 2035 if self._isgooddeltainfo(candidatedelta, textlen): |
2020 nominateddeltas.append(candidatedelta) | 2036 nominateddeltas.append(candidatedelta) |
2021 if nominateddeltas: | 2037 if nominateddeltas: |
2022 deltainfo = min(nominateddeltas, key=lambda x: x.deltalen) | 2038 deltainfo = min(nominateddeltas, key=lambda x: x.deltalen) |
2023 break | 2039 break |
2026 base = deltainfo.base | 2042 base = deltainfo.base |
2027 chainbase = deltainfo.chainbase | 2043 chainbase = deltainfo.chainbase |
2028 data = deltainfo.data | 2044 data = deltainfo.data |
2029 l = deltainfo.deltalen | 2045 l = deltainfo.deltalen |
2030 else: | 2046 else: |
2031 rawtext = self._buildtext(node, p1, p2, btext, cachedelta, fh, | 2047 rawtext = self._buildtext(revinfo, fh) |
2032 flags) | |
2033 data = self.compress(rawtext) | 2048 data = self.compress(rawtext) |
2034 l = len(data[1]) + len(data[0]) | 2049 l = len(data[1]) + len(data[0]) |
2035 base = chainbase = curr | 2050 base = chainbase = curr |
2036 | 2051 |
2037 e = (offset_type(offset, flags), l, textlen, | 2052 e = (offset_type(offset, flags), l, textlen, |
2041 | 2056 |
2042 entry = self._io.packentry(e, self.node, self.version, curr) | 2057 entry = self._io.packentry(e, self.node, self.version, curr) |
2043 self._writeentry(transaction, ifh, dfh, entry, data, link, offset) | 2058 self._writeentry(transaction, ifh, dfh, entry, data, link, offset) |
2044 | 2059 |
2045 if alwayscache and rawtext is None: | 2060 if alwayscache and rawtext is None: |
2046 rawtext = self._buildtext(node, p1, p2, btext, cachedelta, fh, | 2061 rawtext = self._buildtext(revinfo, fh) |
2047 flags) | |
2048 | 2062 |
2049 if type(rawtext) == str: # only accept immutable objects | 2063 if type(rawtext) == str: # only accept immutable objects |
2050 self._cache = (node, curr, rawtext) | 2064 self._cache = (node, curr, rawtext) |
2051 self._chainbasecache[curr] = chainbase | 2065 self._chainbasecache[curr] = chainbase |
2052 return node | 2066 return node |