diff --git a/hgext3rd/perftweaks.py b/hgext3rd/perftweaks.py --- a/hgext3rd/perftweaks.py +++ b/hgext3rd/perftweaks.py @@ -26,12 +26,14 @@ util, ) from mercurial.extensions import wrapfunction -from mercurial.node import bin, nullid, nullrev +from mercurial.node import bin, hex, nullid, nullrev import errno import os testedwith = 'ships-with-fb-hgext' +cachedirname = 'noderevsmap' + def extsetup(ui): wrapfunction(tags, '_readtagcache', _readtagcache) wrapfunction(merge, '_checkcollision', _checkcollision) @@ -66,7 +68,7 @@ def reposetup(ui, repo): if repo.local() is not None: - _preloadrevs(repo) + _preloadrevmap(repo) def _readtagcache(orig, ui, repo): """Disables reading tags if the repo is known to not contain any.""" @@ -114,19 +116,19 @@ def _branchmapwrite(orig, self, repo): result = orig(self, repo) if repo.ui.configbool('perftweaks', 'cachenoderevs', True): - revs = set() + revs = {} nodemap = repo.changelog.nodemap for branch, heads in self.iteritems(): - revs.update(nodemap[n] for n in heads) + revs.update((nodemap[n], n) for n in heads) name = 'branchheads-%s' % repo.filtername - _savepreloadrevs(repo, name, revs) + _savenoderevmap(repo, name, revs) return result def _saveremotenames(orig, repo, remotepath, branches=None, bookmarks=None): result = orig(repo, remotepath, branches=branches, bookmarks=bookmarks) if repo.ui.configbool('perftweaks', 'cachenoderevs', True): - revs = set() + revs = {} nodemap = repo.changelog.nodemap if bookmarks: for b, n in bookmarks.iteritems(): @@ -135,28 +137,28 @@ # changelog yet. It filters them internally, but we need to as # well. if n in nodemap: - revs.add(nodemap[n]) + revs[nodemap[n]] = n if branches: for branch, nodes in branches.iteritems(): for n in nodes: if n in nodemap: - revs.add(nodemap[n]) + revs[nodemap[n]] = n name = 'remotenames-%s' % remotepath - _savepreloadrevs(repo, name, revs) + _savenoderevmap(repo, name, revs) return result def _editphases(orig, self, repo, tr, *args): result = orig(self, repo, tr, *args) def _write(fp): - revs = set() + revs = {} nodemap = repo.changelog.nodemap for phase, roots in enumerate(self.phaseroots): for n in roots: if n in nodemap: - revs.add(nodemap[n]) - _savepreloadrevs(repo, 'phaseroots', revs) + revs[nodemap[n]] = n + _savenoderevmap(repo, 'phaseroots', revs) # We don't actually use the transaction file generator. It's just a hook so # we can write out at the same time as phases. @@ -198,42 +200,37 @@ return True def _cachefilename(name): - return 'noderevs/%s' % name + return '/'.join((cachedirname, name)) -def _preloadrevs(repo): +def _preloadrevmap(repo): # Preloading the node-rev map for likely to be used revs saves 100ms on # every command. This is because normally to look up a node, hg has to scan # the changelog.i file backwards, potentially reading through hundreds of # thousands of entries and building a cache of them. Looking up a rev # however is fast, because we know exactly what offset in the file to read. # Reading old commits is common, since the branchmap needs to to convert old - # branch heads from node to rev. + # branch heads from node to rev. To avoid touching the older parts of the + # index file, we just prepopulate the node to rev map. if repo.ui.configbool('perftweaks', 'cachenoderevs', True): - repo = repo.unfiltered() - revs = set() - cachedir = repo.vfs.join('cache', 'noderevs') + cachedir = repo.vfs.join('cache', cachedirname) try: + nodemap = repo.changelog.nodemap + maxrev = len(repo.changelog) for cachefile in os.listdir(cachedir): filename = _cachefilename(cachefile) - revs.update(int(r) for r in repo.cachevfs(filename)) - - getnode = repo.changelog.node - nodemap = repo.changelog.nodemap - for r in revs: - try: - node = getnode(r) - nodemap[node] = r - except (IndexError, ValueError): - # Rev no longer exists or rev is out of range - pass + for line in repo.cachevfs(filename): + revstr, _, node = line.partition(':') + rev = int(revstr) + if rev < maxrev: + nodemap[bin(node.strip())] = rev except EnvironmentError: # No permission to read? No big deal pass -def _savepreloadrevs(repo, name, revs): +def _savenoderevmap(repo, name, revs): if repo.ui.configbool('perftweaks', 'cachenoderevs', True): - cachedir = repo.vfs.join('cache', 'noderevs') + cachedir = repo.vfs.join('cache', cachedirname) try: repo.vfs.mkdir(cachedir) except OSError as ex: @@ -246,7 +243,8 @@ try: filename = _cachefilename(name) f = repo.cachevfs.open(filename, mode='w+', atomictemp=True) - f.write('\n'.join(str(r) for r in revs)) + for r, n in revs.iteritems(): + f.write('%s:%s\n' % (r, hex(n))) f.close() except EnvironmentError: # No permission to write? No big deal diff --git a/tests/test-perftweaks.t b/tests/test-perftweaks.t --- a/tests/test-perftweaks.t +++ b/tests/test-perftweaks.t @@ -113,7 +113,7 @@ $ cd repo $ touch a $ hg commit -qAm a - $ ls -la .hg/cache/noderevs/ + $ ls -la .hg/cache/noderevsmap/ total * (glob) drwxrw[sx]r-x.? [0-9]+ .* \. (re) drwxrw[sx]r-x.? [0-9]+ .* \.\. (re)