AICoverGen / src /modules /cache_manager.py
R-Kentaren's picture
Upload src/modules/cache_manager.py with huggingface_hub
a52c119 verified
Raw
History Blame Contribute Delete
2.82 kB
"""
Cache Manager for RVC Models
================================
Thread-safe LRU cache for AI models (RVC, MDX, HuBERT).
Stores loaded model objects keyed by their file path. When the cache
is full, the least recently used entry is evicted.
"""
import threading
import time
from collections import OrderedDict
from typing import Any, Optional
class ModelCache:
"""Thread-safe LRU cache for AI models."""
def __init__(self, max_entries: int = 4, max_age_seconds: int = 1800):
self._cache: OrderedDict[str, dict] = OrderedDict()
self._max_entries = max_entries
self._max_age = max_age_seconds
self._lock = threading.RLock()
self._hits = 0
self._misses = 0
def get(self, key: str) -> Optional[Any]:
with self._lock:
entry = self._cache.get(key)
if entry is None:
self._misses += 1
return None
if time.time() - entry["loaded_at"] > self._max_age:
self._evict_entry(key)
self._misses += 1
return None
self._cache.move_to_end(key)
self._hits += 1
return entry["model"]
def put(self, key: str, model: Any, cleanup_fn: Optional[callable] = None) -> None:
with self._lock:
if key in self._cache:
self._cache.move_to_end(key)
self._cache[key] = {
"model": model,
"loaded_at": time.time(),
"cleanup_fn": cleanup_fn,
}
while len(self._cache) > self._max_entries:
oldest_key, oldest_entry = self._cache.popitem(last=False)
self._run_cleanup(oldest_key, oldest_entry)
def clear(self) -> None:
with self._lock:
for key in list(self._cache.keys()):
self._evict_entry(key)
def stats(self) -> dict:
with self._lock:
total = self._hits + self._misses
hit_rate = (self._hits / total * 100) if total > 0 else 0.0
return {
"entries": len(self._cache),
"max_entries": self._max_entries,
"hits": self._hits,
"misses": self._misses,
"hit_rate": f"{hit_rate:.1f}%",
"keys": list(self._cache.keys()),
}
def _evict_entry(self, key: str) -> None:
entry = self._cache.pop(key, None)
if entry is not None:
self._run_cleanup(key, entry)
def _run_cleanup(self, key: str, entry: dict) -> None:
cleanup_fn = entry.get("cleanup_fn")
if cleanup_fn is not None:
try:
cleanup_fn(entry["model"])
except Exception as e:
print(f"[cache] cleanup error for {key}: {e}")