Loading LLD design...
Design a thread-safe, in-memory cache with per-entry TTL (Time To Live) and pluggable eviction policies. The cache supports get, put, delete, contains, size, clear, and keys operations, all protected by reentrant locks for thread safety.
Each entry has an optional TTL; expired entries are lazily removed on access and periodically swept by a background cleanup daemon. When the cache reaches its fixed capacity, new inserts trigger eviction using a pluggable Strategy pattern with three implementations: LRU (OrderedDict / LinkedHashMap for O(1) operations), LFU (frequency-based with LRU tiebreak), and FIFO. The cache also provides a get-or-load (cache-aside) method that atomically loads and caches missing entries, TTL query and update operations, cache statistics (hits, misses, evictions, hit rate), and an Observer-based event listener system.
Put / Get / Delete
Store, retrieve, and remove key-value pairs; get returns null for missing or expired keys
TTL-based expiry
Each entry has an optional TTL; expired entries are lazily evicted on access and periodically via background cleanup
Eviction policies (Strategy pattern)
Pluggable eviction: LRU (Least Recently Used), LFU (Least Frequently Used with LRU tiebreak), FIFO (First In First Out)
Thread safety
All operations are protected by locks (RLock / ReentrantReadWriteLock / recursive_mutex) for concurrent access
Cache statistics
Track hits, misses, evictions, expirations, total puts, and compute hit rate
Get-or-Load (cache-aside)
Atomic get-or-load: if key is missing, call a loader function, cache the result, and return it
TTL management
Query remaining TTL for a key; update TTL for an existing key
Background cleanup daemon
Periodic background thread sweeps and removes expired entries
Event listeners (Observer)
Register listeners notified on PUT, EVICT, and EXPIRE events
Before diving into code, clarify the use cases and edge cases. Understanding the problem deeply leads to better class design.
Identify the primary actions users will perform. For a parking lot: park vehicle, exit vehicle, check availability. Each becomes a method.
Who interacts with the system? Customers, admins, automated systems? Each actor type may need different interfaces.
What are the limits? Max vehicles, supported vehicle types, payment methods. Constraints drive your data structures.
What happens on overflow? Concurrent access? Payment failures? Thinking about edge cases reveals hidden complexity.