# HG changeset patch # User Pierre-Yves David # Date 1344419667 -7200 # Node ID 4d18739b506b3730673584011c67ab4fc8cc98c2 # Parent 4f23f224afb4e11b430e560d752e8da87cb02a8b obsolete: document the cache stuff diff -r 4f23f224afb4 -r 4d18739b506b 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 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()``