proxywhirl.cache.tiers¶
Cache tier implementations for multi-tier caching strategy.
Defines: - CacheTier: Abstract base class for cache tier implementations - MemoryCacheTier: L1 in-memory cache using OrderedDict - FileCacheTier: L2 JSONL file cache with encryption and file locking - SQLiteCacheTier: L3 database cache with full persistence
Classes¶
Abstract base class for cache tier implementations. |
|
L2 SQLite-based cache with encryption and indexed lookups. |
|
L2 JSONL file-based cache with sharding and encryption. |
|
L1 in-memory cache using OrderedDict for LRU tracking. |
|
L3 SQLite database cache with encrypted credentials. |
|
Cache tier types. |
Module Contents¶
- class proxywhirl.cache.tiers.CacheTier(config, tier_type)[source]¶
Bases:
abc.ABCAbstract base class for cache tier implementations.
Defines the interface that all cache tiers (L1, L2, L3) must implement, including graceful degradation on repeated failures.
Initialize cache tier with configuration.
- Parameters:
config (proxywhirl.cache.models.CacheTierConfig) – Configuration for this tier
tier_type (TierType) – Type of tier (L1/L2/L3)
- abstractmethod cleanup_expired()[source]¶
Remove all expired entries in bulk.
- Returns:
Number of entries removed
- Return type:
- abstractmethod clear()[source]¶
Clear all entries, return count of removed entries.
- Returns:
Number of entries removed
- Return type:
- abstractmethod get(key)[source]¶
Retrieve entry by key, None if not found or expired.
- Parameters:
key (str) – Cache key to lookup
- Returns:
CacheEntry if found and valid, None otherwise
- Return type:
- handle_failure(error)[source]¶
Handle tier operation failure for graceful degradation.
Increments failure count and disables tier if threshold exceeded. Called by implementations when operations fail.
- Parameters:
error (Exception) – Exception that occurred
- Return type:
None
- abstractmethod put(key, entry)[source]¶
Store entry, return True if successful.
- Parameters:
key (str) – Cache key for entry
entry (proxywhirl.cache.models.CacheEntry) – CacheEntry to store
- Returns:
True if stored successfully, False otherwise
- Return type:
- class proxywhirl.cache.tiers.DiskCacheTier(config, tier_type, cache_dir, encryptor=None)[source]¶
Bases:
CacheTierL2 SQLite-based cache with encryption and indexed lookups.
Optimized for >10K entries using SQLite with B-tree indexes instead of JSONL. Provides O(log n) lookups vs O(n) for JSONL, achieving <10ms reads for 10K+ entries.
Uses a lightweight SQLite database with: - Primary key index on cache key for fast lookups - Encrypted credentials stored as BLOB - Efficient bulk operations (cleanup, size, keys) - File-based persistence without complex sharding - Persistent connection pooling for performance (RES-005)
- Thread Safety:
Uses a threading.Lock to protect connection access. The connection is created with check_same_thread=False to allow multi-threaded access.
Initialize SQLite-based L2 cache.
- Parameters:
config (proxywhirl.cache.models.CacheTierConfig) – Tier configuration
tier_type (TierType) – Type of tier (should be L2_FILE)
cache_dir (pathlib.Path) – Directory for cache database
encryptor (proxywhirl.cache.crypto.CredentialEncryptor | None) – Credential encryptor for username/password
- cleanup_expired()[source]¶
Remove all expired entries from SQLite L2 database using indexed SQL DELETE.
Performs bulk deletion of expired entries in a single SQL operation. Uses the expires_at index for efficient identification.
- Returns:
Number of expired entries that were removed, 0 on error.
- Return type:
- Side Effects:
Acquires persistent connection via thread-safe _get_connection().
Calculates current timestamp in UTC.
Executes DELETE with WHERE clause using expires_at index.
Commits transaction before returning.
Resets failure counter on success.
- Thread Safety:
Thread-safe via connection lock in _get_connection().
- Performance:
O(m log n) where m is number of expired entries and n is total entries. The idx_l2_expires_at index makes this significantly faster than full table scan.
Example
>>> tier = DiskCacheTier(config, TierType.L2_FILE, cache_dir) >>> removed = tier.cleanup_expired() >>> print(f"Removed {removed} expired entries") Removed 42 expired entries
- clear()[source]¶
Clear all entries from SQLite L2 cache database.
Performs bulk deletion of all cache entries. More efficient than iterating through individual deletes.
- Returns:
Number of entries that were cleared, 0 on error.
- Return type:
- Side Effects:
Acquires persistent connection via thread-safe _get_connection().
Counts total entries before deletion.
Executes DELETE FROM without WHERE clause (removes all rows).
Commits transaction before returning.
Resets failure counter on success.
- Thread Safety:
Thread-safe via connection lock in _get_connection().
- Performance:
O(n) where n is the number of entries, but executes as a single SQL operation with automatic index cleanup.
Example
>>> tier = DiskCacheTier(config, TierType.L2_FILE, cache_dir) >>> tier.size() 1000 >>> cleared = tier.clear() >>> print(f"Cleared {cleared} entries") Cleared 1000 entries >>> tier.size() 0
- close()[source]¶
Close the persistent SQLite connection and release database resources.
Should be called when the cache tier is no longer needed to properly release database resources and file locks. Safe to call multiple times.
- Side Effects:
Acquires connection lock to ensure thread safety.
Closes active SQLite connection if present.
Sets internal connection to None to prevent reuse.
Suppresses any exceptions during close to ensure cleanup completes.
- Thread Safety:
Thread-safe via internal lock. Multiple threads can safely call this method concurrently.
Example
>>> tier = DiskCacheTier(config, TierType.L2_FILE, cache_dir) >>> # ... use tier ... >>> tier.close() # Clean up resources >>> tier.close() # Safe to call again
- Return type:
None
- delete(key)[source]¶
Remove entry from SQLite database by cache key.
Uses SQL DELETE with primary key lookup for O(log n) performance.
- Parameters:
key (str) – Cache key to delete.
- Returns:
True if entry existed and was deleted, False if not found or on error.
- Return type:
- Side Effects:
Acquires persistent connection via thread-safe _get_connection().
Executes DELETE query with parameterized key (SQL injection safe).
Commits transaction before returning.
Does NOT reset failure counter (only success paths do).
- Thread Safety:
Thread-safe via connection lock in _get_connection().
- get(key)[source]¶
Retrieve entry from SQLite database with O(log n) indexed lookup.
- Parameters:
key (str) – Cache key to lookup
- Returns:
CacheEntry if found and valid, None otherwise
- Return type:
- keys()[source]¶
Return list of all cache keys from SQLite L2 database.
Retrieves all cache keys without loading full entry data. Useful for cache inspection, debugging, and bulk operations.
- Side Effects:
Acquires persistent connection via thread-safe _get_connection().
Executes SELECT key query (fetches only key column, not full rows).
Loads all keys into memory as a list.
Resets failure counter on success.
- Thread Safety:
Thread-safe via connection lock in _get_connection().
- Performance:
O(n) where n is number of entries. For large caches (>10K entries), consider using size() to check count before calling.
Warning
For very large caches (>100K entries), this may consume significant memory. Consider pagination or streaming approaches if needed.
- migrate_from_jsonl(jsonl_dir=None)[source]¶
Migrate existing JSONL shard files to SQLite L2 cache.
This method provides a migration path from the old JSONL-based L2 cache to the new SQLite-based implementation. It reads all shard_*.jsonl files from the specified directory and imports them into the SQLite database.
- Parameters:
jsonl_dir (pathlib.Path | None) – Directory containing shard_*.jsonl files. Defaults to self.cache_dir if not specified.
- Returns:
Number of entries successfully migrated
- Return type:
Example
>>> tier = DiskCacheTier(config, TierType.L2_FILE, cache_dir) >>> migrated = tier.migrate_from_jsonl() >>> print(f"Migrated {migrated} entries from JSONL to SQLite")
- put(key, entry)[source]¶
Store entry in SQLite database with INSERT OR REPLACE.
- Parameters:
key (str) – Cache key for entry
entry (proxywhirl.cache.models.CacheEntry) – CacheEntry to store
- Returns:
True if stored successfully, False otherwise
- Return type:
- size()[source]¶
Return current number of entries in SQLite L2 cache database.
Uses SQL COUNT(*) for efficient O(1) size calculation via table metadata.
- Returns:
Number of cache entries currently stored, 0 on error.
- Return type:
- Side Effects:
Acquires persistent connection via thread-safe _get_connection().
Executes SELECT COUNT(*) query (reads table metadata, not rows).
Resets failure counter on success.
- Thread Safety:
Thread-safe via connection lock in _get_connection().
- Performance:
O(1) - SQLite maintains row count in table metadata.
- class proxywhirl.cache.tiers.JsonlCacheTier(config, tier_type, cache_dir, encryptor=None, num_shards=16)[source]¶
Bases:
CacheTierL2 JSONL file-based cache with sharding and encryption.
Provides persistent caching using JSONL (JSON Lines) files with: - Sharded storage for better I/O performance - File locking for concurrent access safety - Encrypted credentials at rest - Simple text format for debugging and portability
Best suited for: - Smaller cache sizes (<10K entries) - Environments where SQLite is unavailable - Cases requiring human-readable cache files - Simple deployment without database dependencies
For larger caches (>10K entries), consider DiskCacheTier (SQLite-based) which provides O(log n) lookups vs O(n) for JSONL.
Initialize JSONL-based L2 cache.
- Parameters:
config (proxywhirl.cache.models.CacheTierConfig) – Tier configuration
tier_type (TierType) – Type of tier (should be L2_FILE)
cache_dir (pathlib.Path) – Directory for JSONL shard files
encryptor (proxywhirl.cache.crypto.CredentialEncryptor | None) – Credential encryptor for username/password
num_shards (int) – Number of shard files (default: 16)
- cleanup_expired()[source]¶
Remove all expired entries from all shards.
- Returns:
Number of entries removed
- Return type:
- get(key)[source]¶
Retrieve entry from JSONL shard.
- Parameters:
key (str) – Cache key to lookup
- Returns:
CacheEntry if found and valid, None otherwise
- Return type:
- put(key, entry)[source]¶
Store entry in JSONL shard with encrypted credentials.
- Parameters:
key (str) – Cache key for entry (should match entry.key)
entry (proxywhirl.cache.models.CacheEntry) – CacheEntry to store
- Returns:
True if stored successfully, False otherwise
- Return type:
- class proxywhirl.cache.tiers.MemoryCacheTier(config, tier_type, on_evict=None)[source]¶
Bases:
CacheTierL1 in-memory cache using OrderedDict for LRU tracking.
Provides O(1) lookups with automatic LRU eviction when max_entries exceeded.
Initialize memory cache with LRU tracking.
- Parameters:
config (proxywhirl.cache.models.CacheTierConfig) – Tier configuration
tier_type (TierType) – Type of tier (L1/L2/L3)
on_evict (Callable[[str, proxywhirl.cache.models.CacheEntry], None] | None) – Optional callback when entry is evicted (key, entry)
- cleanup_expired()[source]¶
Remove all expired entries from memory cache in bulk.
- Returns:
Number of expired entries that were removed.
- Return type:
- Side Effects:
Deletes all entries where is_expired property is True.
- clear()[source]¶
Clear all entries from memory cache.
- Returns:
Number of entries that were removed.
- Return type:
- Side Effects:
Empties the OrderedDict, releasing all cached entries.
- delete(key)[source]¶
Remove entry from memory cache by key.
- Parameters:
key (str) – Cache key to delete.
- Returns:
True if entry existed and was deleted, False if not found.
- Return type:
- Side Effects:
Removes entry from OrderedDict if present.
- get(key)[source]¶
Retrieve entry from memory cache, updating LRU order.
- Parameters:
key (str) – Cache key to lookup.
- Returns:
CacheEntry if found, None otherwise. Updates LRU order on hit by moving the accessed entry to the end of the OrderedDict.
- Return type:
- Side Effects:
Moves accessed entry to end of LRU queue (most recently used position).
- put(key, entry)[source]¶
Store entry in memory cache with automatic LRU eviction.
- Parameters:
key (str) – Cache key for the entry.
entry (proxywhirl.cache.models.CacheEntry) – CacheEntry object to store.
- Returns:
True if stored successfully, False on error.
- Return type:
- Side Effects:
Removes existing entry if key already exists (update operation).
Evicts least recently used entry if max_entries exceeded.
Calls on_evict callback if provided when eviction occurs.
Resets failure counter on success.
- class proxywhirl.cache.tiers.SQLiteCacheTier(config, tier_type, db_path, encryptor=None)[source]¶
Bases:
CacheTierL3 SQLite database cache with encrypted credentials.
Provides durable persistence with SQL indexing for fast lookups.
Initialize SQLite-based L3 cache with health monitoring.
- Parameters:
config (proxywhirl.cache.models.CacheTierConfig) – Tier configuration settings.
tier_type (TierType) – Type of tier (should be L3_SQLITE).
db_path (pathlib.Path) – Path to SQLite database file.
encryptor (proxywhirl.cache.crypto.CredentialEncryptor | None) – Optional credential encryptor for username/password. Creates default CredentialEncryptor if not provided.
- Side Effects:
Creates parent directories for database if they don’t exist.
Initializes database schema with cache_entries and health_history tables.
Creates indexes for expires_at, source, health_status, and last_accessed.
- cleanup_expired()[source]¶
Remove all expired entries in bulk using SQL DELETE.
This is significantly more efficient than iterating through all entries, reducing cleanup from O(n) to O(1) for expired entries.
- Returns:
Number of entries removed
- Return type:
- clear()[source]¶
Clear all entries from SQLite database.
- Returns:
Number of entries that were deleted.
- Return type:
- Side Effects:
Opens new SQLite connection for operation.
Deletes all rows from cache_entries table.
Cascades to delete all health_history records via FOREIGN KEY.
Commits transaction before returning.
Resets failure counter on success.
- delete(key)[source]¶
Remove entry from SQLite database by key.
- Parameters:
key (str) – Cache key to delete.
- Returns:
True if entry existed and was deleted, False if not found.
- Return type:
- Side Effects:
Opens new SQLite connection for deletion.
Cascades to delete related health_history records via FOREIGN KEY.
Commits transaction before returning.
- get(key)[source]¶
Retrieve entry from SQLite database with decrypted credentials.
- Parameters:
key (str) – Cache key to lookup.
- Returns:
CacheEntry if found with decrypted username/password, None otherwise.
- Return type:
- Side Effects:
Opens new SQLite connection for query.
Decrypts username_encrypted and password_encrypted BLOBs.
Converts UNIX timestamps to datetime objects.
Resets failure counter on success.
- keys()[source]¶
Return all cache keys from SQLite database.
- Side Effects:
Opens new SQLite connection for query.
Resets failure counter on success.
- put(key, entry)[source]¶
Store entry in SQLite database with encrypted credentials.
- Parameters:
key (str) – Cache key for the entry.
entry (proxywhirl.cache.models.CacheEntry) – CacheEntry object to store with all fields including health monitoring data.
- Returns:
True if stored successfully, False on error.
- Return type:
- Side Effects:
Opens new SQLite connection for write.
Encrypts username and password fields as BLOBs.
Uses INSERT OR REPLACE (upsert) to handle updates.
Sets created_at and updated_at to current timestamp.
Commits transaction before returning.
Resets failure counter on success.