##// END OF EJS Templates
pytype: import typing directly...
pytype: import typing directly First we no longer needs the pycompat layer, second having the types imported in all case will allow to use them more directly in type annotation, something important to upgrade the old "type comment" to proper type annotation. A lot a stupid assert are needed to keep pyflakes happy. We should be able to remove most of them once the type comment have been upgraded.

File last commit:

r52178:9d372155 default
r52178:9d372155 default
Show More
branchmap.py
883 lines | 31.4 KiB | text/x-python | PythonLexer
Pierre-Yves David
branchmap: create a mercurial.branchmap module...
r18116 # branchmap.py - logic to computes, maintain and stores branchmap for local repo
#
Raphaël Gomès
contributor: change mentions of mpm to olivia...
r47575 # Copyright 2005-2007 Olivia Mackall <olivia@selenic.com>
Pierre-Yves David
branchmap: create a mercurial.branchmap module...
r18116 #
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
Pierre-Yves David
branchmap: extract write logic from localrepo
r18117
Gregory Szorc
branchmap: use absolute_import
r25918
import struct
from .node import (
bin,
hex,
nullrev,
)
pytype: import typing directly...
r52178
from typing import (
Any,
Callable,
Dict,
Iterable,
List,
Optional,
Set,
TYPE_CHECKING,
Tuple,
Union,
)
Gregory Szorc
branchmap: use absolute_import
r25918 from . import (
encoding,
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 error,
av6
branchmap: skip obsolete revisions while computing heads...
r49536 obsolete,
Gregory Szorc
branchmap: use absolute_import
r25918 scmutil,
Simon Farnsworth
mercurial: switch to util.timer for all interval timings...
r30975 util,
Gregory Szorc
branchmap: use absolute_import
r25918 )
pytype: import typing directly...
r52178
Yuya Nishihara
stringutil: bulk-replace call sites to point to new module...
r37102 from .utils import (
repoview: move subsettable in a dedicated module...
r42314 repoviewutil,
Yuya Nishihara
stringutil: bulk-replace call sites to point to new module...
r37102 stringutil,
)
Gregory Szorc
branchmap: use absolute_import
r25918
pytype: import typing directly...
r52178 # keeps pyflakes happy
assert [
Any,
Callable,
Dict,
Iterable,
List,
Optional,
Set,
Tuple,
Union,
]
if TYPE_CHECKING:
Matt Harbison
merge with stable
r47552 from . import localrepo
Augie Fackler
branchmap: annotate constructor type for branchcache...
r44035
pytype: import typing directly...
r52178 assert [localrepo]
Augie Fackler
branchmap: annotate constructor type for branchcache...
r44035
Augie Fackler
formatting: blacken the codebase...
r43346 subsettable = repoviewutil.subsettable
repoview: move subsettable in a dedicated module...
r42314
Gregory Szorc
branchmap: use absolute_import
r25918 calcsize = struct.calcsize
Mads Kiilerich
rbc: use struct unpack_from and pack_into instead of unpack and pack...
r31370 pack_into = struct.pack_into
unpack_from = struct.unpack_from
Pierre-Yves David
branchmap: extract write logic from localrepo
r18117
Pierre-Yves David
branchmap: extract read logic from repo
r18118
Gregory Szorc
py3: use class X: instead of class X(object):...
r49801 class BranchMapCache:
Pulkit Goyal
branchmap: improve doc about BranchMapCache class...
r41867 """mapping of filtered views of repo with their branchcache"""
Augie Fackler
formatting: blacken the codebase...
r43346
Martijn Pieters
branchmap: encapsulate cache updating in the map itself...
r41764 def __init__(self):
self._per_filter = {}
Martijn Pieters
branchmap: add some clarifications and clean up flow...
r41708
Martijn Pieters
branchmap: encapsulate cache updating in the map itself...
r41764 def __getitem__(self, repo):
self.updatecache(repo)
return self._per_filter[repo.filtername]
def updatecache(self, repo):
"""Update the cache for the given filtered view on a repository"""
# This can trigger updates for the caches for subsets of the filtered
# view, e.g. when there is no cache for this filtered view or the cache
# is stale.
Pierre-Yves David
branchmap: extract updatebranchcache from repo
r18121
Martijn Pieters
branchmap: encapsulate cache updating in the map itself...
r41764 cl = repo.changelog
filtername = repo.filtername
bcache = self._per_filter.get(filtername)
if bcache is None or not bcache.validfor(repo):
# cache object missing or cache object stale? Read from disk
bcache = branchcache.fromfile(repo)
Martijn Pieters
branchmap: add some clarifications and clean up flow...
r41708
Martijn Pieters
branchmap: encapsulate cache updating in the map itself...
r41764 revs = []
if bcache is None:
# no (fresh) cache available anymore, perhaps we can re-use
# the cache for a subset, then extend that to add info on missing
# revisions.
subsetname = subsettable.get(filtername)
if subsetname is not None:
subset = repo.filtered(subsetname)
bcache = self[subset].copy()
extrarevs = subset.changelog.filteredrevs - cl.filteredrevs
revs.extend(r for r in extrarevs if r <= bcache.tiprev)
else:
# nothing to fall back on, start empty.
Joerg Sonnenberger
node: introduce nodeconstants class...
r47538 bcache = branchcache(repo)
Durham Goode
revbranchcache: move out of branchmap onto localrepo...
r24373
Martijn Pieters
branchmap: encapsulate cache updating in the map itself...
r41764 revs.extend(cl.revs(start=bcache.tiprev + 1))
if revs:
bcache.update(repo, revs)
Pierre-Yves David
branchmap: store branchcache in a dedicated object...
r18124
Martijn Pieters
branchmap: encapsulate cache updating in the map itself...
r41764 assert bcache.validfor(repo), filtername
self._per_filter[repo.filtername] = bcache
def replace(self, repo, remotebranchmap):
"""Replace the branchmap cache for a repo with a branch mapping.
This is likely only called during clone with a branch map from a
remote.
Gregory Szorc
branchmap: move branch cache code out of streamclone.py...
r26460
Martijn Pieters
branchmap: encapsulate cache updating in the map itself...
r41764 """
cl = repo.changelog
clrev = cl.rev
clbranchinfo = cl.branchinfo
rbheads = []
Martin von Zweigbergk
branchmap: make "closed" a set from beginning instead of converting from list...
r44086 closed = set()
Gregory Szorc
py3: replace pycompat.itervalues(x) with x.values()...
r49790 for bheads in remotebranchmap.values():
Martijn Pieters
branchmap: encapsulate cache updating in the map itself...
r41764 rbheads += bheads
for h in bheads:
r = clrev(h)
b, c = clbranchinfo(r)
if c:
Martin von Zweigbergk
branchmap: make "closed" a set from beginning instead of converting from list...
r44086 closed.add(h)
Gregory Szorc
branchmap: move branch cache code out of streamclone.py...
r26460
Martijn Pieters
branchmap: encapsulate cache updating in the map itself...
r41764 if rbheads:
rtiprev = max((int(clrev(node)) for node in rbheads))
cache = branchcache(
Joerg Sonnenberger
node: introduce nodeconstants class...
r47538 repo,
Augie Fackler
formatting: blacken the codebase...
r43346 remotebranchmap,
repo[rtiprev].node(),
rtiprev,
Martin von Zweigbergk
branchmap: make "closed" a set from beginning instead of converting from list...
r44086 closednodes=closed,
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
branchmap: move branch cache code out of streamclone.py...
r26460
Martijn Pieters
branchmap: encapsulate cache updating in the map itself...
r41764 # Try to stick it as low as possible
# filter above served are unlikely to be fetch from a clone
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 for candidate in (b'base', b'immutable', b'served'):
Martijn Pieters
branchmap: encapsulate cache updating in the map itself...
r41764 rview = repo.filtered(candidate)
if cache.validfor(rview):
self._per_filter[candidate] = cache
cache.write(rview)
return
def clear(self):
self._per_filter.clear()
branchmap: stop writing cache for uncommitted data...
r49526 def write_delayed(self, repo):
unfi = repo.unfiltered()
for filtername, cache in self._per_filter.items():
if cache._delayed:
repo = unfi.filtered(filtername)
cache.write(repo)
Augie Fackler
formatting: blacken the codebase...
r43346
Pulkit Goyal
branchcache: add functions to validate changelog nodes...
r42289 def _unknownnode(node):
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """raises ValueError when branchcache found a node which does not exists"""
Manuel Jacob
py3: use `x.hex()` instead of `pycompat.sysstr(node.hex(x))`
r50195 raise ValueError('node %s does not exist' % node.hex())
Gregory Szorc
branchmap: move branch cache code out of streamclone.py...
r26460
Augie Fackler
formatting: blacken the codebase...
r43346
Martin von Zweigbergk
py3: fix formatting of branchmap log messages with repo.filtername=None...
r42805 def _branchcachedesc(repo):
if repo.filtername is not None:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return b'branch cache (%s)' % repo.filtername
Martin von Zweigbergk
py3: fix formatting of branchmap log messages with repo.filtername=None...
r42805 else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return b'branch cache'
Martin von Zweigbergk
py3: fix formatting of branchmap log messages with repo.filtername=None...
r42805
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
py3: use class X: instead of class X(object):...
r49801 class branchcache:
Brodie Rao
branchmap: add documentation on the branchcache on-disk format
r20181 """A dict like object that hold branches heads cache.
This cache is used to avoid costly computations to determine all the
branch heads of a repo.
The cache is serialized on disk in the following format:
<tip hex node> <tip rev number> [optional filtered repo hex hash]
Brodie Rao
branchmap: cache open/closed branch head information...
r20185 <branch head hex node> <open/closed state> <branch name>
<branch head hex node> <open/closed state> <branch name>
Brodie Rao
branchmap: add documentation on the branchcache on-disk format
r20181 ...
The first line is used to check if the cache is still valid. If the
branch cache is for a filtered repo view, an optional third hash is
av6
branchmap: skip obsolete revisions while computing heads...
r49536 included that hashes the hashes of all filtered and obsolete revisions.
Brodie Rao
branchmap: cache open/closed branch head information...
r20185
The open/closed state is represented by a single letter 'o' or 'c'.
This field can be used to avoid changelog reads when determining if a
branch head closes a branch or not.
Brodie Rao
branchmap: add documentation on the branchcache on-disk format
r20181 """
Pulkit Goyal
branchmap: move __init__ up in branchcache class...
r41826
Augie Fackler
formatting: blacken the codebase...
r43346 def __init__(
self,
Joerg Sonnenberger
node: introduce nodeconstants class...
r47538 repo,
Augie Fackler
formatting: blacken the codebase...
r43346 entries=(),
Joerg Sonnenberger
node: replace nullid and friends with nodeconstants class...
r47771 tipnode=None,
Augie Fackler
formatting: blacken the codebase...
r43346 tiprev=nullrev,
filteredhash=None,
closednodes=None,
hasnode=None,
):
Matt Harbison
merge with stable
r47552 # type: (localrepo.localrepository, Union[Dict[bytes, List[bytes]], Iterable[Tuple[bytes, List[bytes]]]], bytes, int, Optional[bytes], Optional[Set[bytes]], Optional[Callable[[bytes], bool]]) -> None
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """hasnode is a function which can be used to verify whether changelog
Pulkit Goyal
branchcache: have a hasnode function to validate nodes...
r42174 has a given node or not. If it's not provided, we assume that every node
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 we have exists in changelog"""
Joerg Sonnenberger
node: introduce nodeconstants class...
r47538 self._repo = repo
branchmap: stop writing cache for uncommitted data...
r49526 self._delayed = False
Joerg Sonnenberger
node: replace nullid and friends with nodeconstants class...
r47771 if tipnode is None:
self.tipnode = repo.nullid
else:
self.tipnode = tipnode
Pulkit Goyal
branchmap: move __init__ up in branchcache class...
r41826 self.tiprev = tiprev
self.filteredhash = filteredhash
# closednodes is a set of nodes that close their branch. If the branch
# cache has been updated, it may contain nodes that are no longer
# heads.
if closednodes is None:
self._closednodes = set()
else:
Augie Fackler
branchmap: annotate constructor type for branchcache...
r44035 self._closednodes = closednodes
Pulkit Goyal
branchcache: make entries a private attribute...
r42172 self._entries = dict(entries)
Pulkit Goyal
branchcache: add attributes to track which nodes are verified...
r42173 # whether closed nodes are verified or not
self._closedverified = False
# branches for which nodes are verified
self._verifiedbranches = set()
Pulkit Goyal
branchcache: have a hasnode function to validate nodes...
r42174 self._hasnode = hasnode
if self._hasnode is None:
self._hasnode = lambda x: True
Pulkit Goyal
branchmap: remove the dict interface from the branchcache class (API)...
r42168
Pulkit Goyal
branchcache: add functions to validate changelog nodes...
r42289 def _verifyclosed(self):
Kyle Lippincott
black: make codebase compatible with black v21.4b2 and v20.8b1...
r47856 """verify the closed nodes we have"""
Pulkit Goyal
branchcache: add functions to validate changelog nodes...
r42289 if self._closedverified:
return
for node in self._closednodes:
if not self._hasnode(node):
_unknownnode(node)
self._closedverified = True
def _verifybranch(self, branch):
Kyle Lippincott
black: make codebase compatible with black v21.4b2 and v20.8b1...
r47856 """verify head nodes for the given branch."""
Pulkit Goyal
branchcache: add functions to validate changelog nodes...
r42289 if branch not in self._entries or branch in self._verifiedbranches:
return
for n in self._entries[branch]:
if not self._hasnode(n):
_unknownnode(n)
self._verifiedbranches.add(branch)
def _verifyall(self):
Kyle Lippincott
black: make codebase compatible with black v21.4b2 and v20.8b1...
r47856 """verifies nodes of all the branches"""
Pulkit Goyal
branchcache: only iterate over branches which needs to be verified...
r42302 needverification = set(self._entries.keys()) - self._verifiedbranches
for b in needverification:
Pulkit Goyal
branchcache: add functions to validate changelog nodes...
r42289 self._verifybranch(b)
Pulkit Goyal
branchmap: remove the dict interface from the branchcache class (API)...
r42168 def __iter__(self):
Pulkit Goyal
branchcache: make entries a private attribute...
r42172 return iter(self._entries)
Pulkit Goyal
branchmap: remove the dict interface from the branchcache class (API)...
r42168
def __setitem__(self, key, value):
Pulkit Goyal
branchcache: make entries a private attribute...
r42172 self._entries[key] = value
Pulkit Goyal
branchmap: remove the dict interface from the branchcache class (API)...
r42168
def __getitem__(self, key):
Pulkit Goyal
branchcache: lazily validate nodes from the branchmap...
r42290 self._verifybranch(key)
Pulkit Goyal
branchcache: make entries a private attribute...
r42172 return self._entries[key]
Pulkit Goyal
branchmap: remove the dict interface from the branchcache class (API)...
r42168
Pulkit Goyal
branchmap: implement __contains__()...
r42282 def __contains__(self, key):
Pulkit Goyal
branchcache: lazily validate nodes from the branchmap...
r42290 self._verifybranch(key)
Pulkit Goyal
branchmap: implement __contains__()...
r42282 return key in self._entries
Pulkit Goyal
branchmap: remove the dict interface from the branchcache class (API)...
r42168 def iteritems(self):
Gregory Szorc
global: bulk replace simple pycompat.iteritems(x) with x.items()...
r49768 for k, v in self._entries.items():
Pulkit Goyal
branchcache: lazily validate nodes in iteritems()...
r42303 self._verifybranch(k)
yield k, v
Pulkit Goyal
branchmap: remove the dict interface from the branchcache class (API)...
r42168
Martin von Zweigbergk
py3: source-transform only call-sites of iteritems(), not definitions...
r42809 items = iteritems
Pulkit Goyal
branchcache: introduce hasbranch()...
r42171 def hasbranch(self, label):
Kyle Lippincott
black: make codebase compatible with black v21.4b2 and v20.8b1...
r47856 """checks whether a branch of this name exists or not"""
Pulkit Goyal
branchcache: lazily validate nodes from the branchmap...
r42290 self._verifybranch(label)
Pulkit Goyal
branchcache: make entries a private attribute...
r42172 return label in self._entries
Pulkit Goyal
branchcache: introduce hasbranch()...
r42171
Martijn Pieters
branchmap: make branchcache responsible for reading...
r41706 @classmethod
def fromfile(cls, repo):
f = None
try:
f = repo.cachevfs(cls._filename(repo))
lineiter = iter(f)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 cachekey = next(lineiter).rstrip(b'\n').split(b" ", 2)
Martijn Pieters
branchmap: make branchcache responsible for reading...
r41706 last, lrev = cachekey[:2]
last, lrev = bin(last), int(lrev)
filteredhash = None
Pulkit Goyal
branchcache: have a hasnode function to validate nodes...
r42174 hasnode = repo.changelog.hasnode
Martijn Pieters
branchmap: make branchcache responsible for reading...
r41706 if len(cachekey) > 2:
filteredhash = bin(cachekey[2])
Augie Fackler
formatting: blacken the codebase...
r43346 bcache = cls(
Joerg Sonnenberger
node: introduce nodeconstants class...
r47538 repo,
Augie Fackler
formatting: blacken the codebase...
r43346 tipnode=last,
tiprev=lrev,
filteredhash=filteredhash,
hasnode=hasnode,
)
Martijn Pieters
branchmap: make branchcache responsible for reading...
r41706 if not bcache.validfor(repo):
# invalidate the cache
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 raise ValueError('tip differs')
Pulkit Goyal
branchmap: prevent reading the file twice through different iterators...
r41974 bcache.load(repo, lineiter)
Martijn Pieters
branchmap: make branchcache responsible for reading...
r41706 except (IOError, OSError):
return None
except Exception as inst:
if repo.ui.debugflag:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 msg = b'invalid %s: %s\n'
Augie Fackler
formatting: blacken the codebase...
r43346 repo.ui.debug(
Augie Fackler
branchmap: pytype is confused about bytestr...
r43805 msg
% (
_branchcachedesc(repo),
Matt Harbison
branchmap: force Exception to bytes before logging...
r47512 stringutil.forcebytestr(inst),
Augie Fackler
branchmap: pytype is confused about bytestr...
r43805 )
Augie Fackler
formatting: blacken the codebase...
r43346 )
Martijn Pieters
branchmap: make branchcache responsible for reading...
r41706 bcache = None
finally:
if f:
f.close()
return bcache
Pulkit Goyal
branchmap: prevent reading the file twice through different iterators...
r41974 def load(self, repo, lineiter):
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """fully loads the branchcache by reading from the file using the line
Pulkit Goyal
branchmap: prevent reading the file twice through different iterators...
r41974 iterator passed"""
Pulkit Goyal
branchcache: move loading of branch names and nodes into it's own function...
r41959 for line in lineiter:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 line = line.rstrip(b'\n')
Pulkit Goyal
branchcache: move loading of branch names and nodes into it's own function...
r41959 if not line:
continue
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 node, state, label = line.split(b" ", 2)
if state not in b'oc':
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 raise ValueError('invalid branch state')
Pulkit Goyal
branchcache: move loading of branch names and nodes into it's own function...
r41959 label = encoding.tolocal(label.strip())
node = bin(node)
Pulkit Goyal
branchcache: make entries a private attribute...
r42172 self._entries.setdefault(label, []).append(node)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if state == b'c':
Pulkit Goyal
branchcache: move loading of branch names and nodes into it's own function...
r41959 self._closednodes.add(node)
Martijn Pieters
branchmap: make branchcache responsible for reading...
r41706 @staticmethod
def _filename(repo):
"""name of a branchcache file for a given repo or repoview"""
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 filename = b"branch2"
Martijn Pieters
branchmap: make branchcache responsible for reading...
r41706 if repo.filtername:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 filename = b'%s-%s' % (filename, repo.filtername)
Martijn Pieters
branchmap: make branchcache responsible for reading...
r41706 return filename
Pierre-Yves David
branchmap: store branchcache in a dedicated object...
r18124
Pierre-Yves David
branchmap: move validity logic in the object itself...
r18132 def validfor(self, repo):
av6
branchmap: split a long condition in branchcache.validfor(), add comments...
r49568 """check that cache contents are valid for (a subset of) this repo
Pierre-Yves David
branchmap: move validity logic in the object itself...
r18132
av6
branchmap: split a long condition in branchcache.validfor(), add comments...
r49568 - False when the order of changesets changed or if we detect a strip.
- True when cache is up-to-date for the current repo or its subset."""
Pierre-Yves David
branchmap: move validity logic in the object itself...
r18132 try:
av6
branchmap: split a long condition in branchcache.validfor(), add comments...
r49568 node = repo.changelog.node(self.tiprev)
Pierre-Yves David
branchmap: move validity logic in the object itself...
r18132 except IndexError:
av6
branchmap: split a long condition in branchcache.validfor(), add comments...
r49568 # changesets were stripped and now we don't even have enough to
# find tiprev
Pierre-Yves David
branchmap: move validity logic in the object itself...
r18132 return False
av6
branchmap: split a long condition in branchcache.validfor(), add comments...
r49568 if self.tipnode != node:
# tiprev doesn't correspond to tipnode: repo was stripped, or this
# repo has a different order of changesets
return False
tiphash = scmutil.filteredhash(repo, self.tiprev, needobsolete=True)
# hashes don't match if this repo view has a different set of filtered
# revisions (e.g. due to phase changes) or obsolete revisions (e.g.
# history was rewritten)
return self.filteredhash == tiphash
Pierre-Yves David
branchmap: move validity logic in the object itself...
r18132
Brodie Rao
branchmap: introduce branchtip() method
r20186 def _branchtip(self, heads):
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """Return tuple with last open head in heads and false,
otherwise return last closed head and true."""
Brodie Rao
branchmap: introduce branchtip() method
r20186 tip = heads[-1]
closed = True
for h in reversed(heads):
if h not in self._closednodes:
tip = h
closed = False
break
return tip, closed
def branchtip(self, branch):
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """Return the tipmost open head on branch head, otherwise return the
Mads Kiilerich
help: branch names primarily denote the tipmost unclosed branch head...
r20245 tipmost closed head on branch.
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 Raise KeyError for unknown branch."""
Brodie Rao
branchmap: introduce branchtip() method
r20186 return self._branchtip(self[branch])[0]
the31k
branches: correctly show inactive multiheaded branches...
r34076 def iteropen(self, nodes):
return (n for n in nodes if n not in self._closednodes)
Brodie Rao
branchmap: introduce branchheads() method
r20188 def branchheads(self, branch, closed=False):
Pulkit Goyal
branchcache: lazily validate nodes from the branchmap...
r42290 self._verifybranch(branch)
Pulkit Goyal
branchmap: prevent using __getitem__() in branchheads()...
r42281 heads = self._entries[branch]
Brodie Rao
branchmap: introduce branchheads() method
r20188 if not closed:
the31k
branches: correctly show inactive multiheaded branches...
r34076 heads = list(self.iteropen(heads))
Brodie Rao
branchmap: introduce branchheads() method
r20188 return heads
Brodie Rao
branchmap: introduce iterbranches() method
r20190 def iterbranches(self):
Gregory Szorc
global: bulk replace simple pycompat.iteritems(x) with x.items()...
r49768 for bn, heads in self.items():
Brodie Rao
branchmap: introduce iterbranches() method
r20190 yield (bn, heads) + self._branchtip(heads)
Pulkit Goyal
branchcache: rename itervalues() to iterheads()...
r42169 def iterheads(self):
Kyle Lippincott
black: make codebase compatible with black v21.4b2 and v20.8b1...
r47856 """returns all the heads"""
Pulkit Goyal
branchcache: lazily validate nodes from the branchmap...
r42290 self._verifyall()
Gregory Szorc
py3: replace pycompat.itervalues(x) with x.values()...
r49790 return self._entries.values()
Pulkit Goyal
branchcache: rename itervalues() to iterheads()...
r42169
Pierre-Yves David
branchmap: add a copy method...
r18232 def copy(self):
"""return an deep copy of the branchcache object"""
Pulkit Goyal
branchmap: dynamically resolve type of branchcache class...
r42280 return type(self)(
Joerg Sonnenberger
node: introduce nodeconstants class...
r47538 self._repo,
Augie Fackler
formatting: blacken the codebase...
r43346 self._entries,
self.tipnode,
self.tiprev,
self.filteredhash,
self._closednodes,
)
Pierre-Yves David
branchmap: move validity logic in the object itself...
r18132
Pierre-Yves David
branchmap: make write a method on the branchmap object
r18128 def write(self, repo):
branchmap: stop writing cache for uncommitted data...
r49526 tr = repo.currenttransaction()
if not getattr(tr, 'finalized', True):
# Avoid premature writing.
#
# (The cache warming setup by localrepo will update the file later.)
self._delayed = True
return
Pierre-Yves David
branchmap: make write a method on the branchmap object
r18128 try:
branchmap: use a context manager when writing the branchmap...
r50098 filename = self._filename(repo)
with repo.cachevfs(filename, b"w", atomictemp=True) as f:
cachekey = [hex(self.tipnode), b'%d' % self.tiprev]
if self.filteredhash is not None:
cachekey.append(hex(self.filteredhash))
f.write(b" ".join(cachekey) + b'\n')
nodecount = 0
for label, nodes in sorted(self._entries.items()):
label = encoding.fromlocal(label)
for node in nodes:
nodecount += 1
if node in self._closednodes:
state = b'c'
else:
state = b'o'
f.write(b"%s %s %s\n" % (hex(node), state, label))
Augie Fackler
formatting: blacken the codebase...
r43346 repo.ui.log(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'branchcache',
b'wrote %s with %d labels and %d nodes\n',
Augie Fackler
formatting: blacken the codebase...
r43346 _branchcachedesc(repo),
len(self._entries),
nodecount,
)
branchmap: stop writing cache for uncommitted data...
r49526 self._delayed = False
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 except (IOError, OSError, error.Abort) as inst:
Augie Fackler
branchmap: remove superfluous pass statements
r34369 # Abort may be raised by read only opener, so log and continue
Augie Fackler
formatting: blacken the codebase...
r43346 repo.ui.debug(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"couldn't write branch cache: %s\n"
Augie Fackler
formatting: blacken the codebase...
r43346 % stringutil.forcebytestr(inst)
)
Pierre-Yves David
branchmap: make update a method
r18131
Pierre-Yves David
branchmap: pass revision insteads of changectx to the update function...
r18305 def update(self, repo, revgen):
Pierre-Yves David
branchmap: make update a method
r18131 """Given a branchhead cache, self, that may have extra nodes or be
Pierre-Yves David
branchmap: simplify update code...
r20263 missing heads, and a generator of nodes that are strictly a superset of
Pierre-Yves David
branchmap: make update a method
r18131 heads missing, this function updates self to be correct.
"""
Simon Farnsworth
mercurial: switch to util.timer for all interval timings...
r30975 starttime = util.timer()
Pierre-Yves David
branchmap: make update a method
r18131 cl = repo.changelog
# collect new branch entries
newbranches = {}
Durham Goode
revbranchcache: move out of branchmap onto localrepo...
r24373 getbranchinfo = repo.revbranchcache().branchinfo
Pierre-Yves David
branchmap: Save changectx creation during update...
r18307 for r in revgen:
Yuya Nishihara
branchmap: do not specify changelog as an argument...
r40455 branch, closesbranch = getbranchinfo(r)
Pierre-Yves David
branchmap: stop useless rev -> node -> rev round trip...
r20262 newbranches.setdefault(branch, []).append(r)
Brodie Rao
branchmap: cache open/closed branch head information...
r20185 if closesbranch:
Pierre-Yves David
branchmap: stop useless rev -> node -> rev round trip...
r20262 self._closednodes.add(cl.node(r))
Pierre-Yves David
branchmap: pre-filter topological heads before ancestors based filtering...
r22357
Pulkit Goyal
branchcache: store the maximum tip in a variable inside for loop...
r42400 # new tip revision which we found after iterating items from new
# branches
ntiprev = self.tiprev
Joerg Sonnenberger
branchmap: avoid ancestor computations in absence of non-continous branches...
r46880 # Delay fetching the topological heads until they are needed.
# A repository without non-continous branches can skip this part.
topoheads = None
# If a changeset is visible, its parents must be visible too, so
# use the faster unfiltered parent accessor.
parentrevs = repo.unfiltered().changelog.parentrevs
av6
branchmap: skip obsolete revisions while computing heads...
r49536 # Faster than using ctx.obsolete()
obsrevs = obsolete.getrevs(repo, b'obsolete')
Gregory Szorc
global: bulk replace simple pycompat.iteritems(x) with x.items()...
r49768 for branch, newheadrevs in newbranches.items():
Joerg Sonnenberger
branchmap: avoid ancestor computations in absence of non-continous branches...
r46880 # For every branch, compute the new branchheads.
# A branchhead is a revision such that no descendant is on
# the same branch.
#
# The branchheads are computed iteratively in revision order.
# This ensures topological order, i.e. parents are processed
# before their children. Ancestors are inclusive here, i.e.
# any revision is an ancestor of itself.
#
# Core observations:
# - The current revision is always a branchhead for the
# repository up to that point.
# - It is the first revision of the branch if and only if
# there was no branchhead before. In that case, it is the
# only branchhead as there are no possible ancestors on
# the same branch.
# - If a parent is on the same branch, a branchhead can
# only be an ancestor of that parent, if it is parent
# itself. Otherwise it would have been removed as ancestor
# of that parent before.
# - Therefore, if all parents are on the same branch, they
# can just be removed from the branchhead set.
# - If one parent is on the same branch and the other is not
# and there was exactly one branchhead known, the existing
# branchhead can only be an ancestor if it is the parent.
# Otherwise it would have been removed as ancestor of
# the parent before. The other parent therefore can't have
# a branchhead as ancestor.
# - In all other cases, the parents on different branches
# could have a branchhead as ancestor. Those parents are
# kept in the "uncertain" set. If all branchheads are also
# topological heads, they can't have descendants and further
# checks can be skipped. Otherwise, the ancestors of the
# "uncertain" set are removed from branchheads.
# This computation is heavy and avoided if at all possible.
av6
branchmap: don't add branch entries if there are no heads...
r49567 bheads = self._entries.get(branch, [])
Augie Fackler
cleanup: run pyupgrade on our source tree to clean up varying things...
r44937 bheadset = {cl.rev(node) for node in bheads}
Joerg Sonnenberger
branchmap: avoid ancestor computations in absence of non-continous branches...
r46880 uncertain = set()
for newrev in sorted(newheadrevs):
av6
branchmap: skip obsolete revisions while computing heads...
r49536 if newrev in obsrevs:
# We ignore obsolete changesets as they shouldn't be
# considered heads.
continue
Joerg Sonnenberger
branchmap: avoid ancestor computations in absence of non-continous branches...
r46880 if not bheadset:
bheadset.add(newrev)
continue
Pierre-Yves David
branchmap: make update a method
r18131
Joerg Sonnenberger
branchmap: avoid ancestor computations in absence of non-continous branches...
r46880 parents = [p for p in parentrevs(newrev) if p != nullrev]
samebranch = set()
otherbranch = set()
av6
branchmap: skip obsolete revisions while computing heads...
r49536 obsparents = set()
Joerg Sonnenberger
branchmap: avoid ancestor computations in absence of non-continous branches...
r46880 for p in parents:
av6
branchmap: skip obsolete revisions while computing heads...
r49536 if p in obsrevs:
# We ignored this obsolete changeset earlier, but now
# that it has non-ignored children, we need to make
# sure their ancestors are not considered heads. To
# achieve that, we will simply treat this obsolete
# changeset as a parent from other branch.
obsparents.add(p)
elif p in bheadset or getbranchinfo(p)[0] == branch:
Joerg Sonnenberger
branchmap: avoid ancestor computations in absence of non-continous branches...
r46880 samebranch.add(p)
else:
otherbranch.add(p)
av6
branchmap: skip obsolete revisions while computing heads...
r49536 if not (len(bheadset) == len(samebranch) == 1):
Joerg Sonnenberger
branchmap: avoid ancestor computations in absence of non-continous branches...
r46880 uncertain.update(otherbranch)
av6
branchmap: skip obsolete revisions while computing heads...
r49536 uncertain.update(obsparents)
Joerg Sonnenberger
branchmap: avoid ancestor computations in absence of non-continous branches...
r46880 bheadset.difference_update(samebranch)
bheadset.add(newrev)
Pierre-Yves David
branchmap: pre-filter topological heads before ancestors based filtering...
r22357 if uncertain:
Joerg Sonnenberger
branchmap: avoid ancestor computations in absence of non-continous branches...
r46880 if topoheads is None:
topoheads = set(cl.headrevs())
if bheadset - topoheads:
floorrev = min(bheadset)
av6
branchmap: skip obsolete revisions while computing heads...
r49536 if floorrev <= max(uncertain):
ancestors = set(cl.ancestors(uncertain, floorrev))
bheadset -= ancestors
av6
branchmap: don't add branch entries if there are no heads...
r49567 if bheadset:
self[branch] = [cl.node(rev) for rev in sorted(bheadset)]
av6
branchmap: skip obsolete revisions while computing heads...
r49536 tiprev = max(newheadrevs)
Pulkit Goyal
branchcache: store the maximum tip in a variable inside for loop...
r42400 if tiprev > ntiprev:
ntiprev = tiprev
if ntiprev > self.tiprev:
self.tiprev = ntiprev
self.tipnode = cl.node(ntiprev)
Pierre-Yves David
branchmap: make update a method
r18131
Pierre-Yves David
branchmap: remove the droppednodes logic...
r19838 if not self.validfor(repo):
av6
branchmap: skip obsolete revisions while computing heads...
r49536 # old cache key is now invalid for the repo, but we've just updated
# the cache and we assume it's valid, so let's make the cache key
# valid as well by recomputing it from the cached data
Joerg Sonnenberger
node: replace nullid and friends with nodeconstants class...
r47771 self.tipnode = repo.nullid
Pierre-Yves David
branchmap: make update a method
r18131 self.tiprev = nullrev
Pulkit Goyal
branchcache: rename itervalues() to iterheads()...
r42169 for heads in self.iterheads():
av6
branchmap: skip obsolete revisions while computing heads...
r49536 if not heads:
# all revisions on a branch are obsolete
continue
# note: tiprev is not necessarily the tip revision of repo,
# because the tip could be obsolete (i.e. not a head)
Pierre-Yves David
branchmap: make update a method
r18131 tiprev = max(cl.rev(node) for node in heads)
if tiprev > self.tiprev:
self.tipnode = cl.node(tiprev)
self.tiprev = tiprev
av6
branchmap: skip obsolete revisions while computing heads...
r49536 self.filteredhash = scmutil.filteredhash(
repo, self.tiprev, needobsolete=True
)
Gregory Szorc
branchmap: log events related to branch cache...
r21031
Simon Farnsworth
mercurial: switch to util.timer for all interval timings...
r30975 duration = util.timer() - starttime
Augie Fackler
formatting: blacken the codebase...
r43346 repo.ui.log(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'branchcache',
b'updated %s in %.4f seconds\n',
Augie Fackler
formatting: blacken the codebase...
r43346 _branchcachedesc(repo),
duration,
)
Mads Kiilerich
branchcache: introduce revbranchcache for caching of revision branch names...
r23785
Martijn Pieters
branchmap: updating triggers a write...
r41707 self.write(repo)
class remotebranchcache(branchcache):
"""Branchmap info for a remote connection, should not write locally"""
Augie Fackler
formatting: blacken the codebase...
r43346
Martijn Pieters
branchmap: updating triggers a write...
r41707 def write(self, repo):
pass
Mads Kiilerich
branchcache: introduce revbranchcache for caching of revision branch names...
r23785 # Revision branch info cache
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _rbcversion = b'-v1'
_rbcnames = b'rbc-names' + _rbcversion
_rbcrevs = b'rbc-revs' + _rbcversion
Mads Kiilerich
branchcache: introduce revbranchcache for caching of revision branch names...
r23785 # [4 byte hash prefix][4 byte branch name number with sign bit indicating open]
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _rbcrecfmt = b'>4sI'
Mads Kiilerich
branchcache: introduce revbranchcache for caching of revision branch names...
r23785 _rbcrecsize = calcsize(_rbcrecfmt)
Joerg Sonnenberger
reverse-branch-cache: switch to doubling allocating scheme...
r47069 _rbcmininc = 64 * _rbcrecsize
Mads Kiilerich
branchcache: introduce revbranchcache for caching of revision branch names...
r23785 _rbcnodelen = 4
Augie Fackler
formatting: blacken the codebase...
r43346 _rbcbranchidxmask = 0x7FFFFFFF
Mads Kiilerich
branchcache: introduce revbranchcache for caching of revision branch names...
r23785 _rbccloseflag = 0x80000000
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
py3: use class X: instead of class X(object):...
r49801 class revbranchcache:
Mads Kiilerich
branchcache: introduce revbranchcache for caching of revision branch names...
r23785 """Persistent cache, mapping from revision number to branch name and close.
This is a low level cache, independent of filtering.
Branch names are stored in rbc-names in internal encoding separated by 0.
rbc-names is append-only, and each branch name is only stored once and will
thus have a unique index.
The branch info for each revision is stored in rbc-revs as constant size
records. The whole file is read into memory, but it is only 'parsed' on
demand. The file is usually append-only but will be truncated if repo
modification is detected.
The record for each revision contains the first 4 bytes of the
corresponding node hash, and the record is only used if it still matches.
Even a completely trashed rbc-revs fill thus still give the right result
while converging towards full recovery ... assuming no incorrectly matching
node hashes.
The record also contains 4 bytes where 31 bits contains the index of the
branch and the last bit indicate that it is a branch close commit.
The usage pattern for rbc-revs is thus somewhat similar to 00changelog.i
and will grow with it but be 1/8th of its size.
"""
Mads Kiilerich
revisionbranchcache: fall back to slow path if starting readonly (issue4531)...
r24159 def __init__(self, repo, readonly=True):
Mads Kiilerich
branchcache: introduce revbranchcache for caching of revision branch names...
r23785 assert repo.filtername is None
Durham Goode
revbranchcache: store repo on the object...
r24374 self._repo = repo
Augie Fackler
formatting: blacken the codebase...
r43346 self._names = [] # branch names in local encoding with static index
Augie Fackler
py3: use bytearray() instead of array('c', ...) constructions...
r31346 self._rbcrevs = bytearray()
Augie Fackler
formatting: blacken the codebase...
r43346 self._rbcsnameslen = 0 # length of names read at _rbcsnameslen
Mads Kiilerich
branchcache: introduce revbranchcache for caching of revision branch names...
r23785 try:
Boris Feld
cachevfs: migration the revbranchcache to 'cachevfs'...
r33535 bndata = repo.cachevfs.read(_rbcnames)
Augie Fackler
formatting: blacken the codebase...
r43346 self._rbcsnameslen = len(bndata) # for verification before writing
Mads Kiilerich
rbc: empty (and invalid) rbc-names file should give an empty name list...
r31371 if bndata:
Augie Fackler
formatting: blacken the codebase...
r43346 self._names = [
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 encoding.tolocal(bn) for bn in bndata.split(b'\0')
Augie Fackler
formatting: blacken the codebase...
r43346 ]
Gregory Szorc
branchmap: remove unused exception variable
r29423 except (IOError, OSError):
Mads Kiilerich
revisionbranchcache: fall back to slow path if starting readonly (issue4531)...
r24159 if readonly:
# don't try to use cache - fall back to the slow path
self.branchinfo = self._branchinfo
Mads Kiilerich
branchcache: introduce revbranchcache for caching of revision branch names...
r23785 if self._names:
try:
Boris Feld
cachevfs: migration the revbranchcache to 'cachevfs'...
r33535 data = repo.cachevfs.read(_rbcrevs)
Augie Fackler
py3: use bytearray() instead of array('c', ...) constructions...
r31346 self._rbcrevs[:] = data
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except (IOError, OSError) as inst:
Augie Fackler
formatting: blacken the codebase...
r43346 repo.ui.debug(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"couldn't read revision branch cache: %s\n"
Augie Fackler
formatting: blacken the codebase...
r43346 % stringutil.forcebytestr(inst)
)
Mads Kiilerich
branchcache: introduce revbranchcache for caching of revision branch names...
r23785 # remember number of good records on disk
Augie Fackler
formatting: blacken the codebase...
r43346 self._rbcrevslen = min(
len(self._rbcrevs) // _rbcrecsize, len(repo.changelog)
)
Mads Kiilerich
branchcache: introduce revbranchcache for caching of revision branch names...
r23785 if self._rbcrevslen == 0:
self._names = []
Augie Fackler
formatting: blacken the codebase...
r43346 self._rbcnamescount = len(self._names) # number of names read at
# _rbcsnameslen
Mads Kiilerich
branchcache: introduce revbranchcache for caching of revision branch names...
r23785
Mads Kiilerich
cache: rebuild branch cache from scratch when inconsistencies are detected...
r28558 def _clear(self):
self._rbcsnameslen = 0
del self._names[:]
self._rbcnamescount = 0
self._rbcrevslen = len(self._repo.changelog)
Augie Fackler
py3: use bytearray() instead of array('c', ...) constructions...
r31346 self._rbcrevs = bytearray(self._rbcrevslen * _rbcrecsize)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 util.clearcachedproperty(self, b'_namesreverse')
Pulkit Goyal
branchmap: build the revbranchcache._namesreverse() only when required...
r40746
@util.propertycache
def _namesreverse(self):
Augie Fackler
cleanup: run pyupgrade on our source tree to clean up varying things...
r44937 return {b: r for r, b in enumerate(self._names)}
Mads Kiilerich
cache: rebuild branch cache from scratch when inconsistencies are detected...
r28558
Yuya Nishihara
branchmap: do not specify changelog as an argument...
r40455 def branchinfo(self, rev):
Mads Kiilerich
branchcache: introduce revbranchcache for caching of revision branch names...
r23785 """Return branch name and close flag for rev, using and updating
persistent cache."""
Yuya Nishihara
branchmap: do not specify changelog as an argument...
r40455 changelog = self._repo.changelog
Mads Kiilerich
branchcache: introduce revbranchcache for caching of revision branch names...
r23785 rbcrevidx = rev * _rbcrecsize
Yuya Nishihara
revbranchcache: return uncached branchinfo for nullrev (issue4683)...
r25266 # avoid negative index, changelog.read(nullrev) is fast without cache
if rev == nullrev:
return changelog.branchinfo(rev)
Mads Kiilerich
rbc: fix invalid rbc-revs entries caused by missing cache growth...
r29604 # if requested rev isn't allocated, grow and cache the rev info
Mads Kiilerich
branchcache: introduce revbranchcache for caching of revision branch names...
r23785 if len(self._rbcrevs) < rbcrevidx + _rbcrecsize:
Yuya Nishihara
branchmap: do not specify changelog as an argument...
r40455 return self._branchinfo(rev)
Mads Kiilerich
branchcache: introduce revbranchcache for caching of revision branch names...
r23785
# fast path: extract data from cache, use it if node is matching
reponode = changelog.node(rev)[:_rbcnodelen]
Mike Hommey
branchmap: revert c34532365b38 for Python 2.7 compatibility...
r33737 cachenode, branchidx = unpack_from(
Augie Fackler
formatting: blacken the codebase...
r43346 _rbcrecfmt, util.buffer(self._rbcrevs), rbcrevidx
)
Mads Kiilerich
branchcache: introduce revbranchcache for caching of revision branch names...
r23785 close = bool(branchidx & _rbccloseflag)
if close:
branchidx &= _rbcbranchidxmask
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if cachenode == b'\0\0\0\0':
Durham Goode
revbranchcache: populate cache incrementally...
r24376 pass
elif cachenode == reponode:
Mads Kiilerich
rbc: fix superfluous rebuilding from scratch - don't abuse self._rbcnamescount...
r29615 try:
Mads Kiilerich
cache: rebuild branch cache from scratch when inconsistencies are detected...
r28558 return self._names[branchidx], close
Mads Kiilerich
rbc: fix superfluous rebuilding from scratch - don't abuse self._rbcnamescount...
r29615 except IndexError:
# recover from invalid reference to unknown branch
Augie Fackler
formatting: blacken the codebase...
r43346 self._repo.ui.debug(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"referenced branch names not found"
b" - rebuilding revision branch cache from scratch\n"
Augie Fackler
formatting: blacken the codebase...
r43346 )
Mads Kiilerich
rbc: fix superfluous rebuilding from scratch - don't abuse self._rbcnamescount...
r29615 self._clear()
Durham Goode
revbranchcache: populate cache incrementally...
r24376 else:
# rev/node map has changed, invalidate the cache from here up
Augie Fackler
formatting: blacken the codebase...
r43346 self._repo.ui.debug(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"history modification detected - truncating "
b"revision branch cache to revision %d\n" % rev
Augie Fackler
formatting: blacken the codebase...
r43346 )
Durham Goode
revbranchcache: populate cache incrementally...
r24376 truncate = rbcrevidx + _rbcrecsize
del self._rbcrevs[truncate:]
self._rbcrevslen = min(self._rbcrevslen, truncate)
Mads Kiilerich
branchcache: introduce revbranchcache for caching of revision branch names...
r23785 # fall back to slow path and make sure it will be written to disk
Yuya Nishihara
branchmap: do not specify changelog as an argument...
r40455 return self._branchinfo(rev)
Mads Kiilerich
branchcache: introduce revbranchcache for caching of revision branch names...
r23785
Yuya Nishihara
branchmap: do not specify changelog as an argument...
r40455 def _branchinfo(self, rev):
Mads Kiilerich
branchcache: introduce revbranchcache for caching of revision branch names...
r23785 """Retrieve branch info from changelog and update _rbcrevs"""
Yuya Nishihara
branchmap: do not specify changelog as an argument...
r40455 changelog = self._repo.changelog
Mads Kiilerich
branchcache: introduce revbranchcache for caching of revision branch names...
r23785 b, close = changelog.branchinfo(rev)
if b in self._namesreverse:
branchidx = self._namesreverse[b]
else:
branchidx = len(self._names)
self._names.append(b)
self._namesreverse[b] = branchidx
reponode = changelog.node(rev)
if close:
branchidx |= _rbccloseflag
Yuya Nishihara
branchmap: do not specify changelog as an argument...
r40455 self._setcachedata(rev, reponode, branchidx)
Durham Goode
revbranchcache: move entry writing to a separate function...
r24375 return b, close
Joerg Sonnenberger
branchmap: update rev-branch-cache incrementally...
r47084 def setdata(self, rev, changelogrevision):
Boris Feld
revbranchcache: add a public function to update the data...
r36980 """add new data information to the cache"""
Joerg Sonnenberger
branchmap: update rev-branch-cache incrementally...
r47084 branch, close = changelogrevision.branchinfo
Boris Feld
revbranchcache: add a public function to update the data...
r36980 if branch in self._namesreverse:
branchidx = self._namesreverse[branch]
else:
branchidx = len(self._names)
self._names.append(branch)
self._namesreverse[branch] = branchidx
if close:
branchidx |= _rbccloseflag
Joerg Sonnenberger
branchmap: update rev-branch-cache incrementally...
r47084 self._setcachedata(rev, self._repo.changelog.node(rev), branchidx)
Boris Feld
revbranchcache: add a public function to update the data...
r36980 # If no cache data were readable (non exists, bad permission, etc)
# the cache was bypassing itself by setting:
#
# self.branchinfo = self._branchinfo
#
# Since we now have data in the cache, we need to drop this bypassing.
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 if 'branchinfo' in vars(self):
Boris Feld
revbranchcache: add a public function to update the data...
r36980 del self.branchinfo
Yuya Nishihara
branchmap: do not specify changelog as an argument...
r40455 def _setcachedata(self, rev, node, branchidx):
Durham Goode
revbranchcache: move entry writing to a separate function...
r24375 """Writes the node's branch data to the in-memory cache data."""
Durham Goode
branchmap: handle nullrev in setcachedata...
r31454 if rev == nullrev:
return
Mads Kiilerich
branchcache: introduce revbranchcache for caching of revision branch names...
r23785 rbcrevidx = rev * _rbcrecsize
Joerg Sonnenberger
reverse-branch-cache: switch to doubling allocating scheme...
r47069 requiredsize = rbcrevidx + _rbcrecsize
rbccur = len(self._rbcrevs)
if rbccur < requiredsize:
# bytearray doesn't allocate extra space at least in Python 3.7.
# When multiple changesets are added in a row, precise resize would
# result in quadratic complexity. Overallocate to compensate by
# use the classic doubling technique for dynamic arrays instead.
# If there was a gap in the map before, less space will be reserved.
self._rbcrevs.extend(b'\0' * max(_rbcmininc, requiredsize))
Mads Kiilerich
rbc: use struct unpack_from and pack_into instead of unpack and pack...
r31370 pack_into(_rbcrecfmt, self._rbcrevs, rbcrevidx, node, branchidx)
Durham Goode
revbranchcache: populate cache incrementally...
r24376 self._rbcrevslen = min(self._rbcrevslen, rev)
Mads Kiilerich
branchcache: introduce revbranchcache for caching of revision branch names...
r23785
Durham Goode
revbranchcache: move cache writing to the transaction finalizer...
r24377 tr = self._repo.currenttransaction()
if tr:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 tr.addfinalize(b'write-revbranchcache', self.write)
Durham Goode
revbranchcache: move cache writing to the transaction finalizer...
r24377
def write(self, tr=None):
Mads Kiilerich
branchcache: introduce revbranchcache for caching of revision branch names...
r23785 """Save branch cache if it is dirty."""
Durham Goode
revbranchcache: store repo on the object...
r24374 repo = self._repo
Pierre-Yves David
branchmap: acquires lock before writting the rev branch cache...
r29744 wlock = None
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 step = b''
Pierre-Yves David
branchmap: acquires lock before writting the rev branch cache...
r29744 try:
Pulkit Goyal
revbranchcache: factor logic to write names and revs in separate functions...
r42363 # write the new names
Pierre-Yves David
branchmap: preparatory indent of indent the branch rev writing code...
r29743 if self._rbcnamescount < len(self._names):
Pierre-Yves David
branchmap: acquires lock before writting the rev branch cache...
r29744 wlock = repo.wlock(wait=False)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 step = b' names'
Pulkit Goyal
revbranchcache: factor logic to write names and revs in separate functions...
r42363 self._writenames(repo)
Mads Kiilerich
branchcache: introduce revbranchcache for caching of revision branch names...
r23785
Pulkit Goyal
revbranchcache: factor logic to write names and revs in separate functions...
r42363 # write the new revs
Pierre-Yves David
branchmap: preparatory indent of indent the branch rev writing code...
r29743 start = self._rbcrevslen * _rbcrecsize
if start != len(self._rbcrevs):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 step = b''
Pierre-Yves David
branchmap: acquires lock before writting the rev branch cache...
r29744 if wlock is None:
wlock = repo.wlock(wait=False)
Pulkit Goyal
revbranchcache: factor logic to write names and revs in separate functions...
r42363 self._writerevs(repo, start)
Pierre-Yves David
branchmap: simplify error handlind when writing rev branch cache...
r29745 except (IOError, OSError, error.Abort, error.LockError) as inst:
Augie Fackler
formatting: blacken the codebase...
r43346 repo.ui.debug(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"couldn't write revision branch cache%s: %s\n"
Augie Fackler
formatting: blacken the codebase...
r43346 % (step, stringutil.forcebytestr(inst))
)
Pierre-Yves David
branchmap: acquires lock before writting the rev branch cache...
r29744 finally:
if wlock is not None:
wlock.release()
Pulkit Goyal
revbranchcache: factor logic to write names and revs in separate functions...
r42363
def _writenames(self, repo):
Kyle Lippincott
black: make codebase compatible with black v21.4b2 and v20.8b1...
r47856 """write the new branch names to revbranchcache"""
Pulkit Goyal
revbranchcache: factor logic to write names and revs in separate functions...
r42363 if self._rbcnamescount != 0:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 f = repo.cachevfs.open(_rbcnames, b'ab')
Pulkit Goyal
revbranchcache: factor logic to write names and revs in separate functions...
r42363 if f.tell() == self._rbcsnameslen:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 f.write(b'\0')
Pulkit Goyal
revbranchcache: factor logic to write names and revs in separate functions...
r42363 else:
f.close()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.ui.debug(b"%s changed - rewriting it\n" % _rbcnames)
Pulkit Goyal
revbranchcache: factor logic to write names and revs in separate functions...
r42363 self._rbcnamescount = 0
self._rbcrevslen = 0
if self._rbcnamescount == 0:
# before rewriting names, make sure references are removed
repo.cachevfs.unlinkpath(_rbcrevs, ignoremissing=True)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 f = repo.cachevfs.open(_rbcnames, b'wb')
Augie Fackler
formatting: blacken the codebase...
r43346 f.write(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'\0'.join(
Augie Fackler
formatting: blacken the codebase...
r43346 encoding.fromlocal(b)
for b in self._names[self._rbcnamescount :]
)
)
Pulkit Goyal
revbranchcache: factor logic to write names and revs in separate functions...
r42363 self._rbcsnameslen = f.tell()
f.close()
self._rbcnamescount = len(self._names)
def _writerevs(self, repo, start):
Kyle Lippincott
black: make codebase compatible with black v21.4b2 and v20.8b1...
r47856 """write the new revs to revbranchcache"""
Pulkit Goyal
revbranchcache: use context manager in _writerevs() to write to file...
r42364 revs = min(len(repo.changelog), len(self._rbcrevs) // _rbcrecsize)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 with repo.cachevfs.open(_rbcrevs, b'ab') as f:
Pulkit Goyal
revbranchcache: factor logic to write names and revs in separate functions...
r42363 if f.tell() != start:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.ui.debug(
b"truncating cache/%s to %d\n" % (_rbcrevs, start)
)
Pulkit Goyal
revbranchcache: factor logic to write names and revs in separate functions...
r42363 f.seek(start)
Pulkit Goyal
revbranchcache: use context manager in _writerevs() to write to file...
r42364 if f.tell() != start:
start = 0
f.seek(start)
f.truncate()
end = revs * _rbcrecsize
f.write(self._rbcrevs[start:end])
Pulkit Goyal
revbranchcache: factor logic to write names and revs in separate functions...
r42363 self._rbcrevslen = revs