CacheStack

A CacheStack allows combining multiple caches into a single prioritized hierarchy. It is a common pattern to combine a fast, local cache (like an in-memory cache) with a larger, slower, and potentially remote cache (like a database or file system).

Automatic Hit Transfer

Whenever a hit is found in a higher-level cache, it is automatically transferred to the base cache (index 0). This ensures that frequently accessed data migrates to the fastest cache in your stack.

[1]:
import tempfile
import os
from fleche import fleche, cache
from fleche.caches import Cache, CacheStack
from fleche.storage import Memory, PickleFile
from fleche.storage.sql import Sql

# 1. Setup a 'remote' persistent cache
tmp_dir = tempfile.TemporaryDirectory()
# Use PickleFile for values and Sql for calls to simulate a robust remote storage
remote_storage_values = PickleFile.with_cloudpickle(tmp_dir.name)
remote_storage_calls = Sql(f"sqlite:///{os.path.join(tmp_dir.name, 'cache.db')}")
remote_cache = Cache(remote_storage_values, remote_storage_calls)

# 2. Setup a 'local' fast memory cache
local_cache = Cache(Memory({}), Memory({}))

@fleche
def expensive_computation(x):
    print(f"Computing {x}...")
    return x * 10

# Pre-populate the remote cache
with cache(remote_cache):
    expensive_computation(42)

print("Remote cache contains 42:", remote_cache.contains(expensive_computation.digest(42)))
print("Local cache contains 42: ", local_cache.contains(expensive_computation.digest(42)))
No config file found. Using default memory cache.
() ()
Computing 42...
Remote cache contains 42: True
Local cache contains 42:  False

Creating the stack

We prioritize local_cache over remote_cache by putting it at the front of the stack.

[2]:
stack = CacheStack((local_cache, remote_cache))

with cache(stack):
    # Loading 42 will hit remote_cache and automatically transfer it to local_cache
    print("Calling expensive_computation(42) via stack...")
    result = expensive_computation(42)
    print(f"Result: {result}")

print("Local cache now contains 42:", local_cache.contains(expensive_computation.digest(42)))

# Cleanup
tmp_dir.cleanup()
Calling expensive_computation(42) via stack...
Result: 420
Local cache now contains 42: True