Katkat

Design an In-Memory Cloud Storage Service with Users, Backups, and Restore

AirbnbSoftware Engineer · Online Assessment

Last updated

Implement an in-memory cloud storage system supporting user storage limits, globally unique files, ranked file queries, account merges, and transactional backup and restore operations.

Problem Statement

Design an in-memory cloud storage service that manages users and their files with strict quota enforcement, account merging, and snapshot-based backup and restore capabilities.

Implement the CloudStorage class with the following methods:

  • add_user(user_id: str, capacity: int) -> bool: Registers a new user with the given storage capacity (in bytes). Returns True on success. Returns False if user_id already exists or if capacity bool: Uploads a file with file_name and file_size for user_id. File names are globally unique across all users. Returns True if successfully added. Returns False if user_id does not exist, file_size list[str]: Returns a list of up to k file names owned by user_id. Files must be ordered descending by file_size. If sizes are equal, break ties alphabetically (ascending by file_name). If user_id does not exist or has no files, return an empty list.

  • merge_accounts(target_user_id: str, source_user_id: str) -> bool: Merges source_user_id into target_user_id:

    • target_user_id's capacity increases by source_user_id's capacity.
    • Ownership of all files belonging to source_user_id transfers to target_user_id.
    • source_user_id and any backups belonging to it are deleted.
    • Returns False if target_user_id == source_user_id or if either user does not exist. Otherwise, returns True.
  • backup_user(user_id: str) -> bool: Saves a snapshot of the files currently owned by user_id (capturing file names and sizes). Overwrites any existing backup for this user. Returns False if user_id does not exist; otherwise returns True.

  • restore_user(user_id: str) -> bool: Restores the user's files from their latest backup. This operation must be transactional (all-or-nothing):

    • Returns False if user_id does not exist or has no backup.
    • Returns False if any file in the backup is currently owned by another user.
    • Returns False if the total size of files in the backup exceeds user_id's current capacity.
    • If valid, removes all files currently owned by user_id, restores the backup files under user_id, and returns True. If invalid, the system state remains completely unchanged.

Example

storage = CloudStorage()

storage.add_user("alice", 100)       # True
storage.add_user("bob", 50)          # True

storage.add_file("alice", "a.txt", 40)   # True (alice used: 40/100)
storage.add_file("alice", "b.txt", 30)   # True (alice used: 70/100)
storage.add_file("alice", "c.txt", 40)   # False (70 + 40 > 100)

storage.backup_user("alice")             # True (snapshot: a.txt: 40, b.txt: 30)

storage.add_file("alice", "d.txt", 20)   # True (alice used: 90/100)
storage.get_largest_files("alice", 2)    # ["a.txt", "b.txt"]

storage.restore_user("alice")            # True (d.txt is removed; a.txt and b.txt restored)
storage.get_largest_files("alice", 5)    # ["a.txt", "b.txt"]

Constraints

  • user_id and file_name are non-empty strings of alphanumeric characters.
  • 1 = 1
  • Total number of method calls <= 5 * 10^4.

Hints

Hint 1

Maintain a global file registry to check file existence and ownership in O(1) time.

Hint 2

For `get_largest_files`, maintain files per user in a map or set, and sort on query or keep a balanced BST / sorted list per user.

Hint 3

For transactional `restore_user`, validate all preconditions (no name conflicts with other users, capacity limits) before mutating any user or global state.

Follow-up questions

  • How would you optimize `get_largest_files` if reads are much more frequent than file additions or deletions?
  • How would you support concurrent operations across different users using fine-grained locking without causing deadlocks during `merge_accounts`?
  • If backups were versioned by timestamp rather than overwriting the previous snapshot, how would you design the retention and garbage collection policy?