##// END OF EJS Templates
revlog: introduce an explicit tracking of what the revlog is about...
revlog: introduce an explicit tracking of what the revlog is about Since the dawn of time, people have been forced to rely to lossy introspection of the index filename to determine what the purpose and role of the revlog they encounter is. This is hacky, error prone, inflexible, abstraction-leaky, <insert-your-own-complaints-here>. In f63299ee7e4d Raphaël introduced a new attribute to track this information: `revlog_kind`. However it is initialized in an odd place and various instances end up not having it set. In addition is only tracking some of the information we end up having to introspect in various pieces of code. So we add a new attribute that holds more data and is more strictly enforced. This work is done in collaboration with Raphaël. The `revlog_kind` one will be removed/adapted in the next changeset. We expect to be able to clean up various existing piece of code and to simplify coming work around the newer revlog format. Differential Revision: https://phab.mercurial-scm.org/D10352

File last commit:

r47838:4c041c71 default
r47838:4c041c71 default
Show More
filelog.py
299 lines | 8.7 KiB | text/x-python | PythonLexer
mpm@selenic.com
Break apart hg.py...
r1089 # filelog.py - file history class for mercurial
#
Raphaël Gomès
contributor: change mentions of mpm to olivia...
r47575 # Copyright 2005-2007 Olivia Mackall <olivia@selenic.com>
mpm@selenic.com
Break apart hg.py...
r1089 #
Martin Geisler
updated license to be explicit about GPL version 2
r8225 # 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
Break apart hg.py...
r1089
Gregory Szorc
filelog: use absolute_import
r25948 from __future__ import absolute_import
Gregory Szorc
repository: teach addgroup() to receive data with missing parents...
r40425 from .i18n import _
Joerg Sonnenberger
node: replace nullid and friends with nodeconstants class...
r47771 from .node import nullrev
Gregory Szorc
filelog: use absolute_import
r25948 from . import (
Gregory Szorc
filelog: wrap revlog instead of inheriting it (API)...
r37515 error,
Pulkit Goyal
interfaces: create a new folder for interfaces and move repository.py in it...
r43078 revlog,
)
from .interfaces import (
Gregory Szorc
filelog: declare that filelog implements a storage interface...
r37459 repository,
Pulkit Goyal
interfaceutil: move to interfaces/...
r43079 util as interfaceutil,
Gregory Szorc
filelog: use absolute_import
r25948 )
Augie Fackler
formatting: blacken the codebase...
r43346 from .utils import storageutil
revlog: introduce an explicit tracking of what the revlog is about...
r47838 from .revlogutils import (
constants as revlog_constants,
)
Augie Fackler
formatting: blacken the codebase...
r43346
mpm@selenic.com
Break apart hg.py...
r1089
Gregory Szorc
interfaceutil: module to stub out zope.interface...
r37828 @interfaceutil.implementer(repository.ifilestorage)
Gregory Szorc
filelog: wrap revlog instead of inheriting it (API)...
r37515 class filelog(object):
Matt Mackall
revlog: simplify revlog version handling...
r4258 def __init__(self, opener, path):
Augie Fackler
formatting: blacken the codebase...
r43346 self._revlog = revlog.revlog(
revlog: introduce an explicit tracking of what the revlog is about...
r47838 opener,
# XXX should use the unencoded path
target=(revlog_constants.KIND_FILELOG, path),
indexfile=b'/'.join((b'data', path + b'.i')),
censorable=True,
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
filelog: record what's using attributes...
r39819 # Full name of the user visible file, relative to the repository root.
# Used by LFS.
Gregory Szorc
filelog: store filename directly on revlog instance...
r39892 self._revlog.filename = path
Raphaël Gomès
revlog: add attribute on revlogs that specifies its kind...
r47448 self._revlog.revlog_kind = b'filelog'
Joerg Sonnenberger
node: introduce nodeconstants class...
r47538 self.nullid = self._revlog.nullid
Gregory Szorc
filelog: wrap revlog instead of inheriting it (API)...
r37515
def __len__(self):
return len(self._revlog)
def __iter__(self):
return self._revlog.__iter__()
Gregory Szorc
filelog: add a hasnode() method (API)...
r40423 def hasnode(self, node):
Joerg Sonnenberger
node: replace nullid and friends with nodeconstants class...
r47771 if node in (self.nullid, nullrev):
Gregory Szorc
filelog: add a hasnode() method (API)...
r40423 return False
try:
self._revlog.rev(node)
return True
except (TypeError, ValueError, IndexError, error.LookupError):
return False
Gregory Szorc
filelog: wrap revlog instead of inheriting it (API)...
r37515 def revs(self, start=0, stop=None):
return self._revlog.revs(start=start, stop=stop)
def parents(self, node):
return self._revlog.parents(node)
def parentrevs(self, rev):
return self._revlog.parentrevs(rev)
def rev(self, node):
return self._revlog.rev(node)
def node(self, rev):
return self._revlog.node(rev)
def lookup(self, node):
Augie Fackler
formatting: blacken the codebase...
r43346 return storageutil.fileidlookup(
self._revlog, node, self._revlog.indexfile
)
Gregory Szorc
filelog: wrap revlog instead of inheriting it (API)...
r37515
def linkrev(self, rev):
return self._revlog.linkrev(rev)
def commonancestorsheads(self, node1, node2):
return self._revlog.commonancestorsheads(node1, node2)
Gregory Szorc
filelog: record what's using attributes...
r39819 # Used by dagop.blockdescendants().
Gregory Szorc
filelog: wrap revlog instead of inheriting it (API)...
r37515 def descendants(self, revs):
return self._revlog.descendants(revs)
def heads(self, start=None, stop=None):
return self._revlog.heads(start, stop)
Gregory Szorc
filelog: record what's using attributes...
r39819 # Used by hgweb, children extension.
Gregory Szorc
filelog: wrap revlog instead of inheriting it (API)...
r37515 def children(self, node):
return self._revlog.children(node)
def iscensored(self, rev):
return self._revlog.iscensored(rev)
def revision(self, node, _df=None, raw=False):
return self._revlog.revision(node, _df=_df, raw=raw)
rawdata: forward the method call on `filelog` object...
r42946 def rawdata(self, node, _df=None):
return self._revlog.rawdata(node, _df=_df)
Augie Fackler
formatting: blacken the codebase...
r43346 def emitrevisions(
self,
nodes,
nodesorder=None,
revisiondata=False,
assumehaveparentrevisions=False,
deltamode=repository.CG_DELTAMODE_STD,
Raphaël Gomès
changegroupv4: add sidedata helpers...
r47449 sidedata_helpers=None,
Augie Fackler
formatting: blacken the codebase...
r43346 ):
Gregory Szorc
revlog: new API to emit revision data...
r39898 return self._revlog.emitrevisions(
Augie Fackler
formatting: blacken the codebase...
r43346 nodes,
nodesorder=nodesorder,
revisiondata=revisiondata,
Gregory Szorc
revlog: new API to emit revision data...
r39898 assumehaveparentrevisions=assumehaveparentrevisions,
Augie Fackler
formatting: blacken the codebase...
r43346 deltamode=deltamode,
Raphaël Gomès
changegroupv4: add sidedata helpers...
r47449 sidedata_helpers=sidedata_helpers,
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
revlog: new API to emit revision data...
r39898
Augie Fackler
formatting: blacken the codebase...
r43346 def addrevision(
self,
revisiondata,
transaction,
linkrev,
p1,
p2,
node=None,
flags=revlog.REVIDX_DEFAULT_FLAGS,
cachedelta=None,
):
return self._revlog.addrevision(
revisiondata,
transaction,
linkrev,
p1,
p2,
node=node,
flags=flags,
cachedelta=cachedelta,
)
Gregory Szorc
filelog: wrap revlog instead of inheriting it (API)...
r37515
Augie Fackler
formatting: blacken the codebase...
r43346 def addgroup(
self,
deltas,
linkmapper,
transaction,
addrevisioncb=None,
Joerg Sonnenberger
revlog: extend addgroup() with callback for duplicates...
r46373 duplicaterevisioncb=None,
Augie Fackler
formatting: blacken the codebase...
r43346 maybemissingparents=False,
):
Gregory Szorc
repository: teach addgroup() to receive data with missing parents...
r40425 if maybemissingparents:
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.Abort(
_(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'revlog storage does not support missing '
b'parents write mode'
Augie Fackler
formatting: blacken the codebase...
r43346 )
)
Gregory Szorc
repository: teach addgroup() to receive data with missing parents...
r40425
Augie Fackler
formatting: blacken the codebase...
r43346 return self._revlog.addgroup(
Joerg Sonnenberger
revlog: extend addgroup() with callback for duplicates...
r46373 deltas,
linkmapper,
transaction,
addrevisioncb=addrevisioncb,
duplicaterevisioncb=duplicaterevisioncb,
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
filelog: wrap revlog instead of inheriting it (API)...
r37515
def getstrippoint(self, minlink):
return self._revlog.getstrippoint(minlink)
def strip(self, minlink, transaction):
return self._revlog.strip(minlink, transaction)
Gregory Szorc
revlog: move censor logic out of censor extension...
r39814 def censorrevision(self, tr, node, tombstone=b''):
Gregory Szorc
revlog: rewrite censoring logic...
r40092 return self._revlog.censorrevision(tr, node, tombstone=tombstone)
Gregory Szorc
revlog: move censor logic out of censor extension...
r39814
Gregory Szorc
filelog: wrap revlog instead of inheriting it (API)...
r37515 def files(self):
return self._revlog.files()
mpm@selenic.com
Break apart hg.py...
r1089 def read(self, node):
Gregory Szorc
storageutil: new function for extracting metadata-less content from text...
r39916 return storageutil.filtermetadata(self.revision(node))
mpm@selenic.com
Break apart hg.py...
r1089
def add(self, text, meta, transaction, link, p1=None, p2=None):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if meta or text.startswith(b'\1\n'):
Gregory Szorc
storageutil: move metadata parsing and packing from revlog (API)...
r39914 text = storageutil.packmeta(meta, text)
Joerg Sonnenberger
revlog: change addrevision to return the new revision, not node...
r47258 rev = self.addrevision(text, transaction, link, p1, p2)
return self.node(rev)
mpm@selenic.com
Break apart hg.py...
r1089
mpm@selenic.com
Add some rename debugging support
r1116 def renamed(self, node):
Gregory Szorc
storageutil: extract copy metadata retrieval out of filelog...
r40041 return storageutil.filerevisioncopied(self, node)
mpm@selenic.com
Add some rename debugging support
r1116
Matt Mackall
merge: use file size stored in revlog index...
r2898 def size(self, rev):
"""return the size of a given revision"""
# for revisions with renames, we have to go the slow way
node = self.node(rev)
if self.renamed(node):
return len(self.read(node))
Mike Edgar
revlog: add "iscensored()" to revlog public API...
r24118 if self.iscensored(rev):
Mike Edgar
filelog: censored files compare against empty data, have 0 size...
r22597 return 0
Matt Mackall
merge: use file size stored in revlog index...
r2898
Nicolas Dumazet
filelog: test behaviour for data starting with "\1\n"...
r11540 # XXX if self.read(node).startswith("\1\n"), this returns (size+4)
Gregory Szorc
filelog: wrap revlog instead of inheriting it (API)...
r37515 return self._revlog.size(rev)
Matt Mackall
merge: use file size stored in revlog index...
r2898
Matt Mackall
filelog: add hash-based comparisons...
r2887 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.
"""
Gregory Szorc
storageutil: invert logic of file data comparison...
r40043 return not storageutil.filedataequivalent(self, node, text)
Gregory Szorc
filelog: wrap revlog instead of inheriting it (API)...
r37515
Gregory Szorc
verify: start to abstract file verification...
r39878 def verifyintegrity(self, state):
return self._revlog.verifyintegrity(state)
Augie Fackler
formatting: blacken the codebase...
r43346 def storageinfo(
self,
exclusivefiles=False,
sharedfiles=False,
revisionscount=False,
trackedsize=False,
storedsize=False,
):
Gregory Szorc
revlog: add method for obtaining storage info (API)...
r39905 return self._revlog.storageinfo(
Augie Fackler
formatting: blacken the codebase...
r43346 exclusivefiles=exclusivefiles,
sharedfiles=sharedfiles,
revisionscount=revisionscount,
trackedsize=trackedsize,
storedsize=storedsize,
)
Gregory Szorc
revlog: add method for obtaining storage info (API)...
r39905
Gregory Szorc
filelog: record what's using attributes...
r39819 # TODO these aren't part of the interface and aren't internal methods.
# Callers should be fixed to not use them.
# Used by bundlefilelog, unionfilelog.
Gregory Szorc
filelog: wrap revlog instead of inheriting it (API)...
r37515 @property
def indexfile(self):
return self._revlog.indexfile
@indexfile.setter
def indexfile(self, value):
self._revlog.indexfile = value
Gregory Szorc
filelog: record what's using attributes...
r39819 # Used by repo upgrade.
Gregory Szorc
filelog: wrap revlog instead of inheriting it (API)...
r37515 def clone(self, tr, destrevlog, **kwargs):
if not isinstance(destrevlog, filelog):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.ProgrammingError(b'expected filelog to clone()')
Gregory Szorc
filelog: wrap revlog instead of inheriting it (API)...
r37515
return self._revlog.clone(tr, destrevlog._revlog, **kwargs)
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
filelog: custom filelog to be used with narrow repos...
r39801 class narrowfilelog(filelog):
"""Filelog variation to be used with narrow stores."""
def __init__(self, opener, path, narrowmatch):
super(narrowfilelog, self).__init__(opener, path)
self._narrowmatch = narrowmatch
def renamed(self, node):
res = super(narrowfilelog, self).renamed(node)
# Renames that come from outside the narrowspec are problematic
# because we may lack the base text for the rename. This can result
# in code attempting to walk the ancestry or compute a diff
# encountering a missing revision. We address this by silently
# removing rename metadata if the source file is outside the
# narrow spec.
#
# A better solution would be to see if the base revision is available,
# rather than assuming it isn't.
#
# An even better solution would be to teach all consumers of rename
# metadata that the base revision may not be available.
#
# TODO consider better ways of doing this.
if res and not self._narrowmatch(res[0]):
return None
return res
def size(self, rev):
# Because we have a custom renamed() that may lie, we need to call
# the base renamed() to report accurate results.
node = self.node(rev)
if super(narrowfilelog, self).renamed(node):
return len(self.read(node))
else:
return super(narrowfilelog, self).size(rev)
def cmp(self, node, text):
Raphaël Gomès
narrow: fix flaky behavior described in issue6150...
r47280 # We don't call `super` because narrow parents can be buggy in case of a
# ambiguous dirstate. Always take the slow path until there is a better
# fix, see issue6150.
Gregory Szorc
filelog: custom filelog to be used with narrow repos...
r39801
Raphaël Gomès
narrow: fix flaky behavior described in issue6150...
r47280 # Censored files compare against the empty file.
if self.iscensored(self.rev(node)):
return text != b''
Gregory Szorc
filelog: custom filelog to be used with narrow repos...
r39801
Raphaël Gomès
narrow: fix flaky behavior described in issue6150...
r47280 return self.read(node) != text