Anthropic Online Assessment -- Cloud Storage System
Instructions
Your task is to implement a simple cloud storage system. All operations that should be supported are listed below.
Solving this task consists of several levels. Subsequent levels are opened when the current level is correctly solved. You always have access to the data for the current and all previous levels.
Requirements
Your task is to implement a simple cloud storage system that maps objects (files) to their metainformation. Specifically, the storage system should maintain files along with some information about them (name, size, etc.). Note that this system should be in-memory, you do not need to work with the real filesystem.
Plan your design according to the level specifications below:
- Level 1: The cloud storage system should support adding new files, retrieving, and copying files.
- Level 2: The cloud storage system should support finding files by matching prefixes and suffixes.
- Level 3: The cloud storage system should support adding users with various capacity limits.
- Level 4: The cloud storage system should support compressing and decompressing files.
To move to the next level, you need to pass all the tests at this level.
Note
You will receive a list of queries to the system, and the final output should be an array of strings representing the returned values of all queries. Each query will only call one operation.
It is guaranteed that the given queries will never call operations that result in collisions between file and directory names.
Level 1
The cloud storage system should support operations to add files, copy files, and get files stored on the system.
ADD_FILE <name>
<size>
Should add a new file name to the storage. size is the amount of memory required in bytes.
The current operation fails if a file with the same name already exists.
Returns "true"
if the file was added successfully or "false"
otherwise.
COPY_FILE <nameFrom>
<nameTo>
Should copy the file at nameFrom to nameTo.
The operation fails if nameFrom points to a file that does not exist or points to a directory.
The operation fails if the specified file already exists at nameTo.
Returns "true"
if the file was copied successfully or "false"
otherwise.
GET_FILE_SIZE <name>
Should return a string representing the size of the file name if it exists, or an empty string otherwise.
Examples
The example below shows how these operations should work (the section is scrollable to the right):
queries = [
["ADD_FILE", "/dir1/dir2/file.txt", "10"],
["COPY_FILE", "/not-existing.file", "/dir1/file.txt"],
["COPY_FILE", "/dir1/dir2/file.txt", "/dir1/file.txt"],
["ADD_FILE", "/dir1/file.txt", "15"],
["COPY_FILE", "/dir1/file.txt", "/dir1/dir2/file.txt"],
["GET_FILE_SIZE", "/dir1/file.txt"],
["GET_FILE_SIZE", "/not-existing.file"] ]
Explanations:
- returns `"true"`; adds file `"/dir1/dir2/file.txt"` of 10 bytes
- returns `"false"`; the file `"/not-existing.file"` does not exist
- returns `"true"`; adds file `"/dir1/file.txt"` of 10 bytes
- returns `"false"`; the file `"/dir1/file.txt"` exists already
- returns `"false"`; the file `"/dir1/dir2/file.txt"` exists already
- returns `"10"`
- returns `""`; the file `"/not-existing.file"` does not exist
The output should be:
["true", "false", "true", "false", "false", "10", ""]
Level 2
Implement support for retrieving file names by searching directories via prefixes and suffixes.
FIND_FILE <prefix>
<suffix>
Should search for files with names starting with prefix and ending with suffix.
Returns a string representing all matching files in this format:
"<name1>(<size1>), <name2>(<size2>), ..."
The output should be sorted in descending order of file sizes or, in the case of ties, lexicographically. If no files match the required properties, should return an empty string.
Examples
The example below shows how these operations should work (the section is scrollable to the right):
queries = [ ["ADD_FILE", "/root/dir/another_dir/file.mp3", "10"],
["ADD_FILE", "/root/file.mp3", "5"],
["ADD_FILE", "/root/music/file.mp3", "7"],
["COPY_FILE", "/root/music/file.mp3", "/root/dir/file.mp3"],
["FIND_FILE", "/root", ".mp3"],
["FIND_FILE", "/root", "file.txt"],
["FIND_FILE", "/dir", "file.mp3"] ]
Explanations:
- returns `"true"`
- returns `"true"`
- returns `"true"`
- returns `"true"`
- returns `"/root/dir/another_dir/file.mp3(10), /root/dir/file.mp3(7), /root/music/file.mp3(7), /root/file.mp3(5)"`
- returns `""`; there is no file with the prefix `"/root"` and suffix `"file.txt"`
- returns `""`; there is no file with the prefix `"/dir"` and suffix `"file.mp3"`
The output should be:
["true", "true", "true", "true", "/root/dir/another_dir/file.mp3(10), /root/dir/file.mp3(7), /root/music/file.mp3(7), /root/file.mp3(5)", "", ""]
Level 3
Implement support for different users sending queries to the system. All users share a common filesystem in the cloud storage, but each user is assigned an individual storage capacity limit.
ADD_USER <userId>
<capacity>
Should add a new user to the system, with capacity as their storage limit in bytes.
The total size of all files owned by userId cannot exceed capacity.
The operation fails if a user with userId already exists.
Returns "true"
if a user with userId is successfully created, or "false"
otherwise.
ADD_FILE_BY <userId>
<name>
<size>
Should behave in the same way as the ADD_FILE from Level 1, but the added file should be owned by the user with userId.
A new file cannot be added to the storage if doing so will exceed the user’s capacity limit.
Returns a string representing the remaining storage capacity for userId if the file is successfully added or an empty string otherwise.
Note
All queries calling the ADD_FILE operation implemented during Level 1 are run by the user with userId = "admin", who has unlimited storage capacity. Also, assume that the COPY_FILE operation preserves the ownership of the original file.
UPDATE_CAPACITY <userId>
<capacity>
Should change the maximum storage capacity for the user with userId.
If the total size of all user’s files exceeds the new capacity, the largest files (sorted lexicographically in case of a tie) should be removed from the storage until the total size of all remaining files will no longer exceed the new capacity.
Returns a string representing the number of removed files, or an empty string if a user with userId does not exist.
Examples
The example below shows how these operations should work (the section is scrollable to the right):
queries = [
["ADD_USER", "user1", "125"],
["ADD_USER", "user1", "100"],
["ADD_USER", "user2", "100"],
["ADD_FILE_BY", "user1", "/file.med", "30"],
["ADD_FILE_BY", "user2", "/file.med", "40"],
["COPY_FILE", "/file.med", "/dir/another/file.med"],
["COPY_FILE", "/file.med", "/file.small", "10"],
["ADD_FILE_BY", "admin", "/dir/file_small", "5"],
["ADD_FILE_BY", "user1", "/my_folder/file.huge", "100"],
["ADD_FILE_BY", "user3", "/my_folder/file.huge", "100"],
["UPDATE_CAPACITY", "user1", "300"],
["UPDATE_CAPACITY", "user1", "50"],
["UPDATE_CAPACITY", "user2", "1000"]
]
Explanations:
1. returns `"true"`; creates user `"user1"` with 125 bytes capacity
2. returns `"false"`; `"user1"` already exists
3. returns `"true"`; creates user `"user2"` with 100 bytes capacity
4. returns `"75"`
5. returns `""`; file named `"/file.med"` already exists and owned by `"user1"`
6. returns `"true"`; copying preserves the file owner. After copying, `"user1"` has 15 capacity left
7. returns `"false"`; `"user1"` does not have enough storage capacity left to perform copying operation
8. returns `"true"`; this operation is done by `"admin"` with unlimited capacity
9. returns `"false"`; `"user1"` does not have enough storage capacity left to add this file
10. returns `""`; `"user3"` doesn't exist
11. returns `"0"`; all files owned by `"user1"` can fit into the new capacity of 300 bytes
12. returns `"2"`; the files `"/dir/file.big"` and `"/dir/another/file.med"` should be deleted so the remaining files owned by `"user1"` can fit into the new capacity of 50 bytes
13. returns `""`; `"user2"` doesn't exist
The output should be:
["true", "false", "true", "75", "", "true", "false", "true", "false", "", "0", "2", ""]
Level 4
Implement support for file compression.
COMPRESS_FILE <userId>
<name>
Should compress the file name if it belongs to userId.
The compressed file should be replaced with a new file named <name>.COMPRESSED
.
The size of the newly created file should be equal to half of the original file. The size of all files is guaranteed to be even, so there should be no fractional calculations.
It is also guaranteed that name for this operation never points to a compressed file (i.e., it never ends with .COMPRESSED
).
Compressed files should be owned by userId — the owner of the original file.
Returns a string representing the remaining storage capacity for userId if the file was compressed successfully or an empty string otherwise.
Note
Because file names can only contain lowercase letters, compressed files cannot be added via ADD_FILE.
It is guaranteed that all COPY_FILE operations will preserve the suffix.COMPRESSED
.
DECOMPRESS_FILE <userId>
<name>
Should revert the compression of the file name if it belongs to userId.
It is guaranteed that name for this operation always ends with .COMPRESSED
.
If decompression results in the userId exceeding their storage capacity limit or a decompressed version of the file with the given name already exists, the operation fails.
Returns a string representing the remaining capacity of userId if the file was decompressed successfully or an empty string otherwise.
Examples
The example below shows how these operations should work (the section is scrollable to the right):
queries = [
["ADD_USER", "user1", "1000"],
["ADD_USER", "user2", "5000"],
["ADD_FILE_BY", "user1", "/dir/file.mp4", "500"],
["ADD_FILE_BY", "user2", "/dir/file.mp4", "1"],
["COMPRESS_FILE", "user3", "/dir/file.mp4"],
["COMPRESS_FILE", "user1", "/folder/non_existing_file"],
["COMPRESS_FILE", "user1", "/dir/file.mp4"],
["COMPRESS_FILE", "user1", "/dir/file.mp4"],
["GET_FILE_SIZE", "/dir/file.mp4.COMPRESSED"],
["GET_FILE_SIZE", "/dir/file.mp4"],
["COPY_FILE", "/dir/file.mp4.COMPRESSED", "/file.mp4.COMPRESSED"],
["ADD_FILE_BY", "user1", "/dir/file.mp4", "500"],
["DECOMPRESS_FILE", "user1", "/dir/file.mp4.COMPRESSED"],
["UPDATE_CAPACITY", "user1", "2000"],
["DECOMPRESS_FILE", "user2", "/dir/file.mp4.COMPRESSED"],
["DECOMPRESS_FILE", "user3", "/dir/file.mp4.COMPRESSED"],
["DECOMPRESS_FILE", "user1", "/dir/file.mp4.COMPRESSED"]
]
Explanations:
1. returns `"true"`
2. returns `"true"`
3. returns `"500"`
4. returns `""`; the file `"/dir/file.mp4"` is owned by `"user1"`
5. returns `""`; `"user3"` doesn’t exist
6. returns `""`; the file `"/folder/non_existing_file"` doesn’t exist
7. returns `"750"`; the file `"/dir/file.mp4"` is compressed to size = 500 / 2 = 250 bytes
8. returns `""`
9. returns `"250"`
10. returns `""`
11. returns `"true"`
12. returns `"0"`; `"user1"` does not have enough storage capacity to decompress the file
13. returns `"0"`
14. returns `"true"`; the file `"/dir/file.mp4.COMPRESSED"` is owned by `"user1"`
15. returns `""`; `"user3"` doesn’t exist
16. returns `""`; the file `"/dir/file.mp4"` exists already
17. returns `"750"`
The output should be:
["true", "true", "500", "", "", "", "750", "", "250", "", "true", "0", "0", "true", "", "", "750"]