mirror of
https://github.com/facebook/sapling.git
synced 2024-10-11 17:27:53 +03:00
remotenames: resolve remotename lazily
Summary: Before this patch we were reading the whole remotenames file and resolving all the nodes at once. This patch makes us resolve the nodes only when they are needed. On our big repos hg log -r . -T "{node}\n" --profile goes from 0.23s to 0.1s Test Plan: All the tests pass
This commit is contained in:
parent
2e288fd5af
commit
b834e8cae6
114
remotenames.py
114
remotenames.py
@ -16,6 +16,7 @@ remotebranches extension. Ryan McElroy of Facebook also contributed.
|
|||||||
import os
|
import os
|
||||||
import errno
|
import errno
|
||||||
import shutil
|
import shutil
|
||||||
|
import UserDict
|
||||||
|
|
||||||
from mercurial import bookmarks
|
from mercurial import bookmarks
|
||||||
from mercurial import commands
|
from mercurial import commands
|
||||||
@ -205,6 +206,77 @@ def updatecmd(orig, ui, repo, node=None, rev=None, **kwargs):
|
|||||||
del kwargs['bookmark']
|
del kwargs['bookmark']
|
||||||
return orig(ui, repo, node=node, rev=rev, **kwargs)
|
return orig(ui, repo, node=node, rev=rev, **kwargs)
|
||||||
|
|
||||||
|
class lazyremotenamedict(UserDict.DictMixin):
|
||||||
|
"""Read-only dict-like Class to lazily resolve remotename entries
|
||||||
|
|
||||||
|
We are doing that because remotenames startup was slow.
|
||||||
|
We read the remotenames file once to figure out the potential entries
|
||||||
|
and store them in self.potentialentries. Then when asked to resolve an
|
||||||
|
entry, if it is not in self.potentialentries, then it isn't there, if it
|
||||||
|
is in self.potentialentries we resolve it and store the result in
|
||||||
|
self.cache. We cannot be lazy is when asked all the entries (keys).
|
||||||
|
"""
|
||||||
|
def __init__(self, kind, repo):
|
||||||
|
self.cache = {}
|
||||||
|
self.potentialentries = {}
|
||||||
|
self._kind = kind # bookmarks or branches
|
||||||
|
self._repo = repo
|
||||||
|
self._load()
|
||||||
|
|
||||||
|
def _load(self):
|
||||||
|
"""Read the remotenames file, store entries matching selected kind"""
|
||||||
|
repo = self._repo
|
||||||
|
alias_default = repo.ui.configbool('remotenames', 'alias.default')
|
||||||
|
for node, nametype, remote, rname in readremotenames(repo):
|
||||||
|
if nametype != self._kind:
|
||||||
|
continue
|
||||||
|
# handle alias_default here
|
||||||
|
if remote != "default" and rname == "default" and alias_default:
|
||||||
|
name = remote
|
||||||
|
else:
|
||||||
|
name = joinremotename(remote, rname)
|
||||||
|
self.potentialentries[name] = (node, nametype, remote, rname)
|
||||||
|
|
||||||
|
def _resolvedata(self, potentialentry):
|
||||||
|
"""Check that the node for potentialentry exists and return it"""
|
||||||
|
if not potentialentry in self.potentialentries:
|
||||||
|
return None
|
||||||
|
node, nametype, remote, rname = self.potentialentries[potentialentry]
|
||||||
|
repo = self._repo
|
||||||
|
binnode = bin(node)
|
||||||
|
# if the node doesn't exist, skip it
|
||||||
|
try:
|
||||||
|
repo.changelog.rev(binnode)
|
||||||
|
except LookupError:
|
||||||
|
return None
|
||||||
|
# Skip closed branches
|
||||||
|
if (nametype == 'branches' and _branchesenabled(repo.ui) and
|
||||||
|
repo[binnode].closesbranch()):
|
||||||
|
return None
|
||||||
|
return [binnode]
|
||||||
|
|
||||||
|
def __getitem__(self, key):
|
||||||
|
val = self._fetchandcache(key)
|
||||||
|
if val is not None:
|
||||||
|
return val
|
||||||
|
else:
|
||||||
|
raise KeyError()
|
||||||
|
|
||||||
|
def _fetchandcache(self, key):
|
||||||
|
if key in self.cache:
|
||||||
|
return self.cache[key]
|
||||||
|
val = self._resolvedata(key)
|
||||||
|
if val is not None:
|
||||||
|
self.cache[key] = val
|
||||||
|
return val
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def keys(self):
|
||||||
|
for u in self.potentialentries.keys():
|
||||||
|
self._fetchandcache(u)
|
||||||
|
return self.cache.keys()
|
||||||
|
|
||||||
class remotenames(dict):
|
class remotenames(dict):
|
||||||
"""This class encapsulates all the remotenames state. It also contains
|
"""This class encapsulates all the remotenames state. It also contains
|
||||||
methods to access that state in convenient ways. Remotenames are lazy
|
methods to access that state in convenient ways. Remotenames are lazy
|
||||||
@ -219,9 +291,8 @@ class remotenames(dict):
|
|||||||
|
|
||||||
def clearnames(self):
|
def clearnames(self):
|
||||||
"""Clear all remote names state"""
|
"""Clear all remote names state"""
|
||||||
|
self['bookmarks'] = lazyremotenamedict("bookmarks", self._repo)
|
||||||
self['bookmarks'] = {}
|
self['branches'] = lazyremotenamedict("branches", self._repo)
|
||||||
self['branches'] = {}
|
|
||||||
self._invalidatecache()
|
self._invalidatecache()
|
||||||
self._loadednames = False
|
self._loadednames = False
|
||||||
|
|
||||||
@ -231,43 +302,7 @@ class remotenames(dict):
|
|||||||
self._node2hoists = None
|
self._node2hoists = None
|
||||||
self._node2branch = None
|
self._node2branch = None
|
||||||
|
|
||||||
def _loadremotenames(self):
|
|
||||||
|
|
||||||
repo = self._repo
|
|
||||||
alias_default = repo.ui.configbool('remotenames', 'alias.default')
|
|
||||||
# About to repopulate remotenames, clear them out
|
|
||||||
self.clearnames()
|
|
||||||
|
|
||||||
for node, nametype, remote, rname in readremotenames(repo):
|
|
||||||
# handle alias_default here
|
|
||||||
if remote != "default" and rname == "default" and alias_default:
|
|
||||||
name = remote
|
|
||||||
else:
|
|
||||||
name = joinremotename(remote, rname)
|
|
||||||
|
|
||||||
binnode = bin(node)
|
|
||||||
# if the node doesn't exist, skip it
|
|
||||||
try:
|
|
||||||
repo.changelog.rev(binnode)
|
|
||||||
except LookupError:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Skip closed branches
|
|
||||||
if (nametype == 'branches' and _branchesenabled(repo.ui) and
|
|
||||||
repo[binnode].closesbranch()):
|
|
||||||
continue
|
|
||||||
|
|
||||||
nodes = self[nametype].get(name, [])
|
|
||||||
nodes.append(binnode)
|
|
||||||
self[nametype][name] = nodes
|
|
||||||
|
|
||||||
def _loadremotenameslazily(self):
|
|
||||||
if not self._loadednames:
|
|
||||||
self._loadremotenames()
|
|
||||||
self._loadednames = True
|
|
||||||
|
|
||||||
def mark2nodes(self):
|
def mark2nodes(self):
|
||||||
self._loadremotenameslazily()
|
|
||||||
return self['bookmarks']
|
return self['bookmarks']
|
||||||
|
|
||||||
def node2marks(self):
|
def node2marks(self):
|
||||||
@ -301,7 +336,6 @@ class remotenames(dict):
|
|||||||
return self._node2hoists
|
return self._node2hoists
|
||||||
|
|
||||||
def branch2nodes(self):
|
def branch2nodes(self):
|
||||||
self._loadremotenameslazily()
|
|
||||||
return self['branches']
|
return self['branches']
|
||||||
|
|
||||||
def node2branch(self):
|
def node2branch(self):
|
||||||
|
Loading…
Reference in New Issue
Block a user