[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