Implement cloud storage with quotas and compression
Company: Coinbase
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Technical Screen
Quick Answer: This question evaluates the ability to design and implement in-memory state management and algorithmic logic for user-scoped storage, including capacity tracking, deterministic eviction policies, file metadata manipulation, and integer/string operations.
Constraints
- 0 <= len(queries) <= 10^5
- 0 <= capacity, newCapacity <= 2^31 - 1
- 1 <= size <= 2^31 - 1 for ADD_FILE operations
- userId and fileName are non-empty strings
- File names are unique per user
- Compressed sizes use integer division, so a compressed file may become size 0
Examples
Input: ([['ADD_USER', 'alice', '10'], ['ADD_FILE', 'alice', 'a.txt', '6'], ['GET_FILE_SIZE', 'alice', 'a.txt'], ['COMPRESS_FILE', 'alice', 'a.txt'], ['GET_FILE_SIZE', 'alice', 'a.txt'], ['GET_FILE_SIZE', 'alice', 'a.txt.compressed'], ['DECOMPRESS_FILE', 'alice', 'a.txt.compressed'], ['GET_FILE_SIZE', 'alice', 'a.txt'], ['UPDATE_CAPACITY', 'alice', '6']],)
Expected Output: ['true', 'true', '6', 'true', '', '3', 'true', '6', '0']
Explanation: Basic flow: add a user, add a file, compress it, verify the old name disappears and the new name exists with half size, then decompress it back and update capacity without needing deletion.
Input: ([['ADD_USER', 'bob', '20'], ['ADD_FILE', 'bob', 'alpha', '5'], ['ADD_FILE', 'bob', 'beta', '7'], ['ADD_FILE', 'bob', 'gamma', '7'], ['UPDATE_CAPACITY', 'bob', '10'], ['ADD_FILE', 'bob', 'delta', '5'], ['UPDATE_CAPACITY', 'bob', '5'], ['GET_FILE_SIZE', 'bob', 'alpha'], ['GET_FILE_SIZE', 'bob', 'delta']],)
Expected Output: ['true', 'true', 'true', 'true', '2', 'true', '1', '5', '']
Explanation: When capacity drops to 10, the two 7-byte files must be removed; between beta and gamma, gamma is deleted first because it is lexicographically larger. Later alpha and delta tie at size 5, so delta is deleted.
Input: ([['ADD_USER', 'u', '9'], ['ADD_FILE', 'u', 'x', '6'], ['COMPRESS_FILE', 'u', 'x'], ['ADD_FILE', 'u', 'y', '6'], ['DECOMPRESS_FILE', 'u', 'x.compressed'], ['COMPRESS_FILE', 'u', 'y'], ['DECOMPRESS_FILE', 'u', 'x.compressed'], ['GET_FILE_SIZE', 'u', 'x'], ['GET_FILE_SIZE', 'u', 'x.compressed'], ['GET_FILE_SIZE', 'u', 'y.compressed']],)
Expected Output: ['true', 'true', 'true', 'true', 'false', 'true', 'true', '6', '', '3']
Explanation: The first decompression fails because it would exceed capacity. After compressing y, there is enough room, so decompressing x.compressed succeeds.
Input: ([['ADD_FILE', 'ghost', 'a', '1'], ['GET_FILE_SIZE', 'ghost', 'a'], ['UPDATE_CAPACITY', 'ghost', '5'], ['ADD_USER', 'eve', '0'], ['ADD_FILE', 'eve', 'z', '1'], ['COMPRESS_FILE', 'eve', 'missing'], ['DECOMPRESS_FILE', 'eve', 'missing.compressed'], ['ADD_USER', 'eve', '3']],)
Expected Output: ['false', '', '-1', 'true', 'false', 'false', 'false', 'false']
Explanation: Covers missing users, empty-string responses, update on a missing user, zero capacity, missing files, and duplicate user creation.
Input: ([['ADD_USER', 'p', '10'], ['ADD_FILE', 'p', 'a', '6'], ['COMPRESS_FILE', 'p', 'a'], ['ADD_FILE', 'p', 'b', '7'], ['UPDATE_CAPACITY', 'p', '2'], ['GET_FILE_SIZE', 'p', 'a.compressed'], ['GET_FILE_SIZE', 'p', 'b']],)
Expected Output: ['true', 'true', 'true', 'true', '2', '', '']
Explanation: After compressing a, the heap still contains a stale entry for the old uncompressed file. UPDATE_CAPACITY must ignore stale data and delete the current largest valid files until used space is within the new limit.
Input: ([],)
Expected Output: []
Explanation: Edge case: no queries means no results.
Input: ([['ADD_USER', 'odd', '1'], ['ADD_FILE', 'odd', 'f', '1'], ['COMPRESS_FILE', 'odd', 'f'], ['GET_FILE_SIZE', 'odd', 'f.compressed'], ['DECOMPRESS_FILE', 'odd', 'f.compressed'], ['GET_FILE_SIZE', 'odd', 'f']],)
Expected Output: ['true', 'true', 'true', '0', 'true', '0']
Explanation: Compression uses integer division, so a 1-byte file becomes 0 bytes. Decompression then doubles 0 to 0, matching the rules exactly.
Hints
- Use a hash map for each user's files so existence checks and size lookups are O(1) on average.
- For UPDATE_CAPACITY, a priority queue can give the largest file quickly. Since files may be renamed or deleted, think about lazy deletion of outdated heap entries.