Round 1
Questions: Your task is to design and implement an in-memory caching system that is capable of storing and retrieving key-value pairs efficiently. The cache should have a capacity limit, after which the items should be evicted using an eviction policy to make space for new items. The cache should provide the following operations:
- put(key, value): Add a new key-value pair to the cache. If the cache is at capacity, evict the least recently used item before adding the new item.
- get(key): Retrieve the value associated with the given key from the cache. If the key is not present in the cache, retrieve it from a backing store, add it to the cache, and return it. If the value is not found in the backing store, return null.
- remove(key): Remove the key-value pair associated with the given key from the cache.
Additionally, the cache should support several configuration options, such as:
- Expiration strategies: Specify the time-to-live (TTL) for items in the cache. Expired items should be removed from the cache automatically.
- Maximum size: specify the maximum number of items allowed in the cache.
- Write Policy: specify the methodology used to propagate updates in cached data.
Bonus:
- Sync/ Asynchronous loading (cache creation)
- Implement other expiration strategy
- Implement refresh strategies.
Test Cases:
-
Basic Operations
- Test Case 1: Add and Retrieve
- Input:
-> put('key1', 'value1') -> get('key1')
- Expected Output: 'value1'
- Input:
- Test Case 2: Retrieve Non-existent Key
- Input:
-> get('keyX') (where 'keyX' is not in cache)
- Expected Output: Retrieve from backing store or null if not found
- Input:
- Test Case 3: Update Existing Key
- Input:
-> put('key1', 'value1'), put('key1', 'value2') -> get('key1')
- Expected Output: 'value2'
- Input:
- Test Case 4: Remove Key
- Input:
-> put('key1', 'value1'), -> remove('key1') -> get('key1')
- Expected Output: Retrieve from backing store or null if not found
- Input:
- Test Case 1: Add and Retrieve
-
Capacity and Eviction Policy
- Test Case 5: Evict on Capacity
- Setup: Cache capacity set to 2
- Input:
-> put('key1', 'value1') -> put('key2', 'value2') -> put('key3', 'value3') -> get('key1')
- Expected Output: null (or retrieved from backing store if applicable), 'key1' should be evicted.
- Test Case 5: Evict on Capacity
Candidate's Approach
The candidate designed an in-memory caching system using a combination of a hash map for O(1) access time and a doubly linked list to maintain the order of usage for eviction purposes. The implementation included methods for adding, retrieving, and removing items, as well as handling expiration strategies and capacity limits. The candidate also considered edge cases such as handling non-existent keys and ensuring that the eviction policy worked correctly when the cache reached its capacity.
Interviewer's Feedback
The interviewer appreciated the candidate's structured approach to the problem and the clarity of the implementation. They suggested considering additional edge cases and optimizing the eviction strategy further. Overall, the candidate demonstrated a solid understanding of caching mechanisms.