perf: adds cachekey utility to validate changelog+obsstore content
authorPierre-Yves David <pierre-yves.david@ens-lyon.org>
Mon, 01 May 2017 08:07:05 +0200
changeset 2295 017b971ba28f
parent 2294 75996eafab43
child 2296 d6584ce58030
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)
hgext3rd/evolve/obscache.py
--- 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