Katkat

Read and Write Files with Shared Content

CitadelSoftware Engineer · Technical Screen

Last updated

Design an in-memory file system that shares identical content payloads across multiple file paths to save memory, supporting reads, writes, and deduplication tracking.

In-Memory Deduplicated File System

Design an in-memory file system that supports writing and reading files. In many data environments, multiple files share identical content (e.g., duplicate configurations, mirrored datasets). To optimize memory, your system must store identical content payloads only once in memory.

Implement the DeduplicatedFileSystem class:

  • write_file(path: str, content: str) -> None: Saves content at path. If path already exists, overwrite it. Identical contents across different paths (or subsequent overwrites) must share the same underlying storage. If an overwrite causes a previous content payload to have zero remaining references across all files, that payload should no longer be retained in memory.
  • read_file(path: str) -> str | None: Returns the exact, case-sensitive content of the file at path. If the file does not exist, return None.
  • delete_file(path: str) -> bool: Deletes the file at path. If deleted successfully, return True. If path does not exist, return False. Any content payload that is no longer referenced by any file after deletion must be removed from memory.
  • count_unique_contents() -> int: Returns the number of distinct content payloads currently retained in memory.

Examples

fs = DeduplicatedFileSystem()

fs.write_file("/a/b/c.txt", "market_data_v1")
fs.write_file("/a/b/e.txt", "market_data_v1")
fs.count_unique_contents()  # Returns 1 (both paths share "market_data_v1")

fs.read_file("/a/b/c.txt")   # Returns "market_data_v1"

fs.write_file("/a/b/c.txt", "market_data_v2")
fs.count_unique_contents()  # Returns 2 ("market_data_v1" used by /a/b/e.txt, "market_data_v2" by /a/b/c.txt)

fs.delete_file("/a/b/e.txt")
fs.count_unique_contents()  # Returns 1 ("market_data_v1" is freed because no file references it)

fs.read_file("/nonexistent") # Returns None

Constraints

  • path is a non-empty string consisting of valid path characters (/, alphanumeric, ., _).
  • content can be any string, including the empty string "".
  • Path and content comparisons are case-sensitive.
  • At most 20,000 total calls to write_file, read_file, delete_file, and count_unique_contents.

Hints

Hint 1

Map each unique content string or content hash to its stored string payload and maintain a reference count or set of paths referencing it.

Hint 2

When overwriting an existing file, remember to decrement the reference count of its previous content before pointing to the new one.

Hint 3

If a content payload's reference count drops to zero after an overwrite or file deletion, remove it from your storage map so it does not count toward unique contents.

Follow-up questions

  • How would you adapt this design for very large files where computing full-file hashes in memory is too expensive (e.g., chunk-based deduplication)?
  • How would you ensure thread safety if multiple worker threads are concurrently reading and writing files?
  • If using a cryptographic hash function like SHA-256 for content addressing, how do you protect against hash collisions?