Cache Invalidation

Step 5: Cache Invalidation

Caches lie eventually. When the underlying data changes, a stale cached entry must be dropped so the next read goes back to the source. Add an invalidate method that evicts a single key.

After invalidating a key, the next fetch for it is a cache miss again, the proxy rebuilds nothing, but it does call the real service once more, so the call counter climbs.

  • Proxy.invalidate(key). Remove key from the cache if present; do nothing if it was never cached

Invalidating a key that is not in the cache must be harmless, no error.

Hints
Starter code
class RealService:
    def __init__(self, backend):
        self.backend = dict(backend)
        self.calls = 0

    def fetch(self, key):
        self.calls += 1
        return self.backend.get(key)


class Proxy:
    def __init__(self, backend, allowed=None):
        self._backend = dict(backend)
        self._real = None
        self._cache = {}
        self._allowed = allowed

    def _ensure_real(self):
        if self._real is None:
            self._real = RealService(self._backend)

    def _is_allowed(self, key):
        return self._allowed is None or key in self._allowed

    def fetch(self, key):
        if not self._is_allowed(key):
            return None
        if key in self._cache:
            return self._cache[key]
        self._ensure_real()
        value = self._real.fetch(key)
        self._cache[key] = value
        return value

    def invalidate(self, key):
        """Drop key from the cache so the next fetch re-hits the service."""
        # TODO: self._cache.pop(key, None)
        pass
Write it on a laptop

The editor and the test runner need a wide screen. Open this page on a desktop browser and your progress will be waiting.