cache.py 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
  1. """
  2. engine.cache — Compile cache for YAML → Term.
  3. Compilation is deterministic (FROM_CONFIG_SPEC P4), so same hash → same Term.
  4. """
  5. from __future__ import annotations
  6. from collections import OrderedDict
  7. from typing import Any, Optional
  8. class CompileCache:
  9. def __init__(self, maxsize: int = 1000):
  10. self._cache: OrderedDict = OrderedDict()
  11. self._maxsize = maxsize
  12. self.hits = 0
  13. self.misses = 0
  14. def get(self, config_hash: str) -> Optional[Any]:
  15. if config_hash in self._cache:
  16. self._cache.move_to_end(config_hash)
  17. self.hits += 1
  18. return self._cache[config_hash]
  19. self.misses += 1
  20. return None
  21. def put(self, config_hash: str, term: Any):
  22. self._cache[config_hash] = term
  23. self._cache.move_to_end(config_hash)
  24. while len(self._cache) > self._maxsize:
  25. self._cache.popitem(last=False)
  26. def get_or_compile(self, config_hash: str, config: dict) -> Any:
  27. cached = self.get(config_hash)
  28. if cached:
  29. return cached
  30. import tempfile, yaml, os
  31. with tempfile.NamedTemporaryFile(mode='w', suffix='.yml', delete=False, encoding='utf-8') as f:
  32. yaml.dump(config, f, allow_unicode=True)
  33. tmp = f.name
  34. try:
  35. from lambdagent.fromconfig import from_config
  36. term = from_config(tmp)
  37. self.put(config_hash, term)
  38. return term
  39. finally:
  40. os.unlink(tmp)
  41. @property
  42. def stats(self):
  43. total = self.hits + self.misses
  44. return {"size": len(self._cache), "hits": self.hits, "misses": self.misses,
  45. "hit_rate": f"{self.hits/total:.1%}" if total else "N/A"}