Katkat

Implement a simplified memcached server

RedditMachine Learning Engineer · Technical Screen

Last updated

This problem tests your ability to design a thread-safe, in-memory key-value store and implement basic command parsing for an asynchronous network service.

Problem Statement

Design a simplified, thread-safe in-memory key-value store that supports basic operations. You are provided with a skeleton class and need to implement the core logic for storing and retrieving string-based data.

Requirements

Implement a class SimpleCache with the following methods:

  • set(key, value, ttl_seconds): Stores a value with an optional time-to-live (TTL). If the TTL is provided, the entry should expire after the specified number of seconds. If the key already exists, overwrite it.
  • get(key): Returns the value associated with the key if it exists and has not expired; otherwise, return None.
  • delete(key): Removes a key-value pair from the cache.

Constraints

  • Your implementation must be thread-safe for concurrent read/write operations.
  • You should handle expiration lazily (check expiry upon access) or via a background cleanup process.
  • Assume key is a string and value is an arbitrary object.

Example

cache = SimpleCache()
cache.set("user_1", "data_a", 2)  # Expires in 2 seconds
print(cache.get("user_1"))         # Returns "data_a"
# ... wait 3 seconds ...
print(cache.get("user_1"))         # Returns None

Edge Cases to Consider

  • Accessing an expired key.
  • Concurrent writes to the same key.
  • Memory management: How do you prevent memory leaks if thousands of keys are never accessed again?

Hints

Hint 1

Consider using a thread-safe dictionary (like `collections.defaultdict` with a `threading.Lock`) to store the values and their metadata.

Hint 2

Store the expiry time as an absolute timestamp (current time + TTL) to make checking for expiration efficient during a `get` call.

Hint 3

For memory management, discuss the trade-offs between lazy eviction during `get()` and active eviction via a background worker thread.

Follow-up questions

  • How would you modify your implementation to handle Least Recently Used (LRU) eviction if the cache reaches a maximum size limit?
  • If you were to expose this over a network using TCP, how would you handle the byte-level protocol serialization of incoming requests?
  • How does your solution perform under a high read-to-write ratio, and how could you optimize for read-heavy workloads?