Swapping the Strategy

Step 5 β€” Swapping the Strategy

Because the policy is just an object the cache holds, you can replace it at runtime β€” start with FIFO under light load, switch to LFU when traffic spikes, all without disturbing the cached data. To make the new policy correct, seed it with the keys already in the cache.

  • set_policy(policy) β€” replace the eviction strategy and register every current key with it (in insertion order)
Hints
Starter code
class EvictionPolicy:
    def on_insert(self, key):
        raise NotImplementedError

    def on_access(self, key):
        raise NotImplementedError

    def evict(self):
        raise NotImplementedError


class FIFOPolicy(EvictionPolicy):
    def __init__(self):
        self._order = []

    def on_insert(self, key):
        self._order.append(key)

    def on_access(self, key):
        pass

    def evict(self):
        return self._order.pop(0)


class LRUPolicy(EvictionPolicy):
    def __init__(self):
        self._order = []

    def on_insert(self, key):
        self._order.append(key)

    def on_access(self, key):
        if key in self._order:
            self._order.remove(key)
        self._order.append(key)

    def evict(self):
        return self._order.pop(0)


class LFUPolicy(EvictionPolicy):
    def __init__(self):
        self._counts = {}
        self._order = []

    def on_insert(self, key):
        self._counts[key] = 1
        self._order.append(key)

    def on_access(self, key):
        self._counts[key] = self._counts.get(key, 0) + 1

    def evict(self):
        victim = min(self._order, key=lambda k: self._counts[k])
        self._order.remove(victim)
        del self._counts[victim]
        return victim


class Cache:
    def __init__(self, capacity, policy):
        self.capacity = capacity
        self.policy = policy
        self._store = {}

    def get(self, key):
        if key in self._store:
            self.policy.on_access(key)
            return self._store[key]
        return None

    def put(self, key, value):
        if key in self._store:
            self._store[key] = value
            self.policy.on_access(key)
            return
        if len(self._store) >= self.capacity:
            victim = self.policy.evict()
            del self._store[victim]
        self._store[key] = value
        self.policy.on_insert(key)

    def set_policy(self, policy):
        """Swap the eviction strategy, seeding it with the current keys."""
        # TODO:
        #   self.policy = policy
        #   for key in self._store:
        #       policy.on_insert(key)
        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.