Spaces:
Sleeping
Sleeping
| # utils/cache.py | |
| import json, sqlite3, time | |
| import threading | |
| from contextlib import contextmanager | |
| from typing import Any, Optional | |
| class SQLiteCache: | |
| def __init__( | |
| self, | |
| path: str = "/tmp/cache.sqlite", | |
| default_ttl_seconds: int = 3600, | |
| sqlite_timeout_seconds: int = 10, | |
| busy_timeout_ms: int = 5000, | |
| use_wal: bool = True, | |
| ): | |
| self.path = path | |
| self.default_ttl_seconds = default_ttl_seconds | |
| self.sqlite_timeout_seconds = sqlite_timeout_seconds | |
| self.busy_timeout_ms = busy_timeout_ms | |
| self.use_wal = use_wal | |
| self._lock = threading.Lock() | |
| self._init_db() | |
| def _connect(self) -> sqlite3.Connection: | |
| con = sqlite3.connect(self.path, timeout=self.sqlite_timeout_seconds) | |
| if self.use_wal: | |
| con.execute("PRAGMA journal_mode=WAL;") | |
| con.execute("PRAGMA synchronous=NORMAL;") | |
| con.execute(f"PRAGMA busy_timeout={self.busy_timeout_ms};") | |
| return con | |
| def _init_db(self): | |
| with self._connect() as con: | |
| con.execute(""" | |
| CREATE TABLE IF NOT EXISTS cache ( | |
| k TEXT PRIMARY KEY, | |
| v TEXT NOT NULL, | |
| expires_at INTEGER NOT NULL | |
| ) | |
| """) | |
| con.commit() | |
| def get(self, key: str) -> Optional[Any]: | |
| now = int(time.time()) | |
| with self._connect() as con: | |
| row = con.execute("SELECT v, expires_at FROM cache WHERE k=?", (key,)).fetchone() | |
| if not row: | |
| return None | |
| v, expires_at = row | |
| if expires_at < now: | |
| self.delete(key) | |
| return None | |
| try: | |
| return json.loads(v) | |
| except Exception: | |
| self.delete(key) | |
| return None | |
| def set(self, key: str, value: Any, ttl_seconds: Optional[int] = None) -> None: | |
| ttl = self.default_ttl_seconds if ttl_seconds is None else int(ttl_seconds) | |
| expires_at = int(time.time()) + ttl | |
| payload = json.dumps(value) | |
| with self._lock: | |
| with self._connect() as con: | |
| con.execute( | |
| "INSERT OR REPLACE INTO cache (k, v, expires_at) VALUES (?, ?, ?)", | |
| (key, payload, expires_at) | |
| ) | |
| con.commit() | |
| def delete(self, key: str) -> None: | |
| with self._lock: | |
| with self._connect() as con: | |
| con.execute("DELETE FROM cache WHERE k=?", (key,)) | |
| con.commit() | |
| def set_negative(self, key: str, ttl_seconds: int = 600, marker: str = "__no_route__") -> None: | |
| self.set(key, {marker: True}, ttl_seconds=ttl_seconds) |