FastPrepCloud Storage with User Backup and Restore

Cloud Storage with User Backup and Restore

Airbnb logoAirbnb● HardFULLTIMEOA
Learn

Problem statement

Source requirements

Implement a simple cloud storage system that maps objects (files) to their meta-information. The storage maintains files and information about them, such as name and size. The system is in-memory; it does not work with the real filesystem.

Plan the design according to these level specifications:

  • Level 1: The cloud storage system should support adding a new file and retrieving and deleting files.
  • Level 2: The cloud storage system should support displaying the largest files.
  • Level 3: The cloud storage system should support adding users with limited capacities and merging two users.
  • Level 4: The cloud storage system should support backing up and restoring a user's files.

To move to the next level, pass all tests at the current level when submitting the solution.

It is guaranteed that the given queries never call operations that result in collisions between file and directory names.

Level 4

Implement support to allow users to back up their files.

  • backup_user(self, user_id: str) -> int | None: back up the current state of all files owned by user_id, including file names and sizes. Store the backup on a separate storage system so new file-manipulation queries do not affect it. Overwrite any prior backup for the same user. Return the number of backed-up files, or None if user_id does not exist.
  • restore_user(self, user_id: str) -> int | None: restore the state of user_id's files to the latest backup. If there is no backup, delete all files owned by user_id. If a file cannot be restored because another user owns another file with the same name, ignore it. Return the number of files successfully restored, or None if user_id does not exist.

FastPrep practice interface

To make the progressive class operations runnable as one Java, Python, and C++ function, process one finite ordered batch from empty storage and return one string result per operation. The implicit user admin always exists and has unlimited capacity. Files added with ADD_FILE belong to admin. Treat every file name as an opaque string.

Each operation is one of the following:

  • ["ADD_FILE", name, size]: add an admin-owned file if the name is unused. Return "true" on success or "false" otherwise.
  • ["GET_FILE_SIZE", name]: return the file size in decimal, or the empty string if the file does not exist.
  • ["DELETE_FILE", name]: delete the file and return its size in decimal, or the empty string if it does not exist. Deleting a user-owned file frees that user's capacity.
  • ["GET_N_LARGEST", prefix, n]: consider file names that start with prefix, sort them by size descending and then name ascending, and return at most n entries joined by ", ". Format each entry as name(size). Return the empty string when there are no matches.
  • ["ADD_USER", userId, capacity]: create a capacity-limited non-admin user. Return "true" if the user was created, or "false" if the ID is admin or already exists.
  • ["ADD_FILE_BY", userId, name, size]: add a file owned by an existing non-admin user if the name is unused and the user's used capacity plus size does not exceed the user's total capacity. Return the user's remaining capacity after success, or the empty string on failure.
  • ["MERGE_USER", userId1, userId2]: if both IDs name distinct existing non-admin users, transfer every file owned by userId2 to userId1, add userId2's total capacity to userId1's total capacity, remove userId2, and return userId1's remaining capacity. Otherwise return the empty string. The surviving user's prior backup is unchanged, and the removed user's backup is discarded.
  • ["BACKUP_USER", userId]: apply the source backup_user behavior. Return the backed-up file count in decimal, or the empty string when the source method returns None.
  • ["RESTORE_USER", userId]: apply the source restore_user behavior. Return the restored-file count in decimal, including "0" when no file is restored, or the empty string when the source method returns None.

Apply each mutation before processing the next operation. All integer results use ordinary decimal notation.

Function

processCloudStorage(operations: String[][]) → String[]

Examples

Example 1

operations = [["ADD_FILE","/a.txt","10"],["ADD_FILE","/logs/z.log","7"],["ADD_FILE","/logs/a.log","7"],["GET_FILE_SIZE","/a.txt"],["GET_N_LARGEST","/","2"],["DELETE_FILE","/a.txt"],["GET_FILE_SIZE","/a.txt"]]return = ["true","true","true","10","/a.txt(10), /logs/a.log(7)","10",""]

The size query sees the first file. The ranking puts the 10-unit file first and breaks the 7-unit tie by name. After deletion, querying that name returns the empty string.

Example 2

operations = [["ADD_USER","alice","20"],["ADD_USER","bob","15"],["ADD_FILE_BY","alice","/a","12"],["ADD_FILE_BY","bob","/b","10"],["ADD_FILE_BY","bob","/c","6"],["MERGE_USER","alice","bob"],["ADD_FILE_BY","alice","/c","13"],["BACKUP_USER","alice"],["DELETE_FILE","/b"],["RESTORE_USER","alice"],["GET_N_LARGEST","/","3"]]return = ["true","true","8","5","","13","0","3","10","3","/c(13), /a(12), /b(10)"]

Bob cannot add a 6-unit file before the merge. Merging gives Alice 35 units of total capacity and 13 units remaining. Her backup preserves all three files, so restore recreates the deleted 10-unit file.

Example 3

operations = [["ADD_USER","u","20"],["ADD_FILE_BY","u","/keep","8"],["ADD_FILE_BY","u","/conflict","5"],["BACKUP_USER","u"],["DELETE_FILE","/conflict"],["DELETE_FILE","/keep"],["ADD_FILE","/conflict","9"],["ADD_FILE_BY","u","/new","6"],["RESTORE_USER","u"],["GET_FILE_SIZE","/new"],["GET_FILE_SIZE","/keep"],["BACKUP_USER","admin"],["DELETE_FILE","/conflict"],["ADD_FILE","/temp","3"],["RESTORE_USER","admin"],["GET_FILE_SIZE","/temp"],["ADD_USER","v","4"],["ADD_FILE_BY","v","/v","4"],["RESTORE_USER","v"],["GET_FILE_SIZE","/v"]]return = ["true","12","7","2","5","8","true","14","1","","8","1","9","true","1","","true","0","0",""]

User u restores /keep but skips /conflict because admin owns that name. Admin's backup later replaces /temp with the saved conflict file. User v has no backup, so restore deletes /v and returns zero.

Constraints

  • 1 <= operations.length <= 2000.
  • Each operation has exactly the arity shown in the statement and uses one of the listed operation names.
  • File names and user IDs are nonempty printable ASCII strings of length at most 100.
  • A prefix is a printable ASCII string of length at most 100 and may be empty.
  • Every supplied file size is an integer in [1, 10^9].
  • Every supplied capacity is an integer in [1, 10^18].
  • Every supplied n is an integer in [1, 2000].
  • At most 2000 files are live after any operation.
  • All capacities, used-space totals, remaining-capacity values, and merged capacities fit in a signed 64-bit integer.

More Airbnb problems

See Airbnb hiring insights
public String[] processCloudStorage(String[][] operations) {
    // Write your code here.
}
operations[["ADD_FILE","/a.txt","10"],["ADD_FILE","/logs/z.log","7"],["ADD_FILE","/logs/a.log","7"],["GET_FILE_SIZE","/a.txt"],["GET_N_LARGEST","/","2"],["DELETE_FILE","/a.txt"],["GET_FILE_SIZE","/a.txt"]]
expected["true", "true", "true", "10", "/a.txt(10), /logs/a.log(7)", "10", ""]
Checking account…