[PATCH 01 of 14] cache: introduce an abstract class for cache we can upgrade incrementally

Gregory Szorc gregory.szorc at gmail.com
Sun Jul 9 16:32:43 EDT 2017


On Sun, Jul 9, 2017 at 10:52 AM, Boris Feld <boris.feld at octobus.net> wrote:

> # HG changeset patch
> # User Boris Feld <boris.feld at octobus.net>
> # Date 1499458441 -7200
> #      Fri Jul 07 22:14:01 2017 +0200
> # Node ID 6edb62505c697329de034c2fdc47befd5896f31f
> # Parent  89796a25d4bb91fb418ad3e70faad2c586902ffb
> # EXP-Topic obs-cache
> cache: introduce an abstract class for cache we can upgrade incrementally
>
> Right now each class implements their own mechanism for validation, and
> update. We start introducing abstract class to ultimately allow more
> unification of the cache code.
>
> The end goal of this series is to introduce a cache for some obsolescence
> property, not to actually implement the cache. However, taking advantage of
> adding a new cache to introduce the abstract class seems like a win.
>

I don't like saying this, but given the amount of discussion these patches
generated the last time they were proposed and given the proximity to the
code freeze, I doubt these will land in 4.3.

Would you be willing to voluntarily withdrawal them from consideration for
4.3? Or if there are less contentious patches/functionality that you would
like to land in 4.3, would you be willing to pair down the series to the
simpler/less-contentious patches so we can focus on 4.3?


>
> diff -r 89796a25d4bb -r 6edb62505c69 mercurial/cache.py
> --- /dev/null   Thu Jan 01 00:00:00 1970 +0000
> +++ b/mercurial/cache.py        Fri Jul 07 22:14:01 2017 +0200
> @@ -0,0 +1,127 @@
> +# cache.py - utilities for caching
> +#
> +# Copyright 2017 Octobus SAS <contact at octobus.net>
> +#
> +# This software may be used and distributed according to the terms of the
> +# GNU General Public License version 2 or any later version.
> +from __future__ import absolute_import
> +
> +import abc
> +import struct
> +
> +from . import (
> +    util,
> +)
> +
> +class incrementalcachebase(object):
> +    """base class for incremental cache from append only source
> +
> +    There are multiple append only data source we might want to cache
> +    computation from. One of the common pattern is to track the state of
> the
> +    file and update the cache with the extra data (eg: branchmap-cache
> tracking
> +    changelog). This pattern also needs to detect when a the source is
> striped
> +
> +    The overall pattern is similar whatever the actual source is. This
> class
> +    introduces the basic patterns.
> +    """
> +
> +    __metaclass__ = abc.ABCMeta
> +
> +    # default key used for an empty cache
> +    emptykey = ()
> +
> +    _cachekeyspec = '' # used for serialization
> +    _cachename = None # used for debug message
> +
> +    @abc.abstractmethod
> +    def __init__(self):
> +        super(incrementalcachebase, self).__init__()
> +        self._cachekey = None
> +
> +    @util.propertycache
> +    def _cachekeystruct(self):
> +        # dynamic property to help subclass to change it
> +         return struct.Struct('>' + self._cachekeyspec)
> +
> +    @util.propertycache
> +    def _cachekeysize(self):
> +        # dynamic property to help subclass to change it
> +        return self._cachekeystruct.size
> +
> +    @abc.abstractmethod
> +    def _updatefrom(self, repo, data):
> +        """override this method to update you date from incrementally
> read data.
> +
> +        Content of <data> will depends of the sources.
> +        """
> +        raise NotImplementedError
> +
> +    @abc.abstractmethod
> +    def clear(self, reset=False):
> +        """invalidate the cache content
> +
> +        if 'reset' is passed, we detected a strip and the cache will have
> to be
> +        recomputed.
> +
> +        Subclasses MUST overide this method to actually affect the cache
> data.
> +        """
> +        if reset:
> +            self._cachekey = self.emptykey if reset else None
> +        else:
> +            self._cachekey = None
> +
> +    @abc.abstractmethod
> +    def load(self, repo):
> +        """Load data from disk
> +
> +        Subclasses MUST restore the "cachekey" attribute while doing so.
> +        """
> +        raise NotImplementedError
> +
> +    @abc.abstractmethod
> +    def _fetchupdatedata(self, repo):
> +        """Check the source for possible changes and return necessary data
> +
> +        The return is a tree elements tuple: reset, data, cachekey
> +
> +        * reset: `True` when a strip is detected and cache need to be
> reset
> +        * data: new data to take in account, actual type depends of the
> source
> +        * cachekey: the cache key covering <data> and precious covered
> data
> +        """
> +        raise NotImplementedError
> +
> +    # Useful "public" function (no need to override them)
> +
> +    def update(self, repo):
> +        """update the cache with new repository data
> +
> +        The update will be incremental when possible"""
> +        repo = repo.unfiltered()
> +
> +        # If we do not have any data, try loading from disk
> +        if self._cachekey is None:
> +            self.load(repo)
> +
> +        reset, data, newkey = self._fetchupdatedata(repo)
> +        if newkey == self._cachekey:
> +            return
> +        if reset or self._cachekey is None:
> +            repo.ui.log('cache', 'strip detected, %s cache reset\n'
> +                        % self._cachename)
> +            self.clear(reset=True)
> +
> +        starttime = util.timer()
> +        self._updatefrom(repo, data)
> +        duration = util.timer() - starttime
> +        repo.ui.log('cache', 'updated %s in %.4f seconds\n',
> +                    self._cachename, duration)
> +
> +        self._cachekey = newkey
> +
> +    def _serializecachekey(self):
> +        """provide a bytes version of the cachekey"""
> +        return self._cachekeystruct.pack(*self._cachekey)
> +
> +    def _deserializecachekey(self, data):
> +        """read the cachekey from bytes"""
> +        return self._cachekeystruct.unpack(data)
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at mercurial-scm.org
> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.mercurial-scm.org/pipermail/mercurial-devel/attachments/20170709/764bbd73/attachment.html>


More information about the Mercurial-devel mailing list