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