##// END OF EJS Templates
mq: use bytes() instead of str() to encode statusentries for writing...
mq: use bytes() instead of str() to encode statusentries for writing Differential Revision: https://phab.mercurial-scm.org/D1903

File last commit:

r35756:f90f6fd1 default
r35862:522f8686 default
Show More
revlog.py
2491 lines | 89.0 KiB | text/x-python | PythonLexer
Martin Geisler
put license and copyright info into comment blocks
r8226 # revlog.py - storage back-end for mercurial
#
# Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
#
# This software may be used and distributed according to the terms of the
Matt Mackall
Update license to GPLv2+
r10263 # GNU General Public License version 2 or any later version.
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
Martin Geisler
turn some comments back into module docstrings
r8227 """Storage back-end for Mercurial.
This provides efficient delta storage with O(1) retrieve and append
and O(changes) merge between branches.
"""
Gregory Szorc
revlog: use absolute_import
r27361 from __future__ import absolute_import
Pulkit Goyal
py3: catch binascii.Error raised from binascii.unhexlify...
r32969 import binascii
Martin von Zweigbergk
util: drop alias for collections.deque...
r25113 import collections
Gregory Szorc
revlog: use absolute_import
r27361 import errno
Augie Fackler
revlog: use hashlib.sha1 directly instead of through util...
r29339 import hashlib
Boris Feld
sparse-read: move from a recursive-based approach to a heap-based one...
r34881 import heapq
Gregory Szorc
revlog: seek to end of file before writing (issue4943)...
r27430 import os
Gregory Szorc
revlog: use absolute_import
r27361 import struct
import zlib
# import stuff from node for others to import from revlog
from .node import (
bin,
hex,
nullid,
nullrev,
Yuya Nishihara
revlog: add support for partial matching of wdir node id...
r32684 wdirhex,
Yuya Nishihara
revlog: map rev(wdirid) to WdirUnsupported exception...
r32657 wdirid,
Pulkit Goyal
revlog: raise WdirUnsupported when wdirrev is passed...
r32402 wdirrev,
Gregory Szorc
revlog: use absolute_import
r27361 )
from .i18n import _
Paul Morelle
revlog: introduce 'deltainfo' to distinguish from 'delta'...
r35656 from .thirdparty import (
attr,
)
Gregory Szorc
revlog: use absolute_import
r27361 from . import (
ancestor,
error,
mdiff,
Yuya Nishihara
parsers: switch to policy importer...
r32372 policy,
Augie Fackler
revlog: use pycompat.maplist to eagerly evaluate map on Python 3...
r31574 pycompat,
Gregory Szorc
revlog: use absolute_import
r27361 templatefilters,
util,
)
mpm@selenic.com
Add smart node lookup by substring or by rev number
r36
Yuya Nishihara
parsers: switch to policy importer...
r32372 parsers = policy.importmod(r'parsers')
Gregory Szorc
revlog: use compression engine APIs for decompression...
r30817 # Aliased for performance.
_zlibdecompress = zlib.decompress
Matt Mackall
revlog: localize some fastpath functions
r5007
Vishakh H
revlog: add shallow header flag...
r11746 # revlog header flags
mason@suse.com
Implement revlogng....
r2072 REVLOGV0 = 0
Gregory Szorc
revlog: rename constants (API)...
r32316 REVLOGV1 = 1
Gregory Szorc
revlog: skeleton support for version 2 revlogs...
r32697 # Dummy value until file format is finalized.
# Reminder: change the bounds check in revlog.__init__ when this is changed.
REVLOGV2 = 0xDEAD
Gregory Szorc
revlog: rename constants (API)...
r32316 FLAG_INLINE_DATA = (1 << 16)
FLAG_GENERALDELTA = (1 << 17)
REVLOG_DEFAULT_FLAGS = FLAG_INLINE_DATA
REVLOG_DEFAULT_FORMAT = REVLOGV1
mason@suse.com
Use revlogng and inlined data files by default...
r2222 REVLOG_DEFAULT_VERSION = REVLOG_DEFAULT_FORMAT | REVLOG_DEFAULT_FLAGS
Gregory Szorc
revlog: rename constants (API)...
r32316 REVLOGV1_FLAGS = FLAG_INLINE_DATA | FLAG_GENERALDELTA
Gregory Szorc
revlog: skeleton support for version 2 revlogs...
r32697 REVLOGV2_FLAGS = REVLOGV1_FLAGS
Vishakh H
revlog: add shallow header flag...
r11746
# revlog index flags
Mike Edgar
revlog: define censored flag for revlogng index...
r23855 REVIDX_ISCENSORED = (1 << 15) # revision has censor metadata, must be verified
Martin von Zweigbergk
revlog: give EXTSTORED flag value to narrowhg...
r30829 REVIDX_ELLIPSIS = (1 << 14) # revision hash does not match data (narrowhg)
REVIDX_EXTSTORED = (1 << 13) # revision data is stored externally
Mike Edgar
revlog: define censored flag for revlogng index...
r23855 REVIDX_DEFAULT_FLAGS = 0
Remi Chaintron
revlog: flag processor...
r30745 # stable order in which flags need to be processed and their processors applied
REVIDX_FLAGS_ORDER = [
REVIDX_ISCENSORED,
Martin von Zweigbergk
revlog: give EXTSTORED flag value to narrowhg...
r30829 REVIDX_ELLIPSIS,
Remi Chaintron
revlog: REVIDX_EXTSTORED flag...
r30746 REVIDX_EXTSTORED,
Remi Chaintron
revlog: flag processor...
r30745 ]
REVIDX_KNOWN_FLAGS = util.bitsfrom(REVIDX_FLAGS_ORDER)
mason@suse.com
Implement data inlined with the index file...
r2073
Benoit Boissinot
add documentation for revlog._prereadsize
r10916 # max size of revlog with inline data
_maxinline = 131072
Matt Mackall
revlog: remove lazy index
r13253 _chunksize = 1048576
Greg Ward
revlog: factor out _maxinline global....
r10913
Matt Mackall
errors: move revlog errors...
r7633 RevlogError = error.RevlogError
LookupError = error.LookupError
Mike Edgar
revlog: support importing censored file revision tombstones...
r22934 CensoredNodeError = error.CensoredNodeError
Remi Chaintron
revlog: flag processor...
r30745 ProgrammingError = error.ProgrammingError
# Store flag processors (cf. 'addflagprocessor()' to register)
_flagprocessors = {
REVIDX_ISCENSORED: None,
}
def addflagprocessor(flag, processor):
"""Register a flag processor on a revision data flag.
Invariant:
- Flags need to be defined in REVIDX_KNOWN_FLAGS and REVIDX_FLAGS_ORDER.
- Only one flag processor can be registered on a specific flag.
- flagprocessors must be 3-tuples of functions (read, write, raw) with the
following signatures:
Jun Wu
revlog: clarify flagprocessor documentation...
r31749 - (read) f(self, rawtext) -> text, bool
- (write) f(self, text) -> rawtext, bool
- (raw) f(self, rawtext) -> bool
"text" is presented to the user. "rawtext" is stored in revlog data, not
directly visible to the user.
Remi Chaintron
revlog: flag processor...
r30745 The boolean returned by these transforms is used to determine whether
Jun Wu
revlog: clarify flagprocessor documentation...
r31749 the returned text can be used for hash integrity checking. For example,
if "write" returns False, then "text" is used to generate hash. If
"write" returns True, that basically means "rawtext" returned by "write"
should be used to generate hash. Usually, "write" and "read" return
different booleans. And "raw" returns a same boolean as "write".
Remi Chaintron
revlog: flag processor...
r30745
Note: The 'raw' transform is used for changegroup generation and in some
debug commands. In this case the transform only indicates whether the
contents can be used for hash integrity checks.
"""
if not flag & REVIDX_KNOWN_FLAGS:
msg = _("cannot register processor on unknown flag '%#x'.") % (flag)
raise ProgrammingError(msg)
if flag not in REVIDX_FLAGS_ORDER:
msg = _("flag '%#x' undefined in REVIDX_FLAGS_ORDER.") % (flag)
raise ProgrammingError(msg)
if flag in _flagprocessors:
msg = _("cannot register multiple processors on flag '%#x'.") % (flag)
raise error.Abort(msg)
_flagprocessors[flag] = processor
Alexander Solovyov
LookupError should have same __str__ as RevlogError
r6703
Matt Mackall
revlog: some basic code reordering
r4987 def getoffset(q):
return int(q >> 16)
def gettype(q):
return int(q & 0xFFFF)
def offset_type(offset, type):
Cotizo Sima
revlog: ensure that flags do not overflow 2 bytes...
r30543 if (type & ~REVIDX_KNOWN_FLAGS) != 0:
raise ValueError('unknown revlog index flags')
Augie Fackler
revlog: use int instead of long...
r31504 return int(int(offset) << 16 | type)
Matt Mackall
revlog: some basic code reordering
r4987
Augie Fackler
revlog: use hashlib.sha1 directly instead of through util...
r29339 _nullhash = hashlib.sha1(nullid)
Nicolas Dumazet
revlog: faster hash computation when one of the parent node is null...
r7883
mpm@selenic.com
Move hash function back to revlog from node
r1091 def hash(text, p1, p2):
"""generate a hash from the given text and its parent hashes
This hash combines both the current file contents and its history
in a manner that makes it easy to distinguish nodes with the same
content in the revision graph.
"""
Nicolas Dumazet
revlog: faster hash computation when one of the parent node is null...
r7883 # As of now, if one of the parent node is null, p2 is null
if p2 == nullid:
# deep copy of a hash is faster than creating one
Augie Fackler
revlog: mark nullhash as module-private...
r22784 s = _nullhash.copy()
Nicolas Dumazet
revlog: faster hash computation when one of the parent node is null...
r7883 s.update(p1)
else:
# none of the parent nodes are nullid
Alex Gaynor
revlog: micro-optimize the computation of hashes...
r33391 if p1 < p2:
a = p1
b = p2
else:
a = p2
b = p1
s = hashlib.sha1(a)
s.update(b)
mpm@selenic.com
Move hash function back to revlog from node
r1091 s.update(text)
return s.digest()
Paul Morelle
sparse-read: ignore trailing empty revs in each read chunk...
r34899 def _trimchunk(revlog, revs, startidx, endidx=None):
"""returns revs[startidx:endidx] without empty trailing revs
"""
length = revlog.length
if endidx is None:
endidx = len(revs)
# Trim empty revs at the end, but never the very first revision of a chain
while endidx > 1 and endidx > startidx and length(revs[endidx - 1]) == 0:
endidx -= 1
return revs[startidx:endidx]
Paul Morelle
revlog: introduce an experimental flag to slice chunks reads when too sparse...
r34825 def _slicechunk(revlog, revs):
"""slice revs to reduce the amount of unrelated data to be read from disk.
``revs`` is sliced into groups that should be read in one time.
Assume that revs are sorted.
"""
start = revlog.start
length = revlog.length
Boris Feld
sparse-read: move from a recursive-based approach to a heap-based one...
r34881 if len(revs) <= 1:
yield revs
return
Paul Morelle
revlog: introduce an experimental flag to slice chunks reads when too sparse...
r34825
Boris Feld
sparse-read: move from a recursive-based approach to a heap-based one...
r34881 startbyte = start(revs[0])
endbyte = start(revs[-1]) + length(revs[-1])
readdata = deltachainspan = endbyte - startbyte
chainpayload = sum(length(r) for r in revs)
Paul Morelle
revlog: introduce an experimental flag to slice chunks reads when too sparse...
r34825
Boris Feld
sparse-read: move from a recursive-based approach to a heap-based one...
r34881 if deltachainspan:
density = chainpayload / float(deltachainspan)
else:
density = 1.0
Paul Morelle
revlog: introduce an experimental flag to slice chunks reads when too sparse...
r34825
Boris Feld
sparse-read: move from a recursive-based approach to a heap-based one...
r34881 # Store the gaps in a heap to have them sorted by decreasing size
gapsheap = []
heapq.heapify(gapsheap)
prevend = None
for i, rev in enumerate(revs):
revstart = start(rev)
revlen = length(rev)
Paul Morelle
revlog: introduce an experimental flag to slice chunks reads when too sparse...
r34825
Paul Morelle
sparse-read: ignore trailing empty revs in each read chunk...
r34899 # Skip empty revisions to form larger holes
if revlen == 0:
continue
Boris Feld
sparse-read: move from a recursive-based approach to a heap-based one...
r34881 if prevend is not None:
gapsize = revstart - prevend
Paul Morelle
sparse-read: skip gaps too small to be worth splitting...
r34882 # only consider holes that are large enough
if gapsize > revlog._srmingapsize:
Boris Feld
sparse-read: move from a recursive-based approach to a heap-based one...
r34881 heapq.heappush(gapsheap, (-gapsize, i))
prevend = revstart + revlen
# Collect the indices of the largest holes until the density is acceptable
indicesheap = []
heapq.heapify(indicesheap)
while gapsheap and density < revlog._srdensitythreshold:
oppgapsize, gapidx = heapq.heappop(gapsheap)
heapq.heappush(indicesheap, gapidx)
Paul Morelle
revlog: introduce an experimental flag to slice chunks reads when too sparse...
r34825
Boris Feld
sparse-read: move from a recursive-based approach to a heap-based one...
r34881 # the gap sizes are stored as negatives to be sorted decreasingly
# by the heap
readdata -= (-oppgapsize)
if readdata > 0:
density = chainpayload / float(readdata)
else:
density = 1.0
Paul Morelle
revlog: introduce an experimental flag to slice chunks reads when too sparse...
r34825
Boris Feld
sparse-read: move from a recursive-based approach to a heap-based one...
r34881 # Cut the revs at collected indices
previdx = 0
while indicesheap:
idx = heapq.heappop(indicesheap)
Paul Morelle
sparse-read: ignore trailing empty revs in each read chunk...
r34899
chunk = _trimchunk(revlog, revs, previdx, idx)
if chunk:
yield chunk
Boris Feld
sparse-read: move from a recursive-based approach to a heap-based one...
r34881 previdx = idx
Paul Morelle
sparse-read: ignore trailing empty revs in each read chunk...
r34899
chunk = _trimchunk(revlog, revs, previdx)
if chunk:
yield chunk
Paul Morelle
revlog: introduce an experimental flag to slice chunks reads when too sparse...
r34825
Paul Morelle
revlog: introduce 'deltainfo' to distinguish from 'delta'...
r35656 @attr.s(slots=True, frozen=True)
class _deltainfo(object):
distance = attr.ib()
deltalen = attr.ib()
data = attr.ib()
base = attr.ib()
chainbase = attr.ib()
chainlen = attr.ib()
compresseddeltalen = attr.ib()
Paul Morelle
revlog: group delta computation methods under _deltacomputer object...
r35756 class _deltacomputer(object):
def __init__(self, revlog):
self.revlog = revlog
def _getcandidaterevs(self, p1, p2, cachedelta):
"""
Provides revisions that present an interest to be diffed against,
grouped by level of easiness.
"""
revlog = self.revlog
curr = len(revlog)
prev = curr - 1
p1r, p2r = revlog.rev(p1), revlog.rev(p2)
# should we try to build a delta?
if prev != nullrev and revlog.storedeltachains:
tested = set()
# This condition is true most of the time when processing
# changegroup data into a generaldelta repo. The only time it
# isn't true is if this is the first revision in a delta chain
# or if ``format.generaldelta=true`` disabled ``lazydeltabase``.
if cachedelta and revlog._generaldelta and revlog._lazydeltabase:
# Assume what we received from the server is a good choice
# build delta will reuse the cache
yield (cachedelta[0],)
tested.add(cachedelta[0])
if revlog._generaldelta:
# exclude already lazy tested base if any
parents = [p for p in (p1r, p2r)
if p != nullrev and p not in tested]
if parents and not revlog._aggressivemergedeltas:
# Pick whichever parent is closer to us (to minimize the
# chance of having to build a fulltext).
parents = [max(parents)]
tested.update(parents)
yield parents
if prev not in tested:
# other approach failed try against prev to hopefully save us a
# fulltext.
yield (prev,)
def buildtext(self, revinfo, fh):
"""Builds a fulltext version of a revision
revinfo: _revisioninfo instance that contains all needed info
fh: file handle to either the .i or the .d revlog file,
depending on whether it is inlined or not
"""
btext = revinfo.btext
if btext[0] is not None:
return btext[0]
revlog = self.revlog
cachedelta = revinfo.cachedelta
flags = revinfo.flags
node = revinfo.node
baserev = cachedelta[0]
delta = cachedelta[1]
# special case deltas which replace entire base; no need to decode
# base revision. this neatly avoids censored bases, which throw when
# they're decoded.
hlen = struct.calcsize(">lll")
if delta[:hlen] == mdiff.replacediffheader(revlog.rawsize(baserev),
len(delta) - hlen):
btext[0] = delta[hlen:]
else:
basetext = revlog.revision(baserev, _df=fh, raw=True)
btext[0] = mdiff.patch(basetext, delta)
try:
res = revlog._processflags(btext[0], flags, 'read', raw=True)
btext[0], validatehash = res
if validatehash:
revlog.checkhash(btext[0], node, p1=revinfo.p1, p2=revinfo.p2)
if flags & REVIDX_ISCENSORED:
raise RevlogError(_('node %s is not censored') % node)
except CensoredNodeError:
# must pass the censored index flag to add censored revisions
if not flags & REVIDX_ISCENSORED:
raise
return btext[0]
def _builddeltadiff(self, base, revinfo, fh):
revlog = self.revlog
t = self.buildtext(revinfo, fh)
if revlog.iscensored(base):
# deltas based on a censored revision must replace the
# full content in one patch, so delta works everywhere
header = mdiff.replacediffheader(revlog.rawsize(base), len(t))
delta = header + t
else:
ptext = revlog.revision(base, _df=fh, raw=True)
delta = mdiff.textdiff(ptext, t)
return delta
def _builddeltainfo(self, revinfo, base, fh):
# can we use the cached delta?
if revinfo.cachedelta and revinfo.cachedelta[0] == base:
delta = revinfo.cachedelta[1]
else:
delta = self._builddeltadiff(base, revinfo, fh)
revlog = self.revlog
header, data = revlog.compress(delta)
deltalen = len(header) + len(data)
chainbase = revlog.chainbase(base)
offset = revlog.end(len(revlog) - 1)
dist = deltalen + offset - revlog.start(chainbase)
if revlog._generaldelta:
deltabase = base
else:
deltabase = chainbase
chainlen, compresseddeltalen = revlog._chaininfo(base)
chainlen += 1
compresseddeltalen += deltalen
return _deltainfo(dist, deltalen, (header, data), deltabase,
chainbase, chainlen, compresseddeltalen)
def finddeltainfo(self, revinfo, fh):
"""Find an acceptable delta against a candidate revision
revinfo: information about the revision (instance of _revisioninfo)
fh: file handle to either the .i or the .d revlog file,
depending on whether it is inlined or not
Returns the first acceptable candidate revision, as ordered by
_getcandidaterevs
"""
cachedelta = revinfo.cachedelta
p1 = revinfo.p1
p2 = revinfo.p2
revlog = self.revlog
deltainfo = None
for candidaterevs in self._getcandidaterevs(p1, p2, cachedelta):
nominateddeltas = []
for candidaterev in candidaterevs:
candidatedelta = self._builddeltainfo(revinfo, candidaterev, fh)
if revlog._isgooddeltainfo(candidatedelta, revinfo.textlen):
nominateddeltas.append(candidatedelta)
if nominateddeltas:
deltainfo = min(nominateddeltas, key=lambda x: x.deltalen)
break
return deltainfo
Paul Morelle
revlog: group revision info into a dedicated structure
r35659 @attr.s(slots=True, frozen=True)
class _revisioninfo(object):
"""Information about a revision that allows building its fulltext
node: expected hash of the revision
p1, p2: parent revs of the revision
btext: built text cache consisting of a one-element list
cachedelta: (baserev, uncompressed_delta) or None
flags: flags associated to the revision storage
One of btext[0] or cachedelta must be set.
"""
node = attr.ib()
p1 = attr.ib()
p2 = attr.ib()
btext = attr.ib()
Paul Morelle
revlog: refactor out _finddeltainfo from _addrevision...
r35755 textlen = attr.ib()
Paul Morelle
revlog: group revision info into a dedicated structure
r35659 cachedelta = attr.ib()
flags = attr.ib()
Benoit Boissinot
revlog: document v0 format
r18585 # index v0:
# 4 bytes: offset
# 4 bytes: compressed length
# 4 bytes: base rev
# 4 bytes: link rev
Yuya Nishihara
revlog: correct comment about size of v0 index format
r25891 # 20 bytes: parent 1 nodeid
# 20 bytes: parent 2 nodeid
# 20 bytes: nodeid
Alex Gaynor
revlog: use struct.Struct instances for slight performance wins...
r33392 indexformatv0 = struct.Struct(">4l20s20s20s")
indexformatv0_pack = indexformatv0.pack
indexformatv0_unpack = indexformatv0.unpack
Matt Mackall
revlog: raise offset/type helpers to global scope
r4918
Matt Mackall
revlog: add revlogio interface...
r4972 class revlogoldio(object):
def __init__(self):
Alex Gaynor
revlog: use struct.Struct instances for slight performance wins...
r33392 self.size = indexformatv0.size
Matt Mackall
revlog: add revlogio interface...
r4972
Benoit Boissinot
revlog/parseindex: no need to pass the file around
r13264 def parseindex(self, data, inline):
Matt Mackall
revlog: parse revlogv0 indexes into v1 internally...
r4977 s = self.size
Matt Mackall
revlog: add revlogio interface...
r4972 index = []
timeless
cleanup: remove superfluous space after space after equals (python)
r27637 nodemap = {nullid: nullrev}
Matt Mackall
revlog: simplify the v0 parser
r4973 n = off = 0
l = len(data)
while off + s <= l:
cur = data[off:off + s]
off += s
Alex Gaynor
revlog: use struct.Struct instances for slight performance wins...
r33392 e = indexformatv0_unpack(cur)
Matt Mackall
revlog: parse revlogv0 indexes into v1 internally...
r4977 # transform to revlogv1 format
e2 = (offset_type(e[0], 0), e[1], -1, e[2], e[3],
Matt Mackall
revlog: make revlogv0 loading more robust against corruption
r5544 nodemap.get(e[4], nullrev), nodemap.get(e[5], nullrev), e[6])
Matt Mackall
revlog: parse revlogv0 indexes into v1 internally...
r4977 index.append(e2)
nodemap[e[6]] = n
Matt Mackall
revlog: simplify the v0 parser
r4973 n += 1
Matt Mackall
revlog: add revlogio interface...
r4972
Benoit Boissinot
revlog: always add the magic nullid/nullrev entry in parseindex
r13265 # add the magic null revision at -1
index.append((0, 0, 0, -1, -1, -1, -1, nullid))
Matt Mackall
revlog: pull chunkcache back into revlog
r4983 return index, nodemap, None
Matt Mackall
revlog: add revlogio interface...
r4972
Alexis S. L. Carvalho
revlog: fix revlogio.packentry corner case...
r5338 def packentry(self, entry, node, version, rev):
Benoit Boissinot
revlog: don't silently discard revlog flags on revlogv0
r10395 if gettype(entry[0]):
Gregory Szorc
revlog: remove some revlogNG terminology...
r32392 raise RevlogError(_('index entry flags need revlog version 1'))
Matt Mackall
revlog: abstract out index entry packing...
r4986 e2 = (getoffset(entry[0]), entry[1], entry[3], entry[4],
node(entry[5]), node(entry[6]), entry[7])
Alex Gaynor
revlog: use struct.Struct instances for slight performance wins...
r33392 return indexformatv0_pack(*e2)
Matt Mackall
revlog: abstract out index entry packing...
r4986
Matt Mackall
revlog: some basic code reordering
r4987 # index ng:
Martin Geisler
revlog: fix inconsistent comment formatting
r11323 # 6 bytes: offset
# 2 bytes: flags
# 4 bytes: compressed length
# 4 bytes: uncompressed length
# 4 bytes: base rev
# 4 bytes: link rev
# 4 bytes: parent 1 rev
# 4 bytes: parent 2 rev
Matt Mackall
revlog: some basic code reordering
r4987 # 32 bytes: nodeid
Alex Gaynor
revlog: use struct.Struct instances for slight performance wins...
r33392 indexformatng = struct.Struct(">Qiiiiii20s12x")
indexformatng_pack = indexformatng.pack
versionformat = struct.Struct(">I")
versionformat_pack = versionformat.pack
versionformat_unpack = versionformat.unpack
Matt Mackall
revlog: some basic code reordering
r4987
Jordi Gutiérrez Hermoso
revlog: raise an exception earlier if an entry is too large (issue4675)...
r25410 # corresponds to uncompressed length of indexformatng (2 gigs, 4-byte
# signed integer)
_maxentrysize = 0x7fffffff
Matt Mackall
revlog: add revlogio interface...
r4972 class revlogio(object):
def __init__(self):
Alex Gaynor
revlog: use struct.Struct instances for slight performance wins...
r33392 self.size = indexformatng.size
Matt Mackall
revlog: add revlogio interface...
r4972
Benoit Boissinot
revlog/parseindex: no need to pass the file around
r13264 def parseindex(self, data, inline):
Bernhard Leiner
use the new parseindex implementation C in parsers
r7109 # call the C implementation to parse the index data
Matt Mackall
revlog: only build the nodemap on demand
r13254 index, cache = parsers.parse_index2(data, inline)
Bryan O'Sullivan
parsers: use base-16 trie for faster node->rev mapping...
r16414 return index, getattr(index, 'nodemap', None), cache
Matt Mackall
revlog: add revlogio interface...
r4972
Alexis S. L. Carvalho
revlog: fix revlogio.packentry corner case...
r5338 def packentry(self, entry, node, version, rev):
Alex Gaynor
revlog: use struct.Struct instances for slight performance wins...
r33392 p = indexformatng_pack(*entry)
Alexis S. L. Carvalho
revlog: fix revlogio.packentry corner case...
r5338 if rev == 0:
Alex Gaynor
revlog: use struct.Struct instances for slight performance wins...
r33392 p = versionformat_pack(version) + p[4:]
Matt Mackall
revlog: abstract out index entry packing...
r4986 return p
Eric Hopper
Convert all classes to new-style classes by deriving them from object.
r1559 class revlog(object):
mpm@selenic.com
Add some docstrings to revlog.py
r1083 """
the underlying revision storage object
A revlog consists of two parts, an index and the revision data.
The index is a file with a fixed record size containing
Martin Geisler
Fixed docstring typos
r6912 information on each revision, including its nodeid (hash), the
mpm@selenic.com
Add some docstrings to revlog.py
r1083 nodeids of its parents, the position and offset of its data within
the data file, and the revision it's based on. Finally, each entry
contains a linkrev entry that can serve as a pointer to external
data.
The revision data itself is a linear collection of data chunks.
Each chunk represents a revision and is usually represented as a
delta against the previous chunk. To bound lookup time, runs of
deltas are limited to about 2 times the length of the original
version data. This makes retrieval of a version proportional to
its size, or O(1) relative to the number of revisions.
Both pieces of the revlog are written to in an append-only
fashion, which means we never need to rewrite a file to insert or
remove data, and can use some simple techniques to avoid the need
for locking while reading.
FUJIWARA Katsunori
revlog: specify checkambig at writing to avoid file stat ambiguity...
r29997
If checkambig, indexfile is opened with checkambig=True at
writing, to avoid file stat ambiguity.
Mark Thomas
revlog: add option to mmap revlog index...
r34297
If mmaplargeindex is True, and an mmapindexthreshold is set, the
index will be mmapped rather than read if it is larger than the
configured threshold.
mpm@selenic.com
Add some docstrings to revlog.py
r1083 """
Mark Thomas
revlog: add option to mmap revlog index...
r34297 def __init__(self, opener, indexfile, datafile=None, checkambig=False,
mmaplargeindex=False):
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.
"""
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 self.indexfile = indexfile
Jun Wu
changelog: make sure datafile is 00changelog.d (API)...
r32307 self.datafile = datafile or (indexfile[:-2] + ".d")
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 self.opener = opener
FUJIWARA Katsunori
revlog: specify checkambig at writing to avoid file stat ambiguity...
r29997 # When True, indexfile is opened with checkambig=True at writing, to
# avoid file stat ambiguity.
self._checkambig = checkambig
Gregory Szorc
revlog: improve documentation...
r27070 # 3-tuple of (node, rev, text) for a raw revision.
Matt Mackall
revlog: mark cache private
r4984 self._cache = None
Gregory Szorc
revlog: use an LRU cache for delta chain bases...
r29830 # Maps rev to chain base rev.
self._chainbasecache = util.lrucachedict(100)
Gregory Szorc
revlog: improve documentation...
r27070 # 2-tuple of (offset, data) of raw data from the revlog at an offset.
Matt Mackall
revlog: clean up the chunk caching code
r8316 self._chunkcache = (0, '')
Gregory Szorc
revlog: improve documentation...
r27070 # How much data to read and cache into the raw revlog data cache.
Brodie Rao
revlog: allow tuning of the chunk cache size (via format.chunkcachesize)...
r20180 self._chunkcachesize = 65536
Mateusz Kwapich
revlog: add config variable for limiting delta-chain length...
r23255 self._maxchainlen = None
Durham Goode
revlog: add an aggressivemergedelta option...
r26118 self._aggressivemergedeltas = False
Matt Mackall
revlog: simplify revlog.__init__...
r4985 self.index = []
Gregory Szorc
revlog: improve documentation...
r27070 # Mapping of partial identifiers to full nodes.
Matt Mackall
revlog: introduce a cache for partial lookups...
r13258 self._pcache = {}
Gregory Szorc
revlog: improve documentation...
r27070 # Mapping of revision integer to full node.
Matt Mackall
revlog: incrementally build node cache with linear searches...
r13275 self._nodecache = {nullid: nullrev}
self._nodepos = None
Gregory Szorc
localrepo: experimental support for non-zlib revlog compression...
r30818 self._compengine = 'zlib'
revlog: add an experimental option to mitigated delta issues (issue5480)...
r33202 self._maxdeltachainspan = -1
Paul Morelle
revlog: introduce an experimental flag to slice chunks reads when too sparse...
r34825 self._withsparseread = False
self._srdensitythreshold = 0.25
Paul Morelle
sparse-read: skip gaps too small to be worth splitting...
r34882 self._srmingapsize = 262144
Matt Mackall
revlog: simplify revlog.__init__...
r4985
Mark Thomas
revlog: add option to mmap revlog index...
r34297 mmapindexthreshold = None
Matt Mackall
revlog: simplify revlog.__init__...
r4985 v = REVLOG_DEFAULT_VERSION
Augie Fackler
revlog: use getattr instead of hasattr
r14960 opts = getattr(opener, 'options', None)
if opts is not None:
Gregory Szorc
revlog: skeleton support for version 2 revlogs...
r32697 if 'revlogv2' in opts:
# version 2 revlogs always use generaldelta.
v = REVLOGV2 | FLAG_GENERALDELTA | FLAG_INLINE_DATA
elif 'revlogv1' in opts:
Augie Fackler
revlog: use getattr instead of hasattr
r14960 if 'generaldelta' in opts:
Gregory Szorc
revlog: rename constants (API)...
r32316 v |= FLAG_GENERALDELTA
Sune Foldager
revlog: get rid of defversion...
r14333 else:
v = 0
Brodie Rao
revlog: allow tuning of the chunk cache size (via format.chunkcachesize)...
r20180 if 'chunkcachesize' in opts:
self._chunkcachesize = opts['chunkcachesize']
Mateusz Kwapich
revlog: add config variable for limiting delta-chain length...
r23255 if 'maxchainlen' in opts:
self._maxchainlen = opts['maxchainlen']
Durham Goode
revlog: add an aggressivemergedelta option...
r26118 if 'aggressivemergedeltas' in opts:
self._aggressivemergedeltas = opts['aggressivemergedeltas']
Pierre-Yves David
format: introduce 'format.usegeneraldelta`...
r26907 self._lazydeltabase = bool(opts.get('lazydeltabase', False))
Gregory Szorc
localrepo: experimental support for non-zlib revlog compression...
r30818 if 'compengine' in opts:
self._compengine = opts['compengine']
revlog: add an experimental option to mitigated delta issues (issue5480)...
r33202 if 'maxdeltachainspan' in opts:
self._maxdeltachainspan = opts['maxdeltachainspan']
Mark Thomas
revlog: add option to mmap revlog index...
r34297 if mmaplargeindex and 'mmapindexthreshold' in opts:
mmapindexthreshold = opts['mmapindexthreshold']
Paul Morelle
revlog: introduce an experimental flag to slice chunks reads when too sparse...
r34825 self._withsparseread = bool(opts.get('with-sparse-read', False))
if 'sparse-read-density-threshold' in opts:
self._srdensitythreshold = opts['sparse-read-density-threshold']
Paul Morelle
sparse-read: skip gaps too small to be worth splitting...
r34882 if 'sparse-read-min-gap-size' in opts:
self._srmingapsize = opts['sparse-read-min-gap-size']
Brodie Rao
revlog: allow tuning of the chunk cache size (via format.chunkcachesize)...
r20180
if self._chunkcachesize <= 0:
raise RevlogError(_('revlog chunk cache size %r is not greater '
'than 0') % self._chunkcachesize)
elif self._chunkcachesize & (self._chunkcachesize - 1):
raise RevlogError(_('revlog chunk cache size %r is not a power '
'of 2') % self._chunkcachesize)
Pradeepkumar Gayam
revlog: parentdelta flags for revlog index
r11928
Gregory Szorc
revlog: rename generic "i" variable to "indexdata"...
r26241 indexdata = ''
Sune Foldager
changelog: don't use generaldelta
r14334 self._initempty = True
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 try:
Benoit Boissinot
revalidate revlog data after locking the repo (issue132)
r1784 f = self.opener(self.indexfile)
Mark Thomas
revlog: add option to mmap revlog index...
r34297 if (mmapindexthreshold is not None and
self.opener.fstat(f).st_size >= mmapindexthreshold):
indexdata = util.buffer(util.mmapread(f))
else:
indexdata = f.read()
Dan Villiom Podlaski Christiansen
explicitly close files...
r13400 f.close()
Gregory Szorc
revlog: rename generic "i" variable to "indexdata"...
r26241 if len(indexdata) > 0:
Alex Gaynor
revlog: use struct.Struct instances for slight performance wins...
r33392 v = versionformat_unpack(indexdata[:4])[0]
Sune Foldager
changelog: don't use generaldelta
r14334 self._initempty = False
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except IOError as inst:
Bryan O'Sullivan
Make revlog constructor more discerning in its treatment of errors.
r1322 if inst.errno != errno.ENOENT:
raise
Matt Mackall
revlog: simplify revlog.__init__...
r4985
self.version = v
Gregory Szorc
revlog: rename constants (API)...
r32316 self._inline = v & FLAG_INLINE_DATA
self._generaldelta = v & FLAG_GENERALDELTA
mason@suse.com
Implement data inlined with the index file...
r2073 flags = v & ~0xFFFF
fmt = v & 0xFFFF
Gregory Szorc
revlog: tweak wording and logic for flags validation...
r32391 if fmt == REVLOGV0:
if flags:
raise RevlogError(_('unknown flags (%#04x) in version %d '
'revlog %s') %
(flags >> 16, fmt, self.indexfile))
elif fmt == REVLOGV1:
if flags & ~REVLOGV1_FLAGS:
raise RevlogError(_('unknown flags (%#04x) in version %d '
'revlog %s') %
(flags >> 16, fmt, self.indexfile))
Gregory Szorc
revlog: skeleton support for version 2 revlogs...
r32697 elif fmt == REVLOGV2:
if flags & ~REVLOGV2_FLAGS:
raise RevlogError(_('unknown flags (%#04x) in version %d '
'revlog %s') %
(flags >> 16, fmt, self.indexfile))
Gregory Szorc
revlog: tweak wording and logic for flags validation...
r32391 else:
raise RevlogError(_('unknown version (%d) in revlog %s') %
(fmt, self.indexfile))
Matt Mackall
revlog: simplify revlog.__init__...
r4985
Pierre-Yves David
revlog: make 'storedeltachains' a "public" attribute...
r30210 self.storedeltachains = True
Gregory Szorc
revlog: add instance variable controlling delta chain use...
r30154
Matt Mackall
revlog: add revlogio interface...
r4972 self._io = revlogio()
Matt Mackall
revlog: regroup parsing code
r4971 if self.version == REVLOGV0:
Matt Mackall
revlog: add revlogio interface...
r4972 self._io = revlogoldio()
Benoit Boissinot
revlog: always add the magic nullid/nullrev entry in parseindex
r13265 try:
Gregory Szorc
revlog: rename generic "i" variable to "indexdata"...
r26241 d = self._io.parseindex(indexdata, self._inline)
Benoit Boissinot
revlog: always add the magic nullid/nullrev entry in parseindex
r13265 except (ValueError, IndexError):
raise RevlogError(_("index %s is corrupted") % (self.indexfile))
Benoit Boissinot
revlog: explicit test and explicit variable names
r13268 self.index, nodemap, self._chunkcache = d
if nodemap is not None:
Matt Mackall
revlog: incrementally build node cache with linear searches...
r13275 self.nodemap = self._nodecache = nodemap
Benoit Boissinot
revlog: always add the magic nullid/nullrev entry in parseindex
r13265 if not self._chunkcache:
self._chunkclear()
Siddharth Agarwal
revlog: cache chain info after calculating it for a rev (issue4452)...
r23306 # revnum -> (chain-length, sum-delta-length)
self._chaininfocache = {}
Gregory Szorc
revlog: use compression engine APIs for decompression...
r30817 # revlog header -> revlog compressor
self._decompressors = {}
mpm@selenic.com
Only use lazy indexing for big indices and avoid the overhead of the...
r116
Gregory Szorc
revlog: use compression engine API for compression...
r30795 @util.propertycache
def _compressor(self):
Gregory Szorc
localrepo: experimental support for non-zlib revlog compression...
r30818 return util.compengines[self._compengine].revlogcompressor()
Gregory Szorc
revlog: use compression engine API for compression...
r30795
Matt Mackall
revlog: some codingstyle cleanups
r4980 def tip(self):
return self.node(len(self.index) - 2)
Yuya Nishihara
revlog: add __contains__ for fast membership test...
r24030 def __contains__(self, rev):
return 0 <= rev < len(self)
Matt Mackall
add __len__ and __iter__ methods to repo and revlog
r6750 def __len__(self):
Matt Mackall
revlog: some codingstyle cleanups
r4980 return len(self.index) - 1
Matt Mackall
add __len__ and __iter__ methods to repo and revlog
r6750 def __iter__(self):
Durham Goode
commit: increase perf by avoiding unnecessary filteredrevs check...
r17951 return iter(xrange(len(self)))
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)"""
Pierre-Yves David
revlog: allow reverse iteration with revlog.revs...
r17975 step = 1
if stop is not None:
if start > stop:
step = -1
stop += step
Pierre-Yves David
clfilter: make the revlog class responsible of all its iteration...
r17672 else:
Pierre-Yves David
revlog: allow reverse iteration with revlog.revs...
r17975 stop = len(self)
return xrange(start, stop, step)
Matt Mackall
revlog: incrementally build node cache with linear searches...
r13275
@util.propertycache
def nodemap(self):
Alexander Solovyov
remove unused imports and variables
r14064 self.rev(self.node(0))
Matt Mackall
revlog: incrementally build node cache with linear searches...
r13275 return self._nodecache
Matt Mackall
revlog: do revlog node->rev mapping by scanning...
r13259
Matt Mackall
revlog: add hasnode helper method
r16374 def hasnode(self, node):
try:
self.rev(node)
return True
except KeyError:
return False
Bryan O'Sullivan
parsers: use base-16 trie for faster node->rev mapping...
r16414 def clearcaches(self):
Gregory Szorc
revlog: make clearcaches() more effective...
r27465 self._cache = None
Gregory Szorc
revlog: use an LRU cache for delta chain bases...
r29830 self._chainbasecache.clear()
Gregory Szorc
revlog: make clearcaches() more effective...
r27465 self._chunkcache = (0, '')
self._pcache = {}
Bryan O'Sullivan
parsers: use base-16 trie for faster node->rev mapping...
r16414 try:
self._nodecache.clearcaches()
except AttributeError:
self._nodecache = {nullid: nullrev}
self._nodepos = None
Matt Mackall
revlog: do revlog node->rev mapping by scanning...
r13259 def rev(self, node):
Matt Mackall
revlog: incrementally build node cache with linear searches...
r13275 try:
return self._nodecache[node]
Matt Mackall
repoview: fix 0L with pack/unpack for 2.4
r22282 except TypeError:
raise
Bryan O'Sullivan
parsers: use base-16 trie for faster node->rev mapping...
r16414 except RevlogError:
# parsers.c radix tree lookup failed
Yuya Nishihara
revlog: map rev(wdirid) to WdirUnsupported exception...
r32657 if node == wdirid:
raise error.WdirUnsupported
Bryan O'Sullivan
parsers: use base-16 trie for faster node->rev mapping...
r16414 raise LookupError(node, self.indexfile, _('no node'))
Matt Mackall
revlog: incrementally build node cache with linear searches...
r13275 except KeyError:
Bryan O'Sullivan
parsers: use base-16 trie for faster node->rev mapping...
r16414 # pure python cache lookup failed
Matt Mackall
revlog: incrementally build node cache with linear searches...
r13275 n = self._nodecache
i = self.index
p = self._nodepos
if p is None:
p = len(i) - 2
for r in xrange(p, -1, -1):
v = i[r][7]
n[v] = r
if v == node:
self._nodepos = r - 1
return r
Yuya Nishihara
revlog: map rev(wdirid) to WdirUnsupported exception...
r32657 if node == wdirid:
raise error.WdirUnsupported
Matt Mackall
revlog: incrementally build node cache with linear searches...
r13275 raise LookupError(node, self.indexfile, _('no node'))
Gregory Szorc
revlog: reorder index accessors to match data structure order...
r30287 # Accessors for index entries.
# First tuple entry is 8 bytes. First 6 bytes are offset. Last 2 bytes
# are flags.
mason@suse.com
Implement revlogng....
r2072 def start(self, rev):
Matt Mackall
revlog: minor chunk speed-up
r5006 return int(self.index[rev][0] >> 16)
Gregory Szorc
revlog: reorder index accessors to match data structure order...
r30287
def flags(self, rev):
return self.index[rev][0] & 0xFFFF
Matt Mackall
revlog: some codingstyle cleanups
r4980 def length(self, rev):
return self.index[rev][1]
Gregory Szorc
revlog: reorder index accessors to match data structure order...
r30287
def rawsize(self, rev):
"""return the length of the uncompressed text for a given revision"""
l = self.index[rev][2]
if l >= 0:
return l
Jun Wu
revlog: use raw revision for rawsize...
r31801 t = self.revision(rev, raw=True)
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)
if flags & (REVIDX_KNOWN_FLAGS ^ REVIDX_ELLIPSIS) == 0:
return self.rawsize(rev)
return len(self.revision(rev, raw=False))
Gregory Szorc
revlog: reorder index accessors to match data structure order...
r30287
Sune Foldager
revlog: calculate base revisions iteratively...
r14252 def chainbase(self, rev):
Gregory Szorc
revlog: use an LRU cache for delta chain bases...
r29830 base = self._chainbasecache.get(rev)
if base is not None:
return base
Sune Foldager
revlog: calculate base revisions iteratively...
r14252 index = self.index
base = index[rev][3]
while base != rev:
rev = base
base = index[rev][3]
Gregory Szorc
revlog: use an LRU cache for delta chain bases...
r29830
self._chainbasecache[rev] = base
Sune Foldager
revlog: calculate base revisions iteratively...
r14252 return base
Gregory Szorc
revlog: reorder index accessors to match data structure order...
r30287
def linkrev(self, rev):
return self.index[rev][4]
def parentrevs(self, rev):
Pulkit Goyal
revlog: raise WdirUnsupported when wdirrev is passed...
r32402 try:
Gregory Szorc
revlog: don't use slicing to return parents...
r35539 entry = self.index[rev]
Pulkit Goyal
revlog: raise WdirUnsupported when wdirrev is passed...
r32402 except IndexError:
if rev == wdirrev:
raise error.WdirUnsupported
raise
Gregory Szorc
revlog: reorder index accessors to match data structure order...
r30287
Gregory Szorc
revlog: don't use slicing to return parents...
r35539 return entry[5], entry[6]
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):
return self.start(rev) + self.length(rev)
def parents(self, node):
i = self.index
d = i[self.rev(node)]
return i[d[5]][7], i[d[6]][7] # map revisions to nodes inline
Mateusz Kwapich
debugrevlog: fix computing chain length in debugrevlog -d...
r23254 def chainlen(self, rev):
Siddharth Agarwal
revlog: compute length of compressed deltas along with chain length...
r23286 return self._chaininfo(rev)[0]
Siddharth Agarwal
revlog: cache chain info after calculating it for a rev (issue4452)...
r23306
Siddharth Agarwal
revlog: compute length of compressed deltas along with chain length...
r23286 def _chaininfo(self, rev):
Siddharth Agarwal
revlog: cache chain info after calculating it for a rev (issue4452)...
r23306 chaininfocache = self._chaininfocache
if rev in chaininfocache:
return chaininfocache[rev]
Mateusz Kwapich
debugrevlog: fix computing chain length in debugrevlog -d...
r23254 index = self.index
generaldelta = self._generaldelta
iterrev = rev
e = index[iterrev]
clen = 0
Siddharth Agarwal
revlog: compute length of compressed deltas along with chain length...
r23286 compresseddeltalen = 0
Mateusz Kwapich
debugrevlog: fix computing chain length in debugrevlog -d...
r23254 while iterrev != e[3]:
clen += 1
Siddharth Agarwal
revlog: compute length of compressed deltas along with chain length...
r23286 compresseddeltalen += e[1]
Mateusz Kwapich
debugrevlog: fix computing chain length in debugrevlog -d...
r23254 if generaldelta:
iterrev = e[3]
else:
iterrev -= 1
Siddharth Agarwal
revlog: cache chain info after calculating it for a rev (issue4452)...
r23306 if iterrev in chaininfocache:
t = chaininfocache[iterrev]
clen += t[0]
compresseddeltalen += t[1]
break
Mateusz Kwapich
debugrevlog: fix computing chain length in debugrevlog -d...
r23254 e = index[iterrev]
Siddharth Agarwal
revlog: cache chain info after calculating it for a rev (issue4452)...
r23306 else:
# Add text length of base since decompressing that also takes
# work. For cache hits the length is already included.
compresseddeltalen += e[1]
r = (clen, compresseddeltalen)
chaininfocache[rev] = r
return r
Gregory Szorc
revlog: refactor delta chain computation into own function...
r27468 def _deltachain(self, rev, stoprev=None):
"""Obtain the delta chain for a revision.
``stoprev`` specifies a revision to stop at. If not specified, we
stop at the base of the chain.
Returns a 2-tuple of (chain, stopped) where ``chain`` is a list of
revs in ascending order and ``stopped`` is a bool indicating whether
``stoprev`` was hit.
"""
Gregory Szorc
revlog: C implementation of delta chain resolution...
r33168 # Try C implementation.
try:
return self.index.deltachain(rev, stoprev, self._generaldelta)
except AttributeError:
pass
Gregory Szorc
revlog: refactor delta chain computation into own function...
r27468 chain = []
# Alias to prevent attribute lookup in tight loop.
index = self.index
generaldelta = self._generaldelta
iterrev = rev
e = index[iterrev]
while iterrev != e[3] and iterrev != stoprev:
chain.append(iterrev)
if generaldelta:
iterrev = e[3]
else:
iterrev -= 1
e = index[iterrev]
if iterrev == stoprev:
stopped = True
else:
chain.append(iterrev)
stopped = False
chain.reverse()
return chain, stopped
Siddharth Agarwal
revlog.ancestors: add support for including revs...
r18081 def ancestors(self, revs, stoprev=0, inclusive=False):
Greg Ward
revlog: rewrite several method docstrings...
r10047 """Generate the ancestors of 'revs' in reverse topological 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
Siddharth Agarwal
ancestor.lazyancestors: take parentrevs function rather than changelog...
r23328 return ancestor.lazyancestors(self.parentrevs, revs, stoprev=stoprev,
Siddharth Agarwal
revlog: move ancestor generation out to a new class...
r18090 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):
Greg Ward
revlog: rewrite several method docstrings...
r10047 """Generate the descendants of 'revs' in revision order.
Yield a sequence of revision numbers starting with a child of
some rev in revs, i.e., each revision is *not* considered a
descendant of itself. Results are ordered by revision number (a
topological sort)."""
Nicolas Dumazet
revlog: fix descendants() if nullrev is in revs...
r12950 first = min(revs)
if first == nullrev:
for i in self:
yield i
return
Martin Geisler
util: use built-in set and frozenset...
r8150 seen = set(revs)
Pierre-Yves David
clfilter: make the revlog class responsible of all its iteration...
r17672 for i in self.revs(start=first + 1):
Stefano Tortarolo
Add ancestors and descendants to revlog...
r6872 for x in self.parentrevs(i):
if x != nullrev and x in seen:
seen.add(i)
yield i
break
Peter Arrenbrecht
wireproto: add getbundle() function...
r13741 def findcommonmissing(self, common=None, heads=None):
"""Return a tuple of the ancestors of common and the ancestors of heads
Pierre-Yves David
revlog: improve docstring for findcommonmissing
r15835 that are not ancestors of common. In revset terminology, we return the
tuple:
Greg Ward
revlog: rewrite several method docstrings...
r10047
Pierre-Yves David
revlog: improve docstring for findcommonmissing
r15835 ::common, (::heads) - (::common)
Benoit Boissinot
fix pull racing with push/commit (issue1320)...
r7233
Greg Ward
revlog: rewrite several method docstrings...
r10047 The list is sorted by revision number, meaning it is
topologically sorted.
'heads' and 'common' are both lists of node IDs. If heads is
not supplied, uses all of the revlog's heads. If common is not
supplied, uses nullid."""
Benoit Boissinot
fix pull racing with push/commit (issue1320)...
r7233 if common is None:
common = [nullid]
if heads is None:
heads = self.heads()
common = [self.rev(n) for n in common]
heads = [self.rev(n) for n in heads]
# we want the ancestors, but inclusive
Durham Goode
revlog: return lazy set from findcommonmissing...
r20073 class lazyset(object):
def __init__(self, lazyvalues):
self.addedvalues = set()
self.lazyvalues = lazyvalues
def __contains__(self, value):
return value in self.addedvalues or value in self.lazyvalues
def __iter__(self):
added = self.addedvalues
for r in added:
yield r
for r in self.lazyvalues:
if not r in added:
yield r
def add(self, value):
self.addedvalues.add(value)
def update(self, values):
self.addedvalues.update(values)
has = lazyset(self.ancestors(common))
Martin Geisler
replace set-like dictionaries with real sets...
r8152 has.add(nullrev)
has.update(common)
Benoit Boissinot
fix pull racing with push/commit (issue1320)...
r7233
# take all ancestors from heads that aren't in has
Benoit Boissinot
revlog.missing(): use sets instead of a dict
r8453 missing = set()
Martin von Zweigbergk
util: drop alias for collections.deque...
r25113 visit = collections.deque(r for r in heads if r not in has)
Benoit Boissinot
fix pull racing with push/commit (issue1320)...
r7233 while visit:
Bryan O'Sullivan
cleanup: use the deque type where appropriate...
r16803 r = visit.popleft()
Benoit Boissinot
fix pull racing with push/commit (issue1320)...
r7233 if r in missing:
continue
else:
Benoit Boissinot
revlog.missing(): use sets instead of a dict
r8453 missing.add(r)
Benoit Boissinot
fix pull racing with push/commit (issue1320)...
r7233 for p in self.parentrevs(r):
if p not in has:
visit.append(p)
Benoit Boissinot
revlog.missing(): use sets instead of a dict
r8453 missing = list(missing)
Benoit Boissinot
fix pull racing with push/commit (issue1320)...
r7233 missing.sort()
Augie Fackler
revlog: avoid shadowing several variables using list comprehensions
r30391 return has, [self.node(miss) for miss in missing]
Peter Arrenbrecht
wireproto: add getbundle() function...
r13741
Siddharth Agarwal
revlog: add a method to get missing revs incrementally...
r23337 def incrementalmissingrevs(self, common=None):
"""Return an object that can be used to incrementally compute the
revision numbers of the ancestors of arbitrary sets that are not
ancestors of common. This is an ancestor.incrementalmissingancestors
object.
'common' is a list of revision numbers. If common is not supplied, uses
nullrev.
"""
if common is None:
common = [nullrev]
return ancestor.incrementalmissingancestors(self.parentrevs, common)
Siddharth Agarwal
revlog: add rev-specific variant of findmissing...
r17972 def findmissingrevs(self, common=None, heads=None):
"""Return the revision numbers of the ancestors of heads that
are not ancestors of common.
More specifically, return a list of revision numbers corresponding to
nodes N such that every N satisfies the following constraints:
1. N is an ancestor of some node in 'heads'
2. N is not an ancestor of any node in 'common'
The list is sorted by revision number, meaning it is
topologically sorted.
'heads' and 'common' are both lists of revision numbers. If heads is
not supplied, uses all of the revlog's heads. If common is not
supplied, uses nullid."""
if common is None:
common = [nullrev]
if heads is None:
heads = self.headrevs()
Siddharth Agarwal
revlog: switch findmissing* methods to incrementalmissingrevs...
r23338 inc = self.incrementalmissingrevs(common=common)
return inc.missingancestors(heads)
Siddharth Agarwal
revlog: add rev-specific variant of findmissing...
r17972
Peter Arrenbrecht
wireproto: add getbundle() function...
r13741 def findmissing(self, common=None, heads=None):
"""Return the ancestors of heads that are not ancestors of common.
More specifically, return a list of nodes N such that every N
satisfies the following constraints:
1. N is an ancestor of some node in 'heads'
2. N is not an ancestor of any node in 'common'
The list is sorted by revision number, meaning it is
topologically sorted.
'heads' and 'common' are both lists of node IDs. If heads is
not supplied, uses all of the revlog's heads. If common is not
supplied, uses nullid."""
Siddharth Agarwal
revlog: switch findmissing to use ancestor.missingancestors...
r17971 if common is None:
common = [nullid]
if heads is None:
heads = self.heads()
common = [self.rev(n) for n in common]
heads = [self.rev(n) for n in heads]
Siddharth Agarwal
revlog: switch findmissing* methods to incrementalmissingrevs...
r23338 inc = self.incrementalmissingrevs(common=common)
return [self.node(r) for r in inc.missingancestors(heads)]
Benoit Boissinot
fix pull racing with push/commit (issue1320)...
r7233
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 def nodesbetween(self, roots=None, heads=None):
Greg Ward
revlog: rewrite several method docstrings...
r10047 """Return a topological path from 'roots' to 'heads'.
Return a tuple (nodes, outroots, outheads) where 'nodes' is a
topologically sorted list of all nodes N that satisfy both of
these constraints:
1. N is a descendant of some node in 'roots'
2. N is an ancestor of some node in 'heads'
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457
Greg Ward
revlog: rewrite several method docstrings...
r10047 Every node is considered to be both a descendant and an ancestor
of itself, so every reachable node in 'roots' and 'heads' will be
included in 'nodes'.
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457
Greg Ward
revlog: rewrite several method docstrings...
r10047 'outroots' is the list of reachable nodes in 'roots', i.e., the
subset of 'roots' that is returned in 'nodes'. Likewise,
'outheads' is the subset of 'heads' that is also in 'nodes'.
'roots' and 'heads' are both lists of node IDs. If 'roots' is
unspecified, uses nullid as the only root. If 'heads' is
unspecified, uses list of all of the revlog's heads."""
Eric Hopper
Fix to handle case of empty list for roots or heads in nodesbetween.
r1463 nonodes = ([], [], [])
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 if roots is not None:
roots = list(roots)
Eric Hopper
Fix to handle case of empty list for roots or heads in nodesbetween.
r1463 if not roots:
return nonodes
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 lowestrev = min([self.rev(n) for n in roots])
else:
Matt Mackall
check-code: catch misspellings of descendant...
r14549 roots = [nullid] # Everybody's a descendant of nullid
Thomas Arendsen Hein
Define and use nullrev (revision of nullid) instead of -1.
r3578 lowestrev = nullrev
if (lowestrev == nullrev) and (heads is None):
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 # We want _all_ the nodes!
Matt Mackall
add __len__ and __iter__ methods to repo and revlog
r6750 return ([self.node(r) for r in self], [nullid], list(self.heads()))
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 if heads is None:
# All nodes are ancestors, so the latest ancestor is the last
# node.
Matt Mackall
add __len__ and __iter__ methods to repo and revlog
r6750 highestrev = len(self) - 1
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 # Set ancestors to None to signal that every node is an ancestor.
ancestors = None
# Set heads to an empty dictionary for later discovery of heads
heads = {}
else:
Eric Hopper
Fix to handle case of empty list for roots or heads in nodesbetween.
r1463 heads = list(heads)
if not heads:
return nonodes
Benoit Boissinot
revlog: use set instead of dict
r8464 ancestors = set()
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 # Turn heads into a dictionary so we can remove 'fake' heads.
# Also, later we will be using it to filter out the heads we can't
# find from roots.
Martin Geisler
revlog: use real Booleans instead of 0/1 in nodesbetween
r14219 heads = dict.fromkeys(heads, False)
Benoit Boissinot
nodesbetween: fix a bug with duplicate heads
r3360 # Start at the top and keep marking parents until we're done.
Martin Geisler
rebase, revlog: use set(x) instead of set(x.keys())...
r8163 nodestotag = set(heads)
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 # Remember where the top was so we can use it as a limit later.
highestrev = max([self.rev(n) for n in nodestotag])
while nodestotag:
# grab a node to tag
n = nodestotag.pop()
# Never tag nullid
if n == nullid:
continue
# A node's revision number represents its place in a
# topologically sorted list of nodes.
r = self.rev(n)
if r >= lowestrev:
if n not in ancestors:
Matt Mackall
check-code: catch misspellings of descendant...
r14549 # If we are possibly a descendant of one of the roots
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 # and we haven't already been marked as an ancestor
Benoit Boissinot
revlog: use set instead of dict
r8464 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.
Martin Geisler
revlog: let nodestotag be a set instead of a list
r8153 nodestotag.update([p for p in self.parents(n) if
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 p != nullid])
elif n in heads: # We've seen it before, is it a fake head?
# So it is, real heads should not be the ancestors of
# any other heads.
heads.pop(n)
Eric Hopper
Fix small bug in nodesbetween if heads is [nullid].
r1459 if not ancestors:
Eric Hopper
Fix to handle case of empty list for roots or heads in nodesbetween.
r1463 return nonodes
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 # Now that we have our set of ancestors, we want to remove any
# roots that are not ancestors.
# If one of the roots was nullid, everything is included anyway.
Thomas Arendsen Hein
Define and use nullrev (revision of nullid) instead of -1.
r3578 if lowestrev > nullrev:
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 # But, since we weren't, let's recompute the lowest rev to not
# include roots that aren't ancestors.
# Filter out roots that aren't ancestors of heads
Augie Fackler
revlog: avoid shadowing several variables using list comprehensions
r30391 roots = [root for root in roots if root in ancestors]
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 # Recompute the lowest revision
if roots:
Augie Fackler
revlog: avoid shadowing several variables using list comprehensions
r30391 lowestrev = min([self.rev(root) for root in roots])
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 else:
# No more roots? Return empty list
Eric Hopper
Fix to handle case of empty list for roots or heads in nodesbetween.
r1463 return nonodes
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 else:
# We are descending from nullid, and don't need to care about
# any other roots.
Thomas Arendsen Hein
Define and use nullrev (revision of nullid) instead of -1.
r3578 lowestrev = nullrev
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 roots = [nullid]
Martin Geisler
replace set-like dictionaries with real sets...
r8152 # Transform our roots list into a set.
Matt Mackall
check-code: catch misspellings of descendant...
r14549 descendants = set(roots)
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 # Also, keep the original roots so we can filter out roots that aren't
# 'real' roots (i.e. are descended from other roots).
Matt Mackall
check-code: catch misspellings of descendant...
r14549 roots = descendants.copy()
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 # Our topologically sorted list of output nodes.
orderedout = []
# Don't start at nullid since we don't want nullid in our output list,
timeless@mozdev.org
spelling: descendants
r17483 # and if nullid shows up in descendants, empty parents will look like
Matt Mackall
check-code: catch misspellings of descendant...
r14549 # they're descendants.
Pierre-Yves David
clfilter: make the revlog class responsible of all its iteration...
r17672 for r in self.revs(start=max(lowestrev, 0), stop=highestrev + 1):
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 n = self.node(r)
Matt Mackall
check-code: catch misspellings of descendant...
r14549 isdescendant = False
if lowestrev == nullrev: # Everybody is a descendant of nullid
isdescendant = True
elif n in descendants:
# n is already a descendant
isdescendant = True
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 # This check only needs to be done here because all the roots
Matt Mackall
check-code: catch misspellings of descendant...
r14549 # will start being marked is descendants before the loop.
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 if n in roots:
# If n was a root, check if it's a 'real' root.
p = tuple(self.parents(n))
Matt Mackall
check-code: catch misspellings of descendant...
r14549 # If any of its parents are descendants, it's not a root.
if (p[0] in descendants) or (p[1] in descendants):
Martin Geisler
replace set-like dictionaries with real sets...
r8152 roots.remove(n)
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 else:
p = tuple(self.parents(n))
Matt Mackall
check-code: catch misspellings of descendant...
r14549 # A node is a descendant if either of its parents are
# descendants. (We seeded the dependents list with the roots
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 # up there, remember?)
Matt Mackall
check-code: catch misspellings of descendant...
r14549 if (p[0] in descendants) or (p[1] in descendants):
descendants.add(n)
isdescendant = True
if isdescendant and ((ancestors is None) or (n in ancestors)):
# Only include nodes that are both descendants and ancestors.
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 orderedout.append(n)
if (ancestors is not None) and (n in heads):
# We're trying to figure out which heads are reachable
# from roots.
# Mark this head as having been reached
Martin Geisler
revlog: use real Booleans instead of 0/1 in nodesbetween
r14219 heads[n] = True
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 elif ancestors is None:
# Otherwise, we're trying to discover the heads.
# Assume this is a head because if it isn't, the next step
# will eventually remove it.
Martin Geisler
revlog: use real Booleans instead of 0/1 in nodesbetween
r14219 heads[n] = True
Eric Hopper
This implements the nodesbetween method, and it removes the newer method...
r1457 # But, obviously its parents aren't.
for p in self.parents(n):
heads.pop(p, None)
Augie Fackler
revlog: avoid shadowing several variables using list comprehensions
r30391 heads = [head for head, flag in heads.iteritems() 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)
Peter Arrenbrecht
discovery: add new set-based discovery...
r14164 def headrevs(self):
Bryan O'Sullivan
revlog: switch to a C version of headrevs...
r16786 try:
return self.index.headrevs()
except AttributeError:
Pierre-Yves David
clfilter: split `revlog.headrevs` C call from python code...
r17674 return self._headrevs()
Laurent Charignon
phase: default to C implementation for phase computation
r24444 def computephases(self, roots):
Laurent Charignon
phases: fix bug where native phase computation wasn't called...
r25361 return self.index.computephasesmapsets(roots)
Laurent Charignon
phase: default to C implementation for phase computation
r24444
Pierre-Yves David
clfilter: split `revlog.headrevs` C call from python code...
r17674 def _headrevs(self):
Peter Arrenbrecht
discovery: add new set-based discovery...
r14164 count = len(self)
if not count:
return [nullrev]
Pierre-Yves David
clfilter: handle non contiguous iteration in `revlov.headrevs`...
r17673 # we won't iter over filtered rev so nobody is a head at start
ishead = [0] * (count + 1)
Peter Arrenbrecht
discovery: add new set-based discovery...
r14164 index = self.index
Pierre-Yves David
clfilter: make the revlog class responsible of all its iteration...
r17672 for r in self:
Pierre-Yves David
clfilter: handle non contiguous iteration in `revlov.headrevs`...
r17673 ishead[r] = 1 # I may be an head
Peter Arrenbrecht
discovery: add new set-based discovery...
r14164 e = index[r]
Pierre-Yves David
clfilter: handle non contiguous iteration in `revlov.headrevs`...
r17673 ishead[e[5]] = ishead[e[6]] = 0 # my parent are not
return [r for r, val in enumerate(ishead) if val]
Peter Arrenbrecht
discovery: add new set-based discovery...
r14164
Benoit Boissinot
fix calculation of new heads added during push with -r...
r3923 def heads(self, start=None, stop=None):
Benoit Boissinot
add a -r/--rev option to heads to show only heads descendant from rev
r1550 """return the list of all nodes that have no children
Thomas Arendsen Hein
Fixes to "hg heads -r FOO":...
r1551
if start is specified, only heads that are descendants of
start will be returned
Benoit Boissinot
fix calculation of new heads added during push with -r...
r3923 if stop is specified, it will consider all the revs from stop
as if they had no children
Thomas Arendsen Hein
Fixes to "hg heads -r FOO":...
r1551 """
Matt Mackall
revlog: implement a fast path for heads
r4991 if start is None and stop is None:
Peter Arrenbrecht
discovery: add new set-based discovery...
r14164 if not len(self):
Matt Mackall
revlog: implement a fast path for heads
r4991 return [nullid]
Peter Arrenbrecht
discovery: add new set-based discovery...
r14164 return [self.node(r) for r in self.headrevs()]
Matt Mackall
revlog: implement a fast path for heads
r4991
Thomas Arendsen Hein
Fixes to "hg heads -r FOO":...
r1551 if start is None:
start = nullid
Benoit Boissinot
fix calculation of new heads added during push with -r...
r3923 if stop is None:
stop = []
Martin Geisler
replace set-like dictionaries with real sets...
r8152 stoprevs = set([self.rev(n) for n in stop])
Benoit Boissinot
add a -r/--rev option to heads to show only heads descendant from rev
r1550 startrev = self.rev(start)
Martin von Zweigbergk
cleanup: use set literals...
r32291 reachable = {startrev}
heads = {startrev}
mpm@selenic.com
Add some docstrings to revlog.py
r1083
Alexis S. L. Carvalho
Change revlog.heads to walk the revision graph using revision numbers...
r2490 parentrevs = self.parentrevs
Pierre-Yves David
clfilter: make the revlog class responsible of all its iteration...
r17672 for r in self.revs(start=startrev + 1):
Alexis S. L. Carvalho
Change revlog.heads to walk the revision graph using revision numbers...
r2490 for p in parentrevs(r):
if p in reachable:
Benoit Boissinot
fix calculation of new heads added during push with -r...
r3923 if r not in stoprevs:
Benoit Boissinot
revlog: use set instead of dict
r8464 reachable.add(r)
heads.add(r)
Benoit Boissinot
fix calculation of new heads added during push with -r...
r3923 if p in heads and p not in stoprevs:
Benoit Boissinot
revlog: use set instead of dict
r8464 heads.remove(p)
Benoit Boissinot
fix calculation of new heads added during push with -r...
r3923
Alexis S. L. Carvalho
Change revlog.heads to walk the revision graph using revision numbers...
r2490 return [self.node(r) for r in heads]
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
Benoit Boissinot
revlog: put graph related functions together
r10897 def descendant(self, start, end):
Nicolas Dumazet
revlog: if start is nullrev, end is always a descendant
r12949 if start == nullrev:
return True
Bryan O'Sullivan
revlog: descendants(*revs) becomes descendants(revs) (API)...
r16867 for i in self.descendants([start]):
Benoit Boissinot
revlog: put graph related functions together
r10897 if i == end:
return True
elif i > end:
break
return False
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)
try:
ancs = self.index.commonancestorsheads(a, b)
except (AttributeError, OverflowError): # C implementation failed
ancs = ancestor.commonancestorsheads(self.parentrevs, a, b)
Augie Fackler
revlog: use pycompat.maplist to eagerly evaluate map on Python 3...
r31574 return pycompat.maplist(self.node, 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):
"""return True if node a is an ancestor of node b
The implementation of this is trivial but the use of
commonancestorsheads is not."""
return a in self.commonancestorsheads(a, b)
Mads Kiilerich
revlog: backout 514d32de6646 - commonancestors
r21107 def ancestor(self, a, b):
Mads Kiilerich
comments: describe ancestor consistently - avoid 'least common ancestor'...
r22389 """calculate the "best" common ancestor of nodes a and b"""
Mads Kiilerich
revlog: backout 514d32de6646 - commonancestors
r21107
Benoit Boissinot
revlog: put graph related functions together
r10897 a, b = self.rev(a), self.rev(b)
Bryan O'Sullivan
parsers: a C implementation of the new ancestors algorithm...
r18988 try:
ancs = self.index.ancestors(a, b)
Mads Kiilerich
revlog: backout 514d32de6646 - commonancestors
r21107 except (AttributeError, OverflowError):
Bryan O'Sullivan
parsers: a C implementation of the new ancestors algorithm...
r18988 ancs = ancestor.ancestors(self.parentrevs, a, b)
Bryan O'Sullivan
revlog: choose a consistent ancestor when there's a tie...
r18987 if ancs:
# choose a consistent winner when there's a tie
Mads Kiilerich
revlog: backout 514d32de6646 - commonancestors
r21107 return min(map(self.node, ancs))
Bryan O'Sullivan
revlog: choose a consistent ancestor when there's a tie...
r18987 return nullid
Benoit Boissinot
revlog: put graph related functions together
r10897
Matt Mackall
Only look up tags and branches as a last resort
r3453 def _match(self, id):
Matt Mackall
revlog: don't handle long for revision matching...
r16762 if isinstance(id, int):
Benoit Boissinot
cleanups in revlog.lookup...
r3156 # rev
Benoit Boissinot
lookup should allow -1 to represent nullid (if passed an int as arg)
r2641 return self.node(id)
Matt Mackall
revlog.lookup tweaks...
r3438 if len(id) == 20:
# possibly a binary node
# odds of a binary node being all hex in ASCII are 1 in 10**25
try:
node = id
Peter Arrenbrecht
cleanup: drop variables for unused return values...
r7874 self.rev(node) # quick search the index
Matt Mackall
revlog.lookup tweaks...
r3438 return node
Brendan Cully
Add revlog.LookupError exception, and use it instead of RevlogError....
r3930 except LookupError:
Matt Mackall
revlog.lookup tweaks...
r3438 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)
Matt Mackall
revlog: some codingstyle cleanups
r4980 if str(rev) != id:
raise ValueError
if rev < 0:
Matt Mackall
add __len__ and __iter__ methods to repo and revlog
r6750 rev = len(self) + rev
if rev < 0 or rev >= len(self):
Matt Mackall
revlog: some codingstyle cleanups
r4980 raise ValueError
mpm@selenic.com
Add smart node lookup by substring or by rev number
r36 return self.node(rev)
mpm@selenic.com
Various node id lookup tweaks...
r469 except (ValueError, OverflowError):
Benoit Boissinot
cleanups in revlog.lookup...
r3156 pass
Matt Mackall
Only look up tags and branches as a last resort
r3453 if len(id) == 40:
try:
Matt Mackall
revlog.lookup tweaks...
r3438 # a full hex nodeid?
node = bin(id)
Peter Arrenbrecht
cleanup: drop variables for unused return values...
r7874 self.rev(node)
Benoit Boissinot
optimize revlog.lookup when passed hex(node)[:...]...
r3157 return node
Sune Foldager
provide nicer feedback when an unknown node id is passed to a command...
r7062 except (TypeError, LookupError):
Matt Mackall
Only look up tags and branches as a last resort
r3453 pass
def _partialmatch(self, id):
Yuya Nishihara
revlog: add support for partial matching of wdir node id...
r32684 maybewdir = wdirhex.startswith(id)
Bryan O'Sullivan
revlog: speed up prefix matching against nodes...
r16665 try:
Augie Fackler
revlog: avoid shadowing several variables using list comprehensions
r30391 partial = self.index.partialmatch(id)
if partial and self.hasnode(partial):
Yuya Nishihara
revlog: add support for partial matching of wdir node id...
r32684 if maybewdir:
# single 'ff...' match in radix tree, ambiguous with wdir
raise RevlogError
Augie Fackler
revlog: avoid shadowing several variables using list comprehensions
r30391 return partial
Yuya Nishihara
revlog: add support for partial matching of wdir node id...
r32684 if maybewdir:
# no 'ff...' match in radix tree, wdir identified
raise error.WdirUnsupported
Matt Mackall
revlog: handle hidden revs in _partialmatch (issue3979)...
r19471 return None
Bryan O'Sullivan
revlog: speed up prefix matching against nodes...
r16665 except RevlogError:
# 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):
raise LookupError(id, self.indexfile,
_('ambiguous identifier'))
Matt Mackall
revlog: handle hidden revs in _partialmatch (issue3979)...
r19471 # fall through to slow path that filters hidden revisions
Bryan O'Sullivan
revlog: speed up prefix matching against nodes...
r16665 except (AttributeError, ValueError):
# we are pure python, or key was too short to search radix tree
pass
Matt Mackall
revlog: introduce a cache for partial lookups...
r13258 if id in self._pcache:
return self._pcache[id]
Matt Mackall
Only look up tags and branches as a last resort
r3453 if len(id) < 40:
try:
Matt Mackall
revlog.lookup tweaks...
r3438 # hex(node)[:...]
Alejandro Santos
compat: use // for integer division
r9029 l = len(id) // 2 # grab an even number of digits
Matt Mackall
revlog: do revlog node->rev mapping by scanning...
r13259 prefix = bin(id[:l * 2])
nl = [e[7] for e in self.index if e[7].startswith(prefix)]
Matt Mackall
revlog: handle hidden revs in _partialmatch (issue3979)...
r19471 nl = [n for n in nl if hex(n).startswith(id) and
self.hasnode(n)]
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]
raise LookupError(id, self.indexfile,
_('ambiguous identifier'))
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
Pulkit Goyal
py3: catch binascii.Error raised from binascii.unhexlify...
r32969 except (TypeError, binascii.Error):
Matt Mackall
Only look up tags and branches as a last resort
r3453 pass
def lookup(self, id):
"""locate a node based on:
- revision number or str(revision number)
- nodeid or subset of hex nodeid
"""
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
Matt Mackall
revlog: report node and file when lookup fails
r6228 raise LookupError(id, self.indexfile, _('no match found'))
mpm@selenic.com
Add smart node lookup by substring or by rev number
r36
Martin von Zweigbergk
templater: extract shortest() logic from template function...
r34247 def shortest(self, hexnode, minlength=1):
"""Find the shortest unambiguous prefix that matches hexnode."""
def isvalid(test):
try:
if self._partialmatch(test) is None:
return False
try:
i = int(test)
# if we are a pure int, then starting with zero will not be
# confused as a rev; or, obviously, if the int is larger
# than the value of the tip rev
if test[0] == '0' or i > len(self):
return True
return False
except ValueError:
return True
except error.RevlogError:
return False
except error.WdirUnsupported:
# single 'ff...' match
return True
shortest = hexnode
startlength = max(6, minlength)
length = startlength
while True:
test = hexnode[:length]
if isvalid(test):
shortest = test
if length == minlength or length > startlength:
return shortest
length -= 1
else:
length += 1
if len(shortest) <= length:
return shortest
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)
return hash(text, p1, p2) != node
Gregory Szorc
revlog: rename internal functions containing "chunk" to use "segment"...
r32222 def _cachesegment(self, offset, data):
Gregory Szorc
revlog: improve documentation...
r27070 """Add a segment to the revlog cache.
Accepts an absolute offset and the data that is at that location.
"""
Matt Mackall
revlog: clean up the chunk caching code
r8316 o, d = self._chunkcache
# try to add to existing cache
Matt Mackall
revlog: remove lazy index
r13253 if o + len(d) == offset and len(d) + len(data) < _chunksize:
Matt Mackall
revlog: clean up the chunk caching code
r8316 self._chunkcache = o, d + data
else:
self._chunkcache = offset, data
Gregory Szorc
revlog: rename internal functions containing "chunk" to use "segment"...
r32222 def _readsegment(self, offset, length, df=None):
Gregory Szorc
revlog: improve documentation...
r27070 """Load a segment of raw data from the revlog.
Gregory Szorc
revlog: support using an existing file handle when reading revlogs...
r26377
Gregory Szorc
revlog: improve documentation...
r27070 Accepts an absolute offset, length to read, and an optional existing
Gregory Szorc
revlog: support using an existing file handle when reading revlogs...
r26377 file handle to read from.
If an existing file handle is passed, it will be seeked and the
original seek position will NOT be restored.
Gregory Szorc
revlog: improve documentation...
r27070
Returns a str or buffer of raw byte data.
Gregory Szorc
revlog: support using an existing file handle when reading revlogs...
r26377 """
if df is not None:
closehandle = False
Matt Mackall
revlog: refactor chunk cache interface again...
r8650 else:
Gregory Szorc
revlog: support using an existing file handle when reading revlogs...
r26377 if self._inline:
df = self.opener(self.indexfile)
else:
df = self.opener(self.datafile)
closehandle = True
Matt Mackall
revlog: clean up the chunk caching code
r8316
Brodie Rao
revlog: read/cache chunks in fixed windows of 64 KB...
r20179 # Cache data both forward and backward around the requested
# data, in a fixed size window. This helps speed up operations
# involving reading the revlog backwards.
Brodie Rao
revlog: allow tuning of the chunk cache size (via format.chunkcachesize)...
r20180 cachesize = self._chunkcachesize
realoffset = offset & ~(cachesize - 1)
reallength = (((offset + length + cachesize) & ~(cachesize - 1))
- realoffset)
Brodie Rao
revlog: read/cache chunks in fixed windows of 64 KB...
r20179 df.seek(realoffset)
d = df.read(reallength)
Gregory Szorc
revlog: support using an existing file handle when reading revlogs...
r26377 if closehandle:
df.close()
Gregory Szorc
revlog: rename internal functions containing "chunk" to use "segment"...
r32222 self._cachesegment(realoffset, d)
Brodie Rao
revlog: read/cache chunks in fixed windows of 64 KB...
r20179 if offset != realoffset or reallength != length:
return util.buffer(d, offset - realoffset, length)
Matt Mackall
revlog: clean up the chunk caching code
r8316 return d
Gregory Szorc
revlog: rename internal functions containing "chunk" to use "segment"...
r32222 def _getsegment(self, offset, length, df=None):
Gregory Szorc
revlog: improve documentation...
r27070 """Obtain a segment of raw data from the revlog.
Accepts an absolute offset, length of bytes to obtain, and an
optional file handle to the already-opened revlog. If the file
handle is used, it's original seek position will not be preserved.
Requests for data may be returned from a cache.
Returns a str or a buffer instance of raw byte data.
"""
Matt Mackall
revlog: clean up the chunk caching code
r8316 o, d = self._chunkcache
l = len(d)
# is it in the cache?
cachestart = offset - o
cacheend = cachestart + length
if cachestart >= 0 and cacheend <= l:
if cachestart == 0 and cacheend == l:
return d # avoid a copy
Bryan O'Sullivan
revlog: avoid an expensive string copy...
r16423 return util.buffer(d, cachestart, cacheend - cachestart)
Matt Mackall
revlog: clean up the chunk caching code
r8316
Gregory Szorc
revlog: rename internal functions containing "chunk" to use "segment"...
r32222 return self._readsegment(offset, length, df=df)
Matt Mackall
revlog: clean up the chunk caching code
r8316
Gregory Szorc
revlog: rename _chunkraw to _getsegmentforrevs()...
r32224 def _getsegmentforrevs(self, startrev, endrev, df=None):
Gregory Szorc
revlog: improve documentation...
r27070 """Obtain a segment of raw data corresponding to a range of revisions.
Accepts the start and end revisions and an optional already-open
file handle to be used for reading. If the file handle is read, its
seek position will not be preserved.
Requests for data may be satisfied by a cache.
Gregory Szorc
revlog: return offset from _chunkraw()...
r27649 Returns a 2-tuple of (offset, data) for the requested range of
revisions. Offset is the integer offset from the beginning of the
revlog and data is a str or buffer of the raw byte data.
Callers will need to call ``self.start(rev)`` and ``self.length(rev)``
to determine where each revision's data begins and ends.
Gregory Szorc
revlog: improve documentation...
r27070 """
Gregory Szorc
revlog: inline start() and end() for perf reasons...
r30288 # Inlined self.start(startrev) & self.end(endrev) for perf reasons
# (functions are expensive).
index = self.index
istart = index[startrev]
start = int(istart[0] >> 16)
Gregory Szorc
revlog: optimize _chunkraw when startrev==endrev...
r30289 if startrev == endrev:
end = start + istart[1]
else:
iend = index[endrev]
end = int(iend[0] >> 16) + iend[1]
Gregory Szorc
revlog: inline start() and end() for perf reasons...
r30288
Matt Mackall
revlog: add cache priming for reconstructing delta chains
r8318 if self._inline:
start += (startrev + 1) * self._io.size
Siddharth Agarwal
revlog.revision: fix cache preload for inline revlogs...
r19714 end += (endrev + 1) * self._io.size
length = end - start
Gregory Szorc
revlog: return offset from _chunkraw()...
r27649
Gregory Szorc
revlog: rename internal functions containing "chunk" to use "segment"...
r32222 return start, self._getsegment(start, length, df=df)
Matt Mackall
revlog: add cache priming for reconstructing delta chains
r8318
Gregory Szorc
revlog: support using an existing file handle when reading revlogs...
r26377 def _chunk(self, rev, df=None):
Gregory Szorc
revlog: improve documentation...
r27070 """Obtain a single decompressed chunk for a revision.
Accepts an integer revision and an optional already-open file handle
to be used for reading. If used, the seek position of the file will not
be preserved.
Returns a str holding uncompressed data for the requested revision.
"""
Gregory Szorc
revlog: rename _chunkraw to _getsegmentforrevs()...
r32224 return self.decompress(self._getsegmentforrevs(rev, rev, df=df)[1])
Matt Mackall
revlog: refactor chunk cache interface again...
r8650
Gregory Szorc
revlog: support using an existing file handle when reading revlogs...
r26377 def _chunks(self, revs, df=None):
Gregory Szorc
revlog: improve documentation...
r27070 """Obtain decompressed chunks for the specified revisions.
Siddharth Agarwal
revlog: add a fast method for getting a list of chunks...
r19713
Gregory Szorc
revlog: improve documentation...
r27070 Accepts an iterable of numeric revisions that are assumed to be in
ascending order. Also accepts an optional already-open file handle
to be used for reading. If used, the seek position of the file will
not be preserved.
This function is similar to calling ``self._chunk()`` multiple times,
but is faster.
Returns a list with decompressed data for each requested revision.
"""
Siddharth Agarwal
revlog: move chunk cache preload from revision to _chunks...
r19716 if not revs:
return []
Siddharth Agarwal
revlog: add a fast method for getting a list of chunks...
r19713 start = self.start
length = self.length
inline = self._inline
iosize = self._io.size
Siddharth Agarwal
revlog._chunks: inline getchunk...
r19715 buffer = util.buffer
Siddharth Agarwal
revlog: add a fast method for getting a list of chunks...
r19713
l = []
ladd = l.append
Paul Morelle
revlog: introduce an experimental flag to slice chunks reads when too sparse...
r34825 if not self._withsparseread:
slicedchunks = (revs,)
else:
slicedchunks = _slicechunk(self, revs)
for revschunk in slicedchunks:
firstrev = revschunk[0]
# Skip trailing revisions with empty diff
for lastrev in revschunk[::-1]:
if length(lastrev) != 0:
break
Paul Morelle
revlog: ignore empty trailing chunks when reading segments...
r34824
Paul Morelle
revlog: introduce an experimental flag to slice chunks reads when too sparse...
r34825 try:
offset, data = self._getsegmentforrevs(firstrev, lastrev, df=df)
except OverflowError:
# issue4215 - we can't cache a run of chunks greater than
# 2G on Windows
return [self._chunk(rev, df=df) for rev in revschunk]
Siddharth Agarwal
revlog._chunks: inline getchunk...
r19715
Paul Morelle
revlog: introduce an experimental flag to slice chunks reads when too sparse...
r34825 decomp = self.decompress
for rev in revschunk:
chunkstart = start(rev)
if inline:
chunkstart += (rev + 1) * iosize
chunklength = length(rev)
ladd(decomp(buffer(data, chunkstart - offset, chunklength)))
Siddharth Agarwal
revlog: add a fast method for getting a list of chunks...
r19713
return l
Sune Foldager
revlog: introduce _chunkbase to allow filelog to override...
r14075
Matt Mackall
revlog: refactor chunk cache interface again...
r8650 def _chunkclear(self):
Gregory Szorc
revlog: improve documentation...
r27070 """Clear the raw chunk cache."""
Matt Mackall
revlog: refactor chunk cache interface again...
r8650 self._chunkcache = (0, '')
Benoit Boissinot
cleanup of revlog.group when repository is local...
r1598
Pradeepkumar Gayam
revlog: deltachain() returns chain of revs need to construct a revision
r11929 def deltaparent(self, rev):
Sune Foldager
revlog: remove support for parentdelta...
r14195 """return deltaparent of the given revision"""
Sune Foldager
revlog: support reading generaldelta revlogs...
r14253 base = self.index[rev][3]
if base == rev:
Sune Foldager
revlog: compute correct deltaparent in the deltaparent function...
r14208 return nullrev
Sune Foldager
revlog: support reading generaldelta revlogs...
r14253 elif self._generaldelta:
return base
Sune Foldager
revlog: compute correct deltaparent in the deltaparent function...
r14208 else:
return rev - 1
Pradeepkumar Gayam
revlog: deltachain() returns chain of revs need to construct a revision
r11929
Benoit Boissinot
revlog.py: factorization and fixes for rev < 0 (nullid)
r1941 def revdiff(self, rev1, rev2):
Jun Wu
revlog: use raw revisions in revdiff...
r31753 """return or calculate a delta between two revisions
The delta calculated is in binary form and is intended to be written to
revlog data directly. So this function needs raw revision data.
"""
Sune Foldager
revlog: compute correct deltaparent in the deltaparent function...
r14208 if rev1 != nullrev and self.deltaparent(rev2) == rev1:
Augie Fackler
revlog: use bytes() instead of str() to get data from memoryview...
r31369 return bytes(self._chunk(rev2))
Matt Mackall
revlog: minor revdiff reorganization
r5005
Jun Wu
revlog: use raw revisions in revdiff...
r31753 return mdiff.textdiff(self.revision(rev1, raw=True),
self.revision(rev2, raw=True))
mpm@selenic.com
Add code to retrieve or construct a revlog delta
r119
Remi Chaintron
revlog: add 'raw' argument to revision and _addrevision...
r30743 def revision(self, nodeorrev, _df=None, raw=False):
Patrick Mezard
revlog: fix partial revision() docstring (from d7d64b89a65c)
r16435 """return an uncompressed revision of a given node or revision
number.
Gregory Szorc
revlog: support using an existing file handle when reading revlogs...
r26377
Remi Chaintron
revlog: add 'raw' argument to revision and _addrevision...
r30743 _df - an existing file handle to read from. (internal-only)
raw - an optional argument specifying if the revision data is to be
treated as raw data when applying flag transforms. 'raw' should be set
to True when generating changegroups or in debug commands.
Patrick Mezard
revlog: fix partial revision() docstring (from d7d64b89a65c)
r16435 """
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
Benoit Boissinot
revlog.revision(): don't use nullrev as the default value for the cache...
r11996 cachedrev = None
Jun Wu
revlog: avoid calculating "flags" twice in revision()...
r31802 flags = None
Jun Wu
revlog: avoid applying delta chain on cache hit...
r31804 rawtext = None
Matt Mackall
revlog: some codingstyle cleanups
r4980 if node == nullid:
return ""
Gregory Szorc
revlog: drop local assignment of cache variable...
r26242 if self._cache:
if self._cache[0] == node:
Jun Wu
revlog: fix _cache usage in revision()...
r31751 # _cache only stores rawtext
if raw:
return self._cache[2]
Jun Wu
revlog: add a fast path for revision(raw=False)...
r31756 # duplicated, but good for perf
if rev is None:
rev = self.rev(node)
Jun Wu
revlog: avoid calculating "flags" twice in revision()...
r31802 if flags is None:
flags = self.flags(rev)
Jun Wu
revlog: add a fast path for revision(raw=False)...
r31756 # no extra flags set, no flag processor runs, text = rawtext
Jun Wu
revlog: avoid calculating "flags" twice in revision()...
r31802 if flags == REVIDX_DEFAULT_FLAGS:
Jun Wu
revlog: add a fast path for revision(raw=False)...
r31756 return self._cache[2]
Jun Wu
revlog: avoid applying delta chain on cache hit...
r31804 # rawtext is reusable. need to run flag processor
rawtext = self._cache[2]
Jun Wu
revlog: add a fast path for revision(raw=False)...
r31756
Gregory Szorc
revlog: drop local assignment of cache variable...
r26242 cachedrev = self._cache[1]
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
mpm@selenic.com
Add some docstrings to revlog.py
r1083 # look up what we need to read
Jun Wu
revlog: indent block to make review easier
r31803 if rawtext is None:
if rev is None:
rev = self.rev(node)
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
Jun Wu
revlog: indent block to make review easier
r31803 chain, stopped = self._deltachain(rev, stoprev=cachedrev)
if stopped:
rawtext = self._cache[2]
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
Jun Wu
revlog: indent block to make review easier
r31803 # drop cache to save memory
self._cache = None
Matt Mackall
revlog: drop cache after use to save memory footprint...
r11754
Jun Wu
revlog: indent block to make review easier
r31803 bins = self._chunks(chain, df=_df)
if rawtext is None:
rawtext = bytes(bins[0])
bins = bins[1:]
Matt Mackall
revlog: refactor chunk cache interface again...
r8650
Jun Wu
revlog: indent block to make review easier
r31803 rawtext = mdiff.patches(rawtext, bins)
Jun Wu
revlog: avoid applying delta chain on cache hit...
r31804 self._cache = (node, rev, rawtext)
Remi Chaintron
revlog: flag processor...
r30745
Jun Wu
revlog: avoid calculating "flags" twice in revision()...
r31802 if flags is None:
Jun Wu
revlog: avoid applying delta chain on cache hit...
r31804 if rev is None:
rev = self.rev(node)
Jun Wu
revlog: avoid calculating "flags" twice in revision()...
r31802 flags = self.flags(rev)
text, validatehash = self._processflags(rawtext, flags, 'read', raw=raw)
Remi Chaintron
revlog: flag processor...
r30745 if validatehash:
self.checkhash(text, node, rev=rev)
Matt Mackall
revlog: break hash checking into subfunction
r13239 return text
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.
"""
return hash(text, p1, p2)
Remi Chaintron
revlog: flag processor...
r30745 def _processflags(self, text, flags, operation, raw=False):
"""Inspect revision data flags and applies transforms defined by
registered flag processors.
``text`` - the revision data to process
``flags`` - the revision flags
``operation`` - the operation being performed (read or write)
``raw`` - an optional argument describing if the raw transform should be
applied.
This method processes the flags in the order (or reverse order if
``operation`` is 'write') defined by REVIDX_FLAGS_ORDER, applying the
flag processors registered for present flags. The order of flags defined
in REVIDX_FLAGS_ORDER needs to be stable to allow non-commutativity.
Returns a 2-tuple of ``(text, validatehash)`` where ``text`` is the
processed text and ``validatehash`` is a bool indicating whether the
returned text should be checked for hash integrity.
Note: If the ``raw`` argument is set, it has precedence over the
operation and will only update the value of ``validatehash``.
"""
Jun Wu
flagprocessor: add a fast path when flags is 0...
r32286 # fast path: no flag processors will run
if flags == 0:
return text, True
Remi Chaintron
revlog: flag processor...
r30745 if not operation in ('read', 'write'):
raise ProgrammingError(_("invalid '%s' operation ") % (operation))
# Check all flags are known.
if flags & ~REVIDX_KNOWN_FLAGS:
raise RevlogError(_("incompatible revision flag '%#x'") %
(flags & ~REVIDX_KNOWN_FLAGS))
validatehash = True
# Depending on the operation (read or write), the order might be
# reversed due to non-commutative transforms.
orderedflags = REVIDX_FLAGS_ORDER
if operation == 'write':
orderedflags = reversed(orderedflags)
for flag in orderedflags:
# If a flagprocessor has been registered for a known flag, apply the
# related operation transform and update result tuple.
if flag & flags:
vhash = True
if flag not in _flagprocessors:
message = _("missing processor for flag '%#x'") % (flag)
raise RevlogError(message)
processor = _flagprocessors[flag]
if processor is not None:
readtransform, writetransform, rawtransform = processor
if raw:
vhash = rawtransform(self, text)
elif operation == 'read':
text, vhash = readtransform(self, text)
else: # write operation
text, vhash = writetransform(self, text)
validatehash = validatehash and vhash
return text, validatehash
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.
"""
if p1 is None and p2 is None:
p1, p2 = self.parents(node)
Augie Fackler
revlog: move references to revlog.hash to inside the revlog class...
r22785 if node != self.hash(text, p1, p2):
Wojciech Lopata
revlog: extract 'checkhash' method...
r19624 revornode = rev
if revornode is None:
revornode = templatefilters.short(hex(node))
raise RevlogError(_("integrity check failed on %s:%s")
Augie Fackler
revlog: use pycompat.bytestr() to reliably have a %s-able value
r34028 % (self.indexfile, pycompat.bytestr(revornode)))
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
mason@suse.com
Make the appendfile class inline-data index friendly...
r2075 def checkinlinesize(self, tr, fp=None):
Gregory Szorc
revlog: add docstring for checkinlinesize()...
r26376 """Check if the revlog is too big for inline and convert if so.
This should be called after revisions are added to the revlog. If the
revlog has grown too large to be an inline revlog, it will convert it
to use multiple index and data files.
"""
Greg Ward
revlog: factor out _maxinline global....
r10913 if not self._inline or (self.start(-2) + self.length(-2)) < _maxinline:
mason@suse.com
Implement data inlined with the index file...
r2073 return
Matt Mackall
revlog: use index to find index size
r8315
Chris Mason
...
r2084 trinfo = tr.find(self.indexfile)
Martin Geisler
use 'x is None' instead of 'x == None'...
r8527 if trinfo is None:
Thomas Arendsen Hein
Indentation cleanups for 2956948b81f3.
r3680 raise RevlogError(_("%s not found in the transaction")
% self.indexfile)
Chris Mason
...
r2084
trindex = trinfo[2]
Mike Edgar
revlog: make converting from inline to non-line work after a strip...
r24454 if trindex is not None:
dataoff = self.start(trindex)
else:
# revlog was stripped at start of transaction, use all leftover data
trindex = len(self) - 1
dataoff = self.end(-2)
Chris Mason
...
r2084
tr.add(self.datafile, dataoff)
Matt Mackall
revlog: use index to find index size
r8315
Matt Mackall
revlog: use chunk cache to avoid rereading when splitting inline files
r8317 if fp:
fp.flush()
fp.close()
Matt Mackall
revlog: use index to find index size
r8315
mason@suse.com
Implement data inlined with the index file...
r2073 df = self.opener(self.datafile, 'w')
Benoit Boissinot
revlog: make sure the files are closed after an exception happens...
r6261 try:
Matt Mackall
add __len__ and __iter__ methods to repo and revlog
r6750 for r in self:
Gregory Szorc
revlog: rename _chunkraw to _getsegmentforrevs()...
r32224 df.write(self._getsegmentforrevs(r, r)[1])
Benoit Boissinot
revlog: make sure the files are closed after an exception happens...
r6261 finally:
df.close()
FUJIWARA Katsunori
revlog: specify checkambig at writing to avoid file stat ambiguity...
r29997 fp = self.opener(self.indexfile, 'w', atomictemp=True,
checkambig=self._checkambig)
Gregory Szorc
revlog: rename constants (API)...
r32316 self.version &= ~FLAG_INLINE_DATA
Matt Mackall
revlog: change _inline from a function to a variable
r4982 self._inline = False
Matt Mackall
add __len__ and __iter__ methods to repo and revlog
r6750 for i in self:
Alexis S. L. Carvalho
revlog: fix revlogio.packentry corner case...
r5338 e = self._io.packentry(self.index[i], self.node, self.version, i)
mason@suse.com
Implement data inlined with the index file...
r2073 fp.write(e)
Greg Ward
atomictempfile: make close() consistent with other file-like objects....
r15057 # if we don't call close, the temp file will never replace the
mason@suse.com
Create an atomic opener that does not automatically rename on close...
r2076 # real index
Greg Ward
atomictempfile: make close() consistent with other file-like objects....
r15057 fp.close()
Chris Mason
...
r2084
Matt Mackall
revlog: refactor chunk cache interface again...
r8650 tr.replace(self.indexfile, trindex * self._io.size)
self._chunkclear()
mason@suse.com
Implement data inlined with the index file...
r2073
Wojciech Lopata
revlog: pass node as an argument of addrevision...
r19625 def addrevision(self, text, transaction, link, p1, p2, cachedelta=None,
Paul Morelle
revlog: group delta computation methods under _deltacomputer object...
r35756 node=None, flags=REVIDX_DEFAULT_FLAGS, deltacomputer=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
Paul Morelle
revlog: group delta computation methods under _deltacomputer object...
r35756 deltacomputer - an optional _deltacomputer instance shared between
multiple calls
mpm@selenic.com
Add some docstrings to revlog.py
r1083 """
Durham Goode
revlog: add exception when linkrev == nullrev...
r19326 if link == nullrev:
raise RevlogError(_("attempted to add linkrev -1 to %s")
% self.indexfile)
Matt Mackall
revlog: move size limit check to addrevision...
r25459
Remi Chaintron
revlog: flag processor...
r30745 if flags:
node = node or self.hash(text, p1, p2)
Jun Wu
revlog: rename some "text"s to "rawtext"...
r31750 rawtext, validatehash = self._processflags(text, flags, 'write')
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:
Matt Mackall
revlog: move size limit check to addrevision...
r25459 raise RevlogError(
_("%s: size of %d bytes exceeds maximum revlog storage of 2GiB")
Jun Wu
revlog: rename some "text"s to "rawtext"...
r31750 % (self.indexfile, len(rawtext)))
Matt Mackall
revlog: move size limit check to addrevision...
r25459
Jun Wu
revlog: rename some "text"s to "rawtext"...
r31750 node = node or self.hash(rawtext, p1, p2)
Sune Foldager
revlog: remove support for punched/shallow...
r14196 if node in self.nodemap:
Benoit Boissinot
revlog.addrevision(): move computation of nodeid in addrevision()...
r12023 return node
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
Jun Wu
revlog: move part of "addrevision" to "addrawrevision"...
r32240 return self.addrawrevision(rawtext, transaction, link, p1, p2, node,
Paul Morelle
revlog: group delta computation methods under _deltacomputer object...
r35756 flags, cachedelta=cachedelta,
deltacomputer=deltacomputer)
Jun Wu
revlog: move part of "addrevision" to "addrawrevision"...
r32240
def addrawrevision(self, rawtext, transaction, link, p1, p2, node, flags,
Paul Morelle
revlog: group delta computation methods under _deltacomputer object...
r35756 cachedelta=None, deltacomputer=None):
Jun Wu
revlog: move part of "addrevision" to "addrawrevision"...
r32240 """add a raw revision with known flags, node and parents
useful when reusing a revision not stored in this revlog (ex: received
over wire, or read from an external bundle).
"""
Matt Mackall
revlog: simplify addrevision...
r4981 dfh = None
Matt Mackall
revlog: change _inline from a function to a variable
r4982 if not self._inline:
Gregory Szorc
revlog: always open revlogs for reading and appending...
r26378 dfh = self.opener(self.datafile, "a+")
FUJIWARA Katsunori
revlog: specify checkambig at writing to avoid file stat ambiguity...
r29997 ifh = self.opener(self.indexfile, "a+", checkambig=self._checkambig)
Benoit Boissinot
revlog: make sure the files are closed after an exception happens...
r6261 try:
Jun Wu
revlog: rename some "text"s to "rawtext"...
r31750 return self._addrevision(node, rawtext, transaction, link, p1, p2,
Paul Morelle
revlog: group delta computation methods under _deltacomputer object...
r35756 flags, cachedelta, ifh, dfh,
deltacomputer=deltacomputer)
Benoit Boissinot
revlog: make sure the files are closed after an exception happens...
r6261 finally:
if dfh:
dfh.close()
ifh.close()
Alexis S. L. Carvalho
make revlog.addgroup pass its file handles to addrevision...
r3390
Gregory Szorc
revlog: use compression engine API for compression...
r30795 def compress(self, data):
"""Generate a possibly-compressed representation of data."""
if not data:
return '', data
compressed = self._compressor.compress(data)
if compressed:
# The revlog compressor added the header in the returned data.
return '', compressed
Yuya Nishihara
py3: fix slicing of byte string in revlog.compress()...
r31643 if data[0:1] == '\0':
Gregory Szorc
revlog: use compression engine API for compression...
r30795 return '', data
return 'u', data
Bryan O'Sullivan
revlog: make compress a method...
r17128
Gregory Szorc
revlog: move decompress() from module to revlog class (API)...
r30793 def decompress(self, data):
"""Decompress a revlog chunk.
The chunk is expected to begin with a header identifying the
format type so it can be routed to an appropriate decompressor.
"""
if not data:
return data
Gregory Szorc
revlog: use compression engine APIs for decompression...
r30817
# Revlogs are read much more frequently than they are written and many
# chunks only take microseconds to decompress, so performance is
# important here.
#
# We can make a few assumptions about revlogs:
#
# 1) the majority of chunks will be compressed (as opposed to inline
# raw data).
# 2) decompressing *any* data will likely by at least 10x slower than
# returning raw inline data.
# 3) we want to prioritize common and officially supported compression
# engines
#
# It follows that we want to optimize for "decompress compressed data
# when encoded with common and officially supported compression engines"
# case over "raw data" and "data encoded by less common or non-official
# compression engines." That is why we have the inline lookup first
# followed by the compengines lookup.
#
# According to `hg perfrevlogchunks`, this is ~0.5% faster for zlib
# compressed chunks. And this matters for changelog and manifest reads.
Augie Fackler
revlog: extract first byte of revlog with a slice so it's portable
r31356 t = data[0:1]
Gregory Szorc
revlog: use compression engine APIs for decompression...
r30817
Gregory Szorc
revlog: move decompress() from module to revlog class (API)...
r30793 if t == 'x':
try:
Gregory Szorc
revlog: use compression engine APIs for decompression...
r30817 return _zlibdecompress(data)
Gregory Szorc
revlog: move decompress() from module to revlog class (API)...
r30793 except zlib.error as e:
raise RevlogError(_('revlog decompress error: %s') % str(e))
Gregory Szorc
revlog: use compression engine APIs for decompression...
r30817 # '\0' is more common than 'u' so it goes first.
elif t == '\0':
return data
elif t == 'u':
Gregory Szorc
revlog: move decompress() from module to revlog class (API)...
r30793 return util.buffer(data, 1)
Gregory Szorc
revlog: use compression engine APIs for decompression...
r30817
try:
compressor = self._decompressors[t]
except KeyError:
try:
engine = util.compengines.forrevlogheader(t)
compressor = engine.revlogcompressor()
self._decompressors[t] = compressor
except KeyError:
raise RevlogError(_('unknown compression type %r') % t)
return compressor.decompress(data)
Gregory Szorc
revlog: move decompress() from module to revlog class (API)...
r30793
Paul Morelle
revlog: introduce 'deltainfo' to distinguish from 'delta'...
r35656 def _isgooddeltainfo(self, d, textlen):
Durham Goode
revlog: move delta check to it's own function...
r26115 """Returns True if the given delta is good. Good means that it is within
the disk span, disk size, and chain length bounds that we know to be
performant."""
if d is None:
return False
Paul Morelle
revlog: introduce 'deltainfo' to distinguish from 'delta'...
r35656 # - 'd.distance' is the distance from the base revision -- bounding it
# limits the amount of I/O we need to do.
# - 'd.compresseddeltalen' is the sum of the total size of deltas we
# need to apply -- bounding it limits the amount of CPU we consume.
revlog: add an experimental option to mitigated delta issues (issue5480)...
r33202
defaultmax = textlen * 4
maxdist = self._maxdeltachainspan
if not maxdist:
Paul Morelle
revlog: introduce 'deltainfo' to distinguish from 'delta'...
r35656 maxdist = d.distance # ensure the conditional pass
revlog: add an experimental option to mitigated delta issues (issue5480)...
r33202 maxdist = max(maxdist, defaultmax)
Paul Morelle
revlog: introduce 'deltainfo' to distinguish from 'delta'...
r35656 if (d.distance > maxdist or d.deltalen > textlen or
d.compresseddeltalen > textlen * 2 or
(self._maxchainlen and d.chainlen > self._maxchainlen)):
Durham Goode
revlog: move delta check to it's own function...
r26115 return False
return True
Jun Wu
revlog: make _addrevision only accept rawtext...
r31755 def _addrevision(self, node, rawtext, transaction, link, p1, p2, flags,
Paul Morelle
revlog: group delta computation methods under _deltacomputer object...
r35756 cachedelta, ifh, dfh, alwayscache=False,
deltacomputer=None):
Sune Foldager
revlog: add docstring to _addrevision
r14292 """internal function to add revisions to the log
Benoit Boissinot
revlog._addrevision(): allow text argument to be None, build it lazily
r12623
Sune Foldager
revlog: add docstring to _addrevision
r14292 see addrevision for argument descriptions.
Jun Wu
revlog: make _addrevision only accept rawtext...
r31755
note: "addrevision" takes non-raw text, "_addrevision" takes raw text.
Paul Morelle
revlog: group delta computation methods under _deltacomputer object...
r35756 if "deltacomputer" is not provided or None, a defaultdeltacomputer will
be used.
Sune Foldager
revlog: add docstring to _addrevision
r14292 invariants:
Jun Wu
revlog: make _addrevision only accept rawtext...
r31755 - rawtext is optional (can be None); if not set, cachedelta must be set.
Mads Kiilerich
fix trivial spelling errors
r17424 if both are set, they must correspond to each other.
Sune Foldager
revlog: add docstring to _addrevision
r14292 """
Martin von Zweigbergk
revlog: abort on attempt to write null revision...
r33939 if node == nullid:
raise RevlogError(_("%s: attempt to add null revision") %
(self.indexfile))
Martin von Zweigbergk
revlog: move check for wdir from changelog to revlog...
r34029 if node == wdirid:
raise RevlogError(_("%s: attempt to add wdir revision") %
(self.indexfile))
Paul Morelle
revlog: choose between ifh and dfh once for all
r35653 if self._inline:
fh = ifh
else:
fh = dfh
Jun Wu
revlog: make _addrevision only accept rawtext...
r31755 btext = [rawtext]
Benoit Boissinot
revlog._addrevision(): allow text argument to be None, build it lazily
r12623
Matt Mackall
add __len__ and __iter__ methods to repo and revlog
r6750 curr = len(self)
Matt Mackall
revlog: simplify addrevision...
r4981 prev = curr - 1
offset = self.end(prev)
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:
Durham Goode
revlog: move textlen calculation to be above delta chooser...
r26116 textlen = mdiff.patchedsize(self.rawsize(cachedelta[0]),
cachedelta[1])
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:
deltacomputer = _deltacomputer(self)
Paul Morelle
revlog: refactor out _finddeltainfo from _addrevision...
r35755 revinfo = _revisioninfo(node, p1, p2, btext, textlen, cachedelta, flags)
Paul Morelle
revlog: group delta computation methods under _deltacomputer object...
r35756 deltainfo = deltacomputer.finddeltainfo(revinfo, fh)
Paul Morelle
revlog: refactor out the selection of candidate revisions...
r35652
Paul Morelle
revlog: introduce 'deltainfo' to distinguish from 'delta'...
r35656 if deltainfo is not None:
base = deltainfo.base
chainbase = deltainfo.chainbase
data = deltainfo.data
l = deltainfo.deltalen
Martin von Zweigbergk
revlog: make calls to _isgooddelta() consistent...
r27250 else:
Paul Morelle
revlog: group delta computation methods under _deltacomputer object...
r35756 rawtext = deltacomputer.buildtext(revinfo, fh)
Jun Wu
revlog: make _addrevision only accept rawtext...
r31755 data = self.compress(rawtext)
mason@suse.com
Reduce string duplication in compression code...
r1533 l = len(data[1]) + len(data[0])
Sune Foldager
revlog: fix bug in chainbase cache...
r14296 base = chainbase = curr
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
Benoit Boissinot
revlog._addrevision(): allow text argument to be None, build it lazily
r12623 e = (offset_type(offset, flags), l, textlen,
Matt Mackall
revlog: precalculate p1 and p2 revisions
r12889 base, link, p1r, p2r, node)
Matt Mackall
revlog: add a magic null revision to our index...
r4979 self.index.insert(-1, e)
Matt Mackall
revlog: simplify addrevision...
r4981 self.nodemap[node] = curr
Matt Mackall
revlog: parse revlogv0 indexes into v1 internally...
r4977
Alexis S. L. Carvalho
revlog: fix revlogio.packentry corner case...
r5338 entry = self._io.packentry(e, self.node, self.version, curr)
Durham Goode
revlog: move file writing to a separate function...
r20217 self._writeentry(transaction, ifh, dfh, entry, data, link, offset)
Jun Wu
revlog: make _addrevision only accept rawtext...
r31755 if alwayscache and rawtext is None:
Paul Morelle
revlog: group delta computation methods under _deltacomputer object...
r35756 rawtext = deltacomputer._buildtext(revinfo, fh)
Gregory Szorc
revlog: optionally cache the full text when adding revisions...
r26243
Jun Wu
revlog: make _addrevision only accept rawtext...
r31755 if type(rawtext) == str: # only accept immutable objects
self._cache = (node, curr, rawtext)
Gregory Szorc
revlog: use an LRU cache for delta chain bases...
r29830 self._chainbasecache[curr] = chainbase
Durham Goode
revlog: move file writing to a separate function...
r20217 return node
def _writeentry(self, transaction, ifh, dfh, entry, data, link, offset):
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.
# Note: This is likely not necessary on Python 3.
ifh.seek(0, os.SEEK_END)
Martin von Zweigbergk
revlog: fix bad indentation (replace tab by space)
r27441 if dfh:
Gregory Szorc
revlog: seek to end of file before writing (issue4943)...
r27430 dfh.seek(0, os.SEEK_END)
Durham Goode
revlog: move file writing to a separate function...
r20217 curr = len(self) - 1
Matt Mackall
revlog: change _inline from a function to a variable
r4982 if not self._inline:
mason@suse.com
Implement data inlined with the index file...
r2073 transaction.add(self.datafile, offset)
Matt Mackall
revlog: simplify addrevision...
r4981 transaction.add(self.indexfile, curr * len(entry))
mason@suse.com
Implement data inlined with the index file...
r2073 if data[0]:
Alexis S. L. Carvalho
make revlog.addgroup pass its file handles to addrevision...
r3390 dfh.write(data[0])
dfh.write(data[1])
Matt Mackall
revlog: simplify addrevision...
r4981 ifh.write(entry)
mason@suse.com
Implement data inlined with the index file...
r2073 else:
Matt Mackall
revlog: avoid some unnecessary seek/tell syscalls
r4996 offset += curr * self._io.size
Patrick Mezard
revlog: fix inlined revision transaction extra data (issue 749)
r5324 transaction.add(self.indexfile, offset, curr)
Matt Mackall
revlog: simplify addrevision...
r4981 ifh.write(entry)
Alexis S. L. Carvalho
make revlog.addgroup pass its file handles to addrevision...
r3390 ifh.write(data[0])
ifh.write(data[1])
self.checkinlinesize(transaction, ifh)
mason@suse.com
Implement data inlined with the index file...
r2073
Durham Goode
revlog: add revmap back to revlog.addgroup...
r34292 def addgroup(self, deltas, linkmapper, transaction, addrevisioncb=None):
mpm@selenic.com
Add some docstrings to revlog.py
r1083 """
add a delta group
mpm@selenic.com
Add changegroup support
r46
mpm@selenic.com
Add some docstrings to revlog.py
r1083 given a set of deltas, add them to the revision log. the
first delta is against its parent, which should be in our
log, the rest are against the previous delta.
Gregory Szorc
revlog: add support for a callback whenever revisions are added...
r25822
If ``addrevisioncb`` is defined, it will be called with arguments of
this revlog and the node that was added.
mpm@selenic.com
Add some docstrings to revlog.py
r1083 """
Martin von Zweigbergk
revlog: rename list of nodes from "content" to "nodes"...
r32868 nodes = []
mpm@selenic.com
Whitespace cleanups...
r515
Benoit Boissinot
revlog.addgroup(): always use _addrevision() to add new revlog entries...
r12624 r = len(self)
end = 0
mpm@selenic.com
Add changegroup support
r46 if r:
Benoit Boissinot
revlog.addgroup(): always use _addrevision() to add new revlog entries...
r12624 end = self.end(r - 1)
FUJIWARA Katsunori
revlog: specify checkambig at writing to avoid file stat ambiguity...
r29997 ifh = self.opener(self.indexfile, "a+", checkambig=self._checkambig)
Matt Mackall
revlog: avoid some unnecessary seek/tell syscalls
r4996 isize = r * self._io.size
Matt Mackall
revlog: change _inline from a function to a variable
r4982 if self._inline:
Matt Mackall
revlog: avoid some unnecessary seek/tell syscalls
r4996 transaction.add(self.indexfile, end + isize, r)
mason@suse.com
Implement data inlined with the index file...
r2073 dfh = None
else:
Matt Mackall
revlog: avoid some unnecessary seek/tell syscalls
r4996 transaction.add(self.indexfile, isize, r)
mason@suse.com
Implement data inlined with the index file...
r2073 transaction.add(self.datafile, end)
Gregory Szorc
revlog: always open revlogs for reading and appending...
r26378 dfh = self.opener(self.datafile, "a+")
Mike Edgar
revlog: addgroup checks if incoming deltas add censored revs, sets flag bit...
r24255 def flush():
if dfh:
dfh.flush()
ifh.flush()
Benoit Boissinot
revlog: make sure the files are closed after an exception happens...
r6261 try:
Paul Morelle
revlog: group delta computation methods under _deltacomputer object...
r35756 deltacomputer = _deltacomputer(self)
Benoit Boissinot
revlog: make sure the files are closed after an exception happens...
r6261 # loop through our set of deltas
Durham Goode
changegroup: remove changegroup dependency from revlog.addgroup...
r34147 for data in deltas:
Durham Goode
revlog: add revmap back to revlog.addgroup...
r34292 node, p1, p2, linknode, deltabase, delta, flags = data
link = linkmapper(linknode)
Durham Goode
changegroup: remove changegroup dependency from revlog.addgroup...
r34147 flags = flags or REVIDX_DEFAULT_FLAGS
Matt Mackall
bundle: move chunk parsing into unbundle class
r12336
Martin von Zweigbergk
revlog: rename list of nodes from "content" to "nodes"...
r32868 nodes.append(node)
Pierre-Yves David
revlog: make addgroup returns a list of node contained in the added source...
r15890
Sune Foldager
revlog: remove support for punched/shallow...
r14196 if node in self.nodemap:
Benoit Boissinot
revlog: make sure the files are closed after an exception happens...
r6261 # this can happen if two branches make the same change
continue
mpm@selenic.com
Changes to network protocol...
r192
Benoit Boissinot
revlog: make sure the files are closed after an exception happens...
r6261 for p in (p1, p2):
Brodie Rao
cleanup: "not x in y" -> "x not in y"
r16686 if p not in self.nodemap:
Sune Foldager
revlog: remove support for punched/shallow...
r14196 raise LookupError(p, self.indexfile,
_('unknown parent'))
mpm@selenic.com
Add changegroup support
r46
Benoit Boissinot
bundler: make parsechunk return the base revision of the delta
r14141 if deltabase not in self.nodemap:
raise LookupError(deltabase, self.indexfile,
_('unknown delta base'))
mpm@selenic.com
Add changegroup support
r46
Benoit Boissinot
bundler: make parsechunk return the base revision of the delta
r14141 baserev = self.rev(deltabase)
Mike Edgar
revlog: in addgroup, reject ill-formed deltas based on censored nodes...
r24120
if baserev != nullrev and self.iscensored(baserev):
# if base is censored, delta must be full replacement in a
# single patch operation
hlen = struct.calcsize(">lll")
oldlen = self.rawsize(baserev)
newlen = len(delta) - hlen
if delta[:hlen] != mdiff.replacediffheader(oldlen, newlen):
raise error.CensoredBaseError(self.indexfile,
self.node(baserev))
Mike Edgar
changegroup: add flags field to cg3 delta header...
r27433 if not flags and self._peek_iscensored(baserev, delta, flush):
Mike Edgar
revlog: addgroup checks if incoming deltas add censored revs, sets flag bit...
r24255 flags |= REVIDX_ISCENSORED
Gregory Szorc
revlog: optionally cache the full text when adding revisions...
r26243 # We assume consumers of addrevisioncb will want to retrieve
# the added revision, which will require a call to
# revision(). revision() will fast path if there is a cache
# hit. So, we tell _addrevision() to always cache in this case.
Remi Chaintron
revlog: add 'raw' argument to revision and _addrevision...
r30743 # We're only using addgroup() in the context of changegroup
# generation so the revision data can always be handled as raw
# by the flagprocessor.
Durham Goode
revlog: refactor chain variable...
r34146 self._addrevision(node, None, transaction, link,
p1, p2, flags, (baserev, delta),
ifh, dfh,
Paul Morelle
revlog: group delta computation methods under _deltacomputer object...
r35756 alwayscache=bool(addrevisioncb),
deltacomputer=deltacomputer)
Gregory Szorc
revlog: add support for a callback whenever revisions are added...
r25822
if addrevisioncb:
Durham Goode
revlog: refactor chain variable...
r34146 addrevisioncb(self, node)
Gregory Szorc
revlog: add support for a callback whenever revisions are added...
r25822
Benoit Boissinot
revlog.addgroup(): always use _addrevision() to add new revlog entries...
r12624 if not dfh and not self._inline:
# addrevision switched from inline to conventional
# reopen the index
Dan Villiom Podlaski Christiansen
explicitly close files...
r13400 ifh.close()
Gregory Szorc
revlog: always open revlogs for reading and appending...
r26378 dfh = self.opener(self.datafile, "a+")
FUJIWARA Katsunori
revlog: specify checkambig at writing to avoid file stat ambiguity...
r29997 ifh = self.opener(self.indexfile, "a+",
checkambig=self._checkambig)
Benoit Boissinot
revlog: make sure the files are closed after an exception happens...
r6261 finally:
if dfh:
dfh.close()
ifh.close()
mpm@selenic.com
Add changegroup support
r46
Martin von Zweigbergk
revlog: rename list of nodes from "content" to "nodes"...
r32868 return nodes
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."""
return False
Mike Edgar
revlog: addgroup checks if incoming deltas add censored revs, sets flag bit...
r24255 def _peek_iscensored(self, baserev, delta, flush):
"""Quickly check if a delta produces a censored revision."""
return False
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.
"""
brokenrevs = set()
strippoint = len(self)
heads = {}
futurelargelinkrevs = set()
for head in self.headrevs():
headlinkrev = self.linkrev(head)
heads[head] = headlinkrev
if headlinkrev >= minlink:
futurelargelinkrevs.add(headlinkrev)
# This algorithm involves walking down the rev graph, starting at the
# heads. Since the revs are topologically sorted according to linkrev,
# once all head linkrevs are below the minlink, we know there are
# no more revs that could have a linkrev greater than minlink.
# So we can stop walking.
while futurelargelinkrevs:
strippoint -= 1
linkrev = heads.pop(strippoint)
if linkrev < minlink:
brokenrevs.add(strippoint)
else:
futurelargelinkrevs.remove(linkrev)
for p in self.parentrevs(strippoint):
if p != nullrev:
plinkrev = self.linkrev(p)
heads[p] = plinkrev
if plinkrev >= minlink:
futurelargelinkrevs.add(plinkrev)
return strippoint, brokenrevs
Henrik Stuart
strip: make repair.strip transactional to avoid repository corruption...
r8073 def strip(self, minlink, transaction):
Alexis S. L. Carvalho
simplify revlog.strip interface and callers; add docstring...
r5910 """truncate the revlog on the first revision with a linkrev >= minlink
This function is called when we're stripping revision minlink and
its descendants from the repository.
We have to remove all revisions with linkrev >= minlink, because
the equivalent changelog revisions will be renumbered after the
strip.
So we truncate the revlog on the first of these revisions, and
trust that the caller has saved the revisions that shouldn't be
Steven Brown
revlog: clarify strip docstring "readd" -> "re-add"...
r15827 removed and that it'll re-add them after this truncation.
Alexis S. L. Carvalho
simplify revlog.strip interface and callers; add docstring...
r5910 """
Matt Mackall
add __len__ and __iter__ methods to repo and revlog
r6750 if len(self) == 0:
mason@suse.com
Add revlog.strip to truncate away revisions....
r1535 return
Durham Goode
strip: add faster revlog strip computation...
r20074 rev, _ = self.getstrippoint(minlink)
if rev == len(self):
Alexis S. L. Carvalho
strip: calculate list of extra nodes to save and pass it to changegroupsubset...
r5909 return
mason@suse.com
Add revlog.strip to truncate away revisions....
r1535
# first truncate the files on disk
end = self.start(rev)
Matt Mackall
revlog: change _inline from a function to a variable
r4982 if not self._inline:
Henrik Stuart
strip: make repair.strip transactional to avoid repository corruption...
r8073 transaction.add(self.datafile, end)
Matt Mackall
revlog: parse revlogv0 indexes into v1 internally...
r4977 end = rev * self._io.size
mason@suse.com
Implement data inlined with the index file...
r2073 else:
Matt Mackall
revlog: parse revlogv0 indexes into v1 internally...
r4977 end += rev * self._io.size
mason@suse.com
Implement revlogng....
r2072
Henrik Stuart
strip: make repair.strip transactional to avoid repository corruption...
r8073 transaction.add(self.indexfile, end)
mason@suse.com
Add revlog.strip to truncate away revisions....
r1535
# then reset internal state in memory to forget those revisions
Matt Mackall
revlog: mark cache private
r4984 self._cache = None
Siddharth Agarwal
revlog: cache chain info after calculating it for a rev (issue4452)...
r23306 self._chaininfocache = {}
Matt Mackall
revlog: refactor chunk cache interface again...
r8650 self._chunkclear()
Matt Mackall
add __len__ and __iter__ methods to repo and revlog
r6750 for x in xrange(rev, len(self)):
mason@suse.com
Implement revlogng....
r2072 del self.nodemap[self.node(x)]
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):
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:
f = self.opener(self.datafile)
f.seek(0, 2)
actual = f.tell()
Dan Villiom Podlaski Christiansen
explicitly close files...
r13400 f.close()
Matt Mackall
verify: notice extra data in indices
r1667 dd = actual - expected
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except IOError as inst:
Matt Mackall
verify: notice extra data in indices
r1667 if inst.errno != errno.ENOENT:
raise
dd = 0
try:
f = self.opener(self.indexfile)
f.seek(0, 2)
actual = f.tell()
Dan Villiom Podlaski Christiansen
explicitly close files...
r13400 f.close()
Matt Mackall
revlog: parse revlogv0 indexes into v1 internally...
r4977 s = self._io.size
Alejandro Santos
compat: use // for integer division
r9029 i = max(0, actual // s)
Matt Mackall
verify: notice extra data in indices
r1667 di = actual - (i * s)
Matt Mackall
revlog: change _inline from a function to a variable
r4982 if self._inline:
mason@suse.com
Implement data inlined with the index file...
r2073 databytes = 0
Matt Mackall
add __len__ and __iter__ methods to repo and revlog
r6750 for r in self:
Matt Mackall
revlog: more robust for damaged indexes...
r5312 databytes += max(0, self.length(r))
mason@suse.com
Implement data inlined with the index file...
r2073 dd = 0
Matt Mackall
add __len__ and __iter__ methods to repo and revlog
r6750 di = actual - len(self) * s - databytes
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except IOError as inst:
Matt Mackall
verify: notice extra data in indices
r1667 if inst.errno != errno.ENOENT:
raise
di = 0
return (dd, di)
Adrian Buehlmann
revlog: add files method
r6891
def files(self):
Matt Mackall
many, many trivial check-code fixups
r10282 res = [self.indexfile]
Adrian Buehlmann
revlog: add files method
r6891 if not self._inline:
res.append(self.datafile)
return res
Gregory Szorc
revlog: add clone method...
r30778
DELTAREUSEALWAYS = 'always'
DELTAREUSESAMEREVS = 'samerevs'
DELTAREUSENEVER = 'never'
Boris Feld
upgrade: add a 'redeltafullall' mode...
r35346 DELTAREUSEFULLADD = 'fulladd'
DELTAREUSEALL = {'always', 'samerevs', 'never', 'fulladd'}
Gregory Szorc
revlog: add clone method...
r30778
def clone(self, tr, destrevlog, addrevisioncb=None,
deltareuse=DELTAREUSESAMEREVS, aggressivemergedeltas=None):
"""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).
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.
In addition to the delta policy, the ``aggressivemergedeltas`` argument
controls whether to compute deltas against both parents for merges.
By default, the current default is used.
"""
if deltareuse not in self.DELTAREUSEALL:
raise ValueError(_('value for deltareuse invalid: %s') % deltareuse)
if len(destrevlog):
raise ValueError(_('destination revlog is not empty'))
if getattr(self, 'filteredrevs', None):
raise ValueError(_('source revlog has filtered revisions'))
if getattr(destrevlog, 'filteredrevs', None):
raise ValueError(_('destination revlog has filtered revisions'))
# lazydeltabase controls whether to reuse a cached delta, if possible.
oldlazydeltabase = destrevlog._lazydeltabase
oldamd = destrevlog._aggressivemergedeltas
try:
if deltareuse == self.DELTAREUSEALWAYS:
destrevlog._lazydeltabase = True
elif deltareuse == self.DELTAREUSESAMEREVS:
destrevlog._lazydeltabase = False
destrevlog._aggressivemergedeltas = aggressivemergedeltas or oldamd
populatecachedelta = deltareuse in (self.DELTAREUSEALWAYS,
self.DELTAREUSESAMEREVS)
Paul Morelle
revlog: group delta computation methods under _deltacomputer object...
r35756 deltacomputer = _deltacomputer(destrevlog)
Gregory Szorc
revlog: add clone method...
r30778 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.
flags = entry[0] & 0xffff
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
Jun Wu
revlog: use raw revisions in clone...
r31754 rawtext = None
Gregory Szorc
revlog: add clone method...
r30778 if populatecachedelta:
dp = self.deltaparent(rev)
if dp != nullrev:
cachedelta = (dp, str(self._chunk(rev)))
if not cachedelta:
Jun Wu
revlog: use raw revisions in clone...
r31754 rawtext = self.revision(rev, raw=True)
Gregory Szorc
revlog: add clone method...
r30778
Boris Feld
upgrade: add a 'redeltafullall' mode...
r35346
if deltareuse == self.DELTAREUSEFULLADD:
destrevlog.addrevision(rawtext, tr, linkrev, p1, p2,
cachedelta=cachedelta,
Paul Morelle
revlog: group delta computation methods under _deltacomputer object...
r35756 node=node, flags=flags,
deltacomputer=deltacomputer)
Boris Feld
upgrade: add a 'redeltafullall' mode...
r35346 else:
ifh = destrevlog.opener(destrevlog.indexfile, 'a+',
checkambig=False)
dfh = None
if not destrevlog._inline:
dfh = destrevlog.opener(destrevlog.datafile, 'a+')
try:
destrevlog._addrevision(node, rawtext, tr, linkrev, p1,
Paul Morelle
revlog: group delta computation methods under _deltacomputer object...
r35756 p2, flags, cachedelta, ifh, dfh,
deltacomputer=deltacomputer)
Boris Feld
upgrade: add a 'redeltafullall' mode...
r35346 finally:
if dfh:
dfh.close()
ifh.close()
Gregory Szorc
revlog: add clone method...
r30778
if addrevisioncb:
addrevisioncb(self, rev, node)
finally:
destrevlog._lazydeltabase = oldlazydeltabase
destrevlog._aggressivemergedeltas = oldamd