Patchwork [13,of,14] cache: add a way to check if a cache is up to date

login
register
mail settings
Submitter Boris Feld
Date July 9, 2017, 5:55 p.m.
Message ID <7774ff78ef2e74333681.1499622925@FB>
Download mbox | patch
Permalink /patch/22174/
State Changes Requested
Headers show

Comments

Boris Feld - July 9, 2017, 5:55 p.m.
# HG changeset patch
# User Boris Feld <boris.feld@octobus.net>
# Date 1499565372 -7200
#      Sun Jul 09 03:56:12 2017 +0200
# Node ID 7774ff78ef2e7433368184e7de743342b771b91c
# Parent  3a93e99b0e718befd57a32615a14fd0d3c194456
# EXP-Topic obs-cache
cache: add a way to check if a cache is up to date

This will be useful to decide if a cache can be used as-is or not.

Patch

diff -r 3a93e99b0e71 -r 7774ff78ef2e mercurial/cache.py
--- a/mercurial/cache.py	Fri May 19 14:47:01 2017 +0200
+++ b/mercurial/cache.py	Sun Jul 09 03:56:12 2017 +0200
@@ -80,6 +80,15 @@ 
         raise NotImplementedError
 
     @abc.abstractmethod
+    def _uptodate(self, repo):
+        """True if the cache is up to date with the repository
+
+        This function is for overriding only. Use the public 'uptodate(repo)'
+        for actual usage.
+        """
+        raise NotImplementedError
+
+    @abc.abstractmethod
     def _fetchupdatedata(self, repo):
         """Check the source for possible changes and return necessary data
 
@@ -98,6 +107,12 @@ 
 
     # Useful "public" function (no need to override them)
 
+    def uptodate(self, repo):
+        """True if the cache is up to date with the repository"""
+        if self._cachekey is None:
+            self.load(repo)
+        return self._uptodate(repo)
+
     def update(self, repo):
         """update the cache with new repository data
 
@@ -168,6 +183,17 @@ 
         else:
             return False, list(cl.revs(start=keyrev + 1, stop=tiprev)), newkey
 
+    def _checkchangelogkey(self, cachekey, cl):
+        # Exists as its own method to help subclass to reuse it.
+        tiprev = len(cl) - 1
+        tipnode = cl.node(tiprev)
+        newkey = (tiprev, tipnode)
+        tiprev = len(cl) - 1
+        return newkey == cachekey
+
+    def _uptodate(self, repo):
+        return self._checkchangelogkey(self._cachekey, repo.changelog)
+
     def _fetchupdatedata(self, repo):
         return self._fetchchangelogdata(self._cachekey, repo.changelog)
 
@@ -188,6 +214,9 @@ 
     _cachekeyspec = 'I20s'
     _cachename = None # used for debug message
 
+    def _uptodate(self, repo):
+        return repo.obsstore.matchcontentkey(self._cachekey)
+
     def _fetchupdatedata(self, repo):
         return repo.obsstore.getmarkerssince(self._cachekey)
 
@@ -210,6 +239,10 @@ 
                      + obsstoresourcebase._cachekeyspec)
     _cachename = None # used for debug message
 
+    def _uptodate(self, repo):
+        return (self._checkchangelogkey(self._cachekey, repo.changelog)
+                and repo.obsstore.matchcontentkey(self._cachekey))
+
     def _fetchupdatedata(self, repo):
         clkey = self._cachekey[0:2]
         obskey = self._cachekey[2:4]
diff -r 3a93e99b0e71 -r 7774ff78ef2e mercurial/obsolete.py
--- a/mercurial/obsolete.py	Fri May 19 14:47:01 2017 +0200
+++ b/mercurial/obsolete.py	Sun Jul 09 03:56:12 2017 +0200
@@ -547,6 +547,21 @@ 
 
     __bool__ = __nonzero__
 
+    def matchcontentkey(self, key):
+        """provide the cachekey (as usable by """
+        keysize, keyhash = key
+        # XXX This function could avoid loading the whole data from disk (and
+        # only read new markers). It currently use 'self._data' to keep the
+        # code simpler.
+        fulldata = self._data
+        currentsize = len(fulldata)
+        if currentsize != keysize:
+            return False
+        first = max(0, keysize - self._obskeyspan)
+        keydata = fulldata[first:keysize]
+        actualhash = hashlib.sha1(keydata).digest()
+        return actualhash == keyhash
+
     def getmarkerssince(self, previouscontentkey):
         """retrieve all new markers (since "contentkey") + updated content key