Source code for fictive.cache.multilevel

"""
Chain together multiple caches for tiered cacheing strategy

"""

import typing

from fictive.cache.abstract import AbstractCache


[docs]class MultilevelCache(AbstractCache): """ Manage multiple levels of a value cache hierarchy Chain together one or more `AbstractCache` instances to cache a value at multiple storage levels """ # pylint: disable=too-few-public-methods
[docs] class MultilevelCacheMissError(AbstractCache.CacheMissError): """ raised in a cache miss propogates through all cache levels """
[docs] def __init__(self, cache_levels: typing.Sequence, *args, **kwargs): """ :param cache_levels: `AbstractCache` implementation(s); cache(s) will be accessed hierarchically in the provided order """ super(MultilevelCache, self).__init__(**kwargs) self.cache_levels = cache_levels for cache_level in self.cache_levels: cache_level.fetch_impl = self._fetch_next
def _fetch_next(self, cache, *args, **kwargs): """ Trampoline to chain a cache's `fetch_impl` to the next cache's `get_value` """ next_index = self.cache_levels.index(cache) + 1 if next_index < len(self.cache_levels): return self.cache_levels[next_index].get_value(*args, **kwargs) return self.fetch_impl(*args, **kwargs) # pylint: disable=not-callable def _read_impl(self, *args, **kwargs): """ read the lowest level of the cache levels """ return self.cache_levels[0].get_value(*args, **kwargs) def _dispatch_fetch(self, *args, **kwargs): """ fetching handled by cache levels """ raise self.MultilevelCacheMissError() def _set_impl(self, value, *args, **kwargs): """ set the highest level of the cache and then clear the lower levels """ self.cache_levels[-1].set_value(value, *args, **kwargs) for cache_level in reversed(self.cache_levels[:-1]): cache_level.delete_value(cache_level.ANY_VALUE) def _delete_impl(self, cache_value, *args, **kwargs): """ clear all levels of the cache """ any_deleted = False for cache_level in self.cache_levels: level_deleted = cache_level.delete_value(cache_value) if level_deleted: any_deleted = True if level_deleted or cache_value == self.ANY_VALUE: continue return any_deleted return any_deleted