obsolete: document the cache stuff
authorPierre-Yves David <pierre-yves.david@logilab.fr>
Wed, 08 Aug 2012 11:54:27 +0200
changeset 450 4d18739b506b
parent 449 4f23f224afb4
child 451 dc1bd3595075
obsolete: document the cache stuff
hgext/obsolete.py
--- a/hgext/obsolete.py	Wed Aug 08 11:10:43 2012 +0200
+++ b/hgext/obsolete.py	Wed Aug 08 11:54:27 2012 +0200
@@ -67,6 +67,7 @@
 # This extension hold the following code
 #
 # - Extension Helper code
+# - Obsolescence cache
 # - ...
 # - Older format compat
 
@@ -305,14 +306,35 @@
 ### Obsolescence Caching Logic                                    ###
 #####################################################################
 
-### compute cache functions
+# Obsolescence related logic can be very slow if we don't have efficient cache.
+#
+# This section implements a cache mechanism that did not make it into core for
+# time reason. It store meaningful set of revision related to obsolescence
+# (obsolete, unstabletble ...
+#
+# Here is:
+#
+# - Computation of meaningful set,
+# - Cache access logic,
+# - Cache invalidation logic,
+# - revset and ctx using this cache.
+#
 
-computecache = {}
+
+### Computation of meaningful set
+#
+# Most set can be computed with "simple" revset.
+
+#: { set name -> function to compute this set } mapping
+#:   function take a single "repo" argument.
+#:
+#: Use the `cachefor` decorator to register new cache function
+cachefuncs = {}
 def cachefor(name):
     """Decorator to register a function as computing the cache for a set"""
     def decorator(func):
-        assert name not in computecache
-        computecache[name] = func
+        assert name not in cachefuncs
+        cachefuncs[name] = func
         return func
     return decorator
 
@@ -348,36 +370,63 @@
     obsstore.caches = {}
     return orig(obsstore, *args, **kwargs)
 
+### Cache access
+
 def getobscache(repo, name):
+    """Return the set of revision that belong to the <name> set
+
+    Such access may compute the set and cache it for future use"""
     if not repo.obsstore:
         return ()
     if name not in repo.obsstore.caches:
-        repo.obsstore.caches[name] = computecache[name](repo)
+        repo.obsstore.caches[name] = cachefuncs[name](repo)
     return repo.obsstore.caches[name]
 
+### Cache clean up
+#
+# To be simple we need to invalidate obsolescence cache when:
+#
+# - new changeset is added:
+# - public phase is changed
+# - obsolescence marker are added
+# - strip is used a repo
+
 
-### cache clean up
 def clearobscaches(repo):
-    """"""
+    """Remove all obsolescence related cache from a repo
+
+    This remove all cache in obsstore is the obsstore already exist on the
+    repo.
+
+    (We could be smarter here)"""
     if 'obsstore' in repo._filecache:
         repo.obsstore.caches.clear()
 
-@eh.wrapfunction(localrepo.localrepository, 'updatebranchcache')
-@eh.wrapfunction(phases, 'advanceboundary')
+@eh.wrapfunction(localrepo.localrepository, 'addchangegroup')  # new changeset
+@eh.wrapfunction(phases, 'retractboundary')  # phase movement
+@eh.wrapfunction(phases, 'advanceboundary')  # phase movement
+@eh.wrapfunction(localrepo.localrepository, 'destroyed')  # strip
 def wrapclearcache(orig, repo, *args, **kwargs):
     try:
         return orig(repo, *args, **kwargs)
     finally:
+        # we are a bit wide here
+        # we could restrict to:
+        # advanceboundary + phase==public
+        # retractboundary + phase==draft
         clearobscaches(repo)
 
-@eh.wrapfunction(obsolete.obsstore, 'add')
+@eh.wrapfunction(obsolete.obsstore, 'add')  # new marker
 def clearonadd(orig, obsstore, *args, **kwargs):
     try:
         return orig(obsstore, *args, **kwargs)
     finally:
         obsstore.caches.clear()
 
-### cache user
+### Use the case
+# Function in core that could benefic from the cache are overwritten by cache using version
+
+# changectx method
 
 @eh.addattr(context.changectx, 'unstable')
 def unstable(ctx):
@@ -394,6 +443,8 @@
         return False
     return ctx.rev() in getobscache(ctx._repo, 'extinct')
 
+# revset
+
 @eh.revset('obsolete')
 def revsetobsolete(repo, subset, x):
     """``obsolete()``