Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/revlog.py @ 30778:1c7368d1a25f
revlog: add clone method
Upcoming patches will introduce functionality for in-place
repository/store "upgrades." Copying the contents of a revlog
feels sufficiently low-level to warrant being in the revlog
class. So this commit implements that functionality.
Because full delta recomputation can be *very* expensive (we're
talking several hours on the Firefox repository), we support
multiple modes of execution with regards to delta (re)use. This
will allow repository upgrades to choose the "level" of
processing/optimization they wish to perform when converting
revlogs.
It's not obvious from this commit, but "addrevisioncb" will be
used for progress reporting.
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Sun, 18 Dec 2016 17:02:57 -0800 |
parents | 9cb0bb0f29f0 |
children | 4215dc1b708b |
comparison
equal
deleted
inserted
replaced
30777:7de7afd8bdd9 | 30778:1c7368d1a25f |
---|---|
1946 def files(self): | 1946 def files(self): |
1947 res = [self.indexfile] | 1947 res = [self.indexfile] |
1948 if not self._inline: | 1948 if not self._inline: |
1949 res.append(self.datafile) | 1949 res.append(self.datafile) |
1950 return res | 1950 return res |
1951 | |
1952 DELTAREUSEALWAYS = 'always' | |
1953 DELTAREUSESAMEREVS = 'samerevs' | |
1954 DELTAREUSENEVER = 'never' | |
1955 | |
1956 DELTAREUSEALL = set(['always', 'samerevs', 'never']) | |
1957 | |
1958 def clone(self, tr, destrevlog, addrevisioncb=None, | |
1959 deltareuse=DELTAREUSESAMEREVS, aggressivemergedeltas=None): | |
1960 """Copy this revlog to another, possibly with format changes. | |
1961 | |
1962 The destination revlog will contain the same revisions and nodes. | |
1963 However, it may not be bit-for-bit identical due to e.g. delta encoding | |
1964 differences. | |
1965 | |
1966 The ``deltareuse`` argument control how deltas from the existing revlog | |
1967 are preserved in the destination revlog. The argument can have the | |
1968 following values: | |
1969 | |
1970 DELTAREUSEALWAYS | |
1971 Deltas will always be reused (if possible), even if the destination | |
1972 revlog would not select the same revisions for the delta. This is the | |
1973 fastest mode of operation. | |
1974 DELTAREUSESAMEREVS | |
1975 Deltas will be reused if the destination revlog would pick the same | |
1976 revisions for the delta. This mode strikes a balance between speed | |
1977 and optimization. | |
1978 DELTAREUSENEVER | |
1979 Deltas will never be reused. This is the slowest mode of execution. | |
1980 This mode can be used to recompute deltas (e.g. if the diff/delta | |
1981 algorithm changes). | |
1982 | |
1983 Delta computation can be slow, so the choice of delta reuse policy can | |
1984 significantly affect run time. | |
1985 | |
1986 The default policy (``DELTAREUSESAMEREVS``) strikes a balance between | |
1987 two extremes. Deltas will be reused if they are appropriate. But if the | |
1988 delta could choose a better revision, it will do so. This means if you | |
1989 are converting a non-generaldelta revlog to a generaldelta revlog, | |
1990 deltas will be recomputed if the delta's parent isn't a parent of the | |
1991 revision. | |
1992 | |
1993 In addition to the delta policy, the ``aggressivemergedeltas`` argument | |
1994 controls whether to compute deltas against both parents for merges. | |
1995 By default, the current default is used. | |
1996 """ | |
1997 if deltareuse not in self.DELTAREUSEALL: | |
1998 raise ValueError(_('value for deltareuse invalid: %s') % deltareuse) | |
1999 | |
2000 if len(destrevlog): | |
2001 raise ValueError(_('destination revlog is not empty')) | |
2002 | |
2003 if getattr(self, 'filteredrevs', None): | |
2004 raise ValueError(_('source revlog has filtered revisions')) | |
2005 if getattr(destrevlog, 'filteredrevs', None): | |
2006 raise ValueError(_('destination revlog has filtered revisions')) | |
2007 | |
2008 # lazydeltabase controls whether to reuse a cached delta, if possible. | |
2009 oldlazydeltabase = destrevlog._lazydeltabase | |
2010 oldamd = destrevlog._aggressivemergedeltas | |
2011 | |
2012 try: | |
2013 if deltareuse == self.DELTAREUSEALWAYS: | |
2014 destrevlog._lazydeltabase = True | |
2015 elif deltareuse == self.DELTAREUSESAMEREVS: | |
2016 destrevlog._lazydeltabase = False | |
2017 | |
2018 destrevlog._aggressivemergedeltas = aggressivemergedeltas or oldamd | |
2019 | |
2020 populatecachedelta = deltareuse in (self.DELTAREUSEALWAYS, | |
2021 self.DELTAREUSESAMEREVS) | |
2022 | |
2023 index = self.index | |
2024 for rev in self: | |
2025 entry = index[rev] | |
2026 | |
2027 # Some classes override linkrev to take filtered revs into | |
2028 # account. Use raw entry from index. | |
2029 flags = entry[0] & 0xffff | |
2030 linkrev = entry[4] | |
2031 p1 = index[entry[5]][7] | |
2032 p2 = index[entry[6]][7] | |
2033 node = entry[7] | |
2034 | |
2035 # (Possibly) reuse the delta from the revlog if allowed and | |
2036 # the revlog chunk is a delta. | |
2037 cachedelta = None | |
2038 text = None | |
2039 if populatecachedelta: | |
2040 dp = self.deltaparent(rev) | |
2041 if dp != nullrev: | |
2042 cachedelta = (dp, str(self._chunk(rev))) | |
2043 | |
2044 if not cachedelta: | |
2045 text = self.revision(rev) | |
2046 | |
2047 ifh = destrevlog.opener(destrevlog.indexfile, 'a+', | |
2048 checkambig=False) | |
2049 dfh = None | |
2050 if not destrevlog._inline: | |
2051 dfh = destrevlog.opener(destrevlog.datafile, 'a+') | |
2052 try: | |
2053 destrevlog._addrevision(node, text, tr, linkrev, p1, p2, | |
2054 flags, cachedelta, ifh, dfh) | |
2055 finally: | |
2056 if dfh: | |
2057 dfh.close() | |
2058 ifh.close() | |
2059 | |
2060 if addrevisioncb: | |
2061 addrevisioncb(self, rev, node) | |
2062 finally: | |
2063 destrevlog._lazydeltabase = oldlazydeltabase | |
2064 destrevlog._aggressivemergedeltas = oldamd |