##// END OF EJS Templates
push: indent the some part of the command...
push: indent the some part of the command That code will be put in a loop in the next changeset, pre-indenting make the next change clearer. Differential Revision: https://phab.mercurial-scm.org/D10160

File last commit:

r47452:ba8e508a default
r47535:25850879 default
Show More
revlog.py
3258 lines | 110.6 KiB | text/x-python | PythonLexer
Martin Geisler
put license and copyright info into comment blocks
r8226 # revlog.py - storage back-end for mercurial
#
# Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
#
# This software may be used and distributed according to the terms of the
Matt Mackall
Update license to GPLv2+
r10263 # GNU General Public License version 2 or any later version.
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
Martin Geisler
turn some comments back into module docstrings
r8227 """Storage back-end for Mercurial.
This provides efficient delta storage with O(1) retrieve and append
and O(changes) merge between branches.
"""
Gregory Szorc
revlog: use absolute_import
r27361 from __future__ import absolute_import
Martin von Zweigbergk
util: drop alias for collections.deque...
r25113 import collections
Boris Feld
revlog: add a _datareadfp context manager for data access needs...
r35991 import contextlib
Gregory Szorc
revlog: use absolute_import
r27361 import errno
Augie Fackler
cleanup: use named constants for second arg to .seek()...
r42767 import io
Gregory Szorc
revlog: seek to end of file before writing (issue4943)...
r27430 import os
Gregory Szorc
revlog: use absolute_import
r27361 import struct
import zlib
# import stuff from node for others to import from revlog
from .node import (
bin,
hex,
Martin von Zweigbergk
revlog: fix pure version of _partialmatch() to include nullid...
r39227 nullhex,
Gregory Szorc
revlog: use absolute_import
r27361 nullid,
nullrev,
Gregory Szorc
revlog: move revision verification out of verify...
r39908 short,
Yuya Nishihara
revlog: detect pseudo file nodeids to raise WdirUnsupported exception...
r37467 wdirfilenodeids,
Yuya Nishihara
revlog: add support for partial matching of wdir node id...
r32684 wdirhex,
Yuya Nishihara
revlog: map rev(wdirid) to WdirUnsupported exception...
r32657 wdirid,
Pulkit Goyal
revlog: raise WdirUnsupported when wdirrev is passed...
r32402 wdirrev,
Gregory Szorc
revlog: use absolute_import
r27361 )
from .i18n import _
Gregory Szorc
py3: manually import getattr where it is needed...
r43359 from .pycompat import getattr
Boris Feld
revlog: split constants into a new `revlogutils.constants` module...
r39365 from .revlogutils.constants import (
FLAG_GENERALDELTA,
FLAG_INLINE_DATA,
REVLOGV0,
REVLOGV1,
REVLOGV1_FLAGS,
REVLOGV2,
REVLOGV2_FLAGS,
REVLOG_DEFAULT_FLAGS,
REVLOG_DEFAULT_FORMAT,
REVLOG_DEFAULT_VERSION,
)
flagutil: create a `mercurial.revlogutils.flagutil` module...
r42954 from .revlogutils.flagutil import (
REVIDX_DEFAULT_FLAGS,
REVIDX_ELLIPSIS,
REVIDX_EXTSTORED,
REVIDX_FLAGS_ORDER,
copies: add a HASCOPIESINFO flag to highlight rev with useful data...
r46263 REVIDX_HASCOPIESINFO,
flagutil: create a `mercurial.revlogutils.flagutil` module...
r42954 REVIDX_ISCENSORED,
REVIDX_RAWTEXT_CHANGING_FLAGS,
sidedata: register the flag processors if the repository allows for it...
r43305 REVIDX_SIDEDATA,
flagutil: create a `mercurial.revlogutils.flagutil` module...
r42954 )
Augie Fackler
formatting: blacken the codebase...
r43346 from .thirdparty import attr
Gregory Szorc
revlog: use absolute_import
r27361 from . import (
ancestor,
Gregory Szorc
revlog: new API to emit revision data...
r39898 dagop,
Gregory Szorc
revlog: use absolute_import
r27361 error,
mdiff,
Yuya Nishihara
parsers: switch to policy importer...
r32372 policy,
Augie Fackler
revlog: use pycompat.maplist to eagerly evaluate map on Python 3...
r31574 pycompat,
Gregory Szorc
revlog: use absolute_import
r27361 templatefilters,
util,
)
Pulkit Goyal
interfaces: create a new folder for interfaces and move repository.py in it...
r43078 from .interfaces import (
repository,
Pulkit Goyal
interfaceutil: move to interfaces/...
r43079 util as interfaceutil,
Pulkit Goyal
interfaces: create a new folder for interfaces and move repository.py in it...
r43078 )
Boris Feld
revlog: split functionality related to deltas computation in a new module...
r39366 from .revlogutils import (
deltas as deltautil,
flagutil: move the `flagprocessors` mapping in the new module...
r42955 flagutil,
revlogutils: move the NodeMap class in a dedicated nodemap module...
r44486 nodemap as nodemaputil,
sidedata: register the flag processors if the repository allows for it...
r43305 sidedata as sidedatautil,
Boris Feld
revlog: split functionality related to deltas computation in a new module...
r39366 )
Yuya Nishihara
stringutil: bulk-replace call sites to point to new module...
r37102 from .utils import (
Gregory Szorc
storageutil: new module for storage primitives (API)...
r39913 storageutil,
Yuya Nishihara
stringutil: bulk-replace call sites to point to new module...
r37102 stringutil,
)
Raphaël Gomès
revlog: introduce v2 format...
r47438 from .pure import parsers as pureparsers
mpm@selenic.com
Add smart node lookup by substring or by rev number
r36
Boris Feld
revlog: split constants into a new `revlogutils.constants` module...
r39365 # blanked usage of all the name to prevent pyflakes constraints
# We need these name available in the module for extensions.
REVLOGV0
REVLOGV1
REVLOGV2
FLAG_INLINE_DATA
FLAG_GENERALDELTA
REVLOG_DEFAULT_FLAGS
REVLOG_DEFAULT_FORMAT
REVLOG_DEFAULT_VERSION
REVLOGV1_FLAGS
REVLOGV2_FLAGS
REVIDX_ISCENSORED
REVIDX_ELLIPSIS
sidedata: register the flag processors if the repository allows for it...
r43305 REVIDX_SIDEDATA
copies: add a HASCOPIESINFO flag to highlight rev with useful data...
r46263 REVIDX_HASCOPIESINFO
Boris Feld
revlog: split constants into a new `revlogutils.constants` module...
r39365 REVIDX_EXTSTORED
REVIDX_DEFAULT_FLAGS
REVIDX_FLAGS_ORDER
REVIDX_RAWTEXT_CHANGING_FLAGS
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 parsers = policy.importmod('parsers')
rustancestor = policy.importrust('ancestor')
rustdagop = policy.importrust('dagop')
Georges Racinet
rust-index: add a `experimental.rust.index` option to use the wrapper...
r44466 rustrevlog = policy.importrust('revlog')
Yuya Nishihara
parsers: switch to policy importer...
r32372
Gregory Szorc
revlog: use compression engine APIs for decompression...
r30817 # Aliased for performance.
_zlibdecompress = zlib.decompress
Matt Mackall
revlog: localize some fastpath functions
r5007
Benoit Boissinot
add documentation for revlog._prereadsize
r10916 # max size of revlog with inline data
_maxinline = 131072
Matt Mackall
revlog: remove lazy index
r13253 _chunksize = 1048576
Greg Ward
revlog: factor out _maxinline global....
r10913
Gregory Szorc
revlog: define ellipsis flag processors in core...
r39803 # Flag processors for REVIDX_ELLIPSIS.
def ellipsisreadprocessor(rl, text):
Raphaël Gomès
sidedata: move to new sidedata storage in revlogv2...
r47443 return text, False
def ellipsiswriteprocessor(rl, text):
Gregory Szorc
revlog: define ellipsis flag processors in core...
r39803 return text, False
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
revlog: define ellipsis flag processors in core...
r39803 def ellipsisrawprocessor(rl, text):
return False
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
revlog: define ellipsis flag processors in core...
r39803 ellipsisprocessor = (
ellipsisreadprocessor,
ellipsiswriteprocessor,
ellipsisrawprocessor,
)
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
revlog: some basic code reordering
r4987 def getoffset(q):
return int(q >> 16)
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
revlog: some basic code reordering
r4987 def gettype(q):
return int(q & 0xFFFF)
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
revlog: some basic code reordering
r4987 def offset_type(offset, type):
flagutil: move REVIDX_KNOWN_FLAGS source of truth in flagutil (API)...
r42956 if (type & ~flagutil.REVIDX_KNOWN_FLAGS) != 0:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise ValueError(b'unknown revlog index flags')
Augie Fackler
revlog: use int instead of long...
r31504 return int(int(offset) << 16 | type)
Matt Mackall
revlog: some basic code reordering
r4987
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
revlog: split the content verification of a node into a separate method...
r44409 def _verify_revision(rl, skipflags, state, node):
"""Verify the integrity of the given revlog ``node`` while providing a hook
point for extensions to influence the operation."""
if skipflags:
state[b'skipread'].add(node)
else:
# Side-effect: read content and verify hash.
rl.revision(node)
persistent-nodemap: add a "warn" option to the slow-path config...
r47028 # True if a fast implementation for persistent-nodemap is available
#
# We also consider we have a "fast" implementation in "pure" python because
# people using pure don't really have performance consideration (and a
# wheelbarrow of other slowness source)
HAS_FAST_PERSISTENT_NODEMAP = rustrevlog is not None or util.safehasattr(
parsers, 'BaseIndexObject'
)
Paul Morelle
revlog: group revision info into a dedicated structure
r35659 @attr.s(slots=True, frozen=True)
class _revisioninfo(object):
"""Information about a revision that allows building its fulltext
node: expected hash of the revision
p1, p2: parent revs of the revision
btext: built text cache consisting of a one-element list
cachedelta: (baserev, uncompressed_delta) or None
flags: flags associated to the revision storage
One of btext[0] or cachedelta must be set.
"""
Augie Fackler
formatting: blacken the codebase...
r43346
Paul Morelle
revlog: group revision info into a dedicated structure
r35659 node = attr.ib()
p1 = attr.ib()
p2 = attr.ib()
btext = attr.ib()
Paul Morelle
revlog: refactor out _finddeltainfo from _addrevision...
r35755 textlen = attr.ib()
Paul Morelle
revlog: group revision info into a dedicated structure
r35659 cachedelta = attr.ib()
flags = attr.ib()
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
repository: establish API for emitting revision deltas...
r39267 @interfaceutil.implementer(repository.irevisiondelta)
Gregory Szorc
revlog: new API to emit revision data...
r39898 @attr.s(slots=True)
Gregory Szorc
repository: establish API for emitting revision deltas...
r39267 class revlogrevisiondelta(object):
node = attr.ib()
p1node = attr.ib()
p2node = attr.ib()
basenode = attr.ib()
flags = attr.ib()
baserevisionsize = attr.ib()
revision = attr.ib()
delta = attr.ib()
Raphaël Gomès
delta: add sidedata field to revision delta...
r47446 sidedata = attr.ib()
Gregory Szorc
revlog: new API to emit revision data...
r39898 linknode = attr.ib(default=None)
Gregory Szorc
repository: establish API for emitting revision deltas...
r39267
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
verify: start to abstract file verification...
r39878 @interfaceutil.implementer(repository.iverifyproblem)
@attr.s(frozen=True)
class revlogproblem(object):
warning = attr.ib(default=None)
error = attr.ib(default=None)
Gregory Szorc
revlog: move revision verification out of verify...
r39908 node = attr.ib(default=None)
Gregory Szorc
verify: start to abstract file verification...
r39878
Augie Fackler
formatting: blacken the codebase...
r43346
Benoit Boissinot
revlog: document v0 format
r18585 # index v0:
# 4 bytes: offset
# 4 bytes: compressed length
# 4 bytes: base rev
# 4 bytes: link rev
Yuya Nishihara
revlog: correct comment about size of v0 index format
r25891 # 20 bytes: parent 1 nodeid
# 20 bytes: parent 2 nodeid
# 20 bytes: nodeid
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 indexformatv0 = struct.Struct(b">4l20s20s20s")
Alex Gaynor
revlog: use struct.Struct instances for slight performance wins...
r33392 indexformatv0_pack = indexformatv0.pack
indexformatv0_unpack = indexformatv0.unpack
Matt Mackall
revlog: raise offset/type helpers to global scope
r4918
Augie Fackler
formatting: blacken the codebase...
r43346
Martin von Zweigbergk
pure: create type for revlog v0 index...
r38885 class revlogoldindex(list):
revlog: deprecate direct `nodemap` access...
r43974 @property
def nodemap(self):
Denis Laxalde
py3: pass a bytes value for "msg" to nouideprecwarn()...
r44018 msg = b"index.nodemap is deprecated, use index.[has_node|rev|get_rev]"
revlog: deprecate direct `nodemap` access...
r43974 util.nouideprecwarn(msg, b'5.3', stacklevel=2)
return self._nodemap
revlog: move the nodemap into the index object (for pure)...
r43925 @util.propertycache
revlog: deprecate direct `nodemap` access...
r43974 def _nodemap(self):
revlogutils: move the NodeMap class in a dedicated nodemap module...
r44486 nodemap = nodemaputil.NodeMap({nullid: nullrev})
revlog: move the nodemap into the index object (for pure)...
r43925 for r in range(0, len(self)):
n = self[r][7]
nodemap[n] = r
return nodemap
index: add a `has_node` method (API)...
r43934 def has_node(self, node):
"""return True if the node exist in the index"""
revlog: deprecate direct `nodemap` access...
r43974 return node in self._nodemap
index: add a `has_node` method (API)...
r43934
index: add a `rev` method (API)...
r43952 def rev(self, node):
"""return a revision for a node
If the node is unknown, raise a RevlogError"""
revlog: deprecate direct `nodemap` access...
r43974 return self._nodemap[node]
index: add a `rev` method (API)...
r43952
index: add a `get_rev` method (API)...
r43954 def get_rev(self, node):
"""return a revision for a node
If the node is unknown, return None"""
revlog: deprecate direct `nodemap` access...
r43974 return self._nodemap.get(node)
index: add a `get_rev` method (API)...
r43954
revlog: move nodemap update within the index code...
r43931 def append(self, tup):
revlog: deprecate direct `nodemap` access...
r43974 self._nodemap[tup[7]] = len(self)
revlog: move nodemap update within the index code...
r43931 super(revlogoldindex, self).append(tup)
revlog: deal with nodemap deletion within the index...
r43933 def __delitem__(self, i):
if not isinstance(i, slice) or not i.stop == -1 or i.step is not None:
raise ValueError(b"deleting slices only supports a:-1 with step 1")
for r in pycompat.xrange(i.start, len(self)):
revlog: deprecate direct `nodemap` access...
r43974 del self._nodemap[self[r][7]]
revlog: deal with nodemap deletion within the index...
r43933 super(revlogoldindex, self).__delitem__(i)
revlog: move the nodemap into the index object (for pure)...
r43925 def clearcaches(self):
revlog: deprecate direct `nodemap` access...
r43974 self.__dict__.pop('_nodemap', None)
revlog: move the nodemap into the index object (for pure)...
r43925
Martin von Zweigbergk
pure: create type for revlog v0 index...
r38885 def __getitem__(self, i):
Martin von Zweigbergk
index: don't allow index[len(index)] to mean nullid...
r38888 if i == -1:
Martin von Zweigbergk
pure: create type for revlog v0 index...
r38885 return (0, 0, 0, -1, -1, -1, -1, nullid)
return list.__getitem__(self, i)
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
revlog: add revlogio interface...
r4972 class revlogoldio(object):
def __init__(self):
Alex Gaynor
revlog: use struct.Struct instances for slight performance wins...
r33392 self.size = indexformatv0.size
Matt Mackall
revlog: add revlogio interface...
r4972
Benoit Boissinot
revlog/parseindex: no need to pass the file around
r13264 def parseindex(self, data, inline):
Matt Mackall
revlog: parse revlogv0 indexes into v1 internally...
r4977 s = self.size
Matt Mackall
revlog: add revlogio interface...
r4972 index = []
revlogutils: move the NodeMap class in a dedicated nodemap module...
r44486 nodemap = nodemaputil.NodeMap({nullid: nullrev})
Matt Mackall
revlog: simplify the v0 parser
r4973 n = off = 0
l = len(data)
while off + s <= l:
Augie Fackler
formatting: blacken the codebase...
r43346 cur = data[off : off + s]
Matt Mackall
revlog: simplify the v0 parser
r4973 off += s
Alex Gaynor
revlog: use struct.Struct instances for slight performance wins...
r33392 e = indexformatv0_unpack(cur)
Matt Mackall
revlog: parse revlogv0 indexes into v1 internally...
r4977 # transform to revlogv1 format
Augie Fackler
formatting: blacken the codebase...
r43346 e2 = (
offset_type(e[0], 0),
e[1],
-1,
e[2],
e[3],
nodemap.get(e[4], nullrev),
nodemap.get(e[5], nullrev),
e[6],
)
Matt Mackall
revlog: parse revlogv0 indexes into v1 internally...
r4977 index.append(e2)
nodemap[e[6]] = n
Matt Mackall
revlog: simplify the v0 parser
r4973 n += 1
Matt Mackall
revlog: add revlogio interface...
r4972
revlog: move the nodemap into the index object (for pure)...
r43925 index = revlogoldindex(index)
revlog: no longer return the nodemap after parsing...
r43926 return index, None
Matt Mackall
revlog: add revlogio interface...
r4972
Alexis S. L. Carvalho
revlog: fix revlogio.packentry corner case...
r5338 def packentry(self, entry, node, version, rev):
Benoit Boissinot
revlog: don't silently discard revlog flags on revlogv0
r10395 if gettype(entry[0]):
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.RevlogError(
Martin von Zweigbergk
cleanup: join string literals that are already on one line...
r43387 _(b'index entry flags need revlog version 1')
Augie Fackler
formatting: blacken the codebase...
r43346 )
e2 = (
getoffset(entry[0]),
entry[1],
entry[3],
entry[4],
node(entry[5]),
node(entry[6]),
entry[7],
)
Alex Gaynor
revlog: use struct.Struct instances for slight performance wins...
r33392 return indexformatv0_pack(*e2)
Matt Mackall
revlog: abstract out index entry packing...
r4986
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
revlog: some basic code reordering
r4987 # index ng:
Martin Geisler
revlog: fix inconsistent comment formatting
r11323 # 6 bytes: offset
# 2 bytes: flags
# 4 bytes: compressed length
# 4 bytes: uncompressed length
# 4 bytes: base rev
# 4 bytes: link rev
# 4 bytes: parent 1 rev
# 4 bytes: parent 2 rev
Matt Mackall
revlog: some basic code reordering
r4987 # 32 bytes: nodeid
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 indexformatng = struct.Struct(b">Qiiiiii20s12x")
Alex Gaynor
revlog: use struct.Struct instances for slight performance wins...
r33392 indexformatng_pack = indexformatng.pack
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 versionformat = struct.Struct(b">I")
Alex Gaynor
revlog: use struct.Struct instances for slight performance wins...
r33392 versionformat_pack = versionformat.pack
versionformat_unpack = versionformat.unpack
Matt Mackall
revlog: some basic code reordering
r4987
Jordi Gutiérrez Hermoso
revlog: raise an exception earlier if an entry is too large (issue4675)...
r25410 # corresponds to uncompressed length of indexformatng (2 gigs, 4-byte
# signed integer)
Augie Fackler
formatting: blacken the codebase...
r43346 _maxentrysize = 0x7FFFFFFF
Jordi Gutiérrez Hermoso
revlog: raise an exception earlier if an entry is too large (issue4675)...
r25410
Matt Mackall
revlog: add revlogio interface...
r4972 class revlogio(object):
def __init__(self):
Alex Gaynor
revlog: use struct.Struct instances for slight performance wins...
r33392 self.size = indexformatng.size
Matt Mackall
revlog: add revlogio interface...
r4972
Benoit Boissinot
revlog/parseindex: no need to pass the file around
r13264 def parseindex(self, data, inline):
Bernhard Leiner
use the new parseindex implementation C in parsers
r7109 # call the C implementation to parse the index data
Matt Mackall
revlog: only build the nodemap on demand
r13254 index, cache = parsers.parse_index2(data, inline)
revlog: no longer return the nodemap after parsing...
r43926 return index, cache
Matt Mackall
revlog: add revlogio interface...
r4972
Alexis S. L. Carvalho
revlog: fix revlogio.packentry corner case...
r5338 def packentry(self, entry, node, version, rev):
Alex Gaynor
revlog: use struct.Struct instances for slight performance wins...
r33392 p = indexformatng_pack(*entry)
Alexis S. L. Carvalho
revlog: fix revlogio.packentry corner case...
r5338 if rev == 0:
Alex Gaynor
revlog: use struct.Struct instances for slight performance wins...
r33392 p = versionformat_pack(version) + p[4:]
Matt Mackall
revlog: abstract out index entry packing...
r4986 return p
Augie Fackler
formatting: blacken the codebase...
r43346
Raphaël Gomès
revlog: introduce v2 format...
r47438 indexformatv2 = struct.Struct(pureparsers.Index2Mixin.index_format)
indexformatv2_pack = indexformatv2.pack
class revlogv2io(object):
def __init__(self):
self.size = indexformatv2.size
def parseindex(self, data, inline):
index, cache = parsers.parse_index2(data, inline, revlogv2=True)
return index, cache
def packentry(self, entry, node, version, rev):
p = indexformatv2_pack(*entry)
if rev == 0:
p = versionformat_pack(version) + p[4:]
return p
nodemap: add a (python) index class for persistent nodemap testing...
r44794 NodemapRevlogIO = None
if util.safehasattr(parsers, 'parse_index_devel_nodemap'):
class NodemapRevlogIO(revlogio):
"""A debug oriented IO class that return a PersistentNodeMapIndexObject
The PersistentNodeMapIndexObject object is meant to test the persistent nodemap feature.
"""
def parseindex(self, data, inline):
index, cache = parsers.parse_index_devel_nodemap(data, inline)
return index, cache
Georges Racinet
rust-index: add a `experimental.rust.index` option to use the wrapper...
r44466 class rustrevlogio(revlogio):
def parseindex(self, data, inline):
index, cache = super(rustrevlogio, self).parseindex(data, inline)
return rustrevlog.MixedIndex(index), cache
flagprocessors: remove flagprocessorsmixin...
r43265 class revlog(object):
mpm@selenic.com
Add some docstrings to revlog.py
r1083 """
the underlying revision storage object
A revlog consists of two parts, an index and the revision data.
The index is a file with a fixed record size containing
Martin Geisler
Fixed docstring typos
r6912 information on each revision, including its nodeid (hash), the
mpm@selenic.com
Add some docstrings to revlog.py
r1083 nodeids of its parents, the position and offset of its data within
the data file, and the revision it's based on. Finally, each entry
contains a linkrev entry that can serve as a pointer to external
data.
The revision data itself is a linear collection of data chunks.
Each chunk represents a revision and is usually represented as a
delta against the previous chunk. To bound lookup time, runs of
deltas are limited to about 2 times the length of the original
version data. This makes retrieval of a version proportional to
its size, or O(1) relative to the number of revisions.
Both pieces of the revlog are written to in an append-only
fashion, which means we never need to rewrite a file to insert or
remove data, and can use some simple techniques to avoid the need
for locking while reading.
FUJIWARA Katsunori
revlog: specify checkambig at writing to avoid file stat ambiguity...
r29997
If checkambig, indexfile is opened with checkambig=True at
writing, to avoid file stat ambiguity.
Mark Thomas
revlog: add option to mmap revlog index...
r34297
If mmaplargeindex is True, and an mmapindexthreshold is set, the
index will be mmapped rather than read if it is larger than the
configured threshold.
Gregory Szorc
revlog: move censor logic into main revlog class...
r37461
If censorable is True, the revlog can have censored revisions.
revlog: add the option to track the expected compression upper bound...
r42662
If `upperboundcomp` is not None, this is the expected maximal gain from
compression for the data content.
Kyle Lippincott
revlog: add a mechanism to verify expected file position before appending...
r47349
`concurrencychecker` is an optional function that receives 3 arguments: a
file handle, a filename, and an expected position. It should check whether
the current position in the file handle is valid, and log/warn/fail (by
raising).
mpm@selenic.com
Add some docstrings to revlog.py
r1083 """
flagprocessors: move _flagserrorclass attribute on revlog & co...
r43264
_flagserrorclass = error.RevlogError
Augie Fackler
formatting: blacken the codebase...
r43346 def __init__(
self,
opener,
indexfile,
datafile=None,
checkambig=False,
mmaplargeindex=False,
censorable=False,
upperboundcomp=None,
nodemap: write nodemap data on disk...
r44789 persistentnodemap=False,
Kyle Lippincott
revlog: add a mechanism to verify expected file position before appending...
r47349 concurrencychecker=None,
Augie Fackler
formatting: blacken the codebase...
r43346 ):
mpm@selenic.com
Add some docstrings to revlog.py
r1083 """
create a revlog object
opener is a function that abstracts the file opening operation
and can be used to implement COW semantics or the like.
revlog: add the option to track the expected compression upper bound...
r42662
mpm@selenic.com
Add some docstrings to revlog.py
r1083 """
revlog: add the option to track the expected compression upper bound...
r42662 self.upperboundcomp = upperboundcomp
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 self.indexfile = indexfile
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.datafile = datafile or (indexfile[:-2] + b".d")
nodemap: write nodemap data on disk...
r44789 self.nodemap_file = None
if persistentnodemap:
Pulkit Goyal
revlog: refactor logic to compute nodemap file in separate function...
r47196 self.nodemap_file = nodemaputil.get_nodemap_file(
opener, self.indexfile
)
nodemap: write nodemap data on disk...
r44789
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 self.opener = opener
FUJIWARA Katsunori
revlog: specify checkambig at writing to avoid file stat ambiguity...
r29997 # When True, indexfile is opened with checkambig=True at writing, to
# avoid file stat ambiguity.
self._checkambig = checkambig
Gregory Szorc
revlog: store mmaplargeindex as an instance attribute...
r41239 self._mmaplargeindex = mmaplargeindex
Gregory Szorc
revlog: move censor logic into main revlog class...
r37461 self._censorable = censorable
Gregory Szorc
revlog: improve documentation...
r27070 # 3-tuple of (node, rev, text) for a raw revision.
Gregory Szorc
revlog: rename _cache to _revisioncache...
r40088 self._revisioncache = None
Gregory Szorc
revlog: use an LRU cache for delta chain bases...
r29830 # Maps rev to chain base rev.
self._chainbasecache = util.lrucachedict(100)
Gregory Szorc
revlog: improve documentation...
r27070 # 2-tuple of (offset, data) of raw data from the revlog at an offset.
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self._chunkcache = (0, b'')
Gregory Szorc
revlog: improve documentation...
r27070 # How much data to read and cache into the raw revlog data cache.
Brodie Rao
revlog: allow tuning of the chunk cache size (via format.chunkcachesize)...
r20180 self._chunkcachesize = 65536
Mateusz Kwapich
revlog: add config variable for limiting delta-chain length...
r23255 self._maxchainlen = None
Boris Feld
aggressivemergedeltas: rename variable internally...
r38759 self._deltabothparents = True
revlog: move the nodemap into the index object (for pure)...
r43925 self.index = None
nodemap: keep track of the docket for loaded data...
r44804 self._nodemap_docket = None
Gregory Szorc
revlog: improve documentation...
r27070 # Mapping of partial identifiers to full nodes.
Matt Mackall
revlog: introduce a cache for partial lookups...
r13258 self._pcache = {}
Gregory Szorc
revlog: improve documentation...
r27070 # Mapping of revision integer to full node.
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self._compengine = b'zlib'
compression: introduce a `storage.revlog.zlib.level` configuration...
r42210 self._compengineopts = {}
revlog: add an experimental option to mitigated delta issues (issue5480)...
r33202 self._maxdeltachainspan = -1
Paul Morelle
revlog: introduce an experimental flag to slice chunks reads when too sparse...
r34825 self._withsparseread = False
Paul Morelle
sparse-revlog: new requirement enabled with format.sparse-revlog...
r38739 self._sparserevlog = False
Paul Morelle
sparse-read: target density of 50% instead of 25%...
r38651 self._srdensitythreshold = 0.50
Paul Morelle
sparse-read: skip gaps too small to be worth splitting...
r34882 self._srmingapsize = 262144
Matt Mackall
revlog: simplify revlog.__init__...
r4985
Gregory Szorc
revlog: store flag processors per revlog...
r39804 # Make copy of flag processors so each revlog instance can support
# custom flags.
flagutil: move the `flagprocessors` mapping in the new module...
r42955 self._flagprocessors = dict(flagutil.flagprocessors)
Gregory Szorc
revlog: store flag processors per revlog...
r39804
Gregory Szorc
revlog: automatically read from opened file handles...
r40661 # 2-tuple of file handles being used for active writing.
self._writinghandles = None
Gregory Szorc
revlog: inline opener options logic into _loadindex()...
r41240 self._loadindex()
Kyle Lippincott
revlog: add a mechanism to verify expected file position before appending...
r47349 self._concurrencychecker = concurrencychecker
Gregory Szorc
revlog: inline opener options logic into _loadindex()...
r41240 def _loadindex(self):
Mark Thomas
revlog: add option to mmap revlog index...
r34297 mmapindexthreshold = None
vfs: give all vfs an options attribute by default...
r43295 opts = self.opener.options
Gregory Szorc
revlog: always process opener options...
r41236
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if b'revlogv2' in opts:
Gregory Szorc
revlog: use separate variables to track version flags...
r41241 newversionflags = REVLOGV2 | FLAG_INLINE_DATA
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 elif b'revlogv1' in opts:
Gregory Szorc
revlog: use separate variables to track version flags...
r41241 newversionflags = REVLOGV1 | FLAG_INLINE_DATA
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if b'generaldelta' in opts:
Gregory Szorc
revlog: use separate variables to track version flags...
r41241 newversionflags |= FLAG_GENERALDELTA
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 elif b'revlogv0' in self.opener.options:
Yuya Nishihara
revlog: fix resolution of revlog version 0...
r41355 newversionflags = REVLOGV0
Gregory Szorc
revlog: always process opener options...
r41236 else:
Gregory Szorc
revlog: use separate variables to track version flags...
r41241 newversionflags = REVLOG_DEFAULT_VERSION
Gregory Szorc
revlog: always process opener options...
r41236
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if b'chunkcachesize' in opts:
self._chunkcachesize = opts[b'chunkcachesize']
if b'maxchainlen' in opts:
self._maxchainlen = opts[b'maxchainlen']
if b'deltabothparents' in opts:
self._deltabothparents = opts[b'deltabothparents']
self._lazydelta = bool(opts.get(b'lazydelta', True))
storage: introduce a `revlog.reuse-external-delta` config...
r41985 self._lazydeltabase = False
if self._lazydelta:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self._lazydeltabase = bool(opts.get(b'lazydeltabase', False))
if b'compengine' in opts:
self._compengine = opts[b'compengine']
if b'zlib.level' in opts:
self._compengineopts[b'zlib.level'] = opts[b'zlib.level']
if b'zstd.level' in opts:
self._compengineopts[b'zstd.level'] = opts[b'zstd.level']
if b'maxdeltachainspan' in opts:
self._maxdeltachainspan = opts[b'maxdeltachainspan']
if self._mmaplargeindex and b'mmapindexthreshold' in opts:
mmapindexthreshold = opts[b'mmapindexthreshold']
self.hassidedata = bool(opts.get(b'side-data', False))
self._sparserevlog = bool(opts.get(b'sparse-revlog', False))
withsparseread = bool(opts.get(b'with-sparse-read', False))
Gregory Szorc
revlog: always process opener options...
r41236 # sparse-revlog forces sparse-read
self._withsparseread = self._sparserevlog or withsparseread
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if b'sparse-read-density-threshold' in opts:
self._srdensitythreshold = opts[b'sparse-read-density-threshold']
if b'sparse-read-min-gap-size' in opts:
self._srmingapsize = opts[b'sparse-read-min-gap-size']
if opts.get(b'enableellipsis'):
Gregory Szorc
revlog: always process opener options...
r41236 self._flagprocessors[REVIDX_ELLIPSIS] = ellipsisprocessor
# revlog v0 doesn't have flag processors
Gregory Szorc
py3: finish porting iteritems() to pycompat and remove source transformer...
r43376 for flag, processor in pycompat.iteritems(
opts.get(b'flagprocessors', {})
):
flagutil: move insertflagprocessor to the new module (API)
r42957 flagutil.insertflagprocessor(flag, processor, self._flagprocessors)
Matt Harbison
revlog: allow flag processors to be applied via store options...
r40303
Brodie Rao
revlog: allow tuning of the chunk cache size (via format.chunkcachesize)...
r20180 if self._chunkcachesize <= 0:
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.RevlogError(
Martin von Zweigbergk
cleanup: join string literals that are already on one line...
r43387 _(b'revlog chunk cache size %r is not greater than 0')
Augie Fackler
formatting: blacken the codebase...
r43346 % self._chunkcachesize
)
Brodie Rao
revlog: allow tuning of the chunk cache size (via format.chunkcachesize)...
r20180 elif self._chunkcachesize & (self._chunkcachesize - 1):
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.RevlogError(
Martin von Zweigbergk
cleanup: join string literals that are already on one line...
r43387 _(b'revlog chunk cache size %r is not a power of 2')
Augie Fackler
formatting: blacken the codebase...
r43346 % self._chunkcachesize
)
Pradeepkumar Gayam
revlog: parentdelta flags for revlog index
r11928
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 indexdata = b''
Sune Foldager
changelog: don't use generaldelta
r14334 self._initempty = True
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 try:
Boris Feld
revlog: use context manager for index file life time in __init__...
r35987 with self._indexfp() as f:
Augie Fackler
formatting: blacken the codebase...
r43346 if (
mmapindexthreshold is not None
and self.opener.fstat(f).st_size >= mmapindexthreshold
):
Yuya Nishihara
revlog: document that mmap resources are released implicitly by GC...
r41322 # TODO: should .close() to release resources without
# relying on Python GC
Boris Feld
revlog: use context manager for index file life time in __init__...
r35987 indexdata = util.buffer(util.mmapread(f))
else:
indexdata = f.read()
Gregory Szorc
revlog: rename generic "i" variable to "indexdata"...
r26241 if len(indexdata) > 0:
Gregory Szorc
revlog: rename v to versionflags...
r41237 versionflags = versionformat_unpack(indexdata[:4])[0]
Sune Foldager
changelog: don't use generaldelta
r14334 self._initempty = False
Gregory Szorc
revlog: use separate variables to track version flags...
r41241 else:
versionflags = newversionflags
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except IOError as inst:
Bryan O'Sullivan
Make revlog constructor more discerning in its treatment of errors.
r1322 if inst.errno != errno.ENOENT:
raise
Matt Mackall
revlog: simplify revlog.__init__...
r4985
Gregory Szorc
revlog: use separate variables to track version flags...
r41241 versionflags = newversionflags
Gregory Szorc
revlog: rename v to versionflags...
r41237 self.version = versionflags
Gregory Szorc
revlog: always enable generaldelta on version 2 revlogs...
r41238
Gregory Szorc
revlog: rename v to versionflags...
r41237 flags = versionflags & ~0xFFFF
fmt = versionflags & 0xFFFF
Gregory Szorc
revlog: always enable generaldelta on version 2 revlogs...
r41238
Gregory Szorc
revlog: tweak wording and logic for flags validation...
r32391 if fmt == REVLOGV0:
if flags:
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.RevlogError(
Martin von Zweigbergk
cleanup: join string literals that are already on one line...
r43387 _(b'unknown flags (%#04x) in version %d revlog %s')
Augie Fackler
formatting: blacken the codebase...
r43346 % (flags >> 16, fmt, self.indexfile)
)
Gregory Szorc
revlog: always enable generaldelta on version 2 revlogs...
r41238
self._inline = False
self._generaldelta = False
Gregory Szorc
revlog: tweak wording and logic for flags validation...
r32391 elif fmt == REVLOGV1:
if flags & ~REVLOGV1_FLAGS:
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.RevlogError(
Martin von Zweigbergk
cleanup: join string literals that are already on one line...
r43387 _(b'unknown flags (%#04x) in version %d revlog %s')
Augie Fackler
formatting: blacken the codebase...
r43346 % (flags >> 16, fmt, self.indexfile)
)
Gregory Szorc
revlog: always enable generaldelta on version 2 revlogs...
r41238
self._inline = versionflags & FLAG_INLINE_DATA
self._generaldelta = versionflags & FLAG_GENERALDELTA
Gregory Szorc
revlog: skeleton support for version 2 revlogs...
r32697 elif fmt == REVLOGV2:
if flags & ~REVLOGV2_FLAGS:
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.RevlogError(
Martin von Zweigbergk
cleanup: join string literals that are already on one line...
r43387 _(b'unknown flags (%#04x) in version %d revlog %s')
Augie Fackler
formatting: blacken the codebase...
r43346 % (flags >> 16, fmt, self.indexfile)
)
Gregory Szorc
revlog: always enable generaldelta on version 2 revlogs...
r41238
Raphaël Gomès
revlogv2: temporarily forbid inline revlogs...
r47450 # There is a bug in the transaction handling when going from an
# inline revlog to a separate index and data file. Turn it off until
# it's fixed, since v2 revlogs sometimes get rewritten on exchange.
# See issue6485
self._inline = False
Gregory Szorc
revlog: always enable generaldelta on version 2 revlogs...
r41238 # generaldelta implied by version 2 revlogs.
self._generaldelta = True
Gregory Szorc
revlog: tweak wording and logic for flags validation...
r32391 else:
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.RevlogError(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b'unknown version (%d) in revlog %s') % (fmt, self.indexfile)
Augie Fackler
formatting: blacken the codebase...
r43346 )
Boris Feld
revlog: make sure we never use sparserevlog without general delta (issue6056)...
r41525 # sparse-revlog can't be on without general-delta (issue6056)
if not self._generaldelta:
self._sparserevlog = False
Matt Mackall
revlog: simplify revlog.__init__...
r4985
Gregory Szorc
repository: remove storedeltachains from ifilestorage...
r39268 self._storedeltachains = True
Gregory Szorc
revlog: add instance variable controlling delta chain use...
r30154
nodemap: add a (python) index class for persistent nodemap testing...
r44794 devel_nodemap = (
self.nodemap_file
and opts.get(b'devel-force-nodemap', False)
and NodemapRevlogIO is not None
)
rust-nodemap: automatically use the rust index for persistent nodemap...
r45000 use_rust_index = False
if rustrevlog is not None:
if self.nodemap_file is not None:
use_rust_index = True
else:
use_rust_index = self.opener.options.get(b'rust.index')
Matt Mackall
revlog: add revlogio interface...
r4972 self._io = revlogio()
Matt Mackall
revlog: regroup parsing code
r4971 if self.version == REVLOGV0:
Matt Mackall
revlog: add revlogio interface...
r4972 self._io = revlogoldio()
Raphaël Gomès
revlog: introduce v2 format...
r47438 elif fmt == REVLOGV2:
self._io = revlogv2io()
nodemap: add a (python) index class for persistent nodemap testing...
r44794 elif devel_nodemap:
self._io = NodemapRevlogIO()
rust-nodemap: automatically use the rust index for persistent nodemap...
r45000 elif use_rust_index:
revlog: reorder a conditionnal about revlogio...
r44506 self._io = rustrevlogio()
Benoit Boissinot
revlog: always add the magic nullid/nullrev entry in parseindex
r13265 try:
Gregory Szorc
revlog: rename generic "i" variable to "indexdata"...
r26241 d = self._io.parseindex(indexdata, self._inline)
nodemap: provide the on disk data to indexes who support it...
r44801 index, _chunkcache = d
use_nodemap = (
not self._inline
and self.nodemap_file is not None
and util.safehasattr(index, 'update_nodemap_data')
)
if use_nodemap:
nodemap_data = nodemaputil.persisted_data(self)
if nodemap_data is not None:
nodemap: track the tip_node for validation...
r45002 docket = nodemap_data[0]
nodemap: fix validity checking when revlog is too short...
r45481 if (
len(d[0]) > docket.tip_rev
and d[0][docket.tip_rev][7] == docket.tip_node
):
nodemap: track the tip_node for validation...
r45002 # no changelog tampering
self._nodemap_docket = docket
index.update_nodemap_data(*nodemap_data)
Benoit Boissinot
revlog: always add the magic nullid/nullrev entry in parseindex
r13265 except (ValueError, IndexError):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.RevlogError(
_(b"index %s is corrupted") % self.indexfile
)
revlog: no longer return the nodemap after parsing...
r43926 self.index, self._chunkcache = d
Benoit Boissinot
revlog: always add the magic nullid/nullrev entry in parseindex
r13265 if not self._chunkcache:
self._chunkclear()
Siddharth Agarwal
revlog: cache chain info after calculating it for a rev (issue4452)...
r23306 # revnum -> (chain-length, sum-delta-length)
Joerg Sonnenberger
revlog: use LRU for the chain cache...
r46364 self._chaininfocache = util.lrucachedict(500)
Gregory Szorc
revlog: use compression engine APIs for decompression...
r30817 # revlog header -> revlog compressor
self._decompressors = {}
mpm@selenic.com
Only use lazy indexing for big indices and avoid the overhead of the...
r116
Gregory Szorc
revlog: use compression engine API for compression...
r30795 @util.propertycache
def _compressor(self):
compression: introduce a `storage.revlog.zlib.level` configuration...
r42210 engine = util.compengines[self._compengine]
return engine.revlogcompressor(self._compengineopts)
Gregory Szorc
revlog: use compression engine API for compression...
r30795
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 def _indexfp(self, mode=b'r'):
Boris Feld
revlog: move index file opening in a method...
r35986 """file object for the revlog's index file"""
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 args = {'mode': mode}
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if mode != b'r':
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 args['checkambig'] = self._checkambig
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if mode == b'w':
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 args['atomictemp'] = True
Boris Feld
revlog: move index file opening in a method...
r35986 return self.opener(self.indexfile, **args)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 def _datafp(self, mode=b'r'):
Boris Feld
revlog: move datafile opening in a method...
r35985 """file object for the revlog's data file"""
return self.opener(self.datafile, mode=mode)
Boris Feld
revlog: add a _datareadfp context manager for data access needs...
r35991 @contextlib.contextmanager
def _datareadfp(self, existingfp=None):
"""file object suitable to read data"""
Gregory Szorc
revlog: automatically read from opened file handles...
r40661 # Use explicit file handle, if given.
Boris Feld
revlog: add a _datareadfp context manager for data access needs...
r35991 if existingfp is not None:
yield existingfp
Gregory Szorc
revlog: automatically read from opened file handles...
r40661
# Use a file handle being actively used for writes, if available.
# There is some danger to doing this because reads will seek the
# file. However, _writeentry() performs a SEEK_END before all writes,
# so we should be safe.
elif self._writinghandles:
if self._inline:
yield self._writinghandles[0]
else:
yield self._writinghandles[1]
# Otherwise open a new file handle.
Boris Feld
revlog: add a _datareadfp context manager for data access needs...
r35991 else:
if self._inline:
func = self._indexfp
else:
func = self._datafp
with func() as fp:
yield fp
Martin von Zweigbergk
revlog: move tiprev() from changelog up to revlog...
r43745 def tiprev(self):
return len(self.index) - 1
Matt Mackall
revlog: some codingstyle cleanups
r4980 def tip(self):
Martin von Zweigbergk
revlog: move tiprev() from changelog up to revlog...
r43745 return self.node(self.tiprev())
Augie Fackler
formatting: blacken the codebase...
r43346
Yuya Nishihara
revlog: add __contains__ for fast membership test...
r24030 def __contains__(self, rev):
return 0 <= rev < len(self)
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
add __len__ and __iter__ methods to repo and revlog
r6750 def __len__(self):
Martin von Zweigbergk
index: don't include nullid in len()...
r38887 return len(self.index)
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
add __len__ and __iter__ methods to repo and revlog
r6750 def __iter__(self):
Gregory Szorc
global: use pycompat.xrange()...
r38806 return iter(pycompat.xrange(len(self)))
Augie Fackler
formatting: blacken the codebase...
r43346
Pierre-Yves David
clfilter: make the revlog class responsible of all its iteration...
r17672 def revs(self, start=0, stop=None):
"""iterate over all rev in this revlog (from start to stop)"""
Gregory Szorc
storageutil: extract revision number iteration...
r39917 return storageutil.iterrevs(len(self), start=start, stop=stop)
Matt Mackall
revlog: incrementally build node cache with linear searches...
r13275
revlog: deprecate direct `nodemap` access...
r43974 @property
Matt Mackall
revlog: incrementally build node cache with linear searches...
r13275 def nodemap(self):
revlog: deprecate direct `nodemap` access...
r43974 msg = (
Denis Laxalde
py3: pass a bytes value for "msg" to nouideprecwarn()...
r44018 b"revlog.nodemap is deprecated, "
b"use revlog.index.[has_node|rev|get_rev]"
revlog: deprecate direct `nodemap` access...
r43974 )
util.nouideprecwarn(msg, b'5.3', stacklevel=2)
revlog: return the nodemap as the nodecache...
r43928 return self.index.nodemap
Matt Mackall
revlog: do revlog node->rev mapping by scanning...
r13259
revlog: deprecate the _nodecache attribute (API)...
r43930 @property
def _nodecache(self):
Denis Laxalde
py3: pass a bytes value for "msg" to nouideprecwarn()...
r44018 msg = b"revlog._nodecache is deprecated, use revlog.index.nodemap"
revlog: deprecate the _nodecache attribute (API)...
r43930 util.nouideprecwarn(msg, b'5.3', stacklevel=2)
return self.index.nodemap
Matt Mackall
revlog: add hasnode helper method
r16374 def hasnode(self, node):
try:
self.rev(node)
return True
except KeyError:
return False
Jun Wu
changegroup: do not delta lfs revisions...
r36764 def candelta(self, baserev, rev):
"""whether two revisions (baserev, rev) can be delta-ed or not"""
# Disable delta if either rev requires a content-changing flag
# processor (ex. LFS). This is because such flag processor can alter
# the rawtext content that the delta will be based on, and two clients
# could have a same revlog node with different flags (i.e. different
# rawtext contents) and the delta could be incompatible.
Augie Fackler
formatting: blacken the codebase...
r43346 if (self.flags(baserev) & REVIDX_RAWTEXT_CHANGING_FLAGS) or (
self.flags(rev) & REVIDX_RAWTEXT_CHANGING_FLAGS
):
Jun Wu
changegroup: do not delta lfs revisions...
r36764 return False
return True
nodemap: warm the persistent nodemap on disk with debugupdatecache...
r44932 def update_caches(self, transaction):
if self.nodemap_file is not None:
if transaction is None:
nodemaputil.update_persistent_nodemap(self)
else:
nodemaputil.setup_persistent_nodemap(transaction, self)
Bryan O'Sullivan
parsers: use base-16 trie for faster node->rev mapping...
r16414 def clearcaches(self):
Gregory Szorc
revlog: rename _cache to _revisioncache...
r40088 self._revisioncache = None
Gregory Szorc
revlog: use an LRU cache for delta chain bases...
r29830 self._chainbasecache.clear()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self._chunkcache = (0, b'')
Gregory Szorc
revlog: make clearcaches() more effective...
r27465 self._pcache = {}
nodemap: refresh the persistent data on nodemap creation...
r44988 self._nodemap_docket = None
revlog: move the nodemap into the index object (for pure)...
r43925 self.index.clearcaches()
nodemap: refresh the persistent data on nodemap creation...
r44988 # The python code is the one responsible for validating the docket, we
# end up having to refresh it here.
use_nodemap = (
not self._inline
and self.nodemap_file is not None
and util.safehasattr(self.index, 'update_nodemap_data')
)
if use_nodemap:
nodemap_data = nodemaputil.persisted_data(self)
if nodemap_data is not None:
self._nodemap_docket = nodemap_data[0]
self.index.update_nodemap_data(*nodemap_data)
Bryan O'Sullivan
parsers: use base-16 trie for faster node->rev mapping...
r16414
Matt Mackall
revlog: do revlog node->rev mapping by scanning...
r13259 def rev(self, node):
Matt Mackall
revlog: incrementally build node cache with linear searches...
r13275 try:
index: use `index.rev` in `revlog.rev`...
r43953 return self.index.rev(node)
Matt Mackall
repoview: fix 0L with pack/unpack for 2.4
r22282 except TypeError:
raise
Gregory Szorc
revlog: drop RevlogError alias (API)...
r39809 except error.RevlogError:
revlog: move the nodemap into the index object (for pure)...
r43925 # parsers.c radix tree lookup failed
if node == wdirid or node in wdirfilenodeids:
raise error.WdirUnsupported
raise error.LookupError(node, self.indexfile, _(b'no node'))
Matt Mackall
revlog: incrementally build node cache with linear searches...
r13275
Gregory Szorc
revlog: reorder index accessors to match data structure order...
r30287 # Accessors for index entries.
# First tuple entry is 8 bytes. First 6 bytes are offset. Last 2 bytes
# are flags.
mason@suse.com
Implement revlogng....
r2072 def start(self, rev):
Matt Mackall
revlog: minor chunk speed-up
r5006 return int(self.index[rev][0] >> 16)
Gregory Szorc
revlog: reorder index accessors to match data structure order...
r30287
def flags(self, rev):
return self.index[rev][0] & 0xFFFF
Matt Mackall
revlog: some codingstyle cleanups
r4980 def length(self, rev):
return self.index[rev][1]
Gregory Szorc
revlog: reorder index accessors to match data structure order...
r30287
Raphaël Gomès
sidedata: move to new sidedata storage in revlogv2...
r47443 def sidedata_length(self, rev):
if self.version & 0xFFFF != REVLOGV2:
return 0
return self.index[rev][9]
Gregory Szorc
revlog: reorder index accessors to match data structure order...
r30287 def rawsize(self, rev):
"""return the length of the uncompressed text for a given revision"""
l = self.index[rev][2]
Yuya Nishihara
revlog: disallow setting uncompressed length to None...
r38195 if l >= 0:
Gregory Szorc
revlog: reorder index accessors to match data structure order...
r30287 return l
rawdata: update caller in revlog...
r43036 t = self.rawdata(rev)
Gregory Szorc
revlog: reorder index accessors to match data structure order...
r30287 return len(t)
Jun Wu
revlog: make "size" diverge from "rawsize"...
r31856
def size(self, rev):
"""length of non-raw text (processed by a "read" flag processor)"""
# fast path: if no "read" flag processor could change the content,
# size is rawsize. note: ELLIPSIS is known to not change the content.
flags = self.flags(rev)
flagutil: move REVIDX_KNOWN_FLAGS source of truth in flagutil (API)...
r42956 if flags & (flagutil.REVIDX_KNOWN_FLAGS ^ REVIDX_ELLIPSIS) == 0:
Jun Wu
revlog: make "size" diverge from "rawsize"...
r31856 return self.rawsize(rev)
return len(self.revision(rev, raw=False))
Gregory Szorc
revlog: reorder index accessors to match data structure order...
r30287
Sune Foldager
revlog: calculate base revisions iteratively...
r14252 def chainbase(self, rev):
Gregory Szorc
revlog: use an LRU cache for delta chain bases...
r29830 base = self._chainbasecache.get(rev)
if base is not None:
return base
Sune Foldager
revlog: calculate base revisions iteratively...
r14252 index = self.index
Paul Morelle
revlog: make chainbase cache its result for the correct revision...
r38187 iterrev = rev
base = index[iterrev][3]
while base != iterrev:
iterrev = base
base = index[iterrev][3]
Gregory Szorc
revlog: use an LRU cache for delta chain bases...
r29830
self._chainbasecache[rev] = base
Sune Foldager
revlog: calculate base revisions iteratively...
r14252 return base
Gregory Szorc
revlog: reorder index accessors to match data structure order...
r30287
def linkrev(self, rev):
return self.index[rev][4]
def parentrevs(self, rev):
Pulkit Goyal
revlog: raise WdirUnsupported when wdirrev is passed...
r32402 try:
Gregory Szorc
revlog: don't use slicing to return parents...
r35539 entry = self.index[rev]
Pulkit Goyal
revlog: raise WdirUnsupported when wdirrev is passed...
r32402 except IndexError:
if rev == wdirrev:
raise error.WdirUnsupported
raise
Gregory Szorc
revlog: reorder index accessors to match data structure order...
r30287
Gregory Szorc
revlog: don't use slicing to return parents...
r35539 return entry[5], entry[6]
Yuya Nishihara
revlog: optimize ancestors() to not check filtered revisions for each...
r40188 # fast parentrevs(rev) where rev isn't filtered
_uncheckedparentrevs = parentrevs
Gregory Szorc
revlog: reorder index accessors to match data structure order...
r30287 def node(self, rev):
Pulkit Goyal
revlog: raise error.WdirUnsupported from revlog.node() if wdirrev is passed...
r32443 try:
return self.index[rev][7]
except IndexError:
if rev == wdirrev:
raise error.WdirUnsupported
raise
Gregory Szorc
revlog: reorder index accessors to match data structure order...
r30287
# Derived from index values.
def end(self, rev):
Raphaël Gomès
revlogv2: don't assume that the sidedata of the last rev is right after data...
r47444 return self.start(rev) + self.length(rev)
Gregory Szorc
revlog: reorder index accessors to match data structure order...
r30287
def parents(self, node):
i = self.index
d = i[self.rev(node)]
Augie Fackler
formatting: blacken the codebase...
r43346 return i[d[5]][7], i[d[6]][7] # map revisions to nodes inline
Gregory Szorc
revlog: reorder index accessors to match data structure order...
r30287
Mateusz Kwapich
debugrevlog: fix computing chain length in debugrevlog -d...
r23254 def chainlen(self, rev):
Siddharth Agarwal
revlog: compute length of compressed deltas along with chain length...
r23286 return self._chaininfo(rev)[0]
Siddharth Agarwal
revlog: cache chain info after calculating it for a rev (issue4452)...
r23306
Siddharth Agarwal
revlog: compute length of compressed deltas along with chain length...
r23286 def _chaininfo(self, rev):
Siddharth Agarwal
revlog: cache chain info after calculating it for a rev (issue4452)...
r23306 chaininfocache = self._chaininfocache
if rev in chaininfocache:
return chaininfocache[rev]
Mateusz Kwapich
debugrevlog: fix computing chain length in debugrevlog -d...
r23254 index = self.index
generaldelta = self._generaldelta
iterrev = rev
e = index[iterrev]
clen = 0
Siddharth Agarwal
revlog: compute length of compressed deltas along with chain length...
r23286 compresseddeltalen = 0
Mateusz Kwapich
debugrevlog: fix computing chain length in debugrevlog -d...
r23254 while iterrev != e[3]:
clen += 1
Siddharth Agarwal
revlog: compute length of compressed deltas along with chain length...
r23286 compresseddeltalen += e[1]
Mateusz Kwapich
debugrevlog: fix computing chain length in debugrevlog -d...
r23254 if generaldelta:
iterrev = e[3]
else:
iterrev -= 1
Siddharth Agarwal
revlog: cache chain info after calculating it for a rev (issue4452)...
r23306 if iterrev in chaininfocache:
t = chaininfocache[iterrev]
clen += t[0]
compresseddeltalen += t[1]
break
Mateusz Kwapich
debugrevlog: fix computing chain length in debugrevlog -d...
r23254 e = index[iterrev]
Siddharth Agarwal
revlog: cache chain info after calculating it for a rev (issue4452)...
r23306 else:
# Add text length of base since decompressing that also takes
# work. For cache hits the length is already included.
compresseddeltalen += e[1]
r = (clen, compresseddeltalen)
chaininfocache[rev] = r
return r
Gregory Szorc
revlog: refactor delta chain computation into own function...
r27468 def _deltachain(self, rev, stoprev=None):
"""Obtain the delta chain for a revision.
``stoprev`` specifies a revision to stop at. If not specified, we
stop at the base of the chain.
Returns a 2-tuple of (chain, stopped) where ``chain`` is a list of
revs in ascending order and ``stopped`` is a bool indicating whether
``stoprev`` was hit.
"""
Gregory Szorc
revlog: C implementation of delta chain resolution...
r33168 # Try C implementation.
try:
return self.index.deltachain(rev, stoprev, self._generaldelta)
except AttributeError:
pass
Gregory Szorc
revlog: refactor delta chain computation into own function...
r27468 chain = []
# Alias to prevent attribute lookup in tight loop.
index = self.index
generaldelta = self._generaldelta
iterrev = rev
e = index[iterrev]
while iterrev != e[3] and iterrev != stoprev:
chain.append(iterrev)
if generaldelta:
iterrev = e[3]
else:
iterrev -= 1
e = index[iterrev]
if iterrev == stoprev:
stopped = True
else:
chain.append(iterrev)
stopped = False
chain.reverse()
return chain, stopped
Siddharth Agarwal
revlog.ancestors: add support for including revs...
r18081 def ancestors(self, revs, stoprev=0, inclusive=False):
Boris Feld
revlog: update the docstring of `ancestors` to match reality...
r40769 """Generate the ancestors of 'revs' in reverse revision order.
Joshua Redstone
revlog: add optional stoprev arg to revlog.ancestors()...
r16868 Does not generate revs lower than stoprev.
Greg Ward
revlog: rewrite several method docstrings...
r10047
Siddharth Agarwal
revlog: move ancestor generation out to a new class...
r18090 See the documentation for ancestor.lazyancestors for more details."""
Siddharth Agarwal
revlog.ancestors: add support for including revs...
r18081
Yuya Nishihara
revlog: optimize ancestors() to not check filtered revisions for each...
r40188 # first, make sure start revisions aren't filtered
revs = list(revs)
checkrev = self.node
for r in revs:
checkrev(r)
# and we're sure ancestors aren't filtered as well
Georges Racinet
rust-cpython: using the new bindings from Python...
r41150
Georges Racinet
rust: using policy.importrust from Python callers...
r42652 if rustancestor is not None:
lazyancestors = rustancestor.LazyAncestors
Georges Racinet
rust-cpython: using the new bindings from Python...
r41150 arg = self.index
else:
lazyancestors = ancestor.lazyancestors
arg = self._uncheckedparentrevs
return lazyancestors(arg, revs, stoprev=stoprev, inclusive=inclusive)
Stefano Tortarolo
Add ancestors and descendants to revlog...
r6872
Bryan O'Sullivan
revlog: descendants(*revs) becomes descendants(revs) (API)...
r16867 def descendants(self, revs):
Gregory Szorc
dagop: extract descendants() from revlog module...
r40035 return dagop.descendantrevs(revs, self.revs, self.parentrevs)
Stefano Tortarolo
Add ancestors and descendants to revlog...
r6872
Peter Arrenbrecht
wireproto: add getbundle() function...
r13741 def findcommonmissing(self, common=None, heads=None):
"""Return a tuple of the ancestors of common and the ancestors of heads
Pierre-Yves David
revlog: improve docstring for findcommonmissing
r15835 that are not ancestors of common. In revset terminology, we return the
tuple:
Greg Ward
revlog: rewrite several method docstrings...
r10047
Pierre-Yves David
revlog: improve docstring for findcommonmissing
r15835 ::common, (::heads) - (::common)
Benoit Boissinot
fix pull racing with push/commit (issue1320)...
r7233
Greg Ward
revlog: rewrite several method docstrings...
r10047 The list is sorted by revision number, meaning it is
topologically sorted.
'heads' and 'common' are both lists of node IDs. If heads is
not supplied, uses all of the revlog's heads. If common is not
supplied, uses nullid."""
Benoit Boissinot
fix pull racing with push/commit (issue1320)...
r7233 if common is None:
common = [nullid]
if heads is None:
heads = self.heads()
common = [self.rev(n) for n in common]
heads = [self.rev(n) for n in heads]
# we want the ancestors, but inclusive
Durham Goode
revlog: return lazy set from findcommonmissing...
r20073 class lazyset(object):
def __init__(self, lazyvalues):
self.addedvalues = set()
self.lazyvalues = lazyvalues
def __contains__(self, value):
return value in self.addedvalues or value in self.lazyvalues
def __iter__(self):
added = self.addedvalues
for r in added:
yield r
for r in self.lazyvalues:
if not r in added:
yield r
def add(self, value):
self.addedvalues.add(value)
def update(self, values):
self.addedvalues.update(values)
has = lazyset(self.ancestors(common))
Martin Geisler
replace set-like dictionaries with real sets...
r8152 has.add(nullrev)
has.update(common)
Benoit Boissinot
fix pull racing with push/commit (issue1320)...
r7233
# take all ancestors from heads that aren't in has
Benoit Boissinot
revlog.missing(): use sets instead of a dict
r8453 missing = set()
Martin von Zweigbergk
util: drop alias for collections.deque...
r25113 visit = collections.deque(r for r in heads if r not in has)
Benoit Boissinot
fix pull racing with push/commit (issue1320)...
r7233 while visit:
Bryan O'Sullivan
cleanup: use the deque type where appropriate...
r16803 r = visit.popleft()
Benoit Boissinot
fix pull racing with push/commit (issue1320)...
r7233 if r in missing:
continue
else:
Benoit Boissinot
revlog.missing(): use sets instead of a dict
r8453 missing.add(r)
Benoit Boissinot
fix pull racing with push/commit (issue1320)...
r7233 for p in self.parentrevs(r):
if p not in has:
visit.append(p)
Benoit Boissinot
revlog.missing(): use sets instead of a dict
r8453 missing = list(missing)
Benoit Boissinot
fix pull racing with push/commit (issue1320)...
r7233 missing.sort()
Augie Fackler
revlog: avoid shadowing several variables using list comprehensions
r30391 return has, [self.node(miss) for miss in missing]
Peter Arrenbrecht
wireproto: add getbundle() function...
r13741
Siddharth Agarwal
revlog: add a method to get missing revs incrementally...
r23337 def incrementalmissingrevs(self, common=None):
"""Return an object that can be used to incrementally compute the
revision numbers of the ancestors of arbitrary sets that are not
ancestors of common. This is an ancestor.incrementalmissingancestors
object.
'common' is a list of revision numbers. If common is not supplied, uses
nullrev.
"""
if common is None:
common = [nullrev]
Georges Racinet
rust: using policy.importrust from Python callers...
r42652 if rustancestor is not None:
return rustancestor.MissingAncestors(self.index, common)
Siddharth Agarwal
revlog: add a method to get missing revs incrementally...
r23337 return ancestor.incrementalmissingancestors(self.parentrevs, common)
Siddharth Agarwal
revlog: add rev-specific variant of findmissing...
r17972 def findmissingrevs(self, common=None, heads=None):
"""Return the revision numbers of the ancestors of heads that
are not ancestors of common.
More specifically, return a list of revision numbers corresponding to
nodes N such that every N satisfies the following constraints:
1. N is an ancestor of some node in 'heads'
2. N is not an ancestor of any node in 'common'
The list is sorted by revision number, meaning it is
topologically sorted.
'heads' and 'common' are both lists of revision numbers. If heads is
not supplied, uses all of the revlog's heads. If common is not
supplied, uses nullid."""
if common is None:
common = [nullrev]
if heads is None:
heads = self.headrevs()
Siddharth Agarwal
revlog: switch findmissing* methods to incrementalmissingrevs...
r23338 inc = self.incrementalmissingrevs(common=common)
return inc.missingancestors(heads)
Siddharth Agarwal
revlog: add rev-specific variant of findmissing...
r17972
Peter Arrenbrecht
wireproto: add getbundle() function...
r13741 def findmissing(self, common=None, heads=None):
"""Return the ancestors of heads that are not ancestors of common.
More specifically, return a list of nodes N such that every N
satisfies the following constraints:
1. N is an ancestor of some node in 'heads'
2. N is not an ancestor of any node in 'common'
The list is sorted by revision number, meaning it is
topologically sorted.
'heads' and 'common' are both lists of node IDs. If heads is
not supplied, uses all of the revlog's heads. If common is not
supplied, uses nullid."""
Siddharth Agarwal
revlog: switch findmissing to use ancestor.missingancestors...
r17971 if common is None:
common = [nullid]
if heads is None:
heads = self.heads()
common = [self.rev(n) for n in common]
heads = [self.rev(n) for n in heads]
Siddharth Agarwal
revlog: switch findmissing* methods to incrementalmissingrevs...
r23338 inc = self.incrementalmissingrevs(common=common)
return [self.node(r) for r in inc.missingancestors(heads)]
Benoit Boissinot
fix pull racing with push/commit (issue1320)...
r7233
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 def nodesbetween(self, roots=None, heads=None):
Greg Ward
revlog: rewrite several method docstrings...
r10047 """Return a topological path from 'roots' to 'heads'.
Return a tuple (nodes, outroots, outheads) where 'nodes' is a
topologically sorted list of all nodes N that satisfy both of
these constraints:
1. N is a descendant of some node in 'roots'
2. N is an ancestor of some node in 'heads'
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457
Greg Ward
revlog: rewrite several method docstrings...
r10047 Every node is considered to be both a descendant and an ancestor
of itself, so every reachable node in 'roots' and 'heads' will be
included in 'nodes'.
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457
Greg Ward
revlog: rewrite several method docstrings...
r10047 'outroots' is the list of reachable nodes in 'roots', i.e., the
subset of 'roots' that is returned in 'nodes'. Likewise,
'outheads' is the subset of 'heads' that is also in 'nodes'.
'roots' and 'heads' are both lists of node IDs. If 'roots' is
unspecified, uses nullid as the only root. If 'heads' is
unspecified, uses list of all of the revlog's heads."""
Eric Hopper
Fix to handle case of empty list for roots or heads in nodesbetween.
r1463 nonodes = ([], [], [])
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 if roots is not None:
roots = list(roots)
Eric Hopper
Fix to handle case of empty list for roots or heads in nodesbetween.
r1463 if not roots:
return nonodes
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 lowestrev = min([self.rev(n) for n in roots])
else:
Augie Fackler
formatting: blacken the codebase...
r43346 roots = [nullid] # Everybody's a descendant of nullid
Thomas Arendsen Hein
Define and use nullrev (revision of nullid) instead of -1.
r3578 lowestrev = nullrev
if (lowestrev == nullrev) and (heads is None):
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 # We want _all_ the nodes!
Matt Mackall
add __len__ and __iter__ methods to repo and revlog
r6750 return ([self.node(r) for r in self], [nullid], list(self.heads()))
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 if heads is None:
# All nodes are ancestors, so the latest ancestor is the last
# node.
Matt Mackall
add __len__ and __iter__ methods to repo and revlog
r6750 highestrev = len(self) - 1
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 # Set ancestors to None to signal that every node is an ancestor.
ancestors = None
# Set heads to an empty dictionary for later discovery of heads
heads = {}
else:
Eric Hopper
Fix to handle case of empty list for roots or heads in nodesbetween.
r1463 heads = list(heads)
if not heads:
return nonodes
Benoit Boissinot
revlog: use set instead of dict
r8464 ancestors = set()
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 # Turn heads into a dictionary so we can remove 'fake' heads.
# Also, later we will be using it to filter out the heads we can't
# find from roots.
Martin Geisler
revlog: use real Booleans instead of 0/1 in nodesbetween
r14219 heads = dict.fromkeys(heads, False)
Benoit Boissinot
nodesbetween: fix a bug with duplicate heads
r3360 # Start at the top and keep marking parents until we're done.
Martin Geisler
rebase, revlog: use set(x) instead of set(x.keys())...
r8163 nodestotag = set(heads)
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 # Remember where the top was so we can use it as a limit later.
highestrev = max([self.rev(n) for n in nodestotag])
while nodestotag:
# grab a node to tag
n = nodestotag.pop()
# Never tag nullid
if n == nullid:
continue
# A node's revision number represents its place in a
# topologically sorted list of nodes.
r = self.rev(n)
if r >= lowestrev:
if n not in ancestors:
Matt Mackall
check-code: catch misspellings of descendant...
r14549 # If we are possibly a descendant of one of the roots
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 # and we haven't already been marked as an ancestor
Augie Fackler
formatting: blacken the codebase...
r43346 ancestors.add(n) # Mark as ancestor
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 # Add non-nullid parents to list of nodes to tag.
Augie Fackler
formatting: blacken the codebase...
r43346 nodestotag.update(
[p for p in self.parents(n) if p != nullid]
)
elif n in heads: # We've seen it before, is it a fake head?
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 # So it is, real heads should not be the ancestors of
# any other heads.
heads.pop(n)
Eric Hopper
Fix small bug in nodesbetween if heads is [nullid].
r1459 if not ancestors:
Eric Hopper
Fix to handle case of empty list for roots or heads in nodesbetween.
r1463 return nonodes
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 # Now that we have our set of ancestors, we want to remove any
# roots that are not ancestors.
# If one of the roots was nullid, everything is included anyway.
Thomas Arendsen Hein
Define and use nullrev (revision of nullid) instead of -1.
r3578 if lowestrev > nullrev:
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 # But, since we weren't, let's recompute the lowest rev to not
# include roots that aren't ancestors.
# Filter out roots that aren't ancestors of heads
Augie Fackler
revlog: avoid shadowing several variables using list comprehensions
r30391 roots = [root for root in roots if root in ancestors]
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 # Recompute the lowest revision
if roots:
Augie Fackler
revlog: avoid shadowing several variables using list comprehensions
r30391 lowestrev = min([self.rev(root) for root in roots])
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 else:
# No more roots? Return empty list
Eric Hopper
Fix to handle case of empty list for roots or heads in nodesbetween.
r1463 return nonodes
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 else:
# We are descending from nullid, and don't need to care about
# any other roots.
Thomas Arendsen Hein
Define and use nullrev (revision of nullid) instead of -1.
r3578 lowestrev = nullrev
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 roots = [nullid]
Martin Geisler
replace set-like dictionaries with real sets...
r8152 # Transform our roots list into a set.
Matt Mackall
check-code: catch misspellings of descendant...
r14549 descendants = set(roots)
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 # Also, keep the original roots so we can filter out roots that aren't
# 'real' roots (i.e. are descended from other roots).
Matt Mackall
check-code: catch misspellings of descendant...
r14549 roots = descendants.copy()
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 # Our topologically sorted list of output nodes.
orderedout = []
# Don't start at nullid since we don't want nullid in our output list,
timeless@mozdev.org
spelling: descendants
r17483 # and if nullid shows up in descendants, empty parents will look like
Matt Mackall
check-code: catch misspellings of descendant...
r14549 # they're descendants.
Pierre-Yves David
clfilter: make the revlog class responsible of all its iteration...
r17672 for r in self.revs(start=max(lowestrev, 0), stop=highestrev + 1):
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 n = self.node(r)
Matt Mackall
check-code: catch misspellings of descendant...
r14549 isdescendant = False
if lowestrev == nullrev: # Everybody is a descendant of nullid
isdescendant = True
elif n in descendants:
# n is already a descendant
isdescendant = True
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 # This check only needs to be done here because all the roots
Matt Mackall
check-code: catch misspellings of descendant...
r14549 # will start being marked is descendants before the loop.
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 if n in roots:
# If n was a root, check if it's a 'real' root.
p = tuple(self.parents(n))
Matt Mackall
check-code: catch misspellings of descendant...
r14549 # If any of its parents are descendants, it's not a root.
if (p[0] in descendants) or (p[1] in descendants):
Martin Geisler
replace set-like dictionaries with real sets...
r8152 roots.remove(n)
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 else:
p = tuple(self.parents(n))
Matt Mackall
check-code: catch misspellings of descendant...
r14549 # A node is a descendant if either of its parents are
# descendants. (We seeded the dependents list with the roots
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 # up there, remember?)
Matt Mackall
check-code: catch misspellings of descendant...
r14549 if (p[0] in descendants) or (p[1] in descendants):
descendants.add(n)
isdescendant = True
if isdescendant and ((ancestors is None) or (n in ancestors)):
# Only include nodes that are both descendants and ancestors.
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 orderedout.append(n)
if (ancestors is not None) and (n in heads):
# We're trying to figure out which heads are reachable
# from roots.
# Mark this head as having been reached
Martin Geisler
revlog: use real Booleans instead of 0/1 in nodesbetween
r14219 heads[n] = True
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 elif ancestors is None:
# Otherwise, we're trying to discover the heads.
# Assume this is a head because if it isn't, the next step
# will eventually remove it.
Martin Geisler
revlog: use real Booleans instead of 0/1 in nodesbetween
r14219 heads[n] = True
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 # But, obviously its parents aren't.
for p in self.parents(n):
heads.pop(p, None)
Gregory Szorc
py3: finish porting iteritems() to pycompat and remove source transformer...
r43376 heads = [head for head, flag in pycompat.iteritems(heads) if flag]
Martin Geisler
replace set-like dictionaries with real sets...
r8152 roots = list(roots)
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 assert orderedout
assert roots
assert heads
return (orderedout, roots, heads)
Boris Feld
revlog: accept a revs argument in `headrevs`...
r41311 def headrevs(self, revs=None):
if revs is None:
try:
return self.index.headrevs()
except AttributeError:
return self._headrevs()
Georges Racinet
rust: using policy.importrust from Python callers...
r42652 if rustdagop is not None:
return rustdagop.headrevs(self.index, revs)
Georges Racinet
changelog: prefilter in headrevs()...
r41929 return dagop.headrevs(revs, self._uncheckedparentrevs)
Pierre-Yves David
clfilter: split `revlog.headrevs` C call from python code...
r17674
Laurent Charignon
phase: default to C implementation for phase computation
r24444 def computephases(self, roots):
Laurent Charignon
phases: fix bug where native phase computation wasn't called...
r25361 return self.index.computephasesmapsets(roots)
Laurent Charignon
phase: default to C implementation for phase computation
r24444
Pierre-Yves David
clfilter: split `revlog.headrevs` C call from python code...
r17674 def _headrevs(self):
Peter Arrenbrecht
discovery: add new set-based discovery...
r14164 count = len(self)
if not count:
return [nullrev]
Pierre-Yves David
clfilter: handle non contiguous iteration in `revlov.headrevs`...
r17673 # we won't iter over filtered rev so nobody is a head at start
ishead = [0] * (count + 1)
Peter Arrenbrecht
discovery: add new set-based discovery...
r14164 index = self.index
Pierre-Yves David
clfilter: make the revlog class responsible of all its iteration...
r17672 for r in self:
Pierre-Yves David
clfilter: handle non contiguous iteration in `revlov.headrevs`...
r17673 ishead[r] = 1 # I may be an head
Peter Arrenbrecht
discovery: add new set-based discovery...
r14164 e = index[r]
Pierre-Yves David
clfilter: handle non contiguous iteration in `revlov.headrevs`...
r17673 ishead[e[5]] = ishead[e[6]] = 0 # my parent are not
return [r for r, val in enumerate(ishead) if val]
Peter Arrenbrecht
discovery: add new set-based discovery...
r14164
Benoit Boissinot
fix calculation of new heads added during push with -r...
r3923 def heads(self, start=None, stop=None):
Benoit Boissinot
add a -r/--rev option to heads to show only heads descendant from rev
r1550 """return the list of all nodes that have no children
Thomas Arendsen Hein
Fixes to "hg heads -r FOO":...
r1551
if start is specified, only heads that are descendants of
start will be returned
Benoit Boissinot
fix calculation of new heads added during push with -r...
r3923 if stop is specified, it will consider all the revs from stop
as if they had no children
Thomas Arendsen Hein
Fixes to "hg heads -r FOO":...
r1551 """
Matt Mackall
revlog: implement a fast path for heads
r4991 if start is None and stop is None:
Peter Arrenbrecht
discovery: add new set-based discovery...
r14164 if not len(self):
Matt Mackall
revlog: implement a fast path for heads
r4991 return [nullid]
Peter Arrenbrecht
discovery: add new set-based discovery...
r14164 return [self.node(r) for r in self.headrevs()]
Matt Mackall
revlog: implement a fast path for heads
r4991
Thomas Arendsen Hein
Fixes to "hg heads -r FOO":...
r1551 if start is None:
Gregory Szorc
dagop: extract DAG local heads functionality from revlog...
r40036 start = nullrev
else:
start = self.rev(start)
Augie Fackler
cleanup: run pyupgrade on our source tree to clean up varying things...
r44937 stoprevs = {self.rev(n) for n in stop or []}
Gregory Szorc
dagop: extract DAG local heads functionality from revlog...
r40036
Augie Fackler
formatting: blacken the codebase...
r43346 revs = dagop.headrevssubset(
self.revs, self.parentrevs, startrev=start, stoprevs=stoprevs
)
Gregory Szorc
dagop: extract DAG local heads functionality from revlog...
r40036
return [self.node(rev) for rev in revs]
mpm@selenic.com
revlog: add a children function...
r370
def children(self, node):
mpm@selenic.com
Add some docstrings to revlog.py
r1083 """find the children of a given node"""
mpm@selenic.com
revlog: add a children function...
r370 c = []
p = self.rev(node)
Pierre-Yves David
clfilter: make the revlog class responsible of all its iteration...
r17672 for r in self.revs(start=p + 1):
Thomas Arendsen Hein
Fix revlog.children so the real children of the null revision can be calculated.
r4746 prevs = [pr for pr in self.parentrevs(r) if pr != nullrev]
if prevs:
for pr in prevs:
if pr == p:
c.append(self.node(r))
elif p == nullrev:
c.append(self.node(r))
mpm@selenic.com
revlog: add a children function...
r370 return c
mpm@selenic.com
Whitespace cleanups...
r515
Mads Kiilerich
revlog: introduce commonancestorsheads method...
r21104 def commonancestorsheads(self, a, b):
"""calculate all the heads of the common ancestors of nodes a and b"""
a, b = self.rev(a), self.rev(b)
Boris Feld
revlog: refactor out the rev-oriented part of commonancestorheads...
r38531 ancs = self._commonancestorsheads(a, b)
return pycompat.maplist(self.node, ancs)
def _commonancestorsheads(self, *revs):
"""calculate all the heads of the common ancestors of revs"""
Mads Kiilerich
revlog: introduce commonancestorsheads method...
r21104 try:
Boris Feld
revlog: refactor out the rev-oriented part of commonancestorheads...
r38531 ancs = self.index.commonancestorsheads(*revs)
Augie Fackler
formatting: blacken the codebase...
r43346 except (AttributeError, OverflowError): # C implementation failed
Boris Feld
revlog: refactor out the rev-oriented part of commonancestorheads...
r38531 ancs = ancestor.commonancestorsheads(self.parentrevs, *revs)
return ancs
Mads Kiilerich
revlog: introduce commonancestorsheads method...
r21104
Mads Kiilerich
revlog: introduce isancestor method for efficiently determining node lineage...
r22381 def isancestor(self, a, b):
Martin von Zweigbergk
revlog: replace descendant(b, a) by isdescendantrev(a, b) (API)...
r38686 """return True if node a is an ancestor of node b
A revision is considered an ancestor of itself."""
Boris Feld
revlog: reuse 'descendant' implemention in 'isancestor'...
r38533 a, b = self.rev(a), self.rev(b)
Martin von Zweigbergk
revlog: introduce a isancestorrev() and use it in rebase...
r38688 return self.isancestorrev(a, b)
def isancestorrev(self, a, b):
"""return True if revision a is an ancestor of revision b
Martin von Zweigbergk
revlog: delete isdescendantrev() in favor of isancestorrev()...
r38690 A revision is considered an ancestor of itself.
The implementation of this is trivial but the use of
Valentin Gatien-Baron
revlog: speed up isancestor...
r42639 reachableroots is not."""
Martin von Zweigbergk
revlog: delete isdescendantrev() in favor of isancestorrev()...
r38690 if a == nullrev:
return True
elif a == b:
return True
elif a > b:
return False
Valentin Gatien-Baron
revlog: speed up isancestor...
r42639 return bool(self.reachableroots(a, [b], [a], includepath=False))
def reachableroots(self, minroot, heads, roots, includepath=False):
Jun Wu
revlog: fix revset in reachableroots docstring...
r44218 """return (heads(::(<roots> and <roots>::<heads>)))
Valentin Gatien-Baron
revlog: speed up isancestor...
r42639
If includepath is True, return (<roots>::<heads>)."""
try:
Augie Fackler
formatting: blacken the codebase...
r43346 return self.index.reachableroots2(
minroot, heads, roots, includepath
)
Valentin Gatien-Baron
revlog: speed up isancestor...
r42639 except AttributeError:
Augie Fackler
formatting: blacken the codebase...
r43346 return dagop._reachablerootspure(
self.parentrevs, minroot, roots, heads, includepath
)
Mads Kiilerich
revlog: introduce isancestor method for efficiently determining node lineage...
r22381
Mads Kiilerich
revlog: backout 514d32de6646 - commonancestors
r21107 def ancestor(self, a, b):
Mads Kiilerich
comments: describe ancestor consistently - avoid 'least common ancestor'...
r22389 """calculate the "best" common ancestor of nodes a and b"""
Mads Kiilerich
revlog: backout 514d32de6646 - commonancestors
r21107
Benoit Boissinot
revlog: put graph related functions together
r10897 a, b = self.rev(a), self.rev(b)
Bryan O'Sullivan
parsers: a C implementation of the new ancestors algorithm...
r18988 try:
ancs = self.index.ancestors(a, b)
Mads Kiilerich
revlog: backout 514d32de6646 - commonancestors
r21107 except (AttributeError, OverflowError):
Bryan O'Sullivan
parsers: a C implementation of the new ancestors algorithm...
r18988 ancs = ancestor.ancestors(self.parentrevs, a, b)
Bryan O'Sullivan
revlog: choose a consistent ancestor when there's a tie...
r18987 if ancs:
# choose a consistent winner when there's a tie
Mads Kiilerich
revlog: backout 514d32de6646 - commonancestors
r21107 return min(map(self.node, ancs))
Bryan O'Sullivan
revlog: choose a consistent ancestor when there's a tie...
r18987 return nullid
Benoit Boissinot
revlog: put graph related functions together
r10897
Matt Mackall
Only look up tags and branches as a last resort
r3453 def _match(self, id):
Matt Mackall
revlog: don't handle long for revision matching...
r16762 if isinstance(id, int):
Benoit Boissinot
cleanups in revlog.lookup...
r3156 # rev
Benoit Boissinot
lookup should allow -1 to represent nullid (if passed an int as arg)
r2641 return self.node(id)
Matt Mackall
revlog.lookup tweaks...
r3438 if len(id) == 20:
# possibly a binary node
# odds of a binary node being all hex in ASCII are 1 in 10**25
try:
node = id
Augie Fackler
formatting: blacken the codebase...
r43346 self.rev(node) # quick search the index
Matt Mackall
revlog.lookup tweaks...
r3438 return node
Gregory Szorc
revlog: drop LookupError alias (API)...
r39811 except error.LookupError:
Augie Fackler
formatting: blacken the codebase...
r43346 pass # may be partial hex id
mpm@selenic.com
Add smart node lookup by substring or by rev number
r36 try:
Benoit Boissinot
cleanups in revlog.lookup...
r3156 # str(rev)
mpm@selenic.com
Add smart node lookup by substring or by rev number
r36 rev = int(id)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if b"%d" % rev != id:
Matt Mackall
revlog: some codingstyle cleanups
r4980 raise ValueError
if rev < 0:
Matt Mackall
add __len__ and __iter__ methods to repo and revlog
r6750 rev = len(self) + rev
if rev < 0 or rev >= len(self):
Matt Mackall
revlog: some codingstyle cleanups
r4980 raise ValueError
mpm@selenic.com
Add smart node lookup by substring or by rev number
r36 return self.node(rev)
mpm@selenic.com
Various node id lookup tweaks...
r469 except (ValueError, OverflowError):
Benoit Boissinot
cleanups in revlog.lookup...
r3156 pass
Matt Mackall
Only look up tags and branches as a last resort
r3453 if len(id) == 40:
try:
Matt Mackall
revlog.lookup tweaks...
r3438 # a full hex nodeid?
node = bin(id)
Peter Arrenbrecht
cleanup: drop variables for unused return values...
r7874 self.rev(node)
Benoit Boissinot
optimize revlog.lookup when passed hex(node)[:...]...
r3157 return node
Gregory Szorc
revlog: drop LookupError alias (API)...
r39811 except (TypeError, error.LookupError):
Matt Mackall
Only look up tags and branches as a last resort
r3453 pass
def _partialmatch(self, id):
Yuya Nishihara
revlog: detect pseudo file nodeids to raise WdirUnsupported exception...
r37467 # we don't care wdirfilenodeids as they should be always full hash
Yuya Nishihara
revlog: add support for partial matching of wdir node id...
r32684 maybewdir = wdirhex.startswith(id)
Bryan O'Sullivan
revlog: speed up prefix matching against nodes...
r16665 try:
Augie Fackler
revlog: avoid shadowing several variables using list comprehensions
r30391 partial = self.index.partialmatch(id)
if partial and self.hasnode(partial):
Yuya Nishihara
revlog: add support for partial matching of wdir node id...
r32684 if maybewdir:
# single 'ff...' match in radix tree, ambiguous with wdir
Gregory Szorc
revlog: drop RevlogError alias (API)...
r39809 raise error.RevlogError
Augie Fackler
revlog: avoid shadowing several variables using list comprehensions
r30391 return partial
Yuya Nishihara
revlog: add support for partial matching of wdir node id...
r32684 if maybewdir:
# no 'ff...' match in radix tree, wdir identified
raise error.WdirUnsupported
Matt Mackall
revlog: handle hidden revs in _partialmatch (issue3979)...
r19471 return None
Gregory Szorc
revlog: drop RevlogError alias (API)...
r39809 except error.RevlogError:
Bryan O'Sullivan
revlog: speed up prefix matching against nodes...
r16665 # parsers.c radix tree lookup gave multiple matches
Jun Wu
revlog: add a fast path for "ambiguous identifier"...
r29396 # fast path: for unfiltered changelog, radix tree is accurate
if not getattr(self, 'filteredrevs', None):
Gregory Szorc
revlog: drop some more error aliases (API)...
r39810 raise error.AmbiguousPrefixLookupError(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 id, self.indexfile, _(b'ambiguous identifier')
Augie Fackler
formatting: blacken the codebase...
r43346 )
Matt Mackall
revlog: handle hidden revs in _partialmatch (issue3979)...
r19471 # fall through to slow path that filters hidden revisions
Bryan O'Sullivan
revlog: speed up prefix matching against nodes...
r16665 except (AttributeError, ValueError):
# we are pure python, or key was too short to search radix tree
pass
Matt Mackall
revlog: introduce a cache for partial lookups...
r13258 if id in self._pcache:
return self._pcache[id]
Martin von Zweigbergk
revlog: make pure version of _partialmatch() support 40-byte hex nodeids...
r37837 if len(id) <= 40:
Matt Mackall
Only look up tags and branches as a last resort
r3453 try:
Matt Mackall
revlog.lookup tweaks...
r3438 # hex(node)[:...]
Alejandro Santos
compat: use // for integer division
r9029 l = len(id) // 2 # grab an even number of digits
Augie Fackler
formatting: blacken the codebase...
r43346 prefix = bin(id[: l * 2])
Matt Mackall
revlog: do revlog node->rev mapping by scanning...
r13259 nl = [e[7] for e in self.index if e[7].startswith(prefix)]
Augie Fackler
formatting: blacken the codebase...
r43346 nl = [
n for n in nl if hex(n).startswith(id) and self.hasnode(n)
]
Martin von Zweigbergk
revlog: fix pure version of _partialmatch() to include nullid...
r39227 if nullhex.startswith(id):
nl.append(nullid)
Matt Mackall
lookup: speed up partial lookup
r7365 if len(nl) > 0:
Yuya Nishihara
revlog: add support for partial matching of wdir node id...
r32684 if len(nl) == 1 and not maybewdir:
Matt Mackall
revlog: introduce a cache for partial lookups...
r13258 self._pcache[id] = nl[0]
Matt Mackall
lookup: speed up partial lookup
r7365 return nl[0]
Gregory Szorc
revlog: drop some more error aliases (API)...
r39810 raise error.AmbiguousPrefixLookupError(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 id, self.indexfile, _(b'ambiguous identifier')
Augie Fackler
formatting: blacken the codebase...
r43346 )
Yuya Nishihara
revlog: add support for partial matching of wdir node id...
r32684 if maybewdir:
raise error.WdirUnsupported
Matt Mackall
lookup: speed up partial lookup
r7365 return None
Augie Fackler
node: make bin() be a wrapper instead of just an alias...
r36256 except TypeError:
Matt Mackall
Only look up tags and branches as a last resort
r3453 pass
def lookup(self, id):
"""locate a node based on:
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 - revision number or str(revision number)
- nodeid or subset of hex nodeid
Matt Mackall
Only look up tags and branches as a last resort
r3453 """
n = self._match(id)
if n is not None:
return n
n = self._partialmatch(id)
if n:
return n
mpm@selenic.com
Whitespace cleanups...
r515
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.LookupError(id, self.indexfile, _(b'no match found'))
mpm@selenic.com
Add smart node lookup by substring or by rev number
r36
Martin von Zweigbergk
revlog: make shortest() take a full binary nodeid (API)...
r37785 def shortest(self, node, minlength=1):
"""Find the shortest unambiguous prefix that matches node."""
Augie Fackler
formatting: blacken the codebase...
r43346
Martin von Zweigbergk
shortest: rename "test" variable to "prefix"...
r37880 def isvalid(prefix):
Martin von Zweigbergk
templater: extract shortest() logic from template function...
r34247 try:
Martin von Zweigbergk
lookup: don't use "00changelog.i@None" when lookup of prefix fails...
r42852 matchednode = self._partialmatch(prefix)
Yuya Nishihara
revlog: catch more specific exception in shortest()...
r39856 except error.AmbiguousPrefixLookupError:
Martin von Zweigbergk
templater: extract shortest() logic from template function...
r34247 return False
except error.WdirUnsupported:
# single 'ff...' match
return True
Martin von Zweigbergk
lookup: don't use "00changelog.i@None" when lookup of prefix fails...
r42852 if matchednode is None:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.LookupError(node, self.indexfile, _(b'no node'))
Martin von Zweigbergk
shortest: remove unnecessary check for revnum in isvalid()...
r37989 return True
Martin von Zweigbergk
templater: extract shortest() logic from template function...
r34247
Martin von Zweigbergk
revlog: use node tree (native code) for shortest() calculation...
r37987 def maybewdir(prefix):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return all(c == b'f' for c in pycompat.iterbytestr(prefix))
Martin von Zweigbergk
revlog: use node tree (native code) for shortest() calculation...
r37987
Martin von Zweigbergk
revlog: make shortest() take a full binary nodeid (API)...
r37785 hexnode = hex(node)
Martin von Zweigbergk
revlog: use node tree (native code) for shortest() calculation...
r37987
def disambiguate(hexnode, minlength):
Martin von Zweigbergk
shortest: move revnum-disambiguation out of revlog...
r37990 """Disambiguate against wdirid."""
Joerg Sonnenberger
revlog: avoid hard-coded hash sizes...
r45596 for length in range(minlength, len(hexnode) + 1):
Martin von Zweigbergk
revlog: use node tree (native code) for shortest() calculation...
r37987 prefix = hexnode[:length]
Martin von Zweigbergk
shortest: move revnum-disambiguation out of revlog...
r37990 if not maybewdir(prefix):
Martin von Zweigbergk
revlog: use node tree (native code) for shortest() calculation...
r37987 return prefix
if not getattr(self, 'filteredrevs', None):
try:
length = max(self.index.shortest(node), minlength)
return disambiguate(hexnode, length)
Gregory Szorc
revlog: drop RevlogError alias (API)...
r39809 except error.RevlogError:
Martin von Zweigbergk
shortest: make pure code also disambigute against revnums at end...
r37988 if node != wdirid:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.LookupError(node, self.indexfile, _(b'no node'))
Martin von Zweigbergk
revlog: use node tree (native code) for shortest() calculation...
r37987 except AttributeError:
# Fall through to pure code
pass
Martin von Zweigbergk
shortest: make pure code also disambigute against revnums at end...
r37988 if node == wdirid:
Joerg Sonnenberger
revlog: avoid hard-coded hash sizes...
r45596 for length in range(minlength, len(hexnode) + 1):
Martin von Zweigbergk
shortest: make pure code also disambigute against revnums at end...
r37988 prefix = hexnode[:length]
if isvalid(prefix):
return prefix
Joerg Sonnenberger
revlog: avoid hard-coded hash sizes...
r45596 for length in range(minlength, len(hexnode) + 1):
Martin von Zweigbergk
shortest: rename "test" variable to "prefix"...
r37880 prefix = hexnode[:length]
if isvalid(prefix):
Martin von Zweigbergk
shortest: make pure code also disambigute against revnums at end...
r37988 return disambiguate(hexnode, length)
Martin von Zweigbergk
templater: extract shortest() logic from template function...
r34247
Matt Mackall
Move cmp bits from filelog to revlog
r2890 def cmp(self, node, text):
Nicolas Dumazet
cmp: document the fact that we return True if content is different...
r11539 """compare text with a given file revision
returns True if text is different than what is stored.
"""
Matt Mackall
Move cmp bits from filelog to revlog
r2890 p1, p2 = self.parents(node)
Gregory Szorc
storageutil: new module for storage primitives (API)...
r39913 return storageutil.hashrevisionsha1(text, p1, p2) != node
Matt Mackall
Move cmp bits from filelog to revlog
r2890
Gregory Szorc
revlog: rename internal functions containing "chunk" to use "segment"...
r32222 def _cachesegment(self, offset, data):
Gregory Szorc
revlog: improve documentation...
r27070 """Add a segment to the revlog cache.
Accepts an absolute offset and the data that is at that location.
"""
Matt Mackall
revlog: clean up the chunk caching code
r8316 o, d = self._chunkcache
# try to add to existing cache
Matt Mackall
revlog: remove lazy index
r13253 if o + len(d) == offset and len(d) + len(data) < _chunksize:
Matt Mackall
revlog: clean up the chunk caching code
r8316 self._chunkcache = o, d + data
else:
self._chunkcache = offset, data
Gregory Szorc
revlog: rename internal functions containing "chunk" to use "segment"...
r32222 def _readsegment(self, offset, length, df=None):
Gregory Szorc
revlog: improve documentation...
r27070 """Load a segment of raw data from the revlog.
Gregory Szorc
revlog: support using an existing file handle when reading revlogs...
r26377
Gregory Szorc
revlog: improve documentation...
r27070 Accepts an absolute offset, length to read, and an optional existing
Gregory Szorc
revlog: support using an existing file handle when reading revlogs...
r26377 file handle to read from.
If an existing file handle is passed, it will be seeked and the
original seek position will NOT be restored.
Gregory Szorc
revlog: improve documentation...
r27070
Returns a str or buffer of raw byte data.
Gregory Szorc
revlog: detect incomplete revlog reads...
r40660
Raises if the requested number of bytes could not be read.
Gregory Szorc
revlog: support using an existing file handle when reading revlogs...
r26377 """
Brodie Rao
revlog: read/cache chunks in fixed windows of 64 KB...
r20179 # Cache data both forward and backward around the requested
# data, in a fixed size window. This helps speed up operations
# involving reading the revlog backwards.
Brodie Rao
revlog: allow tuning of the chunk cache size (via format.chunkcachesize)...
r20180 cachesize = self._chunkcachesize
realoffset = offset & ~(cachesize - 1)
Augie Fackler
formatting: blacken the codebase...
r43346 reallength = (
(offset + length + cachesize) & ~(cachesize - 1)
) - realoffset
Boris Feld
revlog: add a _datareadfp context manager for data access needs...
r35991 with self._datareadfp(df) as df:
df.seek(realoffset)
d = df.read(reallength)
Gregory Szorc
revlog: detect incomplete revlog reads...
r40660
Gregory Szorc
revlog: rename internal functions containing "chunk" to use "segment"...
r32222 self._cachesegment(realoffset, d)
Brodie Rao
revlog: read/cache chunks in fixed windows of 64 KB...
r20179 if offset != realoffset or reallength != length:
Gregory Szorc
revlog: detect incomplete revlog reads...
r40660 startoffset = offset - realoffset
if len(d) - startoffset < length:
raise error.RevlogError(
Augie Fackler
formatting: blacken the codebase...
r43346 _(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'partial read of revlog %s; expected %d bytes from '
b'offset %d, got %d'
Augie Fackler
formatting: blacken the codebase...
r43346 )
% (
self.indexfile if self._inline else self.datafile,
length,
realoffset,
len(d) - startoffset,
)
)
Gregory Szorc
revlog: detect incomplete revlog reads...
r40660
return util.buffer(d, startoffset, length)
if len(d) < length:
raise error.RevlogError(
Augie Fackler
formatting: blacken the codebase...
r43346 _(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'partial read of revlog %s; expected %d bytes from offset '
b'%d, got %d'
Augie Fackler
formatting: blacken the codebase...
r43346 )
% (
self.indexfile if self._inline else self.datafile,
length,
offset,
len(d),
)
)
Gregory Szorc
revlog: detect incomplete revlog reads...
r40660
Matt Mackall
revlog: clean up the chunk caching code
r8316 return d
Gregory Szorc
revlog: rename internal functions containing "chunk" to use "segment"...
r32222 def _getsegment(self, offset, length, df=None):
Gregory Szorc
revlog: improve documentation...
r27070 """Obtain a segment of raw data from the revlog.
Accepts an absolute offset, length of bytes to obtain, and an
optional file handle to the already-opened revlog. If the file
handle is used, it's original seek position will not be preserved.
Requests for data may be returned from a cache.
Returns a str or a buffer instance of raw byte data.
"""
Matt Mackall
revlog: clean up the chunk caching code
r8316 o, d = self._chunkcache
l = len(d)
# is it in the cache?
cachestart = offset - o
cacheend = cachestart + length
if cachestart >= 0 and cacheend <= l:
if cachestart == 0 and cacheend == l:
Augie Fackler
formatting: blacken the codebase...
r43346 return d # avoid a copy
Bryan O'Sullivan
revlog: avoid an expensive string copy...
r16423 return util.buffer(d, cachestart, cacheend - cachestart)
Matt Mackall
revlog: clean up the chunk caching code
r8316
Gregory Szorc
revlog: rename internal functions containing "chunk" to use "segment"...
r32222 return self._readsegment(offset, length, df=df)
Matt Mackall
revlog: clean up the chunk caching code
r8316
Gregory Szorc
revlog: rename _chunkraw to _getsegmentforrevs()...
r32224 def _getsegmentforrevs(self, startrev, endrev, df=None):
Gregory Szorc
revlog: improve documentation...
r27070 """Obtain a segment of raw data corresponding to a range of revisions.
Accepts the start and end revisions and an optional already-open
file handle to be used for reading. If the file handle is read, its
seek position will not be preserved.
Requests for data may be satisfied by a cache.
Gregory Szorc
revlog: return offset from _chunkraw()...
r27649 Returns a 2-tuple of (offset, data) for the requested range of
revisions. Offset is the integer offset from the beginning of the
revlog and data is a str or buffer of the raw byte data.
Callers will need to call ``self.start(rev)`` and ``self.length(rev)``
to determine where each revision's data begins and ends.
Gregory Szorc
revlog: improve documentation...
r27070 """
Gregory Szorc
revlog: inline start() and end() for perf reasons...
r30288 # Inlined self.start(startrev) & self.end(endrev) for perf reasons
# (functions are expensive).
index = self.index
istart = index[startrev]
start = int(istart[0] >> 16)
Gregory Szorc
revlog: optimize _chunkraw when startrev==endrev...
r30289 if startrev == endrev:
end = start + istart[1]
else:
iend = index[endrev]
end = int(iend[0] >> 16) + iend[1]
Gregory Szorc
revlog: inline start() and end() for perf reasons...
r30288
Matt Mackall
revlog: add cache priming for reconstructing delta chains
r8318 if self._inline:
start += (startrev + 1) * self._io.size
Siddharth Agarwal
revlog.revision: fix cache preload for inline revlogs...
r19714 end += (endrev + 1) * self._io.size
length = end - start
Gregory Szorc
revlog: return offset from _chunkraw()...
r27649
Gregory Szorc
revlog: rename internal functions containing "chunk" to use "segment"...
r32222 return start, self._getsegment(start, length, df=df)
Matt Mackall
revlog: add cache priming for reconstructing delta chains
r8318
Gregory Szorc
revlog: support using an existing file handle when reading revlogs...
r26377 def _chunk(self, rev, df=None):
Gregory Szorc
revlog: improve documentation...
r27070 """Obtain a single decompressed chunk for a revision.
Accepts an integer revision and an optional already-open file handle
to be used for reading. If used, the seek position of the file will not
be preserved.
Returns a str holding uncompressed data for the requested revision.
"""
Gregory Szorc
revlog: rename _chunkraw to _getsegmentforrevs()...
r32224 return self.decompress(self._getsegmentforrevs(rev, rev, df=df)[1])
Matt Mackall
revlog: refactor chunk cache interface again...
r8650
Boris Feld
revlog: enforce chunk slicing down to a certain size...
r38666 def _chunks(self, revs, df=None, targetsize=None):
Gregory Szorc
revlog: improve documentation...
r27070 """Obtain decompressed chunks for the specified revisions.
Siddharth Agarwal
revlog: add a fast method for getting a list of chunks...
r19713
Gregory Szorc
revlog: improve documentation...
r27070 Accepts an iterable of numeric revisions that are assumed to be in
ascending order. Also accepts an optional already-open file handle
to be used for reading. If used, the seek position of the file will
not be preserved.
This function is similar to calling ``self._chunk()`` multiple times,
but is faster.
Returns a list with decompressed data for each requested revision.
"""
Siddharth Agarwal
revlog: move chunk cache preload from revision to _chunks...
r19716 if not revs:
return []
Siddharth Agarwal
revlog: add a fast method for getting a list of chunks...
r19713 start = self.start
length = self.length
inline = self._inline
iosize = self._io.size
Siddharth Agarwal
revlog._chunks: inline getchunk...
r19715 buffer = util.buffer
Siddharth Agarwal
revlog: add a fast method for getting a list of chunks...
r19713
l = []
ladd = l.append
Paul Morelle
revlog: introduce an experimental flag to slice chunks reads when too sparse...
r34825 if not self._withsparseread:
slicedchunks = (revs,)
else:
Augie Fackler
formatting: blacken the codebase...
r43346 slicedchunks = deltautil.slicechunk(
self, revs, targetsize=targetsize
)
Paul Morelle
revlog: introduce an experimental flag to slice chunks reads when too sparse...
r34825
for revschunk in slicedchunks:
firstrev = revschunk[0]
# Skip trailing revisions with empty diff
for lastrev in revschunk[::-1]:
if length(lastrev) != 0:
break
Paul Morelle
revlog: ignore empty trailing chunks when reading segments...
r34824
Paul Morelle
revlog: introduce an experimental flag to slice chunks reads when too sparse...
r34825 try:
offset, data = self._getsegmentforrevs(firstrev, lastrev, df=df)
except OverflowError:
# issue4215 - we can't cache a run of chunks greater than
# 2G on Windows
return [self._chunk(rev, df=df) for rev in revschunk]
Siddharth Agarwal
revlog._chunks: inline getchunk...
r19715
Paul Morelle
revlog: introduce an experimental flag to slice chunks reads when too sparse...
r34825 decomp = self.decompress
for rev in revschunk:
chunkstart = start(rev)
if inline:
chunkstart += (rev + 1) * iosize
chunklength = length(rev)
ladd(decomp(buffer(data, chunkstart - offset, chunklength)))
Siddharth Agarwal
revlog: add a fast method for getting a list of chunks...
r19713
return l
Sune Foldager
revlog: introduce _chunkbase to allow filelog to override...
r14075
Matt Mackall
revlog: refactor chunk cache interface again...
r8650 def _chunkclear(self):
Gregory Szorc
revlog: improve documentation...
r27070 """Clear the raw chunk cache."""
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self._chunkcache = (0, b'')
Benoit Boissinot
cleanup of revlog.group when repository is local...
r1598
Pradeepkumar Gayam
revlog: deltachain() returns chain of revs need to construct a revision
r11929 def deltaparent(self, rev):
Sune Foldager
revlog: remove support for parentdelta...
r14195 """return deltaparent of the given revision"""
Sune Foldager
revlog: support reading generaldelta revlogs...
r14253 base = self.index[rev][3]
if base == rev:
Sune Foldager
revlog: compute correct deltaparent in the deltaparent function...
r14208 return nullrev
Sune Foldager
revlog: support reading generaldelta revlogs...
r14253 elif self._generaldelta:
return base
Sune Foldager
revlog: compute correct deltaparent in the deltaparent function...
r14208 else:
return rev - 1
Pradeepkumar Gayam
revlog: deltachain() returns chain of revs need to construct a revision
r11929
Paul Morelle
revlog: add a method to tells whether rev is stored as a snapshot...
r39185 def issnapshot(self, rev):
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """tells whether rev is a snapshot"""
Boris Feld
revlog: use the native implementation of issnapshot...
r41118 if not self._sparserevlog:
return self.deltaparent(rev) == nullrev
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 elif util.safehasattr(self.index, b'issnapshot'):
Boris Feld
revlog: use the native implementation of issnapshot...
r41118 # directly assign the method to cache the testing and access
self.issnapshot = self.index.issnapshot
return self.issnapshot(rev)
Paul Morelle
revlog: add a method to tells whether rev is stored as a snapshot...
r39185 if rev == nullrev:
return True
Boris Feld
revlog: more efficient implementation for issnapshot...
r41116 entry = self.index[rev]
base = entry[3]
if base == rev:
Paul Morelle
revlog: add a method to tells whether rev is stored as a snapshot...
r39185 return True
Boris Feld
revlog: more efficient implementation for issnapshot...
r41116 if base == nullrev:
return True
p1 = entry[5]
p2 = entry[6]
if base == p1 or base == p2:
Paul Morelle
revlog: also detect intermediate snapshots...
r39186 return False
Boris Feld
revlog: more efficient implementation for issnapshot...
r41116 return self.issnapshot(base)
Paul Morelle
revlog: add a method to tells whether rev is stored as a snapshot...
r39185
Boris Feld
revlog: add a method to retrieve snapshot depth...
r39188 def snapshotdepth(self, rev):
"""number of snapshot in the chain before this one"""
if not self.issnapshot(rev):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.ProgrammingError(b'revision %d not a snapshot')
Boris Feld
revlog: add a method to retrieve snapshot depth...
r39188 return len(self._deltachain(rev)[0]) - 1
Benoit Boissinot
revlog.py: factorization and fixes for rev < 0 (nullid)
r1941 def revdiff(self, rev1, rev2):
Jun Wu
revlog: use raw revisions in revdiff...
r31753 """return or calculate a delta between two revisions
The delta calculated is in binary form and is intended to be written to
revlog data directly. So this function needs raw revision data.
"""
Sune Foldager
revlog: compute correct deltaparent in the deltaparent function...
r14208 if rev1 != nullrev and self.deltaparent(rev2) == rev1:
Augie Fackler
revlog: use bytes() instead of str() to get data from memoryview...
r31369 return bytes(self._chunk(rev2))
Matt Mackall
revlog: minor revdiff reorganization
r5005
Augie Fackler
formatting: blacken the codebase...
r43346 return mdiff.textdiff(self.rawdata(rev1), self.rawdata(rev2))
mpm@selenic.com
Add code to retrieve or construct a revlog delta
r119
flagprocessors: directly duplicate the deprecated layer back into revlog...
r43263 def _processflags(self, text, flags, operation, raw=False):
"""deprecated entry point to access flag processors"""
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 msg = b'_processflag(...) use the specialized variant'
util.nouideprecwarn(msg, b'5.2', stacklevel=2)
flagprocessors: directly duplicate the deprecated layer back into revlog...
r43263 if raw:
return text, flagutil.processflagsraw(self, text, flags)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 elif operation == b'read':
flagprocessors: directly duplicate the deprecated layer back into revlog...
r43263 return flagutil.processflagsread(self, text, flags)
Augie Fackler
formatting: blacken the codebase...
r43346 else: # write operation
Raphaël Gomès
sidedata: move to new sidedata storage in revlogv2...
r47443 return flagutil.processflagswrite(self, text, flags)
flagprocessors: directly duplicate the deprecated layer back into revlog...
r43263
Remi Chaintron
revlog: add 'raw' argument to revision and _addrevision...
r30743 def revision(self, nodeorrev, _df=None, raw=False):
Patrick Mezard
revlog: fix partial revision() docstring (from d7d64b89a65c)
r16435 """return an uncompressed revision of a given node or revision
number.
Gregory Szorc
revlog: support using an existing file handle when reading revlogs...
r26377
Remi Chaintron
revlog: add 'raw' argument to revision and _addrevision...
r30743 _df - an existing file handle to read from. (internal-only)
raw - an optional argument specifying if the revision data is to be
treated as raw data when applying flag transforms. 'raw' should be set
to True when generating changegroups or in debug commands.
Patrick Mezard
revlog: fix partial revision() docstring (from d7d64b89a65c)
r16435 """
revlog: deprecate the use of `revision(..., raw=True)`...
r43111 if raw:
Augie Fackler
formatting: blacken the codebase...
r43346 msg = (
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'revlog.revision(..., raw=True) is deprecated, '
b'use revlog.rawdata(...)'
Augie Fackler
formatting: blacken the codebase...
r43346 )
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 util.nouideprecwarn(msg, b'5.2', stacklevel=2)
revlog: return sidedata map from `_revisiondata`...
r43251 return self._revisiondata(nodeorrev, _df, raw=raw)[0]
revlog: split a `_revisiondata` method to file `revision` job...
r42944
revlog: introduce a `sidedata` method...
r43250 def sidedata(self, nodeorrev, _df=None):
"""a map of extra data related to the changeset but not part of the hash
This function currently return a dictionary. However, more advanced
mapping object will likely be used in the future for a more
efficient/lazy code.
"""
revlog: use the new sidedata map return in the sidedata method...
r43252 return self._revisiondata(nodeorrev, _df)[1]
revlog: introduce a `sidedata` method...
r43250
revlog: split a `_revisiondata` method to file `revision` job...
r42944 def _revisiondata(self, nodeorrev, _df=None, raw=False):
revlog: add some documentation to `_revisiondata` code
r43058 # deal with <nodeorrev> argument type
Matt Mackall
revlog: allow retrieving contents by revision number
r16375 if isinstance(nodeorrev, int):
rev = nodeorrev
node = self.node(rev)
else:
node = nodeorrev
rev = None
revlog: add some documentation to `_revisiondata` code
r43058 # fast path the special `nullid` rev
revlog: move `nullid` early return sooner in `_revisiondata`...
r43057 if node == nullid:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return b"", {}
revlog: move `nullid` early return sooner in `_revisiondata`...
r43057
Matt Harbison
revlog: drop an unused variable assignment...
r44431 # ``rawtext`` is the text as stored inside the revlog. Might be the
# revision or might need to be processed to retrieve the revision.
revlog: split `rawtext` retrieval out of _revisiondata...
r43060 rev, rawtext, validated = self._rawtext(node, rev, _df=_df)
Raphaël Gomès
sidedata: move to new sidedata storage in revlogv2...
r47443 if self.version & 0xFFFF == REVLOGV2:
if rev is None:
rev = self.rev(node)
sidedata = self._sidedata(rev)
else:
sidedata = {}
revlog: split `rawtext` retrieval out of _revisiondata...
r43060 if raw and validated:
# if we don't want to process the raw text and that raw
# text is cached, we can exit early.
Raphaël Gomès
sidedata: move to new sidedata storage in revlogv2...
r47443 return rawtext, sidedata
revlog: split `rawtext` retrieval out of _revisiondata...
r43060 if rev is None:
rev = self.rev(node)
# the revlog's flag for this revision
# (usually alter its state or content)
flags = self.flags(rev)
if validated and flags == REVIDX_DEFAULT_FLAGS:
# no extra flags set, no flag processor runs, text = rawtext
Raphaël Gomès
sidedata: move to new sidedata storage in revlogv2...
r47443 return rawtext, sidedata
revlog: stop using `_processflags` directly...
r43148 if raw:
flagprocessors: make `processflagsraw` a module level function...
r43262 validatehash = flagutil.processflagsraw(self, rawtext, flags)
revlog: stop using `_processflags` directly...
r43148 text = rawtext
else:
Raphaël Gomès
sidedata: move to new sidedata storage in revlogv2...
r47443 r = flagutil.processflagsread(self, rawtext, flags)
text, validatehash = r
revlog: split `rawtext` retrieval out of _revisiondata...
r43060 if validatehash:
self.checkhash(text, node, rev=rev)
if not validated:
self._revisioncache = (node, rev, rawtext)
revlog: return sidedata map from `_revisiondata`...
r43251 return text, sidedata
revlog: split `rawtext` retrieval out of _revisiondata...
r43060
def _rawtext(self, node, rev, _df=None):
"""return the possibly unvalidated rawtext for a revision
returns (rev, rawtext, validated)
"""
# revision in the cache (could be useful to apply delta)
cachedrev = None
revlog: add some documentation to `_revisiondata` code
r43058 # An intermediate text to apply deltas to
revlog: stop calling `basetext` `rawtext` in _revisiondata...
r43056 basetext = None
revlog: add some documentation to `_revisiondata` code
r43058
# Check if we have the entry in cache
# The cache entry looks like (node, rev, rawtext)
Gregory Szorc
revlog: rename _cache to _revisioncache...
r40088 if self._revisioncache:
if self._revisioncache[0] == node:
revlog: split `rawtext` retrieval out of _revisiondata...
r43060 return (rev, self._revisioncache[2], True)
Gregory Szorc
revlog: rename _cache to _revisioncache...
r40088 cachedrev = self._revisioncache[1]
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
revlog: split `rawtext` retrieval out of _revisiondata...
r43060 if rev is None:
rev = self.rev(node)
chain, stopped = self._deltachain(rev, stoprev=cachedrev)
if stopped:
basetext = self._revisioncache[2]
# drop cache to save memory, the caller is expected to
# update self._revisioncache after validating the text
self._revisioncache = None
targetsize = None
rawsize = self.index[rev][2]
if 0 <= rawsize:
targetsize = 4 * rawsize
bins = self._chunks(chain, df=_df, targetsize=targetsize)
if basetext is None:
basetext = bytes(bins[0])
bins = bins[1:]
rawtext = mdiff.patches(basetext, bins)
Augie Fackler
formatting: blacken the codebase...
r43346 del basetext # let us have a chance to free memory early
revlog: split `rawtext` retrieval out of _revisiondata...
r43060 return (rev, rawtext, False)
Matt Mackall
revlog: break hash checking into subfunction
r13239
Raphaël Gomès
sidedata: move to new sidedata storage in revlogv2...
r47443 def _sidedata(self, rev):
"""Return the sidedata for a given revision number."""
index_entry = self.index[rev]
sidedata_offset = index_entry[8]
sidedata_size = index_entry[9]
if self._inline:
sidedata_offset += self._io.size * (1 + rev)
if sidedata_size == 0:
return {}
segment = self._getsegment(sidedata_offset, sidedata_size)
sidedata = sidedatautil.deserialize_sidedata(segment)
return sidedata
revlog: drop silly `raw` parameter to `rawdata` function...
r43054 def rawdata(self, nodeorrev, _df=None):
rawdata: introduce a `rawdata` method on revlog...
r42945 """return an uncompressed raw data of a given node or revision number.
_df - an existing file handle to read from. (internal-only)
"""
revlog: return sidedata map from `_revisiondata`...
r43251 return self._revisiondata(nodeorrev, _df, raw=True)[0]
rawdata: introduce a `rawdata` method on revlog...
r42945
Augie Fackler
revlog: move references to revlog.hash to inside the revlog class...
r22785 def hash(self, text, p1, p2):
"""Compute a node hash.
Available as a function so that subclasses can replace the hash
as needed.
"""
Gregory Szorc
storageutil: new module for storage primitives (API)...
r39913 return storageutil.hashrevisionsha1(text, p1, p2)
Augie Fackler
revlog: move references to revlog.hash to inside the revlog class...
r22785
Remi Chaintron
revlog: merge hash checking subfunctions...
r30584 def checkhash(self, text, node, p1=None, p2=None, rev=None):
"""Check node hash integrity.
Wojciech Lopata
revlog: extract 'checkhash' method...
r19624
Remi Chaintron
revlog: merge hash checking subfunctions...
r30584 Available as a function so that subclasses can extend hash mismatch
behaviors as needed.
"""
Gregory Szorc
revlog: move censor logic into main revlog class...
r37461 try:
if p1 is None and p2 is None:
p1, p2 = self.parents(node)
if node != self.hash(text, p1, p2):
Gregory Szorc
revlog: clear revision cache on hash verification failure...
r40090 # Clear the revision cache on hash failure. The revision cache
# only stores the raw revision and clearing the cache does have
# the side-effect that we won't have a cache hit when the raw
# revision data is accessed. But this case should be rare and
# it is extra work to teach the cache about the hash
# verification state.
if self._revisioncache and self._revisioncache[0] == node:
self._revisioncache = None
Gregory Szorc
revlog: move censor logic into main revlog class...
r37461 revornode = rev
if revornode is None:
revornode = templatefilters.short(hex(node))
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.RevlogError(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b"integrity check failed on %s:%s")
Augie Fackler
formatting: blacken the codebase...
r43346 % (self.indexfile, pycompat.bytestr(revornode))
)
Gregory Szorc
revlog: drop RevlogError alias (API)...
r39809 except error.RevlogError:
Gregory Szorc
storageutil: move _censoredtext() from revlog...
r39915 if self._censorable and storageutil.iscensoredtext(text):
Gregory Szorc
revlog: move censor logic into main revlog class...
r37461 raise error.CensoredNodeError(self.indexfile, node, text)
raise
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
Boris Feld
revlog: rename 'self.checkinlinesize' into '_enforceinlinesize'...
r35992 def _enforceinlinesize(self, tr, fp=None):
Gregory Szorc
revlog: add docstring for checkinlinesize()...
r26376 """Check if the revlog is too big for inline and convert if so.
This should be called after revisions are added to the revlog. If the
revlog has grown too large to be an inline revlog, it will convert it
to use multiple index and data files.
"""
Martin von Zweigbergk
revlog: remove some knowledge of sentinel nullid in index...
r38880 tiprev = len(self) - 1
Augie Fackler
formatting: blacken the codebase...
r43346 if (
not self._inline
or (self.start(tiprev) + self.length(tiprev)) < _maxinline
):
mason@suse.com
Implement data inlined with the index file...
r2073 return
Matt Mackall
revlog: use index to find index size
r8315
Joerg Sonnenberger
transaction: rename find to findoffset and drop backup file support...
r46482 troffset = tr.findoffset(self.indexfile)
if troffset is None:
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.RevlogError(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b"%s not found in the transaction") % self.indexfile
Augie Fackler
formatting: blacken the codebase...
r43346 )
Joerg Sonnenberger
transaction: drop per-file extra data support...
r46481 trindex = 0
tr.add(self.datafile, 0)
Matt Mackall
revlog: use index to find index size
r8315
Matt Mackall
revlog: use chunk cache to avoid rereading when splitting inline files
r8317 if fp:
fp.flush()
fp.close()
Gregory Szorc
revlog: automatically read from opened file handles...
r40661 # We can't use the cached file handle after close(). So prevent
# its usage.
self._writinghandles = None
Matt Mackall
revlog: use index to find index size
r8315
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 with self._indexfp(b'r') as ifh, self._datafp(b'w') as dfh:
Matt Mackall
add __len__ and __iter__ methods to repo and revlog
r6750 for r in self:
Gregory Szorc
revlog: use single file handle when de-inlining revlog...
r40659 dfh.write(self._getsegmentforrevs(r, r, df=ifh)[1])
Joerg Sonnenberger
transaction: drop per-file extra data support...
r46481 if troffset <= self.start(r):
trindex = r
Benoit Boissinot
revlog: make sure the files are closed after an exception happens...
r6261
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 with self._indexfp(b'w') as fp:
Boris Feld
revlog: use context manager for index file lifetime in checkinlinesize...
r35989 self.version &= ~FLAG_INLINE_DATA
self._inline = False
io = self._io
for i in self:
e = io.packentry(self.index[i], self.node, self.version, i)
fp.write(e)
mason@suse.com
Implement data inlined with the index file...
r2073
Boris Feld
revlog: use context manager for index file lifetime in checkinlinesize...
r35989 # the temp file replace the real index when we exit the context
# manager
Chris Mason
...
r2084
Matt Mackall
revlog: refactor chunk cache interface again...
r8650 tr.replace(self.indexfile, trindex * self._io.size)
nodemap: only use persistent nodemap for non-inlined revlog...
r44791 nodemaputil.setup_persistent_nodemap(tr, self)
Matt Mackall
revlog: refactor chunk cache interface again...
r8650 self._chunkclear()
mason@suse.com
Implement data inlined with the index file...
r2073
Boris Feld
revlog: add a callback "tracking" duplicate node addition...
r39922 def _nodeduplicatecallback(self, transaction, node):
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """called when trying to add a node already stored."""
Boris Feld
revlog: add a callback "tracking" duplicate node addition...
r39922
Augie Fackler
formatting: blacken the codebase...
r43346 def addrevision(
self,
text,
transaction,
link,
p1,
p2,
cachedelta=None,
node=None,
flags=REVIDX_DEFAULT_FLAGS,
deltacomputer=None,
sidedata=None,
):
mpm@selenic.com
Add some docstrings to revlog.py
r1083 """add a revision to the log
text - the revision data to add
transaction - the transaction object used for rollback
link - the linkrev data to add
p1, p2 - the parent nodeids of the revision
Benoit Boissinot
revlog: fix docstring
r12012 cachedelta - an optional precomputed delta
Wojciech Lopata
revlog: pass node as an argument of addrevision...
r19625 node - nodeid of revision; typically node is not specified, and it is
computed by default as hash(text, p1, p2), however subclasses might
use different hashing method (and override checkhash() in such case)
Remi Chaintron
revlog: pass revlog flags to addrevision...
r30744 flags - the known flags to set on the revision
Boris Feld
revlog: split functionality related to deltas computation in a new module...
r39366 deltacomputer - an optional deltacomputer instance shared between
Paul Morelle
revlog: group delta computation methods under _deltacomputer object...
r35756 multiple calls
mpm@selenic.com
Add some docstrings to revlog.py
r1083 """
Durham Goode
revlog: add exception when linkrev == nullrev...
r19326 if link == nullrev:
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.RevlogError(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b"attempted to add linkrev -1 to %s") % self.indexfile
Augie Fackler
formatting: blacken the codebase...
r43346 )
Matt Mackall
revlog: move size limit check to addrevision...
r25459
revlog: add a `sidedata` parameters to addrevision...
r43256 if sidedata is None:
sidedata = {}
sidedata: introduce a new requirement to protect the feature...
r43298 elif not self.hassidedata:
raise error.ProgrammingError(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b"trying to add sidedata to a revlog who don't support them")
Augie Fackler
formatting: blacken the codebase...
r43346 )
revlog: add a `sidedata` parameters to addrevision...
r43256
Remi Chaintron
revlog: flag processor...
r30745 if flags:
node = node or self.hash(text, p1, p2)
Raphaël Gomès
sidedata: move to new sidedata storage in revlogv2...
r47443 rawtext, validatehash = flagutil.processflagswrite(self, text, flags)
Remi Chaintron
revlog: flag processor...
r30745
# If the flag processor modifies the revision data, ignore any provided
# cachedelta.
Jun Wu
revlog: rename some "text"s to "rawtext"...
r31750 if rawtext != text:
Remi Chaintron
revlog: flag processor...
r30745 cachedelta = None
Jun Wu
revlog: rename some "text"s to "rawtext"...
r31750 if len(rawtext) > _maxentrysize:
Gregory Szorc
revlog: drop RevlogError alias (API)...
r39809 raise error.RevlogError(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(
b"%s: size of %d bytes exceeds maximum revlog storage of 2GiB"
)
Augie Fackler
formatting: blacken the codebase...
r43346 % (self.indexfile, len(rawtext))
)
Matt Mackall
revlog: move size limit check to addrevision...
r25459
Jun Wu
revlog: rename some "text"s to "rawtext"...
r31750 node = node or self.hash(rawtext, p1, p2)
Joerg Sonnenberger
revlog: change addrevision to return the new revision, not node...
r47258 rev = self.index.get_rev(node)
if rev is not None:
return rev
Benoit Boissinot
revlog.addrevision(): move computation of nodeid in addrevision()...
r12023
Remi Chaintron
revlog: flag processor...
r30745 if validatehash:
Jun Wu
revlog: rename some "text"s to "rawtext"...
r31750 self.checkhash(rawtext, node, p1=p1, p2=p2)
Remi Chaintron
revlog: flag processor...
r30745
Joerg Sonnenberger
revlog: change addrevision to return the new revision, not node...
r47258 return self.addrawrevision(
Augie Fackler
formatting: blacken the codebase...
r43346 rawtext,
transaction,
link,
p1,
p2,
node,
flags,
cachedelta=cachedelta,
deltacomputer=deltacomputer,
Raphaël Gomès
sidedata: move to new sidedata storage in revlogv2...
r47443 sidedata=sidedata,
Augie Fackler
formatting: blacken the codebase...
r43346 )
def addrawrevision(
self,
rawtext,
transaction,
link,
p1,
p2,
node,
flags,
cachedelta=None,
deltacomputer=None,
Raphaël Gomès
sidedata: move to new sidedata storage in revlogv2...
r47443 sidedata=None,
Augie Fackler
formatting: blacken the codebase...
r43346 ):
Jun Wu
revlog: move part of "addrevision" to "addrawrevision"...
r32240 """add a raw revision with known flags, node and parents
useful when reusing a revision not stored in this revlog (ex: received
over wire, or read from an external bundle).
"""
Matt Mackall
revlog: simplify addrevision...
r4981 dfh = None
Matt Mackall
revlog: change _inline from a function to a variable
r4982 if not self._inline:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 dfh = self._datafp(b"a+")
ifh = self._indexfp(b"a+")
Benoit Boissinot
revlog: make sure the files are closed after an exception happens...
r6261 try:
Joerg Sonnenberger
revlog: change addrawrevision to return the revision...
r47257 return self._addrevision(
Augie Fackler
formatting: blacken the codebase...
r43346 node,
rawtext,
transaction,
link,
p1,
p2,
flags,
cachedelta,
ifh,
dfh,
deltacomputer=deltacomputer,
Raphaël Gomès
sidedata: move to new sidedata storage in revlogv2...
r47443 sidedata=sidedata,
Augie Fackler
formatting: blacken the codebase...
r43346 )
Benoit Boissinot
revlog: make sure the files are closed after an exception happens...
r6261 finally:
if dfh:
dfh.close()
ifh.close()
Alexis S. L. Carvalho
make revlog.addgroup pass its file handles to addrevision...
r3390
Gregory Szorc
revlog: use compression engine API for compression...
r30795 def compress(self, data):
"""Generate a possibly-compressed representation of data."""
if not data:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return b'', data
Gregory Szorc
revlog: use compression engine API for compression...
r30795
compressed = self._compressor.compress(data)
if compressed:
# The revlog compressor added the header in the returned data.
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return b'', compressed
if data[0:1] == b'\0':
return b'', data
return b'u', data
Bryan O'Sullivan
revlog: make compress a method...
r17128
Gregory Szorc
revlog: move decompress() from module to revlog class (API)...
r30793 def decompress(self, data):
"""Decompress a revlog chunk.
The chunk is expected to begin with a header identifying the
format type so it can be routed to an appropriate decompressor.
"""
if not data:
return data
Gregory Szorc
revlog: use compression engine APIs for decompression...
r30817
# Revlogs are read much more frequently than they are written and many
# chunks only take microseconds to decompress, so performance is
# important here.
#
# We can make a few assumptions about revlogs:
#
# 1) the majority of chunks will be compressed (as opposed to inline
# raw data).
# 2) decompressing *any* data will likely by at least 10x slower than
# returning raw inline data.
# 3) we want to prioritize common and officially supported compression
# engines
#
# It follows that we want to optimize for "decompress compressed data
# when encoded with common and officially supported compression engines"
# case over "raw data" and "data encoded by less common or non-official
# compression engines." That is why we have the inline lookup first
# followed by the compengines lookup.
#
# According to `hg perfrevlogchunks`, this is ~0.5% faster for zlib
# compressed chunks. And this matters for changelog and manifest reads.
Augie Fackler
revlog: extract first byte of revlog with a slice so it's portable
r31356 t = data[0:1]
Gregory Szorc
revlog: use compression engine APIs for decompression...
r30817
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if t == b'x':
Gregory Szorc
revlog: move decompress() from module to revlog class (API)...
r30793 try:
Gregory Szorc
revlog: use compression engine APIs for decompression...
r30817 return _zlibdecompress(data)
Gregory Szorc
revlog: move decompress() from module to revlog class (API)...
r30793 except zlib.error as e:
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.RevlogError(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b'revlog decompress error: %s')
Augie Fackler
formatting: blacken the codebase...
r43346 % stringutil.forcebytestr(e)
)
Gregory Szorc
revlog: use compression engine APIs for decompression...
r30817 # '\0' is more common than 'u' so it goes first.
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 elif t == b'\0':
Gregory Szorc
revlog: use compression engine APIs for decompression...
r30817 return data
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 elif t == b'u':
Gregory Szorc
revlog: move decompress() from module to revlog class (API)...
r30793 return util.buffer(data, 1)
Gregory Szorc
revlog: use compression engine APIs for decompression...
r30817
try:
compressor = self._decompressors[t]
except KeyError:
try:
engine = util.compengines.forrevlogheader(t)
compression: introduce a `storage.revlog.zlib.level` configuration...
r42210 compressor = engine.revlogcompressor(self._compengineopts)
Gregory Szorc
revlog: use compression engine APIs for decompression...
r30817 self._decompressors[t] = compressor
except KeyError:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.RevlogError(_(b'unknown compression type %r') % t)
Gregory Szorc
revlog: use compression engine APIs for decompression...
r30817
return compressor.decompress(data)
Gregory Szorc
revlog: move decompress() from module to revlog class (API)...
r30793
Augie Fackler
formatting: blacken the codebase...
r43346 def _addrevision(
self,
node,
rawtext,
transaction,
link,
p1,
p2,
flags,
cachedelta,
ifh,
dfh,
alwayscache=False,
deltacomputer=None,
Raphaël Gomès
sidedata: move to new sidedata storage in revlogv2...
r47443 sidedata=None,
Augie Fackler
formatting: blacken the codebase...
r43346 ):
Sune Foldager
revlog: add docstring to _addrevision
r14292 """internal function to add revisions to the log
Benoit Boissinot
revlog._addrevision(): allow text argument to be None, build it lazily
r12623
Sune Foldager
revlog: add docstring to _addrevision
r14292 see addrevision for argument descriptions.
Jun Wu
revlog: make _addrevision only accept rawtext...
r31755
note: "addrevision" takes non-raw text, "_addrevision" takes raw text.
Paul Morelle
revlog: group delta computation methods under _deltacomputer object...
r35756 if "deltacomputer" is not provided or None, a defaultdeltacomputer will
be used.
Sune Foldager
revlog: add docstring to _addrevision
r14292 invariants:
Jun Wu
revlog: make _addrevision only accept rawtext...
r31755 - rawtext is optional (can be None); if not set, cachedelta must be set.
Mads Kiilerich
fix trivial spelling errors
r17424 if both are set, they must correspond to each other.
Sune Foldager
revlog: add docstring to _addrevision
r14292 """
Martin von Zweigbergk
revlog: abort on attempt to write null revision...
r33939 if node == nullid:
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.RevlogError(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b"%s: attempt to add null revision") % self.indexfile
Augie Fackler
formatting: blacken the codebase...
r43346 )
Yuya Nishihara
revlog: detect pseudo file nodeids to raise WdirUnsupported exception...
r37467 if node == wdirid or node in wdirfilenodeids:
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.RevlogError(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b"%s: attempt to add wdir revision") % self.indexfile
Augie Fackler
formatting: blacken the codebase...
r43346 )
Martin von Zweigbergk
revlog: move check for wdir from changelog to revlog...
r34029
Paul Morelle
revlog: choose between ifh and dfh once for all
r35653 if self._inline:
fh = ifh
else:
fh = dfh
Jun Wu
revlog: make _addrevision only accept rawtext...
r31755 btext = [rawtext]
Benoit Boissinot
revlog._addrevision(): allow text argument to be None, build it lazily
r12623
Matt Mackall
add __len__ and __iter__ methods to repo and revlog
r6750 curr = len(self)
Matt Mackall
revlog: simplify addrevision...
r4981 prev = curr - 1
Raphaël Gomès
revlogv2: don't assume that the sidedata of the last rev is right after data...
r47444
offset = self._get_data_offset(prev)
Kyle Lippincott
revlog: add a mechanism to verify expected file position before appending...
r47349
if self._concurrencychecker:
if self._inline:
# offset is "as if" it were in the .d file, so we need to add on
# the size of the entry metadata.
self._concurrencychecker(
ifh, self.indexfile, offset + curr * self._io.size
)
else:
# Entries in the .i are a consistent size.
self._concurrencychecker(
ifh, self.indexfile, curr * self._io.size
)
self._concurrencychecker(dfh, self.datafile, offset)
Matt Mackall
revlog: precalculate p1 and p2 revisions
r12889 p1r, p2r = self.rev(p1), self.rev(p2)
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
Durham Goode
revlog: move textlen calculation to be above delta chooser...
r26116 # full versions are inserted when the needed deltas
# become comparable to the uncompressed text
Jun Wu
revlog: make _addrevision only accept rawtext...
r31755 if rawtext is None:
Jun Wu
revlog: resolve lfs rawtext to vanilla rawtext before applying delta...
r36766 # need rawtext size, before changed by flag processors, which is
# the non-raw size. use revlog explicitly to avoid filelog's extra
# logic that might remove metadata size.
Augie Fackler
formatting: blacken the codebase...
r43346 textlen = mdiff.patchedsize(
revlog.size(self, cachedelta[0]), cachedelta[1]
)
Durham Goode
revlog: move textlen calculation to be above delta chooser...
r26116 else:
Jun Wu
revlog: make _addrevision only accept rawtext...
r31755 textlen = len(rawtext)
Durham Goode
revlog: move textlen calculation to be above delta chooser...
r26116
Paul Morelle
revlog: group delta computation methods under _deltacomputer object...
r35756 if deltacomputer is None:
Boris Feld
revlog: split functionality related to deltas computation in a new module...
r39366 deltacomputer = deltautil.deltacomputer(self)
Paul Morelle
revlog: group delta computation methods under _deltacomputer object...
r35756
Paul Morelle
revlog: refactor out _finddeltainfo from _addrevision...
r35755 revinfo = _revisioninfo(node, p1, p2, btext, textlen, cachedelta, flags)
Jun Wu
revlog: do not use delta for lfs revisions...
r36765
Boris Feld
revlogdeltas: move special cases around raw revisions in finddeltainfo...
r39368 deltainfo = deltacomputer.finddeltainfo(revinfo, fh)
Paul Morelle
revlog: refactor out the selection of candidate revisions...
r35652
Raphaël Gomès
sidedata: move to new sidedata storage in revlogv2...
r47443 if sidedata:
serialized_sidedata = sidedatautil.serialize_sidedata(sidedata)
sidedata_offset = offset + deltainfo.deltalen
else:
serialized_sidedata = b""
# Don't store the offset if the sidedata is empty, that way
# we can easily detect empty sidedata and they will be no different
# than ones we manually add.
sidedata_offset = 0
Augie Fackler
formatting: blacken the codebase...
r43346 e = (
offset_type(offset, flags),
deltainfo.deltalen,
textlen,
deltainfo.base,
link,
p1r,
p2r,
node,
Raphaël Gomès
sidedata: move to new sidedata storage in revlogv2...
r47443 sidedata_offset,
len(serialized_sidedata),
Augie Fackler
formatting: blacken the codebase...
r43346 )
Raphaël Gomès
revlog: introduce v2 format...
r47438
if self.version & 0xFFFF != REVLOGV2:
e = e[:8]
Martin von Zweigbergk
index: replace insert(-1, e) method by append(e) method...
r38886 self.index.append(e)
Alexis S. L. Carvalho
revlog: fix revlogio.packentry corner case...
r5338 entry = self._io.packentry(e, self.node, self.version, curr)
Augie Fackler
formatting: blacken the codebase...
r43346 self._writeentry(
Raphaël Gomès
sidedata: move to new sidedata storage in revlogv2...
r47443 transaction,
ifh,
dfh,
entry,
deltainfo.data,
link,
offset,
serialized_sidedata,
Augie Fackler
formatting: blacken the codebase...
r43346 )
Boris Feld
revlogdeltas: always return a delta info object in finddeltainfo...
r39369
rawtext = btext[0]
Durham Goode
revlog: move file writing to a separate function...
r20217
Jun Wu
revlog: make _addrevision only accept rawtext...
r31755 if alwayscache and rawtext is None:
Boris Feld
revlog: fix typo in 'buildtext' name...
r39228 rawtext = deltacomputer.buildtext(revinfo, fh)
Gregory Szorc
revlog: optionally cache the full text when adding revisions...
r26243
Augie Fackler
formatting: blacken the codebase...
r43346 if type(rawtext) == bytes: # only accept immutable objects
Gregory Szorc
revlog: rename _cache to _revisioncache...
r40088 self._revisioncache = (node, curr, rawtext)
Boris Feld
revlogdeltas: always return a delta info object in finddeltainfo...
r39369 self._chainbasecache[curr] = deltainfo.chainbase
Joerg Sonnenberger
revlog: change _addrevision to return the new revision...
r47256 return curr
Durham Goode
revlog: move file writing to a separate function...
r20217
Raphaël Gomès
revlogv2: don't assume that the sidedata of the last rev is right after data...
r47444 def _get_data_offset(self, prev):
"""Returns the current offset in the (in-transaction) data file.
Versions < 2 of the revlog can get this 0(1), revlog v2 needs a docket
file to store that information: since sidedata can be rewritten to the
end of the data file within a transaction, you can have cases where, for
example, rev `n` does not have sidedata while rev `n - 1` does, leading
to `n - 1`'s sidedata being written after `n`'s data.
TODO cache this in a docket file before getting out of experimental."""
if self.version & 0xFFFF != REVLOGV2:
return self.end(prev)
offset = 0
for rev, entry in enumerate(self.index):
sidedata_end = entry[8] + entry[9]
# Sidedata for a previous rev has potentially been written after
# this rev's end, so take the max.
offset = max(self.end(rev), offset, sidedata_end)
return offset
Raphaël Gomès
sidedata: move to new sidedata storage in revlogv2...
r47443 def _writeentry(
self, transaction, ifh, dfh, entry, data, link, offset, sidedata
):
Gregory Szorc
revlog: seek to end of file before writing (issue4943)...
r27430 # Files opened in a+ mode have inconsistent behavior on various
# platforms. Windows requires that a file positioning call be made
# when the file handle transitions between reads and writes. See
# 3686fa2b8eee and the mixedfilemodewrapper in windows.py. On other
# platforms, Python or the platform itself can be buggy. Some versions
# of Solaris have been observed to not append at the end of the file
# if the file was seeked to before the end. See issue4943 for more.
#
# We work around this issue by inserting a seek() before writing.
Gregory Szorc
revlog: automatically read from opened file handles...
r40661 # Note: This is likely not necessary on Python 3. However, because
# the file handle is reused for reads and may be seeked there, we need
# to be careful before changing this.
Gregory Szorc
revlog: seek to end of file before writing (issue4943)...
r27430 ifh.seek(0, os.SEEK_END)
Martin von Zweigbergk
revlog: fix bad indentation (replace tab by space)
r27441 if dfh:
Gregory Szorc
revlog: seek to end of file before writing (issue4943)...
r27430 dfh.seek(0, os.SEEK_END)
Durham Goode
revlog: move file writing to a separate function...
r20217 curr = len(self) - 1
Matt Mackall
revlog: change _inline from a function to a variable
r4982 if not self._inline:
mason@suse.com
Implement data inlined with the index file...
r2073 transaction.add(self.datafile, offset)
Matt Mackall
revlog: simplify addrevision...
r4981 transaction.add(self.indexfile, curr * len(entry))
mason@suse.com
Implement data inlined with the index file...
r2073 if data[0]:
Alexis S. L. Carvalho
make revlog.addgroup pass its file handles to addrevision...
r3390 dfh.write(data[0])
dfh.write(data[1])
Raphaël Gomès
sidedata: move to new sidedata storage in revlogv2...
r47443 if sidedata:
dfh.write(sidedata)
Matt Mackall
revlog: simplify addrevision...
r4981 ifh.write(entry)
mason@suse.com
Implement data inlined with the index file...
r2073 else:
Matt Mackall
revlog: avoid some unnecessary seek/tell syscalls
r4996 offset += curr * self._io.size
Joerg Sonnenberger
transaction: drop per-file extra data support...
r46481 transaction.add(self.indexfile, offset)
Matt Mackall
revlog: simplify addrevision...
r4981 ifh.write(entry)
Alexis S. L. Carvalho
make revlog.addgroup pass its file handles to addrevision...
r3390 ifh.write(data[0])
ifh.write(data[1])
Raphaël Gomès
sidedata: move to new sidedata storage in revlogv2...
r47443 if sidedata:
ifh.write(sidedata)
Boris Feld
revlog: rename 'self.checkinlinesize' into '_enforceinlinesize'...
r35992 self._enforceinlinesize(transaction, ifh)
nodemap: write nodemap data on disk...
r44789 nodemaputil.setup_persistent_nodemap(transaction, self)
mason@suse.com
Implement data inlined with the index file...
r2073
Joerg Sonnenberger
revlog: extend addgroup() with callback for duplicates...
r46373 def addgroup(
self,
deltas,
linkmapper,
transaction,
Joerg Sonnenberger
revlog: decouple caching from addrevision callback for addgroup...
r47085 alwayscache=False,
Joerg Sonnenberger
revlog: extend addgroup() with callback for duplicates...
r46373 addrevisioncb=None,
duplicaterevisioncb=None,
):
mpm@selenic.com
Add some docstrings to revlog.py
r1083 """
add a delta group
mpm@selenic.com
Add changegroup support
r46
mpm@selenic.com
Add some docstrings to revlog.py
r1083 given a set of deltas, add them to the revision log. the
first delta is against its parent, which should be in our
log, the rest are against the previous delta.
Gregory Szorc
revlog: add support for a callback whenever revisions are added...
r25822
If ``addrevisioncb`` is defined, it will be called with arguments of
this revlog and the node that was added.
mpm@selenic.com
Add some docstrings to revlog.py
r1083 """
Gregory Szorc
revlog: automatically read from opened file handles...
r40661 if self._writinghandles:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.ProgrammingError(b'cannot nest addgroup() calls')
Gregory Szorc
revlog: automatically read from opened file handles...
r40661
Benoit Boissinot
revlog.addgroup(): always use _addrevision() to add new revlog entries...
r12624 r = len(self)
end = 0
mpm@selenic.com
Add changegroup support
r46 if r:
Benoit Boissinot
revlog.addgroup(): always use _addrevision() to add new revlog entries...
r12624 end = self.end(r - 1)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ifh = self._indexfp(b"a+")
Matt Mackall
revlog: avoid some unnecessary seek/tell syscalls
r4996 isize = r * self._io.size
Matt Mackall
revlog: change _inline from a function to a variable
r4982 if self._inline:
Joerg Sonnenberger
transaction: drop per-file extra data support...
r46481 transaction.add(self.indexfile, end + isize)
mason@suse.com
Implement data inlined with the index file...
r2073 dfh = None
else:
Joerg Sonnenberger
transaction: drop per-file extra data support...
r46481 transaction.add(self.indexfile, isize)
mason@suse.com
Implement data inlined with the index file...
r2073 transaction.add(self.datafile, end)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 dfh = self._datafp(b"a+")
Augie Fackler
formatting: blacken the codebase...
r43346
Mike Edgar
revlog: addgroup checks if incoming deltas add censored revs, sets flag bit...
r24255 def flush():
if dfh:
dfh.flush()
ifh.flush()
Gregory Szorc
revlog: automatically read from opened file handles...
r40661
self._writinghandles = (ifh, dfh)
Joerg Sonnenberger
revlog: extend addgroup() with callback for duplicates...
r46373 empty = True
Gregory Szorc
revlog: automatically read from opened file handles...
r40661
Benoit Boissinot
revlog: make sure the files are closed after an exception happens...
r6261 try:
Boris Feld
revlog: split functionality related to deltas computation in a new module...
r39366 deltacomputer = deltautil.deltacomputer(self)
Benoit Boissinot
revlog: make sure the files are closed after an exception happens...
r6261 # loop through our set of deltas
Durham Goode
changegroup: remove changegroup dependency from revlog.addgroup...
r34147 for data in deltas:
Raphaël Gomès
changegroup: add v4 changegroup for revlog v2 exchange...
r47445 node, p1, p2, linknode, deltabase, delta, flags, sidedata = data
Durham Goode
revlog: add revmap back to revlog.addgroup...
r34292 link = linkmapper(linknode)
Durham Goode
changegroup: remove changegroup dependency from revlog.addgroup...
r34147 flags = flags or REVIDX_DEFAULT_FLAGS
Matt Mackall
bundle: move chunk parsing into unbundle class
r12336
Joerg Sonnenberger
revlog: change addgroup callbacks to take revision numbers...
r47259 rev = self.index.get_rev(node)
if rev is not None:
Joerg Sonnenberger
revlog: extend addgroup() with callback for duplicates...
r46373 # this can happen if two branches make the same change
Joerg Sonnenberger
revlog: change addgroup callbacks to take revision numbers...
r47259 self._nodeduplicatecallback(transaction, rev)
Joerg Sonnenberger
revlog: extend addgroup() with callback for duplicates...
r46373 if duplicaterevisioncb:
Joerg Sonnenberger
revlog: change addgroup callbacks to take revision numbers...
r47259 duplicaterevisioncb(self, rev)
Joerg Sonnenberger
revlog: extend addgroup() with callback for duplicates...
r46373 empty = False
Benoit Boissinot
revlog: make sure the files are closed after an exception happens...
r6261 continue
mpm@selenic.com
Changes to network protocol...
r192
Benoit Boissinot
revlog: make sure the files are closed after an exception happens...
r6261 for p in (p1, p2):
index: use `index.has_node` in `revlog.addgroup`...
r43936 if not self.index.has_node(p):
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.LookupError(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 p, self.indexfile, _(b'unknown parent')
Augie Fackler
formatting: blacken the codebase...
r43346 )
mpm@selenic.com
Add changegroup support
r46
index: use `index.has_node` in `revlog.addgroup`...
r43936 if not self.index.has_node(deltabase):
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.LookupError(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 deltabase, self.indexfile, _(b'unknown delta base')
Augie Fackler
formatting: blacken the codebase...
r43346 )
mpm@selenic.com
Add changegroup support
r46
Benoit Boissinot
bundler: make parsechunk return the base revision of the delta
r14141 baserev = self.rev(deltabase)
Mike Edgar
revlog: in addgroup, reject ill-formed deltas based on censored nodes...
r24120
if baserev != nullrev and self.iscensored(baserev):
# if base is censored, delta must be full replacement in a
# single patch operation
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 hlen = struct.calcsize(b">lll")
Mike Edgar
revlog: in addgroup, reject ill-formed deltas based on censored nodes...
r24120 oldlen = self.rawsize(baserev)
newlen = len(delta) - hlen
if delta[:hlen] != mdiff.replacediffheader(oldlen, newlen):
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.CensoredBaseError(
self.indexfile, self.node(baserev)
)
Mike Edgar
revlog: in addgroup, reject ill-formed deltas based on censored nodes...
r24120
Mike Edgar
changegroup: add flags field to cg3 delta header...
r27433 if not flags and self._peek_iscensored(baserev, delta, flush):
Mike Edgar
revlog: addgroup checks if incoming deltas add censored revs, sets flag bit...
r24255 flags |= REVIDX_ISCENSORED
Gregory Szorc
revlog: optionally cache the full text when adding revisions...
r26243 # We assume consumers of addrevisioncb will want to retrieve
# the added revision, which will require a call to
# revision(). revision() will fast path if there is a cache
# hit. So, we tell _addrevision() to always cache in this case.
Remi Chaintron
revlog: add 'raw' argument to revision and _addrevision...
r30743 # We're only using addgroup() in the context of changegroup
# generation so the revision data can always be handled as raw
# by the flagprocessor.
Joerg Sonnenberger
revlog: change addgroup callbacks to take revision numbers...
r47259 rev = self._addrevision(
Augie Fackler
formatting: blacken the codebase...
r43346 node,
None,
transaction,
link,
p1,
p2,
flags,
(baserev, delta),
ifh,
dfh,
Joerg Sonnenberger
revlog: decouple caching from addrevision callback for addgroup...
r47085 alwayscache=alwayscache,
Augie Fackler
formatting: blacken the codebase...
r43346 deltacomputer=deltacomputer,
Raphaël Gomès
delta: add sidedata field to revision delta...
r47446 sidedata=sidedata,
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
revlog: add support for a callback whenever revisions are added...
r25822
if addrevisioncb:
Joerg Sonnenberger
revlog: change addgroup callbacks to take revision numbers...
r47259 addrevisioncb(self, rev)
Joerg Sonnenberger
revlog: extend addgroup() with callback for duplicates...
r46373 empty = False
Gregory Szorc
revlog: add support for a callback whenever revisions are added...
r25822
Benoit Boissinot
revlog.addgroup(): always use _addrevision() to add new revlog entries...
r12624 if not dfh and not self._inline:
# addrevision switched from inline to conventional
# reopen the index
Dan Villiom Podlaski Christiansen
explicitly close files...
r13400 ifh.close()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 dfh = self._datafp(b"a+")
ifh = self._indexfp(b"a+")
Gregory Szorc
revlog: automatically read from opened file handles...
r40661 self._writinghandles = (ifh, dfh)
Benoit Boissinot
revlog: make sure the files are closed after an exception happens...
r6261 finally:
Gregory Szorc
revlog: automatically read from opened file handles...
r40661 self._writinghandles = None
Benoit Boissinot
revlog: make sure the files are closed after an exception happens...
r6261 if dfh:
dfh.close()
ifh.close()
Joerg Sonnenberger
revlog: extend addgroup() with callback for duplicates...
r46373 return not empty
Matt Mackall
verify: add check for mismatch of index and data length
r1493
Mike Edgar
revlog: add "iscensored()" to revlog public API...
r24118 def iscensored(self, rev):
"""Check if a file revision is censored."""
Gregory Szorc
revlog: move censor logic into main revlog class...
r37461 if not self._censorable:
return False
return self.flags(rev) & REVIDX_ISCENSORED
Mike Edgar
revlog: add "iscensored()" to revlog public API...
r24118
Mike Edgar
revlog: addgroup checks if incoming deltas add censored revs, sets flag bit...
r24255 def _peek_iscensored(self, baserev, delta, flush):
"""Quickly check if a delta produces a censored revision."""
Gregory Szorc
revlog: move censor logic into main revlog class...
r37461 if not self._censorable:
return False
Gregory Szorc
storageutil: extract most of peek_censored from revlog...
r40361 return storageutil.deltaiscensored(delta, baserev, self.rawsize)
Mike Edgar
revlog: addgroup checks if incoming deltas add censored revs, sets flag bit...
r24255
Durham Goode
strip: add faster revlog strip computation...
r20074 def getstrippoint(self, minlink):
"""find the minimum rev that must be stripped to strip the linkrev
Returns a tuple containing the minimum rev and a set of all revs that
have linkrevs that will be broken by this strip.
"""
Augie Fackler
formatting: blacken the codebase...
r43346 return storageutil.resolvestripinfo(
minlink,
len(self) - 1,
self.headrevs(),
self.linkrev,
self.parentrevs,
)
Durham Goode
strip: add faster revlog strip computation...
r20074
Henrik Stuart
strip: make repair.strip transactional to avoid repository corruption...
r8073 def strip(self, minlink, transaction):
Alexis S. L. Carvalho
simplify revlog.strip interface and callers; add docstring...
r5910 """truncate the revlog on the first revision with a linkrev >= minlink
This function is called when we're stripping revision minlink and
its descendants from the repository.
We have to remove all revisions with linkrev >= minlink, because
the equivalent changelog revisions will be renumbered after the
strip.
So we truncate the revlog on the first of these revisions, and
trust that the caller has saved the revisions that shouldn't be
Steven Brown
revlog: clarify strip docstring "readd" -> "re-add"...
r15827 removed and that it'll re-add them after this truncation.
Alexis S. L. Carvalho
simplify revlog.strip interface and callers; add docstring...
r5910 """
Matt Mackall
add __len__ and __iter__ methods to repo and revlog
r6750 if len(self) == 0:
mason@suse.com
Add revlog.strip to truncate away revisions....
r1535 return
Durham Goode
strip: add faster revlog strip computation...
r20074 rev, _ = self.getstrippoint(minlink)
if rev == len(self):
Alexis S. L. Carvalho
strip: calculate list of extra nodes to save and pass it to changegroupsubset...
r5909 return
mason@suse.com
Add revlog.strip to truncate away revisions....
r1535
# first truncate the files on disk
end = self.start(rev)
Matt Mackall
revlog: change _inline from a function to a variable
r4982 if not self._inline:
Henrik Stuart
strip: make repair.strip transactional to avoid repository corruption...
r8073 transaction.add(self.datafile, end)
Matt Mackall
revlog: parse revlogv0 indexes into v1 internally...
r4977 end = rev * self._io.size
mason@suse.com
Implement data inlined with the index file...
r2073 else:
Matt Mackall
revlog: parse revlogv0 indexes into v1 internally...
r4977 end += rev * self._io.size
mason@suse.com
Implement revlogng....
r2072
Henrik Stuart
strip: make repair.strip transactional to avoid repository corruption...
r8073 transaction.add(self.indexfile, end)
mason@suse.com
Add revlog.strip to truncate away revisions....
r1535
# then reset internal state in memory to forget those revisions
Gregory Szorc
revlog: rename _cache to _revisioncache...
r40088 self._revisioncache = None
Joerg Sonnenberger
revlog: use LRU for the chain cache...
r46364 self._chaininfocache = util.lrucachedict(500)
Matt Mackall
revlog: refactor chunk cache interface again...
r8650 self._chunkclear()
mason@suse.com
Add revlog.strip to truncate away revisions....
r1535
Matt Mackall
revlog: add a magic null revision to our index...
r4979 del self.index[rev:-1]
mason@suse.com
Add revlog.strip to truncate away revisions....
r1535
Matt Mackall
verify: add check for mismatch of index and data length
r1493 def checksize(self):
revlog: add some documentation to the `checksize` method...
r42038 """Check size of index and data files
return a (dd, di) tuple.
- dd: extra bytes for the "data" file
- di: extra bytes for the "index" file
A healthy revlog will return (0, 0).
"""
Matt Mackall
verify: add check for mismatch of index and data length
r1493 expected = 0
Matt Mackall
add __len__ and __iter__ methods to repo and revlog
r6750 if len(self):
expected = max(0, self.end(len(self) - 1))
Matt Mackall
verify: notice extra data in indices
r1667
Matt Mackall
Handle empty logs in repo.checksize
r1494 try:
Boris Feld
revlog: use context manager for data file lifetime in checksize...
r35990 with self._datafp() as f:
Augie Fackler
cleanup: use named constants for second arg to .seek()...
r42767 f.seek(0, io.SEEK_END)
Boris Feld
revlog: use context manager for data file lifetime in checksize...
r35990 actual = f.tell()
Matt Mackall
verify: notice extra data in indices
r1667 dd = actual - expected
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except IOError as inst:
Matt Mackall
verify: notice extra data in indices
r1667 if inst.errno != errno.ENOENT:
raise
dd = 0
try:
f = self.opener(self.indexfile)
Augie Fackler
cleanup: use named constants for second arg to .seek()...
r42767 f.seek(0, io.SEEK_END)
Matt Mackall
verify: notice extra data in indices
r1667 actual = f.tell()
Dan Villiom Podlaski Christiansen
explicitly close files...
r13400 f.close()
Matt Mackall
revlog: parse revlogv0 indexes into v1 internally...
r4977 s = self._io.size
Alejandro Santos
compat: use // for integer division
r9029 i = max(0, actual // s)
Matt Mackall
verify: notice extra data in indices
r1667 di = actual - (i * s)
Matt Mackall
revlog: change _inline from a function to a variable
r4982 if self._inline:
mason@suse.com
Implement data inlined with the index file...
r2073 databytes = 0
Matt Mackall
add __len__ and __iter__ methods to repo and revlog
r6750 for r in self:
Matt Mackall
revlog: more robust for damaged indexes...
r5312 databytes += max(0, self.length(r))
mason@suse.com
Implement data inlined with the index file...
r2073 dd = 0
Matt Mackall
add __len__ and __iter__ methods to repo and revlog
r6750 di = actual - len(self) * s - databytes
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except IOError as inst:
Matt Mackall
verify: notice extra data in indices
r1667 if inst.errno != errno.ENOENT:
raise
di = 0
return (dd, di)
Adrian Buehlmann
revlog: add files method
r6891
def files(self):
Matt Mackall
many, many trivial check-code fixups
r10282 res = [self.indexfile]
Adrian Buehlmann
revlog: add files method
r6891 if not self._inline:
res.append(self.datafile)
return res
Gregory Szorc
revlog: add clone method...
r30778
Augie Fackler
formatting: blacken the codebase...
r43346 def emitrevisions(
self,
nodes,
nodesorder=None,
revisiondata=False,
assumehaveparentrevisions=False,
deltamode=repository.CG_DELTAMODE_STD,
Raphaël Gomès
changegroupv4: add sidedata helpers...
r47449 sidedata_helpers=None,
Augie Fackler
formatting: blacken the codebase...
r43346 ):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if nodesorder not in (b'nodes', b'storage', b'linear', None):
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.ProgrammingError(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'unhandled value for nodesorder: %s' % nodesorder
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
revlog: new API to emit revision data...
r39898
if nodesorder is None and not self._generaldelta:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 nodesorder = b'storage'
Gregory Szorc
revlog: new API to emit revision data...
r39898
Augie Fackler
formatting: blacken the codebase...
r43346 if (
not self._storedeltachains
and deltamode != repository.CG_DELTAMODE_PREV
):
Boris Feld
changegroup: refactor emitrevision to use a `deltamode` argument...
r40456 deltamode = repository.CG_DELTAMODE_FULL
Gregory Szorc
storageutil: extract most of emitrevisions() to standalone function...
r40044 return storageutil.emitrevisions(
Augie Fackler
formatting: blacken the codebase...
r43346 self,
nodes,
nodesorder,
revlogrevisiondelta,
Gregory Szorc
storageutil: extract most of emitrevisions() to standalone function...
r40044 deltaparentfn=self.deltaparent,
candeltafn=self.candelta,
rawsizefn=self.rawsize,
revdifffn=self.revdiff,
flagsfn=self.flags,
Boris Feld
changegroup: refactor emitrevision to use a `deltamode` argument...
r40456 deltamode=deltamode,
Gregory Szorc
storageutil: extract most of emitrevisions() to standalone function...
r40044 revisiondata=revisiondata,
Augie Fackler
formatting: blacken the codebase...
r43346 assumehaveparentrevisions=assumehaveparentrevisions,
Raphaël Gomès
changegroupv4: add sidedata helpers...
r47449 sidedata_helpers=sidedata_helpers,
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
revlog: new API to emit revision data...
r39898
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 DELTAREUSEALWAYS = b'always'
DELTAREUSESAMEREVS = b'samerevs'
DELTAREUSENEVER = b'never'
DELTAREUSEFULLADD = b'fulladd'
DELTAREUSEALL = {b'always', b'samerevs', b'never', b'fulladd'}
Gregory Szorc
revlog: add clone method...
r30778
Augie Fackler
formatting: blacken the codebase...
r43346 def clone(
self,
tr,
destrevlog,
addrevisioncb=None,
deltareuse=DELTAREUSESAMEREVS,
forcedeltabothparents=None,
revlog: add a way to control sidedata changes during revlog.clone...
r43403 sidedatacompanion=None,
Augie Fackler
formatting: blacken the codebase...
r43346 ):
Gregory Szorc
revlog: add clone method...
r30778 """Copy this revlog to another, possibly with format changes.
The destination revlog will contain the same revisions and nodes.
However, it may not be bit-for-bit identical due to e.g. delta encoding
differences.
The ``deltareuse`` argument control how deltas from the existing revlog
are preserved in the destination revlog. The argument can have the
following values:
DELTAREUSEALWAYS
Deltas will always be reused (if possible), even if the destination
revlog would not select the same revisions for the delta. This is the
fastest mode of operation.
DELTAREUSESAMEREVS
Deltas will be reused if the destination revlog would pick the same
revisions for the delta. This mode strikes a balance between speed
and optimization.
DELTAREUSENEVER
Deltas will never be reused. This is the slowest mode of execution.
This mode can be used to recompute deltas (e.g. if the diff/delta
algorithm changes).
upgrade: document DELTAREUSEFULLADD in revlog.clone...
r43267 DELTAREUSEFULLADD
Revision will be re-added as if their were new content. This is
slower than DELTAREUSEALWAYS but allow more mechanism to kicks in.
eg: large file detection and handling.
Gregory Szorc
revlog: add clone method...
r30778
Delta computation can be slow, so the choice of delta reuse policy can
significantly affect run time.
The default policy (``DELTAREUSESAMEREVS``) strikes a balance between
two extremes. Deltas will be reused if they are appropriate. But if the
delta could choose a better revision, it will do so. This means if you
are converting a non-generaldelta revlog to a generaldelta revlog,
deltas will be recomputed if the delta's parent isn't a parent of the
revision.
Boris Feld
upgrade: clarify "aggressivemergedelta" handling...
r40872 In addition to the delta policy, the ``forcedeltabothparents``
argument controls whether to force compute deltas against both parents
for merges. By default, the current default is used.
revlog: add a way to control sidedata changes during revlog.clone...
r43403
If not None, the `sidedatacompanion` is callable that accept two
arguments:
(srcrevlog, rev)
upgrade: allow sidedata upgrade to modify revision flag...
r46327 and return a quintet that control changes to sidedata content from the
revlog: add a way to control sidedata changes during revlog.clone...
r43403 old revision to the new clone result:
upgrade: allow sidedata upgrade to modify revision flag...
r46327 (dropall, filterout, update, new_flags, dropped_flags)
revlog: add a way to control sidedata changes during revlog.clone...
r43403
* if `dropall` is True, all sidedata should be dropped
* `filterout` is a set of sidedata keys that should be dropped
* `update` is a mapping of additionnal/new key -> value
upgrade: allow sidedata upgrade to modify revision flag...
r46327 * new_flags is a bitfields of new flags that the revision should get
* dropped_flags is a bitfields of new flags that the revision shoudl not longer have
Gregory Szorc
revlog: add clone method...
r30778 """
if deltareuse not in self.DELTAREUSEALL:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise ValueError(
_(b'value for deltareuse invalid: %s') % deltareuse
)
Gregory Szorc
revlog: add clone method...
r30778
if len(destrevlog):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise ValueError(_(b'destination revlog is not empty'))
Gregory Szorc
revlog: add clone method...
r30778
if getattr(self, 'filteredrevs', None):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise ValueError(_(b'source revlog has filtered revisions'))
Gregory Szorc
revlog: add clone method...
r30778 if getattr(destrevlog, 'filteredrevs', None):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise ValueError(_(b'destination revlog has filtered revisions'))
Gregory Szorc
revlog: add clone method...
r30778
revlog: preserve `_lazydelta` attribute in `revlog.clone`...
r42023 # lazydelta and lazydeltabase controls whether to reuse a cached delta,
# if possible.
oldlazydelta = destrevlog._lazydelta
Gregory Szorc
revlog: add clone method...
r30778 oldlazydeltabase = destrevlog._lazydeltabase
Boris Feld
aggressivemergedeltas: rename variable internally...
r38759 oldamd = destrevlog._deltabothparents
Gregory Szorc
revlog: add clone method...
r30778
try:
if deltareuse == self.DELTAREUSEALWAYS:
destrevlog._lazydeltabase = True
revlog: preserve `_lazydelta` attribute in `revlog.clone`...
r42023 destrevlog._lazydelta = True
Gregory Szorc
revlog: add clone method...
r30778 elif deltareuse == self.DELTAREUSESAMEREVS:
destrevlog._lazydeltabase = False
revlog: preserve `_lazydelta` attribute in `revlog.clone`...
r42023 destrevlog._lazydelta = True
elif deltareuse == self.DELTAREUSENEVER:
destrevlog._lazydeltabase = False
destrevlog._lazydelta = False
Gregory Szorc
revlog: add clone method...
r30778
Boris Feld
upgrade: clarify "aggressivemergedelta" handling...
r40872 destrevlog._deltabothparents = forcedeltabothparents or oldamd
Gregory Szorc
revlog: add clone method...
r30778
Augie Fackler
formatting: blacken the codebase...
r43346 self._clone(
revlog: add a way to control sidedata changes during revlog.clone...
r43403 tr,
destrevlog,
addrevisioncb,
deltareuse,
forcedeltabothparents,
sidedatacompanion,
Augie Fackler
formatting: blacken the codebase...
r43346 )
upgrade: move most of revlog.clone method into a _clone method...
r43266
Gregory Szorc
revlog: add clone method...
r30778 finally:
revlog: preserve `_lazydelta` attribute in `revlog.clone`...
r42023 destrevlog._lazydelta = oldlazydelta
Gregory Szorc
revlog: add clone method...
r30778 destrevlog._lazydeltabase = oldlazydeltabase
Boris Feld
aggressivemergedeltas: rename variable internally...
r38759 destrevlog._deltabothparents = oldamd
Gregory Szorc
revlog: move censor logic out of censor extension...
r39814
Augie Fackler
formatting: blacken the codebase...
r43346 def _clone(
revlog: add a way to control sidedata changes during revlog.clone...
r43403 self,
tr,
destrevlog,
addrevisioncb,
deltareuse,
forcedeltabothparents,
sidedatacompanion,
Augie Fackler
formatting: blacken the codebase...
r43346 ):
upgrade: move most of revlog.clone method into a _clone method...
r43266 """perform the core duty of `revlog.clone` after parameter processing"""
deltacomputer = deltautil.deltacomputer(destrevlog)
index = self.index
for rev in self:
entry = index[rev]
# Some classes override linkrev to take filtered revs into
# account. Use raw entry from index.
Augie Fackler
formatting: blacken the codebase...
r43346 flags = entry[0] & 0xFFFF
upgrade: move most of revlog.clone method into a _clone method...
r43266 linkrev = entry[4]
p1 = index[entry[5]][7]
p2 = index[entry[6]][7]
node = entry[7]
upgrade: allow sidedata upgrade to modify revision flag...
r46327 sidedataactions = (False, [], {}, 0, 0)
revlog: add a way to control sidedata changes during revlog.clone...
r43403 if sidedatacompanion is not None:
sidedataactions = sidedatacompanion(self, rev)
upgrade: move most of revlog.clone method into a _clone method...
r43266 # (Possibly) reuse the delta from the revlog if allowed and
# the revlog chunk is a delta.
cachedelta = None
rawtext = None
revlog: add a way to control sidedata changes during revlog.clone...
r43403 if any(sidedataactions) or deltareuse == self.DELTAREUSEFULLADD:
upgrade: allow sidedata upgrade to modify revision flag...
r46327 dropall = sidedataactions[0]
filterout = sidedataactions[1]
update = sidedataactions[2]
new_flags = sidedataactions[3]
dropped_flags = sidedataactions[4]
revlog: add a way to control sidedata changes during revlog.clone...
r43403 text, sidedata = self._revisiondata(rev)
if dropall:
sidedata = {}
for key in filterout:
sidedata.pop(key, None)
sidedata.update(update)
if not sidedata:
sidedata = None
upgrade: allow sidedata upgrade to modify revision flag...
r46327
flags |= new_flags
flags &= ~dropped_flags
Augie Fackler
formatting: blacken the codebase...
r43346 destrevlog.addrevision(
text,
tr,
linkrev,
p1,
p2,
cachedelta=cachedelta,
node=node,
flags=flags,
deltacomputer=deltacomputer,
revlog: add a way to control sidedata changes during revlog.clone...
r43403 sidedata=sidedata,
Augie Fackler
formatting: blacken the codebase...
r43346 )
upgrade: move most of revlog.clone method into a _clone method...
r43266 else:
upgrade: fix DELTAREUSEFULLADD implementation in revlog.clone...
r43268 if destrevlog._lazydelta:
dp = self.deltaparent(rev)
if dp != nullrev:
cachedelta = (dp, bytes(self._chunk(rev)))
if not cachedelta:
rawtext = self.rawdata(rev)
Augie Fackler
formatting: blacken the codebase...
r43346 ifh = destrevlog.opener(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 destrevlog.indexfile, b'a+', checkambig=False
Augie Fackler
formatting: blacken the codebase...
r43346 )
upgrade: move most of revlog.clone method into a _clone method...
r43266 dfh = None
if not destrevlog._inline:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 dfh = destrevlog.opener(destrevlog.datafile, b'a+')
upgrade: move most of revlog.clone method into a _clone method...
r43266 try:
Augie Fackler
formatting: blacken the codebase...
r43346 destrevlog._addrevision(
node,
rawtext,
tr,
linkrev,
p1,
p2,
flags,
cachedelta,
ifh,
dfh,
deltacomputer=deltacomputer,
)
upgrade: move most of revlog.clone method into a _clone method...
r43266 finally:
if dfh:
dfh.close()
ifh.close()
if addrevisioncb:
addrevisioncb(self, rev, node)
Gregory Szorc
revlog: rewrite censoring logic...
r40092 def censorrevision(self, tr, censornode, tombstone=b''):
Gregory Szorc
revlog: move censor logic out of censor extension...
r39814 if (self.version & 0xFFFF) == REVLOGV0:
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.RevlogError(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b'cannot censor with version %d revlogs') % self.version
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
revlog: move censor logic out of censor extension...
r39814
Gregory Szorc
revlog: rewrite censoring logic...
r40092 censorrev = self.rev(censornode)
Gregory Szorc
storageutil: move metadata parsing and packing from revlog (API)...
r39914 tombstone = storageutil.packmeta({b'censored': tombstone}, b'')
Gregory Szorc
revlog: move censor logic out of censor extension...
r39814
Gregory Szorc
revlog: rewrite censoring logic...
r40092 if len(tombstone) > self.rawsize(censorrev):
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.Abort(
Martin von Zweigbergk
cleanup: join string literals that are already on one line...
r43387 _(b'censor tombstone must be no longer than censored data')
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
revlog: move censor logic out of censor extension...
r39814
Gregory Szorc
revlog: rewrite censoring logic...
r40092 # Rewriting the revlog in place is hard. Our strategy for censoring is
# to create a new revlog, copy all revisions to it, then replace the
# revlogs on transaction close.
Gregory Szorc
revlog: move censor logic out of censor extension...
r39814
Gregory Szorc
revlog: rewrite censoring logic...
r40092 newindexfile = self.indexfile + b'.tmpcensored'
newdatafile = self.datafile + b'.tmpcensored'
Gregory Szorc
revlog: move censor logic out of censor extension...
r39814
Gregory Szorc
revlog: rewrite censoring logic...
r40092 # This is a bit dangerous. We could easily have a mismatch of state.
Augie Fackler
formatting: blacken the codebase...
r43346 newrl = revlog(self.opener, newindexfile, newdatafile, censorable=True)
Gregory Szorc
revlog: rewrite censoring logic...
r40092 newrl.version = self.version
newrl._generaldelta = self._generaldelta
newrl._io = self._io
Gregory Szorc
revlog: move censor logic out of censor extension...
r39814
Gregory Szorc
revlog: rewrite censoring logic...
r40092 for rev in self.revs():
node = self.node(rev)
p1, p2 = self.parents(node)
Gregory Szorc
revlog: move censor logic out of censor extension...
r39814
Gregory Szorc
revlog: rewrite censoring logic...
r40092 if rev == censorrev:
Augie Fackler
formatting: blacken the codebase...
r43346 newrl.addrawrevision(
tombstone,
tr,
self.linkrev(censorrev),
p1,
p2,
censornode,
REVIDX_ISCENSORED,
)
Gregory Szorc
revlog: move censor logic out of censor extension...
r39814
Gregory Szorc
revlog: rewrite censoring logic...
r40092 if newrl.deltaparent(rev) != nullrev:
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.Abort(
_(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'censored revision stored as delta; '
b'cannot censor'
Augie Fackler
formatting: blacken the codebase...
r43346 ),
hint=_(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'censoring of revlogs is not '
b'fully implemented; please report '
b'this bug'
Augie Fackler
formatting: blacken the codebase...
r43346 ),
)
Gregory Szorc
revlog: rewrite censoring logic...
r40092 continue
Gregory Szorc
revlog: move censor logic out of censor extension...
r39814
Gregory Szorc
revlog: rewrite censoring logic...
r40092 if self.iscensored(rev):
if self.deltaparent(rev) != nullrev:
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.Abort(
_(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'cannot censor due to censored '
b'revision having delta stored'
Augie Fackler
formatting: blacken the codebase...
r43346 )
)
Gregory Szorc
revlog: rewrite censoring logic...
r40092 rawtext = self._chunk(rev)
Gregory Szorc
revlog: move censor logic out of censor extension...
r39814 else:
rawdata: update caller in revlog...
r43036 rawtext = self.rawdata(rev)
Gregory Szorc
revlog: rewrite censoring logic...
r40092
Augie Fackler
formatting: blacken the codebase...
r43346 newrl.addrawrevision(
rawtext, tr, self.linkrev(rev), p1, p2, node, self.flags(rev)
)
Gregory Szorc
revlog: move censor logic out of censor extension...
r39814
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 tr.addbackup(self.indexfile, location=b'store')
Gregory Szorc
revlog: rewrite censoring logic...
r40092 if not self._inline:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 tr.addbackup(self.datafile, location=b'store')
Gregory Szorc
revlog: rewrite censoring logic...
r40092
self.opener.rename(newrl.indexfile, self.indexfile)
if not self._inline:
self.opener.rename(newrl.datafile, self.datafile)
self.clearcaches()
Gregory Szorc
revlog: inline opener options logic into _loadindex()...
r41240 self._loadindex()
Gregory Szorc
verify: start to abstract file verification...
r39878
def verifyintegrity(self, state):
"""Verifies the integrity of the revlog.
Yields ``revlogproblem`` instances describing problems that are
found.
"""
dd, di = self.checksize()
if dd:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 yield revlogproblem(error=_(b'data length off by %d bytes') % dd)
Gregory Szorc
verify: start to abstract file verification...
r39878 if di:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 yield revlogproblem(error=_(b'index contains %d extra bytes') % di)
Gregory Szorc
verify: start to abstract file verification...
r39878
Gregory Szorc
revlog: use proper version comparison during verify...
r39881 version = self.version & 0xFFFF
# The verifier tells us what version revlog we should be.
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if version != state[b'expectedversion']:
Gregory Szorc
revlog: use proper version comparison during verify...
r39881 yield revlogproblem(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 warning=_(b"warning: '%s' uses revlog format %d; expected %d")
% (self.indexfile, version, state[b'expectedversion'])
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
revlog: add method for obtaining storage info (API)...
r39905
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 state[b'skipread'] = set()
Matt Harbison
verify: allow the storage to signal when renames can be tested on `skipread`...
r44530 state[b'safe_renamed'] = set()
Gregory Szorc
revlog: move revision verification out of verify...
r39908
for rev in self:
node = self.node(rev)
# Verify contents. 4 cases to care about:
#
# common: the most common case
# rename: with a rename
# meta: file content starts with b'\1\n', the metadata
# header defined in filelog.py, but without a rename
# ext: content stored externally
#
# More formally, their differences are shown below:
#
# | common | rename | meta | ext
# -------------------------------------------------------
# flags() | 0 | 0 | 0 | not 0
# renamed() | False | True | False | ?
# rawtext[0:2]=='\1\n'| False | True | True | ?
#
# "rawtext" means the raw text stored in revlog data, which
rawdata: update caller in revlog...
r43036 # could be retrieved by "rawdata(rev)". "text"
# mentioned below is "revision(rev)".
Gregory Szorc
revlog: move revision verification out of verify...
r39908 #
# There are 3 different lengths stored physically:
# 1. L1: rawsize, stored in revlog index
# 2. L2: len(rawtext), stored in revlog data
# 3. L3: len(text), stored in revlog data if flags==0, or
# possibly somewhere else if flags!=0
#
# L1 should be equal to L2. L3 could be different from them.
# "text" may or may not affect commit hash depending on flag
flagutil: move addflagprocessor to the new module (API)
r42958 # processors (see flagutil.addflagprocessor).
Gregory Szorc
revlog: move revision verification out of verify...
r39908 #
# | common | rename | meta | ext
# -------------------------------------------------
# rawsize() | L1 | L1 | L1 | L1
# size() | L1 | L2-LM | L1(*) | L1 (?)
# len(rawtext) | L2 | L2 | L2 | L2
# len(text) | L2 | L2 | L2 | L3
# len(read()) | L2 | L2-LM | L2-LM | L3 (?)
#
# LM: length of metadata, depending on rawtext
# (*): not ideal, see comment in filelog.size
# (?): could be "- len(meta)" if the resolved content has
# rename metadata
#
# Checks needed to be done:
# 1. length check: L1 == L2, in all cases.
# 2. hash check: depending on flag processor, we may need to
# use either "text" (external), or "rawtext" (in revlog).
try:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 skipflags = state.get(b'skipflags', 0)
Gregory Szorc
revlog: move revision verification out of verify...
r39908 if skipflags:
skipflags &= self.flags(rev)
Matt Harbison
revlog: split the content verification of a node into a separate method...
r44409 _verify_revision(self, skipflags, state, node)
Gregory Szorc
revlog: move revision verification out of verify...
r39908
l1 = self.rawsize(rev)
rawdata: update caller in revlog...
r43036 l2 = len(self.rawdata(node))
Gregory Szorc
revlog: move revision verification out of verify...
r39908
if l1 != l2:
yield revlogproblem(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 error=_(b'unpacked size is %d, %d expected') % (l2, l1),
Augie Fackler
formatting: blacken the codebase...
r43346 node=node,
)
Gregory Szorc
revlog: move revision verification out of verify...
r39908
except error.CensoredNodeError:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if state[b'erroroncensored']:
Augie Fackler
formatting: blacken the codebase...
r43346 yield revlogproblem(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 error=_(b'censored file data'), node=node
Augie Fackler
formatting: blacken the codebase...
r43346 )
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 state[b'skipread'].add(node)
Gregory Szorc
revlog: move revision verification out of verify...
r39908 except Exception as e:
yield revlogproblem(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 error=_(b'unpacking %s: %s')
Augie Fackler
formatting: blacken the codebase...
r43346 % (short(node), stringutil.forcebytestr(e)),
node=node,
)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 state[b'skipread'].add(node)
Gregory Szorc
revlog: move revision verification out of verify...
r39908
Augie Fackler
formatting: blacken the codebase...
r43346 def storageinfo(
self,
exclusivefiles=False,
sharedfiles=False,
revisionscount=False,
trackedsize=False,
storedsize=False,
):
Gregory Szorc
revlog: add method for obtaining storage info (API)...
r39905 d = {}
if exclusivefiles:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 d[b'exclusivefiles'] = [(self.opener, self.indexfile)]
Gregory Szorc
revlog: add method for obtaining storage info (API)...
r39905 if not self._inline:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 d[b'exclusivefiles'].append((self.opener, self.datafile))
Gregory Szorc
revlog: add method for obtaining storage info (API)...
r39905
if sharedfiles:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 d[b'sharedfiles'] = []
Gregory Szorc
revlog: add method for obtaining storage info (API)...
r39905
if revisionscount:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 d[b'revisionscount'] = len(self)
Gregory Szorc
revlog: add method for obtaining storage info (API)...
r39905
if trackedsize:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 d[b'trackedsize'] = sum(map(self.rawsize, iter(self)))
Gregory Szorc
revlog: add method for obtaining storage info (API)...
r39905
if storedsize:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 d[b'storedsize'] = sum(
Augie Fackler
formatting: blacken the codebase...
r43346 self.opener.stat(path).st_size for path in self.files()
)
Gregory Szorc
revlog: add method for obtaining storage info (API)...
r39905
return d
Raphaël Gomès
sidedata-exchange: rewrite sidedata on-the-fly whenever possible...
r47452
def rewrite_sidedata(self, helpers, startrev, endrev):
if self.version & 0xFFFF != REVLOGV2:
return
# inline are not yet supported because they suffer from an issue when
# rewriting them (since it's not an append-only operation).
# See issue6485.
assert not self._inline
if not helpers[1] and not helpers[2]:
# Nothing to generate or remove
return
new_entries = []
# append the new sidedata
with self._datafp(b'a+') as fp:
# Maybe this bug still exists, see revlog._writeentry
fp.seek(0, os.SEEK_END)
current_offset = fp.tell()
for rev in range(startrev, endrev + 1):
entry = self.index[rev]
new_sidedata = storageutil.run_sidedata_helpers(
store=self,
sidedata_helpers=helpers,
sidedata={},
rev=rev,
)
serialized_sidedata = sidedatautil.serialize_sidedata(
new_sidedata
)
if entry[8] != 0 or entry[9] != 0:
# rewriting entries that already have sidedata is not
# supported yet, because it introduces garbage data in the
# revlog.
msg = "Rewriting existing sidedata is not supported yet"
raise error.Abort(msg)
entry = entry[:8]
entry += (current_offset, len(serialized_sidedata))
fp.write(serialized_sidedata)
new_entries.append(entry)
current_offset += len(serialized_sidedata)
# rewrite the new index entries
with self._indexfp(b'w+') as fp:
fp.seek(startrev * self._io.size)
for i, entry in enumerate(new_entries):
rev = startrev + i
self.index.replace_sidedata_info(rev, entry[8], entry[9])
packed = self._io.packentry(entry, self.node, self.version, rev)
fp.write(packed)