[PATCH 04 of 18] phases: add to cache allowing to know in which state a changeset is
pierre-yves.david at logilab.fr
pierre-yves.david at logilab.fr
Mon Oct 10 07:28:00 CDT 2011
# HG changeset patch
# User Pierre-Yves David <pierre-yves.david at logilab.fr>
# Date 1318239224 -7200
# Node ID b26e7c7e3ebbcab5f6a7f4bf376b66056b0bb506
# Parent c48674734436d256c467145bc5acaa6fa675b887
phases: add to cache allowing to know in which state a changeset is
diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -169,10 +169,20 @@ class localrepository(repo.repository):
@filecache('phases-heads')
def _phasesheads(self):
return phases.readheads(self)
+ @propertycache
+ def _phasesrev(self):
+ data = phases.readcache(self)
+ if data is None:
+ phases.writecache(self)
+ data = phases.readcache(self)
+ assert data is not None
+ return data
+
+
@filecache('00changelog.i', True)
def changelog(self):
c = changelog.changelog(self.sopener)
if 'HG_PENDING' in os.environ:
p = os.environ['HG_PENDING']
@@ -442,10 +452,14 @@ class localrepository(repo.repository):
for bookmark, n in self._bookmarks.iteritems():
if n == node:
marks.append(bookmark)
return sorted(marks)
+ def nodephase(self, node):
+ """return the node associated to a phase"""
+ return self._phasesrev.get(self.changelog.rev(node), phases.allphases[-1])
+
def _branchtags(self, partial, lrev):
# TODO: rename this function?
tiprev = len(self) - 1
if lrev != tiprev:
ctxgen = (self[r] for r in xrange(lrev + 1, tiprev + 1))
diff --git a/mercurial/phases.py b/mercurial/phases.py
--- a/mercurial/phases.py
+++ b/mercurial/phases.py
@@ -5,11 +5,15 @@
# Augie Fackler <durin42 at gmail.com>
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-from node import nullid
+import os
+from operator import add
+
+import util
+from node import nullid, hex, bin
allphases = range(2)
trackedphases = allphases[:-1]
### I/O code
@@ -31,13 +35,68 @@ def readheads(repo):
if not heads[0]:
heads[0].add(nullid)
return heads
def writeheads(repo):
- """Write phrases head from disk"""
+ """Write phrases head on disk
+ Also invalidate the phases cache.
+ """
f = repo.sopener('phrases-heads', 'w', atomictemp=True)
try:
- for phrase, heads in enumerate(repo._phraseheads):
+ for phrase, heads in enumerate(repo._phasesheads):
for h in heads:
f.write('%i %s\n' % (phrase, hex(h)))
finally:
f.close()
+ invalidatecache(repo)
+
+### Changeset phase cache
+##############################
+
+
+def _computecache(repo):
+ """compute a {rev => phase} mapping"""
+ cache = {}
+ for rev in repo.changelog:
+ cache[rev] = allphases[-1]
+ for phase in reversed(trackedphases):
+ heads = map(repo.changelog.rev, repo._phasesheads[phase])
+ for rev in heads:
+ cache[rev] = phase
+ for rev in repo.changelog.ancestors(*heads):
+ cache[rev] = phase
+ return cache
+
+def writecache(repo):
+ """Compute and write phases cache on disk"""
+ cachedata = _computecache(repo)
+ f = repo.opener('cache/phases', 'w', atomictemp=True)
+ try:
+ for rev, phase in cachedata.iteritems():
+ f.write('%i %i\n' % (rev, phase))
+ finally:
+ f.close()
+
+def readcache(repo):
+ """read phases cache on disk.
+
+ return None if no cache is found.
+ """
+ cachedata = {}
+ try:
+ f = repo.opener('cache/phases')
+ try:
+ for line in f:
+ revstr, phasestr = line.strip().split()
+ cachedata[int(revstr)] = int(phasestr)
+ finally:
+ f.close()
+ except IOError:
+ cachedata = None
+ return cachedata
+
+def invalidatecache(repo):
+ """Invalidate phase cache"""
+ if os.path.exists(repo.join('cache/phases')):
+ util.unlink(repo.join('cache/phases'))
+ if '_phasesrev' in vars(repo):
+ del repo._phasesrev # clear property cache
More information about the Mercurial-devel
mailing list