Katkat

Define a File Store with User Quotas and Compression

AirbnbSoftware Engineer · Online Assessment

Last updated

Implement an in-memory cloud file store that supports file creation, copying, prefix/suffix search, per-user storage quotas, and atomic file compression/expansion.

Problem Statement

Design an in-memory file storage engine that manages files, user quotas, and file compression. Implement the FileStore class with the following methods:

  • set_user_quota(user_id: str, quota: int) -> bool Sets the maximum total storage capacity in bytes that user_id can occupy. If the user already consumes more bytes than quota, reject the change and return False. Otherwise, apply the new quota and return True. If no quota is set for a user, assume their storage capacity is unlimited.

  • add_file(user_id: str, path: str, size: int) -> bool Adds a new file owned by user_id at path with size bytes. Fails and returns False if a file at path already exists, or if adding this file would cause user_id to exceed their quota. Returns True on success.

  • copy_file(source_path: str, dest_path: str) -> bool Creates a duplicate of source_path at dest_path. The new file is owned by the same user who owns source_path and has identical size. Fails and returns False if source_path does not exist, dest_path already exists, or the duplicate causes the owner to exceed their quota. Returns True on success.

  • search_files(prefix: str, suffix: str) -> list[str] Returns a list of all existing file paths that start with prefix and end with suffix, sorted in ascending lexicographical order.

  • compress_file(path: str, factor: float) -> bool Resizes the file at path to floor(current_size * factor) bytes. The owner's current storage usage must be updated accordingly. If factor > 1.0 (decompression/expansion) and the increase would cause the owner to exceed their quota, the operation must fail atomically: return False and leave the file size and user quota unchanged. Returns False if the file does not exist, and True on successful update.

Example

fs = FileStore()
assert fs.set_user_quota("u1", 100) == True
assert fs.add_file("u1", "/docs/notes.txt", 60) == True
assert fs.add_file("u1", "/docs/code.py", 50) == False  # 60 + 50 > 100
assert fs.copy_file("/docs/notes.txt", "/backup/notes.txt") == False  # 60 + 60 > 100

# Compress notes.txt to 50% (30 bytes), making current total usage 30 bytes
assert fs.compress_file("/docs/notes.txt", 0.5) == True
assert fs.copy_file("/docs/notes.txt", "/backup/notes.txt") == True  # 30 + 30 <= 100

# Prefix/Suffix search
assert fs.search_files("/", ".txt") == ["/backup/notes.txt", "/docs/notes.txt"]

# Decompression exceeding quota must fail atomically
assert fs.compress_file("/docs/notes.txt", 3.0) == False  # (30 * 3) + 30 = 120 > 100

Constraints

  • 1 <= len(user_id), len(path) <= 100
  • 1 <= size, quota <= 10^9
  • 0.0 < factor <= 10.0
  • Up to 5 * 10^4 total operations across all methods.

Hints

Hint 1

Track file metadata (path, owner, size) and user metadata (quota, total_used) using hash maps for O(1) lookups and updates.

Hint 2

For atomic compression, compute the candidate new size and the resulting delta against the owner's quota before mutating any stored values.

Hint 3

For prefix and suffix search, either iterate through all keys if total files are small or maintain a Trie/sorted list if query frequency requires faster sublinear matching.

Follow-up questions

  • How would you optimize `search_files` if the file system contained millions of paths and read queries were frequent?
  • How would you handle concurrent operations safely without acquiring a coarse global lock across the entire file store?
  • If users could belong to shared organization accounts with hierarchical quotas, how would you restructure your quota-tracking model?