▮ RECOMMENDED USE
Solid daily-driver scaffolding for ACID/async patterns — produces runnable, well-structured code, but needs a human pass for __slots__, monotonic clocks, and lock granularity before production.
▮ REFACTORED PATCH
# FIX 1: Add __slots__ for memory efficiency
@dataclass
class Node:
__slots__ = ('key', 'value', 'freq', 'expires_at', 'prev', 'next')
key: Any
value: Any
freq: int
expires_at: Optional[float]
prev: Optional['Node'] = None
next: Optional['Node'] = None
# FIX 2: Use monotonic clock everywhere (get/put/_add_node/commit)
# time.time() -> time.monotonic()
# e.g.
expires_at = time.monotonic() + ttl_seconds if ttl_seconds else None
# FIX 3: Make _cleanup_freq_lists O(1) — bump min_freq incrementally
# instead of recomputing min() across all tiers:
# In _update_freq, when emptying the min_freq bucket, only bump min_freq
# if you're evicting from it; otherwise leave it. Delete the global
# min(self.freq_map.keys()) scan. For background sweeps, prune empty
# buckets lazily on next _evict() rather than scanning proactively.
# FIX 4: Shrink commit critical section — apply writes into a staging
# structure under the lock, then release; or use per-bucket locks so
# readers on unrelated keys aren't blocked.
# FIX 5: Add MVCC version to Node; in commit, raise/abort if the
# stored version != the version seen at tx.get() time (lost-update detect).