perf: adds cachekey utility to validate changelog+obsstore content
We adds more helper about cache key to prepare the arrival of a cache that can
be updated iteratively (similar to branchmap cache)
--- a/hgext3rd/evolve/obscache.py Mon May 01 08:05:45 2017 +0200
+++ b/hgext3rd/evolve/obscache.py Mon May 01 08:07:05 2017 +0200
@@ -63,3 +63,78 @@
obsstore.__class__ = cachekeyobsstore
return obsstore
+
+def getcachekey(repo):
+ """get a cache key covering the changesets and obsmarkers content
+
+ IT contains the following data. Combined with 'upgradeneeded' it allows to
+ do iterative upgrade for cache depending of theses two data.
+
+ The cache key parts are"
+ - tip-rev,
+ - tip-node,
+ - obsstore-length (nb markers),
+ - obsstore-file-size (in bytes),
+ - obsstore "cache key"
+ """
+ assert repo.filtername is None
+ cl = repo.changelog
+ index, key = repo.obsstore.cachekey()
+ tiprev = len(cl) - 1
+ return (tiprev,
+ cl.node(tiprev),
+ len(repo.obsstore),
+ index,
+ key)
+
+def upgradeneeded(repo, key):
+ """return (valid, start-rev, start-obs-idx)
+
+ 'valid': is "False" if older cache value needs invalidation,
+
+ 'start-rev': first revision not in the cache. None if cache is up to date,
+
+ 'start-obs-idx': index of the first obs-markers not in the cache. None is
+ up to date.
+ """
+
+ # XXX ideally, this function would return a bounded amount of changeset and
+ # obsmarkers and the associated new cache key. Otherwise we are exposed to
+ # a race condition between the time the cache is updated and the new cache
+ # key is computed. (however, we do not want to compute the full new cache
+ # key in all case because we want to skip reading the obsstore content. We
+ # could have a smarter implementation here.
+ #
+ # In pratice the cache should be updated after each transaction within a
+ # lock. So we should be fine. We could enforce this with a new repository
+ # requirement (or fix the race, that is not too hard).
+ invalid = (False, 0, 0)
+ if key is None:
+ return invalid
+
+ ### Is the cache valid ?
+ keytiprev, keytipnode, keyobslength, keyobssize, keyobskey = key
+ # check for changelog strip
+ cl = repo.changelog
+ tiprev = len(cl) - 1
+ if (tiprev < keytiprev
+ or cl.node(keytiprev) != keytipnode):
+ return invalid
+ # check for obsstore strip
+ obssize, obskey = repo.obsstore.cachekey(index=keyobssize)
+ if obskey != keyobskey:
+ return invalid
+
+ ### cache is valid, is there anything to update
+
+ # any new changesets ?
+ startrev = None
+ if keytiprev < tiprev:
+ startrev = keytiprev + 1
+
+ # any new markers
+ startidx = None
+ if keyobssize < obssize:
+ startidx = keyobslength
+
+ return True, startrev, startidx