Cloud Storage with User Backup and Restore
Reported by candidates from Airbnb's online assessment. Pattern, common pitfall, and the honest play if you blank under the timer.
Airbnb reportedly asked this one in August 2026, and it's a progressive design question, not a classic algorithm puzzle. Four levels build on each other: file add/get/delete, top-N by prefix, users with capacity and merging, then backup and restore. You pass each level's tests before the next unlocks. The trap hides in level 4, where restore has to skip files whose names another user now owns. If you only prepared array and hash map drills, this will feel unfamiliar. If you blank on the state bookkeeping, StealthCoder is the invisible safety net running during the live OA.
The problem
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.
Reported by candidates. Source: FastPrep
Pattern and pitfall
The pattern is design plus hash tables. Keep one global map from file name to (size, owner), and per-user records holding capacity, used bytes, and a backup snapshot. GET_N_LARGEST can just scan and sort by size descending, then name ascending. The edge case that breaks naive solutions is restore. Backups must be deep copies, not references to live data. Restore first deletes the user's current files, then re-adds each backed-up file only if no other user owns that name, and counts only successes. With no backup, it wipes everything and returns 0. Merge is the other sink: move ownership, add capacity, delete the removed user's backup, and keep the survivor's backup untouched. Also remember capacity must be recomputed on restore. If the interaction of these rules tangles on you mid-assessment, StealthCoder can read the spec and hand you a clean structure as a hedge.
The honest play: practice the pattern, and have StealthCoder ready for the one you didn't see coming.
You can drill Cloud Storage with User Backup and Restore cold, or you can hedge it. StealthCoder runs invisibly during screen share and surfaces a working solution in under 2 seconds. The proctor sees the IDE. They don't see what's behind it. Built for the candidate who saw this exact problem leak two days before his OA and wondered if anyone had a play.
Get StealthCoderRelated leaked OAs
You've seen the question.
Make sure you actually pass Airbnb's OA.
Airbnb reuses patterns across OAs. Built for the candidate who saw this exact problem leak two days before his OA and wondered if anyone had a play. Works on HackerRank, CodeSignal, CoderPad, and Karat.
Cloud Storage with User Backup and Restore FAQ
What's the real trick in the Airbnb cloud storage OA?+
Ownership bookkeeping. One global name-to-file map with an owner field, plus per-user capacity, used space and backup snapshot. Most failures come from restore and merge edge cases, not from the sorting or lookup logic.
How should backup_user store data so later changes don't affect it?+
Copy the data. Store a new dictionary of name to size for that user at backup time. Never keep references to live file objects. Overwrite any previous backup for the same user, and return the count of files copied.
What does restore do when a file name is taken by another user?+
It skips that file and doesn't count it. First remove all the user's current files and free their capacity. Then re-add each backed-up file only if the name is unowned. Return the number actually restored, which can be 0.
How do I handle GET_N_LARGEST efficiently enough?+
Filter names by prefix, sort by size descending then name ascending, slice to n, and format as name(size) joined by commas and spaces. A scan and sort is fine for an in-memory batch. Return an empty string for no matches.
How do I prepare for this in 48 hours?+
Write the class once end to end, level by level, and test the edge cases: merge with backups, restore with name collisions, delete freeing capacity, and unknown users returning empty strings. Practice reading the spec carefully, since details decide the tests.