Overview
The caching framework centers aroundArgCache, which handles:
- Function-level cache parameterization by arguments
- Automatic cache key generation from Python objects
- Dependency tracking and propagation
- Bulk invalidation through tokens and signatures
Key Concepts
ArgCache
The core class that manages cached functions. AnArgCache contains a cache parameterized by a list of arguments and exports a similar API to Django’s cache objects, but keys are lists of Python objects rather than strings.
Invalidation Strategy
The framework uses a signature-based invalidation system:- Each cache entry stores a value along with a signature
- Before returning a value, the signature is checked for validity
- Invalid signatures cause the cache to behave as if the value never existed
- Signatures are computed from shared tokens that allow bulk invalidation
Key Sets
Key sets represent groups of cache keys using dictionaries that map argument names to sets of objects. They support:- Wildcard values (matches everything)
- Specific objects (exact matches)
- Cartesian products of argument sets
Tokens
Tokens generate signatures for cache entries and enable efficient bulk invalidation. EachArgCache maintains a list of tokens that:
- Generate signatures based on cache keys
- Know how to invalidate specific classes of key sets
- Enable targeted cache clearing without invalidating everything
Using the Cache Decorator
The simplest way to use caching is through the@cache_function decorator:
Creating Tokens
Tokens allow efficient invalidation of cache subsets:Managing Dependencies
The framework provides methods to automatically invalidate caches when data changes:depend_on_row
Invalidate when a database row changes:Use lambda expressions for model references to avoid circular import issues, since dependencies are processed after all modules load.
depend_on_cache
Invalidate based on changes to other caches:- Default arguments capture wildcard values
**kwargscaptures unknown or irrelevant arguments- Return a dictionary specifying which keys to invalidate
depend_on_m2m
Invalidate when many-to-many relationships change:Complete Example
Here’s a fully configured cached function:Best Practices
Split Functions for Caching
Split Functions for Caching
Since caching works at function-level granularity, split large functions into smaller cacheable pieces. Each function should ideally be side-effect free.
Use Lambdas for Forward References
Use Lambdas for Forward References
When referencing models before they’re defined, wrap them in lambdas:
Handle Wildcards in Mappings
Handle Wildcards in Mappings
When writing cache dependency mappings, wildcard operations return wildcards (similar to NaN), so you rarely need explicit checks.
Create Appropriate Tokens
Create Appropriate Tokens
Create tokens that match your invalidation patterns. More specific tokens allow more targeted cache clearing.
Cache Loader
Dependency processing is delayed until after all modules load via theesp.cache_loader module, which must be loaded last. After it runs, defining new caches becomes an error.
Implementation Notes
- Keys are intentionally independent of tokens to enable
get_manybulk operations - The
marinademodule handles stringifying Python objects into cache keys - Cache signatures are stored as tuples with the cached value
- The system uses Django’s signal framework for dependency notifications
Related
- See
esp/esp/tagdict/models.pyfor examples of@cache_functionusage - See
esp/esp/dbmail/models.pyfor cache dependencies on model changes