##// END OF EJS Templates
hgweb: stop using the `pycompat.open()` shim
hgweb: stop using the `pycompat.open()` shim

File last commit:

r53071:bcd4962e default
r53263:c9baa354 default
Show More
revlog.py
4244 lines | 150.0 KiB | text/x-python | PythonLexer
Martin Geisler
put license and copyright info into comment blocks
r8226 # revlog.py - storage back-end for mercurial
revlog: store sidedata in their own file...
r48181 # coding: utf8
Martin Geisler
put license and copyright info into comment blocks
r8226 #
Raphaël Gomès
contributor: change mentions of mpm to olivia...
r47575 # Copyright 2005-2007 Olivia Mackall <olivia@selenic.com>
Martin Geisler
put license and copyright info into comment blocks
r8226 #
# 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.
"""
Matt Harbison
typing: add `from __future__ import annotations` to most files...
r52756 from __future__ import annotations
Gregory Szorc
revlog: use absolute_import
r27361
Valentin Gatien-Baron
revlog: fix error about unknown compression format in py3...
r47611 import binascii
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
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
Matt Harbison
typing: induce pytype to use the standard `attr` instead of the vendored copy...
r52622 import typing
revlog-split: make sure the self._indexfile attribut is reset (issue6811)...
r51320 import weakref
Gregory Szorc
revlog: use absolute_import
r27361 import zlib
Matt Harbison
typing: add a few type hints to `mercurial/revlog.py`...
r52570 from typing import (
Matt Harbison
typing: lock in new pytype gains from making revlog related classes typeable...
r52719 Iterable,
Iterator,
Matt Harbison
typing: add a few type hints to `mercurial/revlog.py`...
r52570 Optional,
Tuple,
)
Gregory Szorc
revlog: use absolute_import
r27361 # import stuff from node for others to import from revlog
from .node import (
bin,
hex,
nullrev,
Joerg Sonnenberger
node: introduce nodeconstants class...
r47538 sha1nodeconstants,
Gregory Szorc
revlog: move revision verification out of verify...
r39908 short,
Pulkit Goyal
revlog: raise WdirUnsupported when wdirrev is passed...
r32402 wdirrev,
Gregory Szorc
revlog: use absolute_import
r27361 )
from .i18n import _
Boris Feld
revlog: split constants into a new `revlogutils.constants` module...
r39365 from .revlogutils.constants import (
revlog: introduce an explicit tracking of what the revlog is about...
r47838 ALL_KINDS,
changelogv2: use a dedicated version number...
r48040 CHANGELOGV2,
revlog: implement a "default compression" mode...
r48029 COMP_MODE_DEFAULT,
revlog: add a "data compression mode" entry in the index tuple...
r48023 COMP_MODE_INLINE,
revlog: introduce a plain compression mode...
r48027 COMP_MODE_PLAIN,
find-delta: pass the cache-delta usage policy alongside the cache-delta...
r50572 DELTA_BASE_REUSE_NO,
DELTA_BASE_REUSE_TRY,
rank: naive rank property computation and retrieval...
r49606 ENTRY_RANK,
revlog: unify flag processing when loading index...
r48005 FEATURES_BY_VERSION,
Boris Feld
revlog: split constants into a new `revlogutils.constants` module...
r39365 FLAG_GENERALDELTA,
FLAG_INLINE_DATA,
revlog: move the "index header" struct inside revlog.utils.constants...
r47618 INDEX_HEADER,
changelogv2: introduce a "changelogv2" feature...
r48037 KIND_CHANGELOG,
Matt Harbison
revlog: use the user facing filename as the display_id for filelogs...
r50429 KIND_FILELOG,
rank: naive rank property computation and retrieval...
r49606 RANK_UNKNOWN,
Boris Feld
revlog: split constants into a new `revlogutils.constants` module...
r39365 REVLOGV0,
REVLOGV1,
REVLOGV1_FLAGS,
REVLOGV2,
REVLOGV2_FLAGS,
REVLOG_DEFAULT_FLAGS,
REVLOG_DEFAULT_FORMAT,
REVLOG_DEFAULT_VERSION,
revlog: unify checks for supported flag...
r48004 SUPPORTED_FLAGS,
Boris Feld
revlog: split constants into a new `revlogutils.constants` module...
r39365 )
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,
)
Augie Fackler
formatting: blacken the codebase...
r43346 from .thirdparty import attr
Matt Harbison
typing: induce pytype to use the standard `attr` instead of the vendored copy...
r52622
# Force pytype to use the non-vendored package
if typing.TYPE_CHECKING:
# noinspection PyPackageRequirements
import attr
Raphaël Gomès
revlog: add the glue to use the Rust `InnerRevlog` from Python...
r53060 from .pure.parsers import BaseIndexObject
Matt Harbison
typing: induce pytype to use the standard `attr` instead of the vendored copy...
r52622
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,
revlog: move `offset_type` to `revlogutils`...
r48186 revlogutils,
Gregory Szorc
revlog: use absolute_import
r27361 templatefilters,
util,
Matt Harbison
typing: add type hints to the `opener` attributes and arguments of revlog...
r52713 vfs as vfsmod,
Gregory Szorc
revlog: use absolute_import
r27361 )
Pulkit Goyal
interfaces: create a new folder for interfaces and move repository.py in it...
r43078 from .interfaces import (
repository,
)
Boris Feld
revlog: split functionality related to deltas computation in a new module...
r39366 from .revlogutils import (
deltas as deltautil,
revlogv2: introduce a very basic docket file...
r48008 docket as docketutil,
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,
Simon Sapin
revlog: Extract low-level random-access file read caching logic...
r48218 randomaccessfile,
revlog: code for `revlogv0` in its own module...
r47812 revlogv0,
revlog: rewrite `censors.py` to `rewrite.py`...
r48257 rewrite,
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,
)
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.
Raphaël Gomès
sidedata: replace sidedata upgrade mechanism with the new one...
r47847
Boris Feld
revlog: split constants into a new `revlogutils.constants` module...
r39365 REVLOGV0
REVLOGV1
REVLOGV2
pacien
revlog: register changelogv2 C implementation in parsers...
r49618 CHANGELOGV2
Boris Feld
revlog: split constants into a new `revlogutils.constants` module...
r39365 FLAG_INLINE_DATA
FLAG_GENERALDELTA
REVLOG_DEFAULT_FLAGS
REVLOG_DEFAULT_FORMAT
REVLOG_DEFAULT_VERSION
REVLOGV1_FLAGS
REVLOGV2_FLAGS
REVIDX_ISCENSORED
REVIDX_ELLIPSIS
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
Arseniy Alekseyev
revlog: fix misleading comment about _maxinline
r50723 # max size of inline data embedded into a revlog
Benoit Boissinot
add documentation for revlog._prereadsize
r10916 _maxinline = 131072
Greg Ward
revlog: factor out _maxinline global....
r10913
Arseniy Alekseyev
unbundle: faster computation of changed heads...
r52288
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 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)
safehasattr: drop usage in favor of hasattr...
r51821 HAS_FAST_PERSISTENT_NODEMAP = rustrevlog is not None or hasattr(
persistent-nodemap: add a "warn" option to the slow-path config...
r47028 parsers, 'BaseIndexObject'
)
Gregory Szorc
revlog: new API to emit revision data...
r39898 @attr.s(slots=True)
Matt Harbison
revlog: drop the CamelCase name for `revlog.revlogrevisiondelta`...
r52957 class revlogrevisiondelta: # (repository.irevisiondelta)
Gregory Szorc
repository: establish API for emitting revision deltas...
r39267 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()
Raphaël Gomès
cg4: introduce protocol flag to signify the presence of sidedata...
r47843 protocol_flags = 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 @attr.s(frozen=True)
Matt Harbison
revlog: drop the CamelCase name for `revlog.revlogproblem`...
r52958 class revlogproblem: # (repository.iverifyproblem)
Matt Harbison
typing: add types to `revlog.revlogproblem`...
r52718 warning = attr.ib(default=None, type=Optional[bytes])
error = attr.ib(default=None, type=Optional[bytes])
node = attr.ib(default=None, type=Optional[bytes])
Gregory Szorc
verify: start to abstract file verification...
r39878
Augie Fackler
formatting: blacken the codebase...
r43346
revlog: remove the revlogio class...
r47810 def parse_index_v1(data, inline):
# call the C implementation to parse the index data
index, cache = parsers.parse_index2(data, inline)
return index, cache
def parse_index_v2(data, inline):
# call the C implementation to parse the index data
pacien
revlog: register changelogv2 C implementation in parsers...
r49618 index, cache = parsers.parse_index2(data, inline, format=REVLOGV2)
revlog: remove the revlogio class...
r47810 return index, cache
changelogv2: use a dedicated on disk format for changelogv2...
r48044 def parse_index_cl_v2(data, inline):
# call the C implementation to parse the index data
pacien
revlog: register changelogv2 C implementation in parsers...
r49618 index, cache = parsers.parse_index2(data, inline, format=CHANGELOGV2)
changelogv2: use a dedicated on disk format for changelogv2...
r48044 return index, cache
safehasattr: drop usage in favor of hasattr...
r51821 if hasattr(parsers, 'parse_index_devel_nodemap'):
revlog: remove the revlogio class...
r47810
def parse_index_v1_nodemap(data, inline):
index, cache = parsers.parse_index_devel_nodemap(data, inline)
return index, cache
else:
parse_index_v1_nodemap = None
Georges Racinet on incendie.racinet.fr
rust-index: renamed `MixedIndex` as `Index`...
r52147 def parse_index_v1_rust(data, inline, default_header):
Georges Racinet
rust-index: stop instantiating a C Index...
r52146 cache = (0, data) if inline else None
Georges Racinet on incendie.racinet.fr
rust-index: renamed `MixedIndex` as `Index`...
r52147 return rustrevlog.Index(data, default_header), cache
Matt Mackall
revlog: add revlogio interface...
r4972
Augie Fackler
formatting: blacken the codebase...
r43346
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
revlog: store sidedata in their own file...
r48181 FILE_TOO_SHORT_MSG = _(
b'cannot read from revlog %s;'
b' expected %d bytes from offset %d, data size is %d'
)
Arseniy Alekseyev
revlog: make _partialmatch fail fast on almost-hex inputs...
r50310 hexdigits = b'0123456789abcdefABCDEF'
Jordi Gutiérrez Hermoso
revlog: raise an exception earlier if an entry is too large (issue4675)...
r25410
revlog: overwrite revlog config through copy of the config object...
r51923 class _Config:
def copy(self):
return self.__class__(**self.__dict__)
revlog: move configuration attribute into dedicated object...
r51922 @attr.s()
revlog: overwrite revlog config through copy of the config object...
r51923 class FeatureConfig(_Config):
revlog: move configuration attribute into dedicated object...
r51922 """Hold configuration values about the available revlog features"""
# the default compression engine
compression_engine = attr.ib(default=b'zlib')
# compression engines options
compression_engine_options = attr.ib(default=attr.Factory(dict))
# can we use censor on this revlog
censorable = attr.ib(default=False)
# does this revlog use the "side data" feature
has_side_data = attr.ib(default=False)
# might remove rank configuration once the computation has no impact
compute_rank = attr.ib(default=False)
# parent order is supposed to be semantically irrelevant, so we
# normally resort parents to ensure that the first parent is non-null,
# if there is a non-null parent at all.
# filelog abuses the parent order as flag to mark some instances of
# meta-encoded files, so allow it to disable this behavior.
canonical_parent_order = attr.ib(default=False)
# can ellipsis commit be used
enable_ellipsis = attr.ib(default=False)
revlog: overwrite revlog config through copy of the config object...
r51923 def copy(self):
new = super().copy()
new.compression_engine_options = self.compression_engine_options.copy()
return new
revlog: move configuration attribute into dedicated object...
r51922
@attr.s()
revlog: overwrite revlog config through copy of the config object...
r51923 class DataConfig(_Config):
revlog: move configuration attribute into dedicated object...
r51922 """Hold configuration value about how the revlog data are read"""
# should we try to open the "pending" version of the revlog
try_pending = attr.ib(default=False)
# should we try to open the "splitted" version of the revlog
try_split = attr.ib(default=False)
# When True, indexfile should be opened with checkambig=True at writing,
# to avoid file stat ambiguity.
check_ambig = attr.ib(default=False)
# If true, use mmap instead of reading to deal with large index
mmap_large_index = attr.ib(default=False)
# how much data is large
mmap_index_threshold = attr.ib(default=None)
# How much data to read and cache into the raw revlog data cache.
chunk_cache_size = attr.ib(default=65536)
revlog: add a small cache of unfiltered chunk...
r52001 # The size of the uncompressed cache compared to the largest revision seen.
uncompressed_cache_factor = attr.ib(default=None)
# The number of chunk cached
uncompressed_cache_count = attr.ib(default=None)
revlog: move configuration attribute into dedicated object...
r51922 # Allow sparse reading of the revlog data
with_sparse_read = attr.ib(default=False)
# minimal density of a sparse read chunk
sr_density_threshold = attr.ib(default=0.50)
# minimal size of data we skip when performing sparse read
sr_min_gap_size = attr.ib(default=262144)
# are delta encoded against arbitrary bases.
generaldelta = attr.ib(default=False)
@attr.s()
revlog: overwrite revlog config through copy of the config object...
r51923 class DeltaConfig(_Config):
revlog: move configuration attribute into dedicated object...
r51922 """Hold configuration value about how new delta are computed
Some attributes are duplicated from DataConfig to help havign each object
self contained.
"""
# can delta be encoded against arbitrary bases.
general_delta = attr.ib(default=False)
# Allow sparse writing of the revlog data
sparse_revlog = attr.ib(default=False)
# maximum length of a delta chain
max_chain_len = attr.ib(default=None)
# Maximum distance between delta chain base start and end
max_deltachain_span = attr.ib(default=-1)
# If `upper_bound_comp` is not None, this is the expected maximal gain from
# compression for the data content.
upper_bound_comp = attr.ib(default=None)
# Should we try a delta against both parent
delta_both_parents = attr.ib(default=True)
# Test delta base candidate group by chunk of this maximal size.
candidate_group_chunk_size = attr.ib(default=0)
# Should we display debug information about delta computation
debug_delta = attr.ib(default=False)
# trust incoming delta by default
lazy_delta = attr.ib(default=True)
# trust the base of incoming delta by default
lazy_delta_base = attr.ib(default=False)
revlog: create a iteration of a _InnerRevlog object within the revlog...
r51979 class _InnerRevlog:
"""An inner layer of the revlog object
That layer exist to be able to delegate some operation to Rust, its
boundaries are arbitrary and based on what we can delegate to Rust.
"""
Matt Harbison
typing: add type hints to the `opener` attributes and arguments of revlog...
r52713 opener: vfsmod.vfs
revlog: create a iteration of a _InnerRevlog object within the revlog...
r51979 def __init__(
self,
Matt Harbison
typing: add type hints to the `opener` attributes and arguments of revlog...
r52713 opener: vfsmod.vfs,
revlog: create a iteration of a _InnerRevlog object within the revlog...
r51979 index,
index_file,
data_file,
sidedata_file,
inline,
data_config,
revlog: add a couple more of useful method on the inner object...
r51986 delta_config,
revlog: move the compression/decompression logic on the inner object...
r51984 feature_config,
revlog: create a iteration of a _InnerRevlog object within the revlog...
r51979 chunk_cache,
revlog: move the compression/decompression logic on the inner object...
r51984 default_compression_header,
revlog: create a iteration of a _InnerRevlog object within the revlog...
r51979 ):
self.opener = opener
Raphaël Gomès
revlog: add the glue to use the Rust `InnerRevlog` from Python...
r53060 self.index: BaseIndexObject = index
revlog: create a iteration of a _InnerRevlog object within the revlog...
r51979
changelog: disallow delayed write on inline changesets...
r52075 self.index_file = index_file
revlog: create a iteration of a _InnerRevlog object within the revlog...
r51979 self.data_file = data_file
self.sidedata_file = sidedata_file
self.inline = inline
self.data_config = data_config
revlog: add a couple more of useful method on the inner object...
r51986 self.delta_config = delta_config
revlog: move the compression/decompression logic on the inner object...
r51984 self.feature_config = feature_config
changelog-delay: move the delay/divert logic inside the (inner) revlog...
r51999 # used during diverted write.
self._orig_index_file = None
revlog: move the compression/decompression logic on the inner object...
r51984 self._default_compression_header = default_compression_header
revlog: create a iteration of a _InnerRevlog object within the revlog...
r51979
# index
# 3-tuple of file handles being used for active writing.
self._writinghandles = None
self._segmentfile = randomaccessfile.randomaccessfile(
self.opener,
(self.index_file if self.inline else self.data_file),
self.data_config.chunk_cache_size,
chunk_cache,
)
self._segmentfile_sidedata = randomaccessfile.randomaccessfile(
self.opener,
self.sidedata_file,
self.data_config.chunk_cache_size,
)
revlog: move the compression/decompression logic on the inner object...
r51984 # revlog header -> revlog compressor
self._decompressors = {}
revlog: move the_revisioncache on the inner object...
r51989 # 3-tuple of (node, rev, text) for a raw revision.
self._revisioncache = None
revlog: move the compression/decompression logic on the inner object...
r51984
revlog: add a small cache of unfiltered chunk...
r52001 # cache some uncompressed chunks
# rev → uncompressed_chunk
#
# the max cost is dynamically updated to be proportionnal to the
# size of revision we actually encounter.
self._uncompressed_chunk_cache = None
if self.data_config.uncompressed_cache_factor is not None:
self._uncompressed_chunk_cache = util.lrucachedict(
self.data_config.uncompressed_cache_count,
maxcost=65536, # some arbitrary initial value
)
changelog-delay: move the delay/divert logic inside the (inner) revlog...
r51999 self._delay_buffer = None
revlog: add a couple more of useful method on the inner object...
r51986 def __len__(self):
return len(self.index)
revlog: consolidate cache invalidation within the inner objet...
r51994 def clear_cache(self):
changelog-delay: move the delay/divert logic inside the (inner) revlog...
r51999 assert not self.is_delaying
revlog: consolidate cache invalidation within the inner objet...
r51994 self._revisioncache = None
revlog: add a small cache of unfiltered chunk...
r52001 if self._uncompressed_chunk_cache is not None:
self._uncompressed_chunk_cache.clear()
revlog: consolidate cache invalidation within the inner objet...
r51994 self._segmentfile.clear_cache()
self._segmentfile_sidedata.clear_cache()
revlog: add a `canonical_index_file` attribute on inner revlog...
r51998 @property
def canonical_index_file(self):
changelog-delay: move the delay/divert logic inside the (inner) revlog...
r51999 if self._orig_index_file is not None:
return self._orig_index_file
revlog: add a `canonical_index_file` attribute on inner revlog...
r51998 return self.index_file
changelog-delay: move the delay/divert logic inside the (inner) revlog...
r51999 @property
def is_delaying(self):
"""is the revlog is currently delaying the visibility of written data?
The delaying mechanism can be either in-memory or written on disk in a
side-file."""
return (self._delay_buffer is not None) or (
self._orig_index_file is not None
)
revlog: create a iteration of a _InnerRevlog object within the revlog...
r51979 # Derived from index values.
def start(self, rev):
"""the offset of the data chunk for this revision"""
return int(self.index[rev][0] >> 16)
def length(self, rev):
"""the length of the data chunk for this revision"""
return self.index[rev][1]
def end(self, rev):
"""the end of the data chunk for this revision"""
return self.start(rev) + self.length(rev)
revlog: add a couple more of useful method on the inner object...
r51986 def deltaparent(self, rev):
"""return deltaparent of the given revision"""
base = self.index[rev][3]
if base == rev:
return nullrev
elif self.delta_config.general_delta:
return base
else:
return rev - 1
def issnapshot(self, rev):
"""tells whether rev is a snapshot"""
if not self.delta_config.sparse_revlog:
return self.deltaparent(rev) == nullrev
elif hasattr(self.index, 'issnapshot'):
# directly assign the method to cache the testing and access
self.issnapshot = self.index.issnapshot
return self.issnapshot(rev)
if rev == nullrev:
return True
entry = self.index[rev]
base = entry[3]
if base == rev:
return True
if base == nullrev:
return True
p1 = entry[5]
while self.length(p1) == 0:
b = self.deltaparent(p1)
if b == p1:
break
p1 = b
p2 = entry[6]
while self.length(p2) == 0:
b = self.deltaparent(p2)
if b == p2:
break
p2 = b
if base == p1 or base == p2:
return False
return self.issnapshot(base)
revlog: move the `deltachain` method on the inner object...
r51988 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.
"""
generaldelta = self.delta_config.general_delta
# Try C implementation.
try:
Raphaël Gomès
revlog: add the glue to use the Rust `InnerRevlog` from Python...
r53060 return self.index.deltachain(
rev, stoprev, generaldelta
) # pytype: disable=attribute-error
revlog: move the `deltachain` method on the inner object...
r51988 except AttributeError:
pass
chain = []
# Alias to prevent attribute lookup in tight loop.
index = self.index
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
revlog: move the compression/decompression logic on the inner object...
r51984 @util.propertycache
def _compressor(self):
engine = util.compengines[self.feature_config.compression_engine]
return engine.revlogcompressor(
self.feature_config.compression_engine_options
)
@util.propertycache
def _decompressor(self):
"""the default decompressor"""
if self._default_compression_header is None:
return None
t = self._default_compression_header
c = self._get_decompressor(t)
return c.decompress
Matt Harbison
typing: add a few type hints to `mercurial/revlog.py`...
r52570 def _get_decompressor(self, t: bytes):
revlog: move the compression/decompression logic on the inner object...
r51984 try:
compressor = self._decompressors[t]
except KeyError:
try:
engine = util.compengines.forrevlogheader(t)
compressor = engine.revlogcompressor(
self.feature_config.compression_engine_options
)
self._decompressors[t] = compressor
except KeyError:
raise error.RevlogError(
_(b'unknown compression type %s') % binascii.hexlify(t)
)
return compressor
Matt Harbison
typing: add a few type hints to `mercurial/revlog.py`...
r52570 def compress(self, data: bytes) -> Tuple[bytes, bytes]:
revlog: move the compression/decompression logic on the inner object...
r51984 """Generate a possibly-compressed representation of data."""
if not data:
return b'', data
compressed = self._compressor.compress(data)
if compressed:
# The revlog compressor added the header in the returned data.
return b'', compressed
if data[0:1] == b'\0':
return b'', data
return b'u', data
Matt Harbison
typing: add a few type hints to `mercurial/revlog.py`...
r52570 def decompress(self, data: bytes):
revlog: move the compression/decompression logic on the inner object...
r51984 """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
# 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.
t = data[0:1]
if t == b'x':
try:
return _zlibdecompress(data)
except zlib.error as e:
raise error.RevlogError(
_(b'revlog decompress error: %s')
% stringutil.forcebytestr(e)
)
# '\0' is more common than 'u' so it goes first.
elif t == b'\0':
return data
elif t == b'u':
return util.buffer(data, 1)
compressor = self._get_decompressor(t)
return compressor.decompress(data)
revlog: create a iteration of a _InnerRevlog object within the revlog...
r51979 @contextlib.contextmanager
def reading(self):
"""Context manager that keeps data and sidedata files open for reading"""
if len(self.index) == 0:
yield # nothing to be read
changelog: disallow delayed write on inline changesets...
r52075 elif self._delay_buffer is not None and self.inline:
msg = "revlog with delayed write should not be inline"
raise error.ProgrammingError(msg)
revlog: create a iteration of a _InnerRevlog object within the revlog...
r51979 else:
with self._segmentfile.reading():
with self._segmentfile_sidedata.reading():
yield
@property
def is_writing(self):
"""True is a writing context is open"""
return self._writinghandles is not None
changelog-delay: adds some check around delaying and diverting write...
r51995 @property
def is_open(self):
"""True if any file handle is being held
Used for assert and debug in the python code"""
return self._segmentfile.is_open or self._segmentfile_sidedata.is_open
revlog: create a iteration of a _InnerRevlog object within the revlog...
r51979 @contextlib.contextmanager
def writing(self, transaction, data_end=None, sidedata_end=None):
"""Open the revlog files for writing
Add content to a revlog should be done within such context.
"""
if self.is_writing:
yield
else:
ifh = dfh = sdfh = None
try:
r = len(self.index)
# opening the data file.
dsize = 0
if r:
dsize = self.end(r - 1)
dfh = None
if not self.inline:
try:
dfh = self.opener(self.data_file, mode=b"r+")
if data_end is None:
dfh.seek(0, os.SEEK_END)
else:
dfh.seek(data_end, os.SEEK_SET)
except FileNotFoundError:
dfh = self.opener(self.data_file, mode=b"w+")
transaction.add(self.data_file, dsize)
if self.sidedata_file is not None:
assert sidedata_end is not None
# revlog-v2 does not inline, help Pytype
assert dfh is not None
try:
sdfh = self.opener(self.sidedata_file, mode=b"r+")
dfh.seek(sidedata_end, os.SEEK_SET)
except FileNotFoundError:
sdfh = self.opener(self.sidedata_file, mode=b"w+")
transaction.add(self.sidedata_file, sidedata_end)
# opening the index file.
isize = r * self.index.entry_size
ifh = self.__index_write_fp()
if self.inline:
transaction.add(self.index_file, dsize + isize)
else:
transaction.add(self.index_file, isize)
# exposing all file handle for writing.
self._writinghandles = (ifh, dfh, sdfh)
self._segmentfile.writing_handle = ifh if self.inline else dfh
self._segmentfile_sidedata.writing_handle = sdfh
yield
finally:
self._writinghandles = None
self._segmentfile.writing_handle = None
self._segmentfile_sidedata.writing_handle = None
if dfh is not None:
dfh.close()
if sdfh is not None:
sdfh.close()
# closing the index file last to avoid exposing referent to
# potential unflushed data content.
if ifh is not None:
ifh.close()
def __index_write_fp(self, index_end=None):
"""internal method to open the index file for writing
You should not use this directly and use `_writing` instead
"""
try:
changelog-delay: move the delay/divert logic inside the (inner) revlog...
r51999 if self._delay_buffer is None:
f = self.opener(
self.index_file,
mode=b"r+",
checkambig=self.data_config.check_ambig,
)
else:
# check_ambig affect we way we open file for writing, however
# here, we do not actually open a file for writting as write
# will appened to a delay_buffer. So check_ambig is not
# meaningful and unneeded here.
f = randomaccessfile.appender(
self.opener, self.index_file, b"r+", self._delay_buffer
)
revlog: create a iteration of a _InnerRevlog object within the revlog...
r51979 if index_end is None:
f.seek(0, os.SEEK_END)
else:
f.seek(index_end, os.SEEK_SET)
return f
except FileNotFoundError:
changelog-delay: move the delay/divert logic inside the (inner) revlog...
r51999 if self._delay_buffer is None:
return self.opener(
self.index_file,
mode=b"w+",
checkambig=self.data_config.check_ambig,
)
else:
return randomaccessfile.appender(
self.opener, self.index_file, b"w+", self._delay_buffer
)
revlog: create a iteration of a _InnerRevlog object within the revlog...
r51979
def __index_new_fp(self):
"""internal method to create a new index file for writing
You should not use this unless you are upgrading from inline revlog
"""
return self.opener(
self.index_file,
mode=b"w",
checkambig=self.data_config.check_ambig,
)
revlog: move the splitting-inline-revlog logic inside the inner object...
r51983 def split_inline(self, tr, header, new_index_file_path=None):
"""split the data of an inline revlog into an index and a data file"""
revlog: add one more assert about state of thing when splitting...
r52057 assert self._delay_buffer is None
revlog: move the splitting-inline-revlog logic inside the inner object...
r51983 existing_handles = False
if self._writinghandles is not None:
existing_handles = True
fp = self._writinghandles[0]
fp.flush()
fp.close()
# We can't use the cached file handle after close(). So prevent
# its usage.
self._writinghandles = None
self._segmentfile.writing_handle = None
# No need to deal with sidedata writing handle as it is only
# relevant with revlog-v2 which is never inline, not reaching
# this code
new_dfh = self.opener(self.data_file, mode=b"w+")
new_dfh.truncate(0) # drop any potentially existing data
try:
with self.reading():
for r in range(len(self.index)):
new_dfh.write(self.get_segment_for_revs(r, r)[1])
new_dfh.flush()
if new_index_file_path is not None:
self.index_file = new_index_file_path
with self.__index_new_fp() as fp:
self.inline = False
for i in range(len(self.index)):
e = self.index.entry_binary(i)
if i == 0:
packed_header = self.index.pack_header(header)
e = packed_header + e
fp.write(e)
# If we don't use side-write, the temp file replace the real
# index when we exit the context manager
self._segmentfile = randomaccessfile.randomaccessfile(
self.opener,
self.data_file,
self.data_config.chunk_cache_size,
)
if existing_handles:
# switched from inline to conventional reopen the index
ifh = self.__index_write_fp()
self._writinghandles = (ifh, new_dfh, None)
self._segmentfile.writing_handle = new_dfh
new_dfh = None
# No need to deal with sidedata writing handle as it is only
# relevant with revlog-v2 which is never inline, not reaching
# this code
finally:
if new_dfh is not None:
new_dfh.close()
return self.index_file
revlog: move _getsegmentforrevs on the internal object...
r51980 def get_segment_for_revs(self, startrev, endrev):
"""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.
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.
API: we should consider making this a private part of the InnerRevlog
at some point.
"""
# Inlined self.start(startrev) & self.end(endrev) for perf reasons
# (functions are expensive).
index = self.index
istart = index[startrev]
start = int(istart[0] >> 16)
if startrev == endrev:
end = start + istart[1]
else:
iend = index[endrev]
end = int(iend[0] >> 16) + iend[1]
if self.inline:
start += (startrev + 1) * self.index.entry_size
end += (endrev + 1) * self.index.entry_size
length = end - start
return start, self._segmentfile.read_chunk(start, length)
revlog: move the `_chunk` method on the inner object...
r51985 def _chunk(self, rev):
"""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.
"""
revlog: add a small cache of unfiltered chunk...
r52001 if self._uncompressed_chunk_cache is not None:
uncomp = self._uncompressed_chunk_cache.get(rev)
if uncomp is not None:
return uncomp
revlog: move the `_chunk` method on the inner object...
r51985 compression_mode = self.index[rev][10]
data = self.get_segment_for_revs(rev, rev)[1]
if compression_mode == COMP_MODE_PLAIN:
revlog: add a small cache of unfiltered chunk...
r52001 uncomp = data
revlog: move the `_chunk` method on the inner object...
r51985 elif compression_mode == COMP_MODE_DEFAULT:
revlog: add a small cache of unfiltered chunk...
r52001 uncomp = self._decompressor(data)
revlog: move the `_chunk` method on the inner object...
r51985 elif compression_mode == COMP_MODE_INLINE:
revlog: add a small cache of unfiltered chunk...
r52001 uncomp = self.decompress(data)
revlog: move the `_chunk` method on the inner object...
r51985 else:
msg = b'unknown compression mode %d'
msg %= compression_mode
raise error.RevlogError(msg)
revlog: add a small cache of unfiltered chunk...
r52001 if self._uncompressed_chunk_cache is not None:
self._uncompressed_chunk_cache.insert(rev, uncomp, cost=len(uncomp))
return uncomp
revlog: move the `_chunk` method on the inner object...
r51985
revlog: move the `_chunks` method on the inner object...
r51987 def _chunks(self, revs, targetsize=None):
"""Obtain decompressed chunks for the specified revisions.
Accepts an iterable of numeric revisions that are assumed to be in
Raphaël Gomès
revlog: cleanup some outdated docstrings
r52748 ascending order.
revlog: move the `_chunks` method on the inner object...
r51987
This function is similar to calling ``self._chunk()`` multiple times,
but is faster.
Returns a list with decompressed data for each requested revision.
"""
if not revs:
return []
start = self.start
length = self.length
inline = self.inline
iosize = self.index.entry_size
buffer = util.buffer
revlog: add a small cache of unfiltered chunk...
r52001 fetched_revs = []
fadd = fetched_revs.append
revlog: minor refactor in the chunk gather process...
r52000 chunks = []
ladd = chunks.append
revlog: move the `_chunks` method on the inner object...
r51987
revlog: add a small cache of unfiltered chunk...
r52001 if self._uncompressed_chunk_cache is None:
fetched_revs = revs
else:
for rev in revs:
cached_value = self._uncompressed_chunk_cache.get(rev)
if cached_value is None:
fadd(rev)
else:
ladd((rev, cached_value))
if not fetched_revs:
slicedchunks = ()
elif not self.data_config.with_sparse_read:
slicedchunks = (fetched_revs,)
revlog: move the `_chunks` method on the inner object...
r51987 else:
slicedchunks = deltautil.slicechunk(
self,
revlog: add a small cache of unfiltered chunk...
r52001 fetched_revs,
revlog: move the `_chunks` method on the inner object...
r51987 targetsize=targetsize,
)
for revschunk in slicedchunks:
firstrev = revschunk[0]
# Skip trailing revisions with empty diff
for lastrev in revschunk[::-1]:
if length(lastrev) != 0:
break
try:
offset, data = self.get_segment_for_revs(firstrev, lastrev)
except OverflowError:
# issue4215 - we can't cache a run of chunks greater than
# 2G on Windows
revlog: minor refactor in the chunk gather process...
r52000 for rev in revschunk:
ladd((rev, self._chunk(rev)))
revlog: move the `_chunks` method on the inner object...
r51987
decomp = self.decompress
# self._decompressor might be None, but will not be used in that case
def_decomp = self._decompressor
for rev in revschunk:
chunkstart = start(rev)
if inline:
chunkstart += (rev + 1) * iosize
chunklength = length(rev)
comp_mode = self.index[rev][10]
c = buffer(data, chunkstart - offset, chunklength)
if comp_mode == COMP_MODE_PLAIN:
revlog: minor refactor in the chunk gather process...
r52000 c = c
revlog: move the `_chunks` method on the inner object...
r51987 elif comp_mode == COMP_MODE_INLINE:
revlog: minor refactor in the chunk gather process...
r52000 c = decomp(c)
revlog: move the `_chunks` method on the inner object...
r51987 elif comp_mode == COMP_MODE_DEFAULT:
revlog: minor refactor in the chunk gather process...
r52000 c = def_decomp(c)
revlog: move the `_chunks` method on the inner object...
r51987 else:
msg = b'unknown compression mode %d'
msg %= comp_mode
raise error.RevlogError(msg)
revlog: minor refactor in the chunk gather process...
r52000 ladd((rev, c))
revlog: add a small cache of unfiltered chunk...
r52001 if self._uncompressed_chunk_cache is not None:
self._uncompressed_chunk_cache.insert(rev, c, len(c))
chunks.sort()
revlog: minor refactor in the chunk gather process...
r52000 return [x[1] for x in chunks]
revlog: move the `_chunks` method on the inner object...
r51987
Matt Harbison
typing: explicitly set the return type of `_InnerRevLog.raw_text()`...
r52753 def raw_text(self, node, rev) -> bytes:
revlog: move the `rawtext` method on the inner object...
r51990 """return the possibly unvalidated rawtext for a revision
Raphaël Gomès
revlog: simplify rawtext return value...
r52749 returns rawtext
revlog: move the `rawtext` method on the inner object...
r51990 """
# revision in the cache (could be useful to apply delta)
cachedrev = None
# An intermediate text to apply deltas to
basetext = None
# Check if we have the entry in cache
# The cache entry looks like (node, rev, rawtext)
if self._revisioncache:
cachedrev = self._revisioncache[1]
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._inner._revisioncache after validating the text
self._revisioncache = None
targetsize = None
rawsize = self.index[rev][2]
if 0 <= rawsize:
targetsize = 4 * rawsize
revlog: add a small cache of unfiltered chunk...
r52001 if self._uncompressed_chunk_cache is not None:
# dynamically update the uncompressed_chunk_cache size to the
# largest revision we saw in this revlog.
factor = self.data_config.uncompressed_cache_factor
candidate_size = rawsize * factor
if candidate_size > self._uncompressed_chunk_cache.maxcost:
self._uncompressed_chunk_cache.maxcost = candidate_size
revlog: move the `rawtext` method on the inner object...
r51990 bins = self._chunks(chain, targetsize=targetsize)
if basetext is None:
basetext = bytes(bins[0])
bins = bins[1:]
rawtext = mdiff.patches(basetext, bins)
del basetext # let us have a chance to free memory early
Raphaël Gomès
revlog: simplify rawtext return value...
r52749 return rawtext
revlog: move the `rawtext` method on the inner object...
r51990
revlog: move `sidedata` in the inner object...
r51991 def sidedata(self, rev, sidedata_end):
"""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.index.entry_size * (1 + rev)
if sidedata_size == 0:
return {}
if sidedata_end < sidedata_offset + sidedata_size:
filename = self.sidedata_file
end = sidedata_end
offset = sidedata_offset
length = sidedata_size
m = FILE_TOO_SHORT_MSG % (filename, length, offset, end)
raise error.RevlogError(m)
comp_segment = self._segmentfile_sidedata.read_chunk(
sidedata_offset, sidedata_size
)
comp = self.index[rev][11]
if comp == COMP_MODE_PLAIN:
segment = comp_segment
elif comp == COMP_MODE_DEFAULT:
segment = self._decompressor(comp_segment)
elif comp == COMP_MODE_INLINE:
segment = self.decompress(comp_segment)
else:
msg = b'unknown compression mode %d'
msg %= comp
raise error.RevlogError(msg)
sidedata = sidedatautil.deserialize_sidedata(segment)
return sidedata
revlog: move entry writing in the inner object...
r51992 def write_entry(
self,
transaction,
entry,
data,
link,
offset,
sidedata,
sidedata_offset,
index_end,
data_end,
sidedata_end,
):
# 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.
# 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.
if self._writinghandles is None:
msg = b'adding revision outside `revlog._writing` context'
raise error.ProgrammingError(msg)
ifh, dfh, sdfh = self._writinghandles
if index_end is None:
ifh.seek(0, os.SEEK_END)
else:
ifh.seek(index_end, os.SEEK_SET)
if dfh:
if data_end is None:
dfh.seek(0, os.SEEK_END)
else:
dfh.seek(data_end, os.SEEK_SET)
if sdfh:
sdfh.seek(sidedata_end, os.SEEK_SET)
curr = len(self.index) - 1
if not self.inline:
transaction.add(self.data_file, offset)
if self.sidedata_file:
transaction.add(self.sidedata_file, sidedata_offset)
revlog: add a `canonical_index_file` attribute on inner revlog...
r51998 transaction.add(self.canonical_index_file, curr * len(entry))
revlog: move entry writing in the inner object...
r51992 if data[0]:
dfh.write(data[0])
dfh.write(data[1])
if sidedata:
sdfh.write(sidedata)
changelog-delay: move the delay/divert logic inside the (inner) revlog...
r51999 if self._delay_buffer is None:
ifh.write(entry)
else:
self._delay_buffer.append(entry)
changelog: disallow delayed write on inline changesets...
r52075 elif self._delay_buffer is not None:
msg = b'invalid delayed write on inline revlog'
raise error.ProgrammingError(msg)
revlog: move entry writing in the inner object...
r51992 else:
offset += curr * self.index.entry_size
revlog: add a `canonical_index_file` attribute on inner revlog...
r51998 transaction.add(self.canonical_index_file, offset)
revlog: move entry writing in the inner object...
r51992 assert not sidedata
changelog: disallow delayed write on inline changesets...
r52075 ifh.write(entry)
ifh.write(data[0])
ifh.write(data[1])
revlog: move entry writing in the inner object...
r51992 return (
ifh.tell(),
dfh.tell() if dfh else None,
sdfh.tell() if sdfh else None,
)
changelog-delay: move the delay/divert logic inside the (inner) revlog...
r51999 def _divert_index(self):
inline-changelog: fix pending transaction visibility when splitting...
r52531 index_file = self.index_file
# when we encounter a legacy inline-changelog, split it. However it is
# important to use the expected filename for pending content
# (<radix>.a) otherwise hooks won't be seeing the content of the
# pending transaction.
if index_file.endswith(b'.s'):
index_file = self.index_file[:-2]
return index_file + b'.a'
changelog-delay: move the delay/divert logic inside the (inner) revlog...
r51999
def delay(self):
assert not self.is_open
changelog: disallow delayed write on inline changesets...
r52075 if self.inline:
msg = "revlog with delayed write should not be inline"
raise error.ProgrammingError(msg)
changelog-delay: move the delay/divert logic inside the (inner) revlog...
r51999 if self._delay_buffer is not None or self._orig_index_file is not None:
# delay or divert already in place
return None
elif len(self.index) == 0:
self._orig_index_file = self.index_file
self.index_file = self._divert_index()
assert self._orig_index_file is not None
assert self.index_file is not None
if self.opener.exists(self.index_file):
self.opener.unlink(self.index_file)
return self.index_file
else:
revlog: avoid exposing delayed index entry too widely in non-inline revlog...
r52058 self._delay_buffer = []
changelog-delay: move the delay/divert logic inside the (inner) revlog...
r51999 return None
def write_pending(self):
assert not self.is_open
changelog: disallow delayed write on inline changesets...
r52075 if self.inline:
msg = "revlog with delayed write should not be inline"
raise error.ProgrammingError(msg)
changelog-delay: move the delay/divert logic inside the (inner) revlog...
r51999 if self._orig_index_file is not None:
return None, True
any_pending = False
pending_index_file = self._divert_index()
if self.opener.exists(pending_index_file):
self.opener.unlink(pending_index_file)
util.copyfile(
self.opener.join(self.index_file),
self.opener.join(pending_index_file),
)
if self._delay_buffer:
with self.opener(pending_index_file, b'r+') as ifh:
ifh.seek(0, os.SEEK_END)
ifh.write(b"".join(self._delay_buffer))
any_pending = True
revlog: avoid exposing delayed index entry too widely in non-inline revlog...
r52058 self._delay_buffer = None
changelog-delay: move the delay/divert logic inside the (inner) revlog...
r51999 self._orig_index_file = self.index_file
self.index_file = pending_index_file
return self.index_file, any_pending
def finalize_pending(self):
assert not self.is_open
changelog: disallow delayed write on inline changesets...
r52075 if self.inline:
msg = "revlog with delayed write should not be inline"
raise error.ProgrammingError(msg)
changelog-delay: move the delay/divert logic inside the (inner) revlog...
r51999
delay = self._delay_buffer is not None
divert = self._orig_index_file is not None
if delay and divert:
assert False, "unreachable"
elif delay:
if self._delay_buffer:
with self.opener(self.index_file, b'r+') as ifh:
ifh.seek(0, os.SEEK_END)
ifh.write(b"".join(self._delay_buffer))
changelog: disallow delayed write on inline changesets...
r52075 self._delay_buffer = None
changelog-delay: move the delay/divert logic inside the (inner) revlog...
r51999 elif divert:
if self.opener.exists(self.index_file):
self.opener.rename(
self.index_file,
self._orig_index_file,
checkambig=True,
)
self.index_file = self._orig_index_file
self._orig_index_file = None
else:
msg = b"not delay or divert found on this revlog"
raise error.ProgrammingError(msg)
return self.canonical_index_file
revlog: create a iteration of a _InnerRevlog object within the revlog...
r51979
Raphaël Gomès
revlog: add the glue to use the Rust `InnerRevlog` from Python...
r53060 if typing.TYPE_CHECKING:
# Tell Pytype what kind of object we expect
ProxyBase = BaseIndexObject
else:
ProxyBase = object
class RustIndexProxy(ProxyBase):
"""Wrapper around the Rust index to fake having direct access to the index.
Rust enforces xor mutability (one mutable reference XOR 1..n non-mutable),
so we can't expose the index from Rust directly, since the `InnerRevlog`
already has ownership of the index. This object redirects all calls to the
index through the Rust-backed `InnerRevlog` glue which defines all
necessary forwarding methods.
"""
def __init__(self, inner):
# Do not rename as it's being used to access the index from Rust
self.inner = inner
# TODO possibly write all index methods manually to save on overhead?
def __getattr__(self, name):
return getattr(self.inner, f"_index_{name}")
# Magic methods need to be defined explicitely
def __len__(self):
return self.inner._index___len__()
def __getitem__(self, key):
return self.inner._index___getitem__(key)
def __contains__(self, key):
return self.inner._index___contains__(key)
def __delitem__(self, key):
return self.inner._index___delitem__(key)
class RustVFSWrapper:
"""Used to wrap a Python VFS to pass it to Rust to lower the overhead of
calling back multiple times into Python.
"""
def __init__(self, inner):
self.inner = inner
def __call__(
self,
path: bytes,
mode: bytes = b"rb",
atomictemp=False,
checkambig=False,
):
fd = self.inner.__call__(
path=path, mode=mode, atomictemp=atomictemp, checkambig=checkambig
)
# Information that Rust needs to get ownership of the file that's
# being opened.
return (os.dup(fd.fileno()), fd._tempname if atomictemp else None)
def __getattr__(self, name):
return getattr(self.inner, name)
Gregory Szorc
py3: use class X: instead of class X(object):...
r49801 class revlog:
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).
revlog: improve documentation of the entry tuple...
r48020
revlog: move entry documentation alongside new related constants...
r48185 See mercurial/revlogutils/contants.py for details about the content of an
index entry.
mpm@selenic.com
Add some docstrings to revlog.py
r1083 """
flagprocessors: move _flagserrorclass attribute on revlog & co...
r43264
_flagserrorclass = error.RevlogError
Matt Harbison
bundlerepo: fix mismatches with repository and revlog classes...
r52764 _inner: "_InnerRevlog"
flagprocessors: move _flagserrorclass attribute on revlog & co...
r43264
Matt Harbison
typing: add type hints to the `opener` attributes and arguments of revlog...
r52713 opener: vfsmod.vfs
branching: merge with stable
r51579 @staticmethod
def is_inline_index(header_bytes):
revlog: document the `is_inline_index` method...
r51895 """Determine if a revlog is inline from the initial bytes of the index"""
Arseniy Alekseyev
stream-clone: fix a crash when a repo with an empty revlog is cloned
r51970 if len(header_bytes) == 0:
return True
branching: merge with stable
r51579 header = INDEX_HEADER.unpack(header_bytes)[0]
_format_flags = header & ~0xFFFF
_format_version = header & 0xFFFF
features = FEATURES_BY_VERSION[_format_version]
return features[b'inline'](_format_flags)
Matt Harbison
typing: add a few type hints to `mercurial/revlog.py`...
r52570 _docket_file: Optional[bytes]
Augie Fackler
formatting: blacken the codebase...
r43346 def __init__(
self,
Matt Harbison
typing: add type hints to the `opener` attributes and arguments of revlog...
r52713 opener: vfsmod.vfs,
revlog: introduce an explicit tracking of what the revlog is about...
r47838 target,
revlog: use a "radix" to address revlog...
r47921 radix,
revlog: move the `trypending` logic from the `changelog` to the `revlog`...
r48014 postfix=None, # only exist for `tmpcensored` now
Augie Fackler
formatting: blacken the codebase...
r43346 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,
revlog: move the `trypending` logic from the `changelog` to the `revlog`...
r48014 trypending=False,
revlog: improve the robustness of the splitting process...
r51242 try_split=False,
Joerg Sonnenberger
revlog: recommit 49fd21f32695 with a fix for issue6528...
r49876 canonical_parent_order=True,
revlog: allow explicit passing of config to revlog...
r52050 data_config=None,
delta_config=None,
feature_config=None,
revlog: add a `may_inline` argument to revlog...
r52051 may_inline=True, # may inline new revlog
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
revlog: introduce an explicit tracking of what the revlog is about...
r47838 `target`: a (KIND, ID) tuple that identify the content stored in
this revlog. It help the rest of the code to understand what the revlog
is about without having to resort to heuristic and index filename
analysis. Note: that this must be reliably be set by normal code, but
that test, debug, or performance measurement code might not set this to
accurate value.
mpm@selenic.com
Add some docstrings to revlog.py
r1083 """
revlog: use a "radix" to address revlog...
r47921
self.radix = radix
revlogv2: introduce a very basic docket file...
r48008 self._docket_file = None
revlog: define the actual index and datafile at loading time...
r47939 self._indexfile = None
self._datafile = None
revlog: store sidedata in their own file...
r48181 self._sidedatafile = None
revlog: rename `nodemap_file` to `_nodemap_file`...
r47935 self._nodemap_file = None
revlog: deal with special "postfix" explicitely...
r47916 self.postfix = postfix
revlog: move the `trypending` logic from the `changelog` to the `revlog`...
r48014 self._trypending = trypending
revlog: improve the robustness of the splitting process...
r51242 self._try_split = try_split
revlog: add a `may_inline` argument to revlog...
r52051 self._may_inline = may_inline
Raphaël Gomès
revlog: add the glue to use the Rust `InnerRevlog` from Python...
r53060 self.uses_rust = False
revlog: stop usage of `_indexfile` to computing nodemap path...
r47922 self.opener = opener
nodemap: write nodemap data on disk...
r44789 if persistentnodemap:
revlog: rename `nodemap_file` to `_nodemap_file`...
r47935 self._nodemap_file = nodemaputil.get_nodemap_file(self)
revlog: stop usage of `_indexfile` to computing nodemap path...
r47922
revlog: introduce an explicit tracking of what the revlog is about...
r47838 assert target[0] in ALL_KINDS
assert len(target) == 2
self.target = target
revlog: allow explicit passing of config to revlog...
r52050 if feature_config is not None:
self.feature_config = feature_config.copy()
elif b'feature-config' in self.opener.options:
revlog: create the revlog object at the repository level...
r51924 self.feature_config = self.opener.options[b'feature-config'].copy()
else:
self.feature_config = FeatureConfig()
self.feature_config.censorable = censorable
self.feature_config.canonical_parent_order = canonical_parent_order
revlog: allow explicit passing of config to revlog...
r52050 if data_config is not None:
self.data_config = data_config.copy()
elif b'data-config' in self.opener.options:
revlog: create the revlog object at the repository level...
r51924 self.data_config = self.opener.options[b'data-config'].copy()
else:
self.data_config = DataConfig()
self.data_config.check_ambig = checkambig
self.data_config.mmap_large_index = mmaplargeindex
revlog: allow explicit passing of config to revlog...
r52050 if delta_config is not None:
self.delta_config = delta_config.copy()
elif b'delta-config' in self.opener.options:
revlog: create the revlog object at the repository level...
r51924 self.delta_config = self.opener.options[b'delta-config'].copy()
else:
self.delta_config = DeltaConfig()
revlog: also migrates `revlog.upperboundcomp` to ConfigClass...
r51976 self.delta_config.upper_bound_comp = upperboundcomp
revlog: move configuration attribute into dedicated object...
r51922
Gregory Szorc
revlog: use an LRU cache for delta chain bases...
r29830 # Maps rev to chain base rev.
self._chainbasecache = util.lrucachedict(100)
revlog: move configuration attribute into dedicated object...
r51922
Raphaël Gomès
revlog: add the glue to use the Rust `InnerRevlog` from Python...
r53060 self.index: Optional[BaseIndexObject] = None
revlogv2: introduce a very basic docket file...
r48008 self._docket = 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 = {}
Matt Mackall
revlog: simplify revlog.__init__...
r4985
changelog-v2: add a configuration to disable rank computation...
r50558 # other optionnals features
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)
revlog: introduce a mandatory `_writing` context to update revlog content...
r47988 # prevent nesting of addgroup
self._adding_group = None
Gregory Szorc
revlog: automatically read from opened file handles...
r40661
Raphaël Gomès
revlog: add the glue to use the Rust `InnerRevlog` from Python...
r53060 index, chunk_cache = self._loadindex()
self._load_inner(index, chunk_cache)
Kyle Lippincott
revlog: add a mechanism to verify expected file position before appending...
r47349 self._concurrencychecker = concurrencychecker
revlog: split the option initialisation in its own method...
r47915 def _init_opts(self):
"""process options (from above/config) to setup associated default revlog mode
These values might be affected when actually reading on disk information.
The relevant values are returned for use in _loadindex().
* newversionflags:
version header to use if we need to create a new revlog
* mmapindexthreshold:
minimal index size for start to use mmap
* force_nodemap:
force the usage of a "development" version of the nodemap code
"""
vfs: give all vfs an options attribute by default...
r43295 opts = self.opener.options
Gregory Szorc
revlog: always process opener options...
r41236
changelogv2: introduce a "changelogv2" feature...
r48037 if b'changelogv2' in opts and self.revlog_kind == KIND_CHANGELOG:
changelogv2: use a dedicated version number...
r48040 new_header = CHANGELOGV2
revlog: move configuration attribute into dedicated object...
r51922 compute_rank = opts.get(b'changelogv2.compute-rank', True)
self.feature_config.compute_rank = compute_rank
changelogv2: introduce a "changelogv2" feature...
r48037 elif b'revlogv2' in opts:
revlogv2: no longer attempt to use inline for new revlog...
r48035 new_header = REVLOGV2
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 elif b'revlogv1' in opts:
revlog: add a `may_inline` argument to revlog...
r52051 new_header = REVLOGV1
if self._may_inline:
new_header |= FLAG_INLINE_DATA
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if b'generaldelta' in opts:
revlog: rename `newversionflags` to `new_header`...
r47942 new_header |= FLAG_GENERALDELTA
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 elif b'revlogv0' in self.opener.options:
revlog: rename `newversionflags` to `new_header`...
r47942 new_header = REVLOGV0
Gregory Szorc
revlog: always process opener options...
r41236 else:
revlog: rename `newversionflags` to `new_header`...
r47942 new_header = REVLOG_DEFAULT_VERSION
Gregory Szorc
revlog: always process opener options...
r41236
revlog: skip opener options to pass mmap_index_threshold value...
r51935 mmapindexthreshold = None
revlog: remove legacy usage of `_mmaplargeindex`...
r51942 if self.data_config.mmap_large_index:
revlog: skip opener options to pass mmap_index_threshold value...
r51935 mmapindexthreshold = self.data_config.mmap_index_threshold
revlog: skip opener options to pass enable_ellipsis...
r51934 if self.feature_config.enable_ellipsis:
Gregory Szorc
revlog: always process opener options...
r41236 self._flagprocessors[REVIDX_ELLIPSIS] = ellipsisprocessor
# revlog v0 doesn't have flag processors
Gregory Szorc
revlog: remove pycompat.iteritems()...
r49783 for flag, processor in opts.get(b'flagprocessors', {}).items():
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
revlog: move configuration attribute into dedicated object...
r51922 chunk_cache_size = self.data_config.chunk_cache_size
if chunk_cache_size <= 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')
revlog: move configuration attribute into dedicated object...
r51922 % chunk_cache_size
Augie Fackler
formatting: blacken the codebase...
r43346 )
revlog: move configuration attribute into dedicated object...
r51922 elif chunk_cache_size & (chunk_cache_size - 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')
revlog: move configuration attribute into dedicated object...
r51922 % chunk_cache_size
Augie Fackler
formatting: blacken the codebase...
r43346 )
revlog: split the option initialisation in its own method...
r47915 force_nodemap = opts.get(b'devel-force-nodemap', False)
revlog: rename `newversionflags` to `new_header`...
r47942 return new_header, mmapindexthreshold, force_nodemap
revlog: split the option initialisation in its own method...
r47915
revlogv2: track current index size in the docket...
r48012 def _get_data(self, filepath, mmap_threshold, size=None):
revlog: move index reading logic in a dedicated method...
r47940 """return a file content with or without mmap
If the file is missing return the empty string"""
try:
with self.opener(filepath) as fp:
if mmap_threshold is not None:
file_size = self.opener.fstat(fp).st_size
mmap: only use mmap to read revlog index if it is safe...
r52546 if (
file_size >= mmap_threshold
and self.opener.is_mmap_safe(filepath)
):
revlogv2: track current index size in the docket...
r48012 if size is not None:
# avoid potentiel mmap crash
size = min(file_size, size)
revlog: move index reading logic in a dedicated method...
r47940 # TODO: should .close() to release resources without
# relying on Python GC
revlogv2: track current index size in the docket...
r48012 if size is None:
return util.buffer(util.mmapread(fp))
else:
return util.buffer(util.mmapread(fp, size))
if size is None:
return fp.read()
else:
return fp.read(size)
Manuel Jacob
py3: catch FileNotFoundError instead of checking errno == ENOENT
r50201 except FileNotFoundError:
revlog: move index reading logic in a dedicated method...
r47940 return b''
branching: merge with stable
r51579 def get_streams(self, max_linkrev, force_inline=False):
revlog: document the `get_streams` method...
r51896 """return a list of streams that represent this revlog
This is used by stream-clone to do bytes to bytes copies of a repository.
This streams data for all revisions that refer to a changelog revision up
to `max_linkrev`.
If `force_inline` is set, it enforces that the stream will represent an inline revlog.
It returns is a list of three-tuple:
[
(filename, bytes_stream, stream_size),
]
"""
branching: merge with stable
r51579 n = len(self)
index = self.index
while n > 0:
linkrev = index[n - 1][4]
if linkrev < max_linkrev:
break
# note: this loop will rarely go through multiple iterations, since
# it only traverses commits created during the current streaming
# pull operation.
#
# If this become a problem, using a binary search should cap the
# runtime of this.
n = n - 1
if n == 0:
# no data to send
return []
index_size = n * index.entry_size
data_size = self.end(n - 1)
# XXX we might have been split (or stripped) since the object
# initialization, We need to close this race too, but having a way to
# pre-open the file we feed to the revlog and never closing them before
# we are done streaming.
if self._inline:
def get_stream():
revlog: remove the `_indexfp` method...
r51974 with self.opener(self._indexfile, mode=b"r") as fp:
branching: merge with stable
r51579 yield None
size = index_size + data_size
if size <= 65536:
yield fp.read(size)
else:
yield from util.filechunkiter(fp, limit=size)
inline_stream = get_stream()
next(inline_stream)
return [
(self._indexfile, inline_stream, index_size + data_size),
]
elif force_inline:
def get_stream():
stream-clone: use `revlog.reading` in `revlog.get_streams`...
r51911 with self.reading():
branching: merge with stable
r51579 yield None
for rev in range(n):
idx = self.index.entry_binary(rev)
if rev == 0 and self._docket is None:
# re-inject the inline flag
header = self._format_flags
header |= self._format_version
header |= FLAG_INLINE_DATA
header = self.index.pack_header(header)
idx = header + idx
yield idx
revlog: move _getsegmentforrevs on the internal object...
r51980 yield self._inner.get_segment_for_revs(rev, rev)[1]
branching: merge with stable
r51579
inline_stream = get_stream()
next(inline_stream)
return [
(self._indexfile, inline_stream, index_size + data_size),
]
else:
def get_index_stream():
revlog: remove the `_indexfp` method...
r51974 with self.opener(self._indexfile, mode=b"r") as fp:
branching: merge with stable
r51579 yield None
if index_size <= 65536:
yield fp.read(index_size)
else:
yield from util.filechunkiter(fp, limit=index_size)
def get_data_stream():
with self._datafp() as fp:
yield None
if data_size <= 65536:
yield fp.read(data_size)
else:
yield from util.filechunkiter(fp, limit=data_size)
index_stream = get_index_stream()
next(index_stream)
data_stream = get_data_stream()
next(data_stream)
return [
(self._datafile, data_stream, data_size),
(self._indexfile, index_stream, index_size),
]
revlog: allow to pass an existing docket to `_loadindex()`...
r48194 def _loadindex(self, docket=None):
revlog: rename `newversionflags` to `new_header`...
r47942 new_header, mmapindexthreshold, force_nodemap = self._init_opts()
revlog: define the actual index and datafile at loading time...
r47939
revlog: move the `trypending` logic from the `changelog` to the `revlog`...
r48014 if self.postfix is not None:
entry_point = b'%s.i.%s' % (self.radix, self.postfix)
elif self._trypending and self.opener.exists(b'%s.i.a' % self.radix):
entry_point = b'%s.i.a' % self.radix
revlog: move the computation of the split_index path in a property...
r51554 elif self._try_split and self.opener.exists(self._split_index_file):
entry_point = self._split_index_file
revlog: move the `trypending` logic from the `changelog` to the `revlog`...
r48014 else:
revlog: use "entry_point" phrasing for loading the revlog...
r47946 entry_point = b'%s.i' % self.radix
revlog: define the actual index and datafile at loading time...
r47939
revlog: allow to pass an existing docket to `_loadindex()`...
r48194 if docket is not None:
self._docket = docket
self._docket_file = entry_point
revlog: move index reading logic in a dedicated method...
r47940 else:
revlog: allow to pass an existing docket to `_loadindex()`...
r48194 self._initempty = True
entry_data = self._get_data(entry_point, mmapindexthreshold)
if len(entry_data) > 0:
header = INDEX_HEADER.unpack(entry_data[:4])[0]
self._initempty = False
revlogv2: introduce a very basic docket file...
r48008 else:
revlog: allow to pass an existing docket to `_loadindex()`...
r48194 header = new_header
self._format_flags = header & ~0xFFFF
self._format_version = header & 0xFFFF
supported_flags = SUPPORTED_FLAGS.get(self._format_version)
if supported_flags is None:
msg = _(b'unknown version (%d) in revlog %s')
msg %= (self._format_version, self.display_id)
raise error.RevlogError(msg)
elif self._format_flags & ~supported_flags:
msg = _(b'unknown flags (%#04x) in version %d revlog %s')
display_flag = self._format_flags >> 16
msg %= (display_flag, self._format_version, self.display_id)
raise error.RevlogError(msg)
features = FEATURES_BY_VERSION[self._format_version]
self._inline = features[b'inline'](self._format_flags)
revlog: move configuration attribute into dedicated object...
r51922 self.delta_config.general_delta = features[b'generaldelta'](
self._format_flags
)
Raphaël Gomès
changelog: also set the general delta config flag in the data config...
r53059 self.data_config.generaldelta = self.delta_config.general_delta
revlog: move configuration attribute into dedicated object...
r51922 self.feature_config.has_side_data = features[b'sidedata']
revlog: allow to pass an existing docket to `_loadindex()`...
r48194
if not features[b'docket']:
self._indexfile = entry_point
index_data = entry_data
else:
self._docket_file = entry_point
if self._initempty:
self._docket = docketutil.default_docket(self, header)
else:
self._docket = docketutil.parse_docket(
self, entry_data, use_pending=self._trypending
)
if self._docket is not None:
revlogv2: introduce a very basic docket file...
r48008 self._indexfile = self._docket.index_filepath()
revlogv2: track current index size in the docket...
r48012 index_data = b''
index_size = self._docket.index_end
if index_size > 0:
index_data = self._get_data(
self._indexfile, mmapindexthreshold, size=index_size
)
if len(index_data) < index_size:
msg = _(b'too few index data for %s: got %d, expected %d')
msg %= (self.display_id, len(index_data), index_size)
raise error.RevlogError(msg)
revlogv2: introduce a very basic docket file...
r48008 self._inline = False
# generaldelta implied by version 2 revlogs.
revlog: move configuration attribute into dedicated object...
r51922 self.delta_config.general_delta = True
Raphaël Gomès
changelog: also set the general delta config flag in the data config...
r53059 self.data_config.generaldelta = True
revlogv2: introduce a very basic docket file...
r48008 # the logic for persistent nodemap will be dealt with within the
# main docket, so disable it for now.
self._nodemap_file = None
revlog: use "entry_point" phrasing for loading the revlog...
r47946
revlogv2: use a unique filename for data...
r48115 if self._docket is not None:
self._datafile = self._docket.data_filepath()
revlog: store sidedata in their own file...
r48181 self._sidedatafile = self._docket.sidedata_filepath()
revlogv2: use a unique filename for data...
r48115 elif self.postfix is None:
revlog: use "entry_point" phrasing for loading the revlog...
r47946 self._datafile = b'%s.d' % self.radix
else:
self._datafile = b'%s.d.%s' % (self.radix, self.postfix)
Joerg Sonnenberger
node: introduce nodeconstants class...
r47538 self.nodeconstants = sha1nodeconstants
self.nullid = self.nodeconstants.nullid
Boris Feld
revlog: make sure we never use sparserevlog without general delta (issue6056)...
r41525 # sparse-revlog can't be on without general-delta (issue6056)
revlog: remove legacy usage of `_generaldelta`...
r51939 if not self.delta_config.general_delta:
revlog: move configuration attribute into dedicated object...
r51922 self.delta_config.sparse_revlog = 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 = (
revlog: rename `nodemap_file` to `_nodemap_file`...
r47935 self._nodemap_file
revlog: split the option initialisation in its own method...
r47915 and force_nodemap
revlog: remove the revlogio class...
r47810 and parse_index_v1_nodemap is not None
nodemap: add a (python) index class for persistent nodemap testing...
r44794 )
rust-nodemap: automatically use the rust index for persistent nodemap...
r45000 use_rust_index = False
Raphaël Gomès
revlog: add the glue to use the Rust `InnerRevlog` from Python...
r53060 rust_applicable = self._nodemap_file is not None
rust_applicable = rust_applicable or self.target[0] == KIND_FILELOG
rust_applicable = rust_applicable and getattr(
self.opener, "rust_compatible", True
)
if rustrevlog is not None and rust_applicable:
rust: disable the RustIndex without persistent nodemap...
r52321 # we would like to use the rust_index in all case, especially
# because it is necessary for AncestorsIterator and LazyAncestors
# since the 6.7 cycle.
#
# However, the performance impact of inconditionnaly building the
# nodemap is currently a problem for non-persistent nodemap
# repository.
use_rust_index = True
rust-nodemap: automatically use the rust index for persistent nodemap...
r45000
Raphaël Gomès
revlog: add the glue to use the Rust `InnerRevlog` from Python...
r53060 if self._format_version != REVLOGV1:
use_rust_index = False
Raphaël Gomès
revlog: add glue to use a pure-Rust VFS...
r53069 if hasattr(self.opener, "fncache"):
vfs = self.opener.vfs
if not self.opener.uses_dotencode:
use_rust_index = False
if not isinstance(vfs, vfsmod.vfs):
# Be cautious since we don't support other vfs
use_rust_index = False
else:
# Rust only supports repos with fncache
use_rust_index = False
revlog: remove the revlogio class...
r47810 self._parse_index = parse_index_v1
revlog: split the `version` attribute into its two components...
r47910 if self._format_version == REVLOGV0:
revlog: code for `revlogv0` in its own module...
r47812 self._parse_index = revlogv0.parse_index_v0
revlog: directly use self._format_version when loading index...
r47944 elif self._format_version == REVLOGV2:
revlog: remove the revlogio class...
r47810 self._parse_index = parse_index_v2
changelogv2: use a dedicated version number...
r48040 elif self._format_version == CHANGELOGV2:
changelogv2: use a dedicated on disk format for changelogv2...
r48044 self._parse_index = parse_index_cl_v2
nodemap: add a (python) index class for persistent nodemap testing...
r44794 elif devel_nodemap:
revlog: remove the revlogio class...
r47810 self._parse_index = parse_index_v1_nodemap
Raphaël Gomès
revlog: add the glue to use the Rust `InnerRevlog` from Python...
r53060
if use_rust_index:
# Let the Rust code parse its own index
index, chunkcache = (index_data, None)
self.uses_rust = True
else:
try:
d = self._parse_index(index_data, self._inline)
index, chunkcache = d
self._register_nodemap_info(index)
except (ValueError, IndexError):
raise error.RevlogError(
_(b"index %s is corrupted") % self.display_id
)
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)
mpm@selenic.com
Only use lazy indexing for big indices and avoid the overhead of the...
r116
Raphaël Gomès
revlog: add the glue to use the Rust `InnerRevlog` from Python...
r53060 return index, chunkcache
def _load_inner(self, index, chunk_cache):
revlog: move the compression/decompression logic on the inner object...
r51984 if self._docket is None:
default_compression_header = None
else:
default_compression_header = self._docket.default_compression_header
Raphaël Gomès
revlog: add the glue to use the Rust `InnerRevlog` from Python...
r53060 if self.uses_rust:
Raphaël Gomès
revlog: add glue to use a pure-Rust VFS...
r53069 vfs_is_readonly = False
fncache = None
if hasattr(self.opener, "vfs"):
vfs = self.opener
if isinstance(vfs, vfsmod.readonlyvfs):
vfs_is_readonly = True
vfs = vfs.vfs
fncache = vfs.fncache
vfs = vfs.vfs
else:
vfs = self.opener
vfs_base = vfs.base
assert fncache is not None, "Rust only supports repos with fncache"
Raphaël Gomès
revlog: add the glue to use the Rust `InnerRevlog` from Python...
r53060 self._inner = rustrevlog.InnerRevlog(
Raphaël Gomès
revlog: add glue to use a pure-Rust VFS...
r53069 vfs_base=vfs_base,
fncache=fncache,
vfs_is_readonly=vfs_is_readonly,
Raphaël Gomès
revlog: add the glue to use the Rust `InnerRevlog` from Python...
r53060 index_data=index,
index_file=self._indexfile,
data_file=self._datafile,
sidedata_file=self._sidedatafile,
inline=self._inline,
data_config=self.data_config,
delta_config=self.delta_config,
feature_config=self.feature_config,
chunk_cache=chunk_cache,
default_compression_header=default_compression_header,
revlog_type=self.target[0],
Raphaël Gomès
rust-revlog: don't create an in-memory nodemap for filelogs from Python...
r53071 use_persistent_nodemap=self._nodemap_file is not None,
Raphaël Gomès
revlog: add the glue to use the Rust `InnerRevlog` from Python...
r53060 )
self.index = RustIndexProxy(self._inner)
self._register_nodemap_info(self.index)
self.uses_rust = True
else:
self._inner = _InnerRevlog(
opener=self.opener,
index=index,
index_file=self._indexfile,
data_file=self._datafile,
sidedata_file=self._sidedatafile,
inline=self._inline,
data_config=self.data_config,
delta_config=self.delta_config,
feature_config=self.feature_config,
chunk_cache=chunk_cache,
default_compression_header=default_compression_header,
)
self.index = self._inner.index
def _register_nodemap_info(self, index):
use_nodemap = (
not self._inline
and self._nodemap_file is not None
and hasattr(index, 'update_nodemap_data')
revlog: create a iteration of a _InnerRevlog object within the revlog...
r51979 )
Raphaël Gomès
revlog: add the glue to use the Rust `InnerRevlog` from Python...
r53060 if use_nodemap:
nodemap_data = nodemaputil.persisted_data(self)
if nodemap_data is not None:
docket = nodemap_data[0]
if (
len(index) > docket.tip_rev
and index[docket.tip_rev][7] == docket.tip_node
):
# no changelog tampering
self._nodemap_docket = docket
index.update_nodemap_data(
*nodemap_data
) # pytype: disable=attribute-error
mpm@selenic.com
Only use lazy indexing for big indices and avoid the overhead of the...
r116
branching: merge with stable
r51579 def get_revlog(self):
"""simple function to mirror API of other not-really-revlog API"""
return self
Gregory Szorc
revlog: use compression engine API for compression...
r30795 @util.propertycache
revlog: replace the old `revlog_kind` approach with the new `target` one...
r47839 def revlog_kind(self):
return self.target[0]
@util.propertycache
revlog: introduce a `display_id` property...
r47924 def display_id(self):
"""The public facing "ID" of the revlog that we use in message"""
Matt Harbison
revlog: use the user facing filename as the display_id for filelogs...
r50429 if self.revlog_kind == KIND_FILELOG:
# Reference the file without the "data/" prefix, so it is familiar
# to the user.
return self.target[1]
else:
return self.radix
revlog: introduce a `display_id` property...
r47924
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"""
revlog: rename `datafile` to `datafile`...
r47920 return self.opener(self._datafile, mode=mode)
Boris Feld
revlog: move datafile opening in a method...
r35985
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 Harbison
typing: lock in new pytype gains from making revlog related classes typeable...
r52719 def __iter__(self) -> Iterator[int]:
Manuel Jacob
py3: replace `pycompat.xrange` by `range`
r50179 return iter(range(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
Matt Mackall
revlog: add hasnode helper method
r16374 def hasnode(self, node):
try:
self.rev(node)
return True
except KeyError:
return False
revlog: make the `candelta` method private...
r51897 def _candelta(self, baserev, rev):
Jun Wu
changegroup: do not delta lfs revisions...
r36764 """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):
revlog: document the `update_caches` method...
r51898 """update on disk cache
If a transaction is passed, the update may be delayed to transaction
commit."""
revlog: rename `nodemap_file` to `_nodemap_file`...
r47935 if self._nodemap_file is not None:
nodemap: warm the persistent nodemap on disk with debugupdatecache...
r44932 if transaction is None:
nodemaputil.update_persistent_nodemap(self)
else:
nodemaputil.setup_persistent_nodemap(transaction, self)
Matt Harbison
revlog: make `clearcaches()` signature consistent with ManifestRevlog...
r52765 def clearcaches(self, clear_persisted_data: bool = False) -> None:
revlog: document the `clearcaches` method...
r51899 """Clear in-memory caches"""
Gregory Szorc
revlog: use an LRU cache for delta chain bases...
r29830 self._chainbasecache.clear()
revlog: consolidate cache invalidation within the inner objet...
r51994 self._inner.clear_cache()
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
revlog: rename `nodemap_file` to `_nodemap_file`...
r47935 and self._nodemap_file is not None
safehasattr: drop usage in favor of hasattr...
r51821 and hasattr(self.index, 'update_nodemap_data')
nodemap: refresh the persistent data on nodemap creation...
r44988 )
if use_nodemap:
nodemap_data = nodemaputil.persisted_data(self)
if nodemap_data is not None:
self._nodemap_docket = nodemap_data[0]
Raphaël Gomès
revlog: add the glue to use the Rust `InnerRevlog` from Python...
r53060 self.index.update_nodemap_data(
*nodemap_data
) # pytype: disable=attribute-error
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):
revlog: document the `rev` method...
r51900 """return the revision number associated with a <nodeid>"""
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
Joerg Sonnenberger
node: replace nullid and friends with nodeconstants class...
r47771 if (
node == self.nodeconstants.wdirid
or node in self.nodeconstants.wdirfilenodeids
):
revlog: move the nodemap into the index object (for pure)...
r43925 raise error.WdirUnsupported
revlog: use revlog.display_id in LookupError...
r47926 raise error.LookupError(node, self.display_id, _(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
revlog: store sidedata in their own file...
r48181 def sidedata_cut_off(self, rev):
sd_cut_off = self.index[rev][8]
if sd_cut_off != 0:
return sd_cut_off
# This is some annoying dance, because entries without sidedata
# currently use 0 as their ofsset. (instead of previous-offset +
# previous-size)
#
# We should reconsider this sidedata → 0 sidata_offset policy.
# In the meantime, we need this.
while 0 <= rev:
e = self.index[rev]
if e[9] != 0:
return e[8] + e[9]
rev -= 1
return 0
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):
revlog: remove legacy usage of `hassidedata`...
r51954 if not self.feature_config.has_side_data:
Raphaël Gomès
sidedata: move to new sidedata storage in revlogv2...
r47443 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)
Raphaël Gomès
revlog: remove deprecated APIs...
r49360 return len(self.revision(rev))
Gregory Szorc
revlog: reorder index accessors to match data structure order...
r30287
rank: naive rank property computation and retrieval...
r49606 def fast_rank(self, rev):
"""Return the rank of a revision if already known, or None otherwise.
The rank of a revision is the size of the sub-graph it defines as a
head. Equivalently, the rank of a revision `r` is the size of the set
`ancestors(r)`, `r` included.
This method returns the rank retrieved from the revlog in constant
time. It makes no attempt at computing unknown values for versions of
the revlog which do not persist the rank.
"""
rank = self.index[rev][ENTRY_RANK]
pacien
revlog: return 0 for the fast_rank of nullrev...
r49706 if self._format_version != CHANGELOGV2 or rank == RANK_UNKNOWN:
rank: naive rank property computation and retrieval...
r49606 return None
pacien
revlog: return 0 for the fast_rank of nullrev...
r49706 if rev == nullrev:
return 0 # convention
rank: naive rank property computation and retrieval...
r49606 return rank
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
corruption: backout changeset 49fd21f32695 (issue6528)...
r48355
revlog: remove legacy usage of `canonical_parent_order`...
r51958 if self.feature_config.canonical_parent_order and entry[5] == nullrev:
Joerg Sonnenberger
revlog: recommit 49fd21f32695 with a fix for issue6528...
r49876 return entry[6], entry[5]
else:
return entry[5], entry[6]
Gregory Szorc
revlog: don't use slicing to return parents...
r35539
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)]
Joerg Sonnenberger
revlog: recommit 49fd21f32695 with a fix for issue6528...
r49876 # inline node() to avoid function call overhead
revlog: remove legacy usage of `canonical_parent_order`...
r51958 if self.feature_config.canonical_parent_order and d[5] == self.nullid:
Joerg Sonnenberger
revlog: recommit 49fd21f32695 with a fix for issue6528...
r49876 return i[d[6]][7], i[d[5]][7]
else:
return i[d[5]][7], i[d[6]][7]
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
revlog: remove legacy usage of `_generaldelta`...
r51939 generaldelta = self.delta_config.general_delta
Mateusz Kwapich
debugrevlog: fix computing chain length in debugrevlog -d...
r23254 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):
revlog: move the `deltachain` method on the inner object...
r51988 return self._inner._deltachain(rev, stoprev=stoprev)
Gregory Szorc
revlog: refactor delta chain computation into own function...
r27468
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
revlog: do not call Rust code if the index is not compatible with it...
r48043 if rustancestor is not None and self.index.rust_ext_compat:
Georges Racinet
rust: using policy.importrust from Python callers...
r42652 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:
Joerg Sonnenberger
node: replace nullid and friends with nodeconstants class...
r47771 common = [self.nullid]
Benoit Boissinot
fix pull racing with push/commit (issue1320)...
r7233 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
Gregory Szorc
py3: use class X: instead of class X(object):...
r49801 class lazyset:
Durham Goode
revlog: return lazy set from findcommonmissing...
r20073 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]
revlog: do not call Rust code if the index is not compatible with it...
r48043 if rustancestor is not None and self.index.rust_ext_compat:
Georges Racinet
rust: using policy.importrust from Python callers...
r42652 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:
Joerg Sonnenberger
node: replace nullid and friends with nodeconstants class...
r47771 common = [self.nullid]
Siddharth Agarwal
revlog: switch findmissing to use ancestor.missingancestors...
r17971 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:
Joerg Sonnenberger
node: replace nullid and friends with nodeconstants class...
r47771 roots = [self.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!
Joerg Sonnenberger
node: replace nullid and friends with nodeconstants class...
r47771 return (
[self.node(r) for r in self],
[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
Joerg Sonnenberger
node: replace nullid and friends with nodeconstants class...
r47771 if n == self.nullid:
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 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(
Joerg Sonnenberger
node: replace nullid and friends with nodeconstants class...
r47771 [p for p in self.parents(n) if p != self.nullid]
Augie Fackler
formatting: blacken the codebase...
r43346 )
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
Joerg Sonnenberger
node: replace nullid and friends with nodeconstants class...
r47771 roots = [self.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
global: bulk replace simple pycompat.iteritems(x) with x.items()...
r49768 heads = [head for head, flag in heads.items() 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)
branchmap-v3: introduce a "stop_rev" argument to `headsrevs`...
r52870 def headrevs(self, revs=None, stop_rev=None):
Boris Feld
revlog: accept a revs argument in `headrevs`...
r41311 if revs is None:
head-revs: add a native implementation of the `stop_rev` parameter...
r52872 return self.index.headrevs(None, stop_rev)
revlog: do not call Rust code if the index is not compatible with it...
r48043 if rustdagop is not None and self.index.rust_ext_compat:
Georges Racinet
rust: using policy.importrust from Python callers...
r42652 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
Arseniy Alekseyev
unbundle: faster computation of changed heads...
r52288 def headrevsdiff(self, start, stop):
try:
Raphaël Gomès
revlog: add the glue to use the Rust `InnerRevlog` from Python...
r53060 return self.index.headrevsdiff(
start, stop
) # pytype: disable=attribute-error
Arseniy Alekseyev
unbundle: faster computation of changed heads...
r52288 except AttributeError:
return dagop.headrevsdiff(self._uncheckedparentrevs, start, stop)
Laurent Charignon
phase: default to C implementation for phase computation
r24444 def computephases(self, roots):
Raphaël Gomès
revlog: add the glue to use the Rust `InnerRevlog` from Python...
r53060 return self.index.computephasesmapsets(
roots
) # pytype: disable=attribute-error
Laurent Charignon
phase: default to C implementation for phase computation
r24444
Raphaël Gomès
rust-index: add fast-path for getting a list of all heads as nodes...
r52155 def _head_node_ids(self):
try:
Raphaël Gomès
revlog: add the glue to use the Rust `InnerRevlog` from Python...
r53060 return self.index.head_node_ids() # pytype: disable=attribute-error
Raphaël Gomès
rust-index: add fast-path for getting a list of all heads as nodes...
r52155 except AttributeError:
return [self.node(r) for r in self.headrevs()]
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):
Joerg Sonnenberger
node: replace nullid and friends with nodeconstants class...
r47771 return [self.nullid]
Raphaël Gomès
rust-index: add fast-path for getting a list of all heads as nodes...
r52155 return self._head_node_ids()
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
Arseniy Alekseyev
unbundle: faster computation of changed heads...
r52288 def diffheads(self, start, stop):
"""return the nodes that make up the difference between
heads of revs before `start` and heads of revs before `stop`"""
removed, added = self.headrevsdiff(start, stop)
return [self.node(r) for r in removed], [self.node(r) for r in added]
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:
Raphaël Gomès
revlog: add the glue to use the Rust `InnerRevlog` from Python...
r53060 ancs = self.index.commonancestorsheads(
*revs
) # pytype: disable=attribute-error
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
Raphaël Gomès
revlog: add the glue to use the Rust `InnerRevlog` from Python...
r53060 ) # pytype: disable=attribute-error
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:
Raphaël Gomès
revlog: add the glue to use the Rust `InnerRevlog` from Python...
r53060 ancs = self.index.ancestors(a, b) # pytype: disable=attribute-error
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))
Joerg Sonnenberger
node: replace nullid and friends with nodeconstants class...
r47771 return self.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)
Joerg Sonnenberger
core: don't hard-code node length...
r47816 if len(id) == self.nodeconstants.nodelen:
Matt Mackall
revlog.lookup tweaks...
r3438 # 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
Joerg Sonnenberger
core: don't hard-code hex node lengths...
r47815 if len(id) == 2 * self.nodeconstants.nodelen:
Matt Mackall
Only look up tags and branches as a last resort
r3453 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
Manuel Jacob
node: stop converting binascii.Error to TypeError in bin()...
r50143 except (binascii.Error, 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
Joerg Sonnenberger
node: replace nullid and friends with nodeconstants class...
r47771 maybewdir = self.nodeconstants.wdirhex.startswith(id)
Martin von Zweigbergk
revlog: avoid raising no-arg RevlogError for internal flow control...
r48074 ambiguous = False
Bryan O'Sullivan
revlog: speed up prefix matching against nodes...
r16665 try:
Raphaël Gomès
revlog: add the glue to use the Rust `InnerRevlog` from Python...
r53060 partial = self.index.partialmatch(
id
) # pytype: disable=attribute-error
Augie Fackler
revlog: avoid shadowing several variables using list comprehensions
r30391 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
Martin von Zweigbergk
revlog: avoid raising no-arg RevlogError for internal flow control...
r48074 ambiguous = True
else:
return partial
elif maybewdir:
Yuya Nishihara
revlog: add support for partial matching of wdir node id...
r32684 # no 'ff...' match in radix tree, wdir identified
raise error.WdirUnsupported
Martin von Zweigbergk
revlog: avoid raising no-arg RevlogError for internal flow control...
r48074 else:
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):
Martin von Zweigbergk
revlog: avoid raising no-arg RevlogError for internal flow control...
r48074 ambiguous = True
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):
Arseniy Alekseyev
revlog: make _partialmatch fail fast on almost-hex inputs...
r50310 # we are pure python, or key is not hex
Bryan O'Sullivan
revlog: speed up prefix matching against nodes...
r16665 pass
Martin von Zweigbergk
revlog: avoid raising no-arg RevlogError for internal flow control...
r48074 if ambiguous:
raise error.AmbiguousPrefixLookupError(
id, self.display_id, _(b'ambiguous identifier')
)
Bryan O'Sullivan
revlog: speed up prefix matching against nodes...
r16665
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:
Manuel Jacob
revlog: make try block smaller...
r50142 # hex(node)[:...]
l = len(id) // 2 * 2 # grab an even number of digits
Matt Mackall
Only look up tags and branches as a last resort
r3453 try:
Arseniy Alekseyev
revlog: make _partialmatch fail fast on almost-hex inputs...
r50310 # we're dropping the last digit, so let's check that it's hex,
# to avoid the expensive computation below if it's not
if len(id) % 2 > 0:
if not (id[-1] in hexdigits):
return None
Manuel Jacob
revlog: make round-down pattern clearer
r50141 prefix = bin(id[:l])
Manuel Jacob
node: stop converting binascii.Error to TypeError in bin()...
r50143 except binascii.Error:
Manuel Jacob
revlog: make try block smaller...
r50142 pass
else:
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)
]
Joerg Sonnenberger
node: replace nullid and friends with nodeconstants class...
r47771 if self.nodeconstants.nullhex.startswith(id):
nl.append(self.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(
revlog: use revlog.display_id in ambiguity errors...
r47930 id, self.display_id, _(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
Matt Mackall
Only look up tags and branches as a last resort
r3453
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
revlog: use revlog.display_id in LookupError...
r47926 raise error.LookupError(id, self.display_id, _(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:
revlog: use revlog.display_id in LookupError...
r47926 raise error.LookupError(node, self.display_id, _(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:
Raphaël Gomès
revlog: add the glue to use the Rust `InnerRevlog` from Python...
r53060 shortest = self.index.shortest(
node
) # pytype: disable=attribute-error
length = max(shortest, minlength)
Martin von Zweigbergk
revlog: use node tree (native code) for shortest() calculation...
r37987 return disambiguate(hexnode, length)
Gregory Szorc
revlog: drop RevlogError alias (API)...
r39809 except error.RevlogError:
Joerg Sonnenberger
node: replace nullid and friends with nodeconstants class...
r47771 if node != self.nodeconstants.wdirid:
revlog: rename `indexfile` to `_indexfile`...
r47919 raise error.LookupError(
revlog: use revlog.display_id in LookupError...
r47926 node, self.display_id, _(b'no node')
revlog: rename `indexfile` to `_indexfile`...
r47919 )
Martin von Zweigbergk
revlog: use node tree (native code) for shortest() calculation...
r37987 except AttributeError:
# Fall through to pure code
pass
Joerg Sonnenberger
node: replace nullid and friends with nodeconstants class...
r47771 if node == self.nodeconstants.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
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
revlog: remove legacy usage of `_generaldelta`...
r51939 elif self.delta_config.general_delta:
Sune Foldager
revlog: support reading generaldelta revlogs...
r14253 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"""
revlog: add a couple more of useful method on the inner object...
r51986 ret = self._inner.issnapshot(rev)
self.issnapshot = self._inner.issnapshot
return ret
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')
revlog: move the `deltachain` method on the inner object...
r51988 return len(self._inner._deltachain(rev)[0]) - 1
Boris Feld
revlog: add a method to retrieve snapshot depth...
r39188
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:
revlog: move the `_chunk` method on the inner object...
r51985 return bytes(self._inner._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
revlog: drop the df argument to `revision`...
r51915 def revision(self, nodeorrev):
Patrick Mezard
revlog: fix partial revision() docstring (from d7d64b89a65c)
r16435 """return an uncompressed revision of a given node or revision
number.
"""
revlog: drop the df argument to `revision`...
r51915 return self._revisiondata(nodeorrev)
revlog: split a `_revisiondata` method to file `revision` job...
r42944
revlog: drop the df argument to `sidedata`...
r51917 def sidedata(self, nodeorrev):
revlog: introduce a `sidedata` method...
r43250 """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: implement sidedata without using _revisiondata...
r48174 # deal with <nodeorrev> argument type
if isinstance(nodeorrev, int):
rev = nodeorrev
else:
rev = self.rev(nodeorrev)
return self._sidedata(rev)
revlog: introduce a `sidedata` method...
r43250
revlog: move the `rawtext` method on the inner object...
r51990 def _rawtext(self, node, rev):
"""return the possibly unvalidated rawtext for a revision
returns (rev, rawtext, validated)
"""
# Check if we have the entry in cache
# The cache entry looks like (node, rev, rawtext)
if self._inner._revisioncache:
if self._inner._revisioncache[0] == node:
return (rev, self._inner._revisioncache[2], True)
if rev is None:
rev = self.rev(node)
Raphaël Gomès
revlog: simplify rawtext return value...
r52749 text = self._inner.raw_text(node, rev)
return (rev, text, False)
revlog: move the `rawtext` method on the inner object...
r51990
revlog: drop more file description passing between private function...
r51919 def _revisiondata(self, nodeorrev, 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
Joerg Sonnenberger
node: replace nullid and friends with nodeconstants class...
r47771 if node == self.nullid:
revlog: no longer return sidedata from `_revisiondata`...
r48177 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: drop more file description passing between private function...
r51919 rev, rawtext, validated = self._rawtext(node, rev)
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.
revlog: no longer return sidedata from `_revisiondata`...
r48177 return rawtext
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
revlog: no longer return sidedata from `_revisiondata`...
r48177 return rawtext
Raphaël Gomès
sidedata: move to new sidedata storage in revlogv2...
r47443
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:
revlog: move the_revisioncache on the inner object...
r51989 self._inner._revisioncache = (node, rev, rawtext)
revlog: split `rawtext` retrieval out of _revisiondata...
r43060
revlog: no longer return sidedata from `_revisiondata`...
r48177 return text
revlog: split `rawtext` retrieval out of _revisiondata...
r43060
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."""
Raphaël Gomès
revlog: add an early return for getting sidedata...
r52750 if self._sidedatafile is None:
return {}
revlog: move `sidedata` in the inner object...
r51991 sidedata_end = None
if self._docket is not None:
sidedata_end = self._docket.sidedata_end
return self._inner.sidedata(rev, sidedata_end)
Raphaël Gomès
sidedata: move to new sidedata storage in revlogv2...
r47443
revlog: drop the df argument to `rawdata`...
r51916 def rawdata(self, nodeorrev):
"""return an uncompressed raw data of a given node or revision number."""
return self._revisiondata(nodeorrev, raw=True)
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.
revlog: move the_revisioncache on the inner object...
r51989 if (
self._inner._revisioncache
and self._inner._revisioncache[0] == node
):
self._inner._revisioncache = None
Gregory Szorc
revlog: clear revision cache on hash verification failure...
r40090
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")
revlog: use revlog.display_id in integrity error...
r47931 % (self.display_id, pycompat.bytestr(revornode))
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
revlog: drop RevlogError alias (API)...
r39809 except error.RevlogError:
revlog: remove legacy usage of `_censorable`...
r51943 if self.feature_config.censorable and storageutil.iscensoredtext(
text
):
revlog: use revlog.display_id in censor related errors...
r47932 raise error.CensoredNodeError(self.display_id, node, text)
Gregory Szorc
revlog: move censor logic into main revlog class...
r37461 raise
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
revlog: move the computation of the split_index path in a property...
r51554 @property
def _split_index_file(self):
"""the path where to expect the index of an ongoing splitting operation
The file will only exist if a splitting operation is in progress, but
it is always expected at the same location."""
revlog: fix the naming scheme use by split temporary file...
r51707 parts = self.radix.split(b'/')
revlog: avoid possible collision between directory and temporary index...
r51555 if len(parts) > 1:
# adds a '-s' prefix to the ``data/` or `meta/` base
head = parts[0] + b'-s'
revlog: fix the naming scheme use by split temporary file...
r51707 mids = parts[1:-1]
tail = parts[-1] + b'.i'
pieces = [head] + mids + [tail]
return b'/'.join(pieces)
revlog: avoid possible collision between directory and temporary index...
r51555 else:
# the revlog is stored at the root of the store (changelog or
# manifest), no risk of collision.
return self.radix + b'.i.s'
revlog: move the computation of the split_index path in a property...
r51554
changelog: drop the side_write argument to revlog splitting...
r52210 def _enforceinlinesize(self, tr):
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
revlog: simplify a conditionnal in _enforceinlinesize...
r47938 total_size = self.start(tiprev) + self.length(tiprev)
changelog: disallow delayed write on inline changesets...
r52075 if not self._inline or (self._may_inline and total_size < _maxinline):
mason@suse.com
Implement data inlined with the index file...
r2073 return
Matt Mackall
revlog: use index to find index size
r8315
revlog: drop reference to docket in the inline-splitting code...
r51981 if self._docket is not None:
msg = b"inline revlog should not have a docket"
raise error.ProgrammingError(msg)
changelog: never inline changelog...
r52074 # In the common case, we enforce inline size because the revlog has
# been appened too. And in such case, it must have an initial offset
# recorded in the transaction.
revlog: add a `canonical_index_file` attribute on inner revlog...
r51998 troffset = tr.findoffset(self._inner.canonical_index_file)
changelog: never inline changelog...
r52074 pre_touched = troffset is not None
if not pre_touched and self.target[0] != KIND_CHANGELOG:
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.RevlogError(
revlog: rename `indexfile` to `_indexfile`...
r47919 _(b"%s not found in the transaction") % self._indexfile
Augie Fackler
formatting: blacken the codebase...
r43346 )
changelog: never inline changelog...
r52074
tr.addbackup(self._inner.canonical_index_file, for_offset=pre_touched)
revlog: rename `datafile` to `datafile`...
r47920 tr.add(self._datafile, 0)
Matt Mackall
revlog: use index to find index size
r8315
revlog: move the splitting-inline-revlog logic inside the inner object...
r51983 new_index_file_path = None
changelog: drop the side_write argument to revlog splitting...
r52210 old_index_file_path = self._indexfile
new_index_file_path = self._split_index_file
opener = self.opener
weak_self = weakref.ref(self)
# the "split" index replace the real index when the transaction is
# finalized
def finalize_callback(tr):
opener.rename(
new_index_file_path,
old_index_file_path,
checkambig=True,
)
maybe_self = weak_self()
if maybe_self is not None:
maybe_self._indexfile = old_index_file_path
maybe_self._inner.index_file = maybe_self._indexfile
def abort_callback(tr):
maybe_self = weak_self()
if maybe_self is not None:
maybe_self._indexfile = old_index_file_path
maybe_self._inner.inline = True
maybe_self._inner.index_file = old_index_file_path
tr.registertmp(new_index_file_path)
inline-changelog: fix a critical bug in write_pending that delete data...
r52530 # we use 001 here to make this this happens after the finalisation of
# pending changelog write (using 000). Otherwise the two finalizer
# would step over each other and delete the changelog.i file.
changelog: drop the side_write argument to revlog splitting...
r52210 if self.target[1] is not None:
inline-changelog: fix a critical bug in write_pending that delete data...
r52530 callback_id = b'001-revlog-split-%d-%s' % self.target
changelog: drop the side_write argument to revlog splitting...
r52210 else:
inline-changelog: fix a critical bug in write_pending that delete data...
r52530 callback_id = b'001-revlog-split-%d' % self.target[0]
changelog: drop the side_write argument to revlog splitting...
r52210 tr.addfinalize(callback_id, finalize_callback)
tr.addabort(callback_id, abort_callback)
Matt Mackall
revlog: use index to find index size
r8315
revlog: move the splitting-inline-revlog logic inside the inner object...
r51983 self._format_flags &= ~FLAG_INLINE_DATA
self._inner.split_inline(
tr,
self._format_flags | self._format_version,
new_index_file_path=new_index_file_path,
)
self._inline = False
if new_index_file_path is not None:
self._indexfile = new_index_file_path
nodemaputil.setup_persistent_nodemap(tr, self)
revlog: introduce a mandatory `_writing` context to update revlog content...
r47988
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
revlog: introduce a mandatory `_writing` context to update revlog content...
r47988 @contextlib.contextmanager
Simon Sapin
copies: Keep changelog sidedata file open during copy tracing...
r48256 def reading(self):
revlog: create a iteration of a _InnerRevlog object within the revlog...
r51979 with self._inner.reading():
yield
Simon Sapin
copies: Keep changelog sidedata file open during copy tracing...
r48256
@contextlib.contextmanager
revlog: introduce a mandatory `_writing` context to update revlog content...
r47988 def _writing(self, transaction):
revlog: move the `trypending` logic from the `changelog` to the `revlog`...
r48014 if self._trypending:
msg = b'try to write in a `trypending` revlog: %s'
msg %= self.display_id
raise error.ProgrammingError(msg)
revlog: create a iteration of a _InnerRevlog object within the revlog...
r51979 if self._inner.is_writing:
revlog: introduce a mandatory `_writing` context to update revlog content...
r47988 yield
else:
revlog: create a iteration of a _InnerRevlog object within the revlog...
r51979 data_end = None
sidedata_end = None
if self._docket is not None:
data_end = self._docket.data_end
sidedata_end = self._docket.sidedata_end
with self._inner.writing(
transaction,
data_end=data_end,
sidedata_end=sidedata_end,
):
revlog: simplify the try nesting in the `_writing` context...
r48118 yield
if self._docket is not None:
self._write_docket(transaction)
revlog: introduce a mandatory `_writing` context to update revlog content...
r47988
changelog-delay: move the delay/divert logic inside the (inner) revlog...
r51999 @property
def is_delaying(self):
return self._inner.is_delaying
revlog: introduce a mandatory `_writing` context to update revlog content...
r47988
revlogv2: delay the update of the changelog docket to transaction end...
r48013 def _write_docket(self, transaction):
"""write the current docket on disk
Exist as a method to help changelog to implement transaction logic
We could also imagine using the same transaction logic for all revlog
since docket are cheap."""
self._docket.write(transaction)
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(
revlog: use revlog.display_id in error related to bad revisions...
r47934 _(b"attempted to add linkrev -1 to %s") % self.display_id
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 = {}
revlog: remove legacy usage of `hassidedata`...
r51954 elif sidedata and not self.feature_config.has_side_data:
sidedata: introduce a new requirement to protect the feature...
r43298 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"
)
revlog: use revlog.display_id in "revision too big" errors...
r47933 % (self.display_id, len(rawtext))
Augie Fackler
formatting: blacken the codebase...
r43346 )
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).
"""
revlog: introduce a mandatory `_writing` context to update revlog content...
r47988 with self._writing(transaction):
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,
deltacomputer=deltacomputer,
Raphaël Gomès
sidedata: move to new sidedata storage in revlogv2...
r47443 sidedata=sidedata,
Augie Fackler
formatting: blacken the codebase...
r43346 )
Alexis S. L. Carvalho
make revlog.addgroup pass its file handles to addrevision...
r3390
Matt Harbison
typing: add a few type hints to `mercurial/revlog.py`...
r52570 def compress(self, data: bytes) -> Tuple[bytes, bytes]:
revlog: move the compression/decompression logic on the inner object...
r51984 return self._inner.compress(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):
revlog: move the compression/decompression logic on the inner object...
r51984 return self._inner.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,
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 """
Joerg Sonnenberger
node: replace nullid and friends with nodeconstants class...
r47771 if node == self.nullid:
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.RevlogError(
revlog: use revlog.display_id in error related to bad revisions...
r47934 _(b"%s: attempt to add null revision") % self.display_id
Augie Fackler
formatting: blacken the codebase...
r43346 )
Joerg Sonnenberger
node: replace nullid and friends with nodeconstants class...
r47771 if (
node == self.nodeconstants.wdirid
or node in self.nodeconstants.wdirfilenodeids
):
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.RevlogError(
revlog: use revlog.display_id in error related to bad revisions...
r47934 _(b"%s: attempt to add wdir revision") % self.display_id
Augie Fackler
formatting: blacken the codebase...
r43346 )
Raphaël Gomès
revlog: use the method to check if the revlog is being written to...
r52751 if not self._inner.is_writing:
revlog: introduce a mandatory `_writing` context to update revlog content...
r47988 msg = b'adding revision outside `revlog._writing` context'
raise error.ProgrammingError(msg)
Martin von Zweigbergk
revlog: move check for wdir from changelog to revlog...
r34029
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:
revlog: create a iteration of a _InnerRevlog object within the revlog...
r51979 ifh, dfh, sdfh = self._inner._writinghandles
revlog: store sidedata in their own file...
r48181 # XXX no checking for the sidedata file
Kyle Lippincott
revlog: add a mechanism to verify expected file position before appending...
r47349 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(
revlog: rename `indexfile` to `_indexfile`...
r47919 ifh, self._indexfile, offset + curr * self.index.entry_size
Kyle Lippincott
revlog: add a mechanism to verify expected file position before appending...
r47349 )
else:
# Entries in the .i are a consistent size.
self._concurrencychecker(
revlog: rename `indexfile` to `_indexfile`...
r47919 ifh, self._indexfile, curr * self.index.entry_size
Kyle Lippincott
revlog: add a mechanism to verify expected file position before appending...
r47349 )
revlog: rename `datafile` to `datafile`...
r47920 self._concurrencychecker(dfh, self._datafile, offset)
Kyle Lippincott
revlog: add a mechanism to verify expected file position before appending...
r47349
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:
deltas: add a `debug.revlog.debug-delta` config option enable output...
r50122 write_debug = None
revlog: remove legacy usage of `_debug_delta`...
r51947 if self.delta_config.debug_delta:
deltas: add a `debug.revlog.debug-delta` config option enable output...
r50122 write_debug = transaction._report
deltacomputer = deltautil.deltacomputer(
self, write_debug=write_debug
)
Paul Morelle
revlog: group delta computation methods under _deltacomputer object...
r35756
find-delta: pass the cache-delta usage policy alongside the cache-delta...
r50572 if cachedelta is not None and len(cachedelta) == 2:
# If the cached delta has no information about how it should be
# reused, add the default reuse instruction according to the
# revlog's configuration.
revlog: remove legacy usage of `_generaldelta`...
r51939 if (
self.delta_config.general_delta
and self.delta_config.lazy_delta_base
):
find-delta: pass the cache-delta usage policy alongside the cache-delta...
r50572 delta_base_reuse = DELTA_BASE_REUSE_TRY
else:
delta_base_reuse = DELTA_BASE_REUSE_NO
cachedelta = (cachedelta[0], cachedelta[1], delta_base_reuse)
revlog: move `revisioninfo` in `revlogutils`...
r48191 revinfo = revlogutils.revisioninfo(
node,
p1,
p2,
btext,
textlen,
cachedelta,
flags,
)
Jun Wu
revlog: do not use delta for lfs revisions...
r36765
delta-computer: stop explicitly taking file handle...
r51913 deltainfo = deltacomputer.finddeltainfo(revinfo)
Paul Morelle
revlog: refactor out the selection of candidate revisions...
r35652
revlog: introduce a plain compression mode...
r48027 compression_mode = COMP_MODE_INLINE
if self._docket is not None:
revlog: factor the logic to determine the delta compression out...
r48245 default_comp = self._docket.default_compression_header
r = deltautil.delta_compression(default_comp, deltainfo)
compression_mode, deltainfo = r
revlog: introduce a plain compression mode...
r48027
revlog: introduce a compression mode for sidedata in the revlog index...
r48030 sidedata_compression_mode = COMP_MODE_INLINE
revlog: remove legacy usage of `hassidedata`...
r51954 if sidedata and self.feature_config.has_side_data:
revlog: introduce a compression mode for sidedata in the revlog index...
r48030 sidedata_compression_mode = COMP_MODE_PLAIN
Raphaël Gomès
sidedata: move to new sidedata storage in revlogv2...
r47443 serialized_sidedata = sidedatautil.serialize_sidedata(sidedata)
revlog: store sidedata in their own file...
r48181 sidedata_offset = self._docket.sidedata_end
revlog: move the compression/decompression logic on the inner object...
r51984 h, comp_sidedata = self._inner.compress(serialized_sidedata)
revlog: compress sidedata in `_writeentry`...
r48032 if (
h != b'u'
and comp_sidedata[0:1] != b'\0'
and len(comp_sidedata) < len(serialized_sidedata)
):
assert not h
if (
comp_sidedata[0:1]
== self._docket.default_compression_header
):
sidedata_compression_mode = COMP_MODE_DEFAULT
serialized_sidedata = comp_sidedata
else:
sidedata_compression_mode = COMP_MODE_INLINE
serialized_sidedata = comp_sidedata
Raphaël Gomès
sidedata: move to new sidedata storage in revlogv2...
r47443 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
rank: naive rank property computation and retrieval...
r49606 rank = RANK_UNKNOWN
revlog: remove legacy usage of `_compute_rank`...
r51957 if self.feature_config.compute_rank:
pacien
rank: compute property incrementally...
r49610 if (p1r, p2r) == (nullrev, nullrev):
rank = 1
elif p1r != nullrev and p2r == nullrev:
rank = 1 + self.fast_rank(p1r)
elif p1r == nullrev and p2r != nullrev:
rank = 1 + self.fast_rank(p2r)
else: # merge node
pacien
revlog: use rust rank computation if available...
r49710 if rustdagop is not None and self.index.rust_ext_compat:
rank = rustdagop.rank(self.index, p1r, p2r)
else:
pmin, pmax = sorted((p1r, p2r))
rank = 1 + self.fast_rank(pmax)
rank += sum(1 for _ in self.findmissingrevs([pmax], [pmin]))
rank: naive rank property computation and retrieval...
r49606
revlog: use the new `entry` function in revlog.py...
r48188 e = revlogutils.entry(
flags=flags,
data_offset=offset,
data_compressed_length=deltainfo.deltalen,
data_uncompressed_length=textlen,
data_compression_mode=compression_mode,
data_delta_base=deltainfo.base,
link_rev=link,
parent_rev_1=p1r,
parent_rev_2=p2r,
node_id=node,
sidedata_offset=sidedata_offset,
sidedata_compressed_length=len(serialized_sidedata),
sidedata_compression_mode=sidedata_compression_mode,
rank: naive rank property computation and retrieval...
r49606 rank=rank,
Augie Fackler
formatting: blacken the codebase...
r43346 )
Raphaël Gomès
revlog: introduce v2 format...
r47438
Martin von Zweigbergk
index: replace insert(-1, e) method by append(e) method...
r38886 self.index.append(e)
revlog: have an explicit "pack_header" method...
r47811 entry = self.index.entry_binary(curr)
revlogv2: store version information in the docket only...
r48009 if curr == 0 and self._docket is None:
revlog: split the `version` attribute into its two components...
r47910 header = self._format_flags | self._format_version
header = self.index.pack_header(header)
revlog: have an explicit "pack_header" method...
r47811 entry = header + entry
Augie Fackler
formatting: blacken the codebase...
r43346 self._writeentry(
Raphaël Gomès
sidedata: move to new sidedata storage in revlogv2...
r47443 transaction,
entry,
deltainfo.data,
link,
offset,
serialized_sidedata,
revlog: store sidedata in their own file...
r48181 sidedata_offset,
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:
delta-computer: stop explicitly taking file handle...
r51913 rawtext = deltacomputer.buildtext(revinfo)
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
revlog: move the_revisioncache on the inner object...
r51989 self._inner._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."""
revlogv2: also keep track for the size of the "data" file...
r48016 if self._docket is None:
Raphaël Gomès
revlogv2: don't assume that the sidedata of the last rev is right after data...
r47444 return self.end(prev)
revlogv2: also keep track for the size of the "data" file...
r48016 else:
return self._docket.data_end
Raphaël Gomès
revlogv2: don't assume that the sidedata of the last rev is right after data...
r47444
revlog: store sidedata in their own file...
r48181 def _writeentry(
revlog: move entry writing in the inner object...
r51992 self,
transaction,
entry,
data,
link,
offset,
sidedata,
sidedata_offset,
revlog: store sidedata in their own file...
r48181 ):
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.
revlog: move entry writing in the inner object...
r51992 index_end = data_end = sidedata_end = None
revlogv2: track current index size in the docket...
r48012 if self._docket is not None:
revlog: move entry writing in the inner object...
r51992 index_end = self._docket.index_end
data_end = self._docket.data_end
sidedata_end = self._docket.sidedata_end
files_end = self._inner.write_entry(
transaction,
entry,
data,
link,
offset,
sidedata,
sidedata_offset,
index_end,
data_end,
sidedata_end,
)
self._enforceinlinesize(transaction)
if self._docket is not None:
self._docket.index_end = files_end[0]
self._docket.data_end = files_end[1]
self._docket.sidedata_end = files_end[2]
revlogv2: track current index size in the docket...
r48012
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,
debug: add an option to display statistic about a unbundling operation...
r50506 debug_info=None,
changegroup: add `delta_base_reuse_policy` argument...
r50660 delta_base_reuse_policy=None,
Joerg Sonnenberger
revlog: extend addgroup() with callback for duplicates...
r46373 ):
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 """
revlog: introduce a mandatory `_writing` context to update revlog content...
r47988 if self._adding_group:
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
changegroup: add `delta_base_reuse_policy` argument...
r50660 # read the default delta-base reuse policy from revlog config if the
# group did not specify one.
if delta_base_reuse_policy is None:
revlog: remove legacy usage of `_generaldelta`...
r51939 if (
self.delta_config.general_delta
and self.delta_config.lazy_delta_base
):
changegroup: add `delta_base_reuse_policy` argument...
r50660 delta_base_reuse_policy = DELTA_BASE_REUSE_TRY
else:
delta_base_reuse_policy = DELTA_BASE_REUSE_NO
revlog: introduce a mandatory `_writing` context to update revlog content...
r47988 self._adding_group = True
Joerg Sonnenberger
revlog: extend addgroup() with callback for duplicates...
r46373 empty = True
Benoit Boissinot
revlog: make sure the files are closed after an exception happens...
r6261 try:
revlog: introduce a mandatory `_writing` context to update revlog content...
r47988 with self._writing(transaction):
deltas: add a `debug.revlog.debug-delta` config option enable output...
r50122 write_debug = None
revlog: remove legacy usage of `_debug_delta`...
r51947 if self.delta_config.debug_delta:
deltas: add a `debug.revlog.debug-delta` config option enable output...
r50122 write_debug = transaction._report
deltacomputer = deltautil.deltacomputer(
self,
write_debug=write_debug,
debug: add an option to display statistic about a unbundling operation...
r50506 debug_info=debug_info,
deltas: add a `debug.revlog.debug-delta` config option enable output...
r50122 )
revlog: preindent some code in addgroup...
r47986 # loop through our set of deltas
for data in deltas:
(
node,
p1,
p2,
linknode,
deltabase,
delta,
flags,
sidedata,
) = data
link = linkmapper(linknode)
flags = flags or REVIDX_DEFAULT_FLAGS
rev = self.index.get_rev(node)
if rev is not None:
# this can happen if two branches make the same change
self._nodeduplicatecallback(transaction, rev)
if duplicaterevisioncb:
duplicaterevisioncb(self, rev)
empty = False
continue
for p in (p1, p2):
if not self.index.has_node(p):
raise error.LookupError(
p, self.radix, _(b'unknown parent')
)
if not self.index.has_node(deltabase):
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.LookupError(
revlog: preindent some code in addgroup...
r47986 deltabase, self.display_id, _(b'unknown delta base')
Augie Fackler
formatting: blacken the codebase...
r43346 )
Mike Edgar
revlog: in addgroup, reject ill-formed deltas based on censored nodes...
r24120
revlog: preindent some code in addgroup...
r47986 baserev = self.rev(deltabase)
if baserev != nullrev and self.iscensored(baserev):
# if base is censored, delta must be full replacement in a
# single patch operation
hlen = struct.calcsize(b">lll")
oldlen = self.rawsize(baserev)
newlen = len(delta) - hlen
if delta[:hlen] != mdiff.replacediffheader(
oldlen, newlen
):
raise error.CensoredBaseError(
self.display_id, self.node(baserev)
)
if not flags and self._peek_iscensored(baserev, delta):
flags |= REVIDX_ISCENSORED
# 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.
# We're only using addgroup() in the context of changegroup
# generation so the revision data can always be handled as raw
# by the flagprocessor.
rev = self._addrevision(
node,
None,
transaction,
link,
p1,
p2,
flags,
changegroup: add `delta_base_reuse_policy` argument...
r50660 (baserev, delta, delta_base_reuse_policy),
revlog: preindent some code in addgroup...
r47986 alwayscache=alwayscache,
deltacomputer=deltacomputer,
sidedata=sidedata,
)
if addrevisioncb:
addrevisioncb(self, rev)
empty = False
Benoit Boissinot
revlog: make sure the files are closed after an exception happens...
r6261 finally:
revlog: introduce a mandatory `_writing` context to update revlog content...
r47988 self._adding_group = False
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."""
revlog: remove legacy usage of `_censorable`...
r51943 if not self.feature_config.censorable:
Gregory Szorc
revlog: move censor logic into main revlog class...
r37461 return False
return self.flags(rev) & REVIDX_ISCENSORED
Mike Edgar
revlog: add "iscensored()" to revlog public API...
r24118
revlog: drop `flush` parameter from `_peek_iscensored`...
r47937 def _peek_iscensored(self, baserev, delta):
Mike Edgar
revlog: addgroup checks if incoming deltas add censored revs, sets flag bit...
r24255 """Quickly check if a delta produces a censored revision."""
revlog: remove legacy usage of `_censorable`...
r51943 if not self.feature_config.censorable:
Gregory Szorc
revlog: move censor logic into main revlog class...
r37461 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
revlogv2: also keep track for the size of the "data" file...
r48016 data_end = self.start(rev)
Matt Mackall
revlog: change _inline from a function to a variable
r4982 if not self._inline:
revlogv2: also keep track for the size of the "data" file...
r48016 transaction.add(self._datafile, data_end)
revlog: replace revlog._io.size with a new revlog.index.entry_size...
r47736 end = rev * self.index.entry_size
mason@suse.com
Implement data inlined with the index file...
r2073 else:
revlogv2: also keep track for the size of the "data" file...
r48016 end = data_end + (rev * self.index.entry_size)
mason@suse.com
Implement revlogng....
r2072
revlog: store sidedata in their own file...
r48181 if self._sidedatafile:
sidedata_end = self.sidedata_cut_off(rev)
transaction.add(self._sidedatafile, sidedata_end)
revlog: rename `indexfile` to `_indexfile`...
r47919 transaction.add(self._indexfile, end)
revlogv2: track current index size in the docket...
r48012 if self._docket is not None:
# XXX we could, leverage the docket while stripping. However it is
# not powerfull enough at the time of this comment
self._docket.index_end = end
revlogv2: also keep track for the size of the "data" file...
r48016 self._docket.data_end = data_end
revlog: store sidedata in their own file...
r48181 self._docket.sidedata_end = sidedata_end
revlogv2: track current index size in the docket...
r48012 self._docket.write(transaction, stripping=True)
mason@suse.com
Add revlog.strip to truncate away revisions....
r1535
# then reset internal state in memory to forget those revisions
Joerg Sonnenberger
revlog: use LRU for the chain cache...
r46364 self._chaininfocache = util.lrucachedict(500)
revlog: consolidate cache invalidation within the inner objet...
r51994 self._inner.clear_cache()
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
Manuel Jacob
py3: catch FileNotFoundError instead of checking errno == ENOENT
r50201 except FileNotFoundError:
Matt Mackall
verify: notice extra data in indices
r1667 dd = 0
try:
revlog: rename `indexfile` to `_indexfile`...
r47919 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()
revlog: replace revlog._io.size with a new revlog.index.entry_size...
r47736 s = self.index.entry_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
Manuel Jacob
py3: catch FileNotFoundError instead of checking errno == ENOENT
r50201 except FileNotFoundError:
Matt Mackall
verify: notice extra data in indices
r1667 di = 0
return (dd, di)
Adrian Buehlmann
revlog: add files method
r6891
def files(self):
revlog: small doc to the `files` method
r51975 """return list of files that compose this revlog"""
revlog: rename `indexfile` to `_indexfile`...
r47919 res = [self._indexfile]
revlogv2: fix `hg verify` with revlog v2...
r48243 if self._docket_file is None:
if not self._inline:
res.append(self._datafile)
else:
res.append(self._docket_file)
revlog: list older-but-still-around file in `files`...
r48248 res.extend(self._docket.old_index_filepaths(include_empty=False))
revlogv2: fix `hg verify` with revlog v2...
r48243 if self._docket.data_end:
res.append(self._datafile)
revlog: list older-but-still-around file in `files`...
r48248 res.extend(self._docket.old_data_filepaths(include_empty=False))
revlogv2: fix `hg verify` with revlog v2...
r48243 if self._docket.sidedata_end:
res.append(self._sidedatafile)
revlog: list older-but-still-around file in `files`...
r48248 res.extend(self._docket.old_sidedata_filepaths(include_empty=False))
Adrian Buehlmann
revlog: add files method
r6891 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,
debug: add an option to display statistic about a bundling operation...
r50505 debug_info=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
revlog: remove legacy usage of `_generaldelta`...
r51939 if nodesorder is None and not self.delta_config.general_delta:
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,
revlog: make the `candelta` method private...
r51897 candeltafn=self._candelta,
Gregory Szorc
storageutil: extract most of emitrevisions() to standalone function...
r40044 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,
debug: add an option to display statistic about a bundling operation...
r50505 debug_info=debug_info,
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,
Raphaël Gomès
sidedata: replace sidedata upgrade mechanism with the new one...
r47847 sidedata_helpers=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
Raphaël Gomès
sidedata: move documentation about sidedata helpers to sidedata module...
r47849 See `revlogutil.sidedata.get_sidedata_helpers` for the doc on
`sidedata_helpers`.
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.
revlog: overwrite revlog config through copy of the config object...
r51923 old_delta_config = destrevlog.delta_config
destrevlog.delta_config = destrevlog.delta_config.copy()
Gregory Szorc
revlog: add clone method...
r30778
try:
if deltareuse == self.DELTAREUSEALWAYS:
revlog: move configuration attribute into dedicated object...
r51922 destrevlog.delta_config.lazy_delta_base = True
destrevlog.delta_config.lazy_delta = True
Gregory Szorc
revlog: add clone method...
r30778 elif deltareuse == self.DELTAREUSESAMEREVS:
revlog: move configuration attribute into dedicated object...
r51922 destrevlog.delta_config.lazy_delta_base = False
destrevlog.delta_config.lazy_delta = True
revlog: preserve `_lazydelta` attribute in `revlog.clone`...
r42023 elif deltareuse == self.DELTAREUSENEVER:
revlog: move configuration attribute into dedicated object...
r51922 destrevlog.delta_config.lazy_delta_base = False
destrevlog.delta_config.lazy_delta = False
revlog: overwrite revlog config through copy of the config object...
r51923 delta_both_parents = (
forcedeltabothparents or old_delta_config.delta_both_parents
)
revlog: move configuration attribute into dedicated object...
r51922 destrevlog.delta_config.delta_both_parents = delta_both_parents
Gregory Szorc
revlog: add clone method...
r30778
revlog: avoid opening and closing the file for each cloned revision...
r52007 with self.reading(), destrevlog._writing(tr):
self._clone(
tr,
destrevlog,
addrevisioncb,
deltareuse,
forcedeltabothparents,
sidedata_helpers,
)
upgrade: move most of revlog.clone method into a _clone method...
r43266
Gregory Szorc
revlog: add clone method...
r30778 finally:
revlog: overwrite revlog config through copy of the config object...
r51923 destrevlog.delta_config = old_delta_config
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,
Raphaël Gomès
sidedata: replace sidedata upgrade mechanism with the new one...
r47847 sidedata_helpers,
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"""
deltas: add a `debug.revlog.debug-delta` config option enable output...
r50122 write_debug = None
revlog: remove legacy usage of `_debug_delta`...
r51947 if self.delta_config.debug_delta:
deltas: add a `debug.revlog.debug-delta` config option enable output...
r50122 write_debug = tr._report
deltacomputer = deltautil.deltacomputer(
destrevlog,
write_debug=write_debug,
)
upgrade: move most of revlog.clone method into a _clone method...
r43266 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]
# (Possibly) reuse the delta from the revlog if allowed and
# the revlog chunk is a delta.
cachedelta = None
rawtext = None
Raphaël Gomès
sidedata: replace sidedata upgrade mechanism with the new one...
r47847 if deltareuse == self.DELTAREUSEFULLADD:
revlog: no longer return sidedata from `_revisiondata`...
r48177 text = self._revisiondata(rev)
revlog: use `self.sidedata` directly in `revlog.clone`...
r48176 sidedata = self.sidedata(rev)
Raphaël Gomès
sidedata: replace sidedata upgrade mechanism with the new one...
r47847
if sidedata_helpers is not None:
Raphaël Gomès
sidedata: move sidedata-related utils to the dedicated module...
r47848 (sidedata, new_flags) = sidedatautil.run_sidedata_helpers(
Raphaël Gomès
sidedata: replace sidedata upgrade mechanism with the new one...
r47847 self, sidedata_helpers, sidedata, rev
)
flags = flags | new_flags[0] & ~new_flags[1]
upgrade: allow sidedata upgrade to modify revision flag...
r46327
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:
revlog: remove legacy usage of `_lazydelta`...
r51959 if destrevlog.delta_config.lazy_delta:
upgrade: fix DELTAREUSEFULLADD implementation in revlog.clone...
r43268 dp = self.deltaparent(rev)
if dp != nullrev:
revlog: move the `_chunk` method on the inner object...
r51985 cachedelta = (dp, bytes(self._inner._chunk(rev)))
upgrade: fix DELTAREUSEFULLADD implementation in revlog.clone...
r43268
Raphaël Gomès
sidedata: replace sidedata upgrade mechanism with the new one...
r47847 sidedata = None
upgrade: fix DELTAREUSEFULLADD implementation in revlog.clone...
r43268 if not cachedelta:
censor: accept censored revision during upgrade...
r52006 try:
rawtext = self._revisiondata(rev)
except error.CensoredNodeError as censored:
assert flags & REVIDX_ISCENSORED
rawtext = censored.tombstone
revlog: use `self.sidedata` directly in `revlog.clone`...
r48176 sidedata = self.sidedata(rev)
Raphaël Gomès
sidedata: replace sidedata upgrade mechanism with the new one...
r47847 if sidedata is None:
sidedata = self.sidedata(rev)
if sidedata_helpers is not None:
Raphaël Gomès
sidedata: move sidedata-related utils to the dedicated module...
r47848 (sidedata, new_flags) = sidedatautil.run_sidedata_helpers(
Raphaël Gomès
sidedata: replace sidedata upgrade mechanism with the new one...
r47847 self, sidedata_helpers, sidedata, rev
)
flags = flags | new_flags[0] & ~new_flags[1]
upgrade: fix DELTAREUSEFULLADD implementation in revlog.clone...
r43268
revlog: avoid opening and closing the file for each cloned revision...
r52007 destrevlog._addrevision(
node,
rawtext,
tr,
linkrev,
p1,
p2,
flags,
cachedelta,
deltacomputer=deltacomputer,
sidedata=sidedata,
)
upgrade: move most of revlog.clone method into a _clone method...
r43266
if addrevisioncb:
addrevisioncb(self, rev, node)
censor: accept multiple revision in a single call...
r52163 def censorrevision(self, tr, censor_nodes, tombstone=b''):
revlog: split the `version` attribute into its two components...
r47910 if self._format_version == REVLOGV0:
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.RevlogError(
revlog: split the `version` attribute into its two components...
r47910 _(b'cannot censor with version %d revlogs')
% self._format_version
Augie Fackler
formatting: blacken the codebase...
r43346 )
revlog: move censoring code in a dedicated module...
r48183 elif self._format_version == REVLOGV1:
censor: accept multiple revision in a single call...
r52163 rewrite.v1_censor(self, tr, censor_nodes, tombstone)
revlog: move censoring code in a dedicated module...
r48183 else:
censor: accept multiple revision in a single call...
r52163 rewrite.v2_censor(self, tr, censor_nodes, tombstone)
Gregory Szorc
revlog: move censor logic out of censor extension...
r39814
Matt Harbison
revlog: drop the CamelCase name for `revlog.revlogproblem`...
r52958 def verifyintegrity(self, state) -> Iterable[revlogproblem]:
Gregory Szorc
verify: start to abstract file verification...
r39878 """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
revlog: split the `version` attribute into its two components...
r47910 version = self._format_version
Gregory Szorc
revlog: use proper version comparison during verify...
r39881
# 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")
revlog: use revlog.display_id in format related errors...
r47928 % (self.display_id, 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:
revlog: rename `indexfile` to `_indexfile`...
r47919 d[b'exclusivefiles'] = [(self.opener, self._indexfile)]
Gregory Szorc
revlog: add method for obtaining storage info (API)...
r39905 if not self._inline:
revlog: rename `datafile` to `datafile`...
r47920 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
revlog: pass a transaction object to `rewrite_sidedata`...
r47990 def rewrite_sidedata(self, transaction, helpers, startrev, endrev):
revlog: remove legacy usage of `hassidedata`...
r51954 if not self.feature_config.has_side_data:
Raphaël Gomès
sidedata-exchange: rewrite sidedata on-the-fly whenever possible...
r47452 return
revlogv2: introduce a very basic docket file...
r48008 # revlog formats with sidedata support does not support inline
Raphaël Gomès
sidedata-exchange: rewrite sidedata on-the-fly whenever possible...
r47452 assert not self._inline
if not helpers[1] and not helpers[2]:
# Nothing to generate or remove
return
new_entries = []
# append the new sidedata
revlog: use `_writing` in `rewrite_sidedata`...
r47992 with self._writing(transaction):
revlog: create a iteration of a _InnerRevlog object within the revlog...
r51979 ifh, dfh, sdfh = self._inner._writinghandles
revlog: store sidedata in their own file...
r48181 dfh.seek(self._docket.sidedata_end, os.SEEK_SET)
current_offset = sdfh.tell()
Raphaël Gomès
sidedata-exchange: rewrite sidedata on-the-fly whenever possible...
r47452 for rev in range(startrev, endrev + 1):
entry = self.index[rev]
Raphaël Gomès
sidedata: move sidedata-related utils to the dedicated module...
r47848 new_sidedata, flags = sidedatautil.run_sidedata_helpers(
Raphaël Gomès
sidedata-exchange: rewrite sidedata on-the-fly whenever possible...
r47452 store=self,
sidedata_helpers=helpers,
sidedata={},
rev=rev,
)
serialized_sidedata = sidedatautil.serialize_sidedata(
new_sidedata
)
revlog: compress sidedata when doing "post-pull" sidedata update...
r48033
sidedata_compression_mode = COMP_MODE_INLINE
revlog: remove legacy usage of `hassidedata`...
r51954 if serialized_sidedata and self.feature_config.has_side_data:
revlog: compress sidedata when doing "post-pull" sidedata update...
r48033 sidedata_compression_mode = COMP_MODE_PLAIN
revlog: move the compression/decompression logic on the inner object...
r51984 h, comp_sidedata = self._inner.compress(serialized_sidedata)
revlog: compress sidedata when doing "post-pull" sidedata update...
r48033 if (
h != b'u'
and comp_sidedata[0] != b'\0'
and len(comp_sidedata) < len(serialized_sidedata)
):
assert not h
if (
comp_sidedata[0]
== self._docket.default_compression_header
):
sidedata_compression_mode = COMP_MODE_DEFAULT
serialized_sidedata = comp_sidedata
else:
sidedata_compression_mode = COMP_MODE_INLINE
serialized_sidedata = comp_sidedata
Raphaël Gomès
sidedata-exchange: rewrite sidedata on-the-fly whenever possible...
r47452 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.
revlog: fix capitalisation of an error...
r48002 msg = b"rewriting existing sidedata is not supported yet"
Raphaël Gomès
sidedata-exchange: rewrite sidedata on-the-fly whenever possible...
r47452 raise error.Abort(msg)
Raphaël Gomès
sidedata: enable sidedata computers to optionally rewrite flags...
r47844
# Apply (potential) flags to add and to remove after running
# the sidedata helpers
new_offset_flags = entry[0] | flags[0] & ~flags[1]
revlog: simplify entry update logic in `rewrite_sidedata`...
r48019 entry_update = (
current_offset,
len(serialized_sidedata),
new_offset_flags,
revlog: compress sidedata when doing "post-pull" sidedata update...
r48033 sidedata_compression_mode,
revlog: simplify entry update logic in `rewrite_sidedata`...
r48019 )
Raphaël Gomès
sidedata-exchange: rewrite sidedata on-the-fly whenever possible...
r47452
revlog: open files in 'r+' instead of 'a+'...
r47991 # the sidedata computation might have move the file cursors around
revlog: store sidedata in their own file...
r48181 sdfh.seek(current_offset, os.SEEK_SET)
sdfh.write(serialized_sidedata)
revlog: simplify entry update logic in `rewrite_sidedata`...
r48019 new_entries.append(entry_update)
Raphaël Gomès
sidedata-exchange: rewrite sidedata on-the-fly whenever possible...
r47452 current_offset += len(serialized_sidedata)
revlog: store sidedata in their own file...
r48181 self._docket.sidedata_end = sdfh.tell()
Raphaël Gomès
sidedata-exchange: rewrite sidedata on-the-fly whenever possible...
r47452
revlog: use `_writing` in `rewrite_sidedata`...
r47992 # rewrite the new index entries
ifh.seek(startrev * self.index.entry_size)
Raphaël Gomès
sidedata: enable sidedata computers to optionally rewrite flags...
r47844 for i, e in enumerate(new_entries):
Raphaël Gomès
sidedata-exchange: rewrite sidedata on-the-fly whenever possible...
r47452 rev = startrev + i
Raphaël Gomès
revlog: add the glue to use the Rust `InnerRevlog` from Python...
r53060 self.index.replace_sidedata_info(
rev, *e
) # pytype: disable=attribute-error
revlog: have an explicit "pack_header" method...
r47811 packed = self.index.entry_binary(rev)
revlogv2: store version information in the docket only...
r48009 if rev == 0 and self._docket is None:
revlog: split the `version` attribute into its two components...
r47910 header = self._format_flags | self._format_version
header = self.index.pack_header(header)
revlog: have an explicit "pack_header" method...
r47811 packed = header + packed
revlog: rename variable in `rewrite_sidedata` to match other code...
r47989 ifh.write(packed)