Implement an In-Memory File Storage System
Company: Instacart
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Take-home Project
Quick Answer: This question evaluates the ability to design and implement efficient in-memory data structures and algorithms for stateful file management, covering string-keyed storage, size accounting, querying and sorting, and user quota enforcement.
Constraints
- 1 <= len(operations) <= 2 * 10^4
- 0 <= size, capacity, newCapacity <= 10^9
- Path names and user IDs are non-empty strings of length at most 100
- 'admin' is a reserved built-in user and should not be added with addUser
- At most 2 * 10^4 files exist at any time
Examples
Input: [('addFile', '/docs/a.txt', 120), ('addFile', '/docs/b.txt', 80), ('addFile', '/docs/a.txt', 50), ('getFileSize', '/docs/a.txt'), ('copyFile', '/docs/a.txt', '/backup/a.txt'), ('findFiles', '/', 'a.txt'), ('findFiles', '/docs', '.txt')]
Expected Output: [True, True, False, 120, True, ['/backup/a.txt(120)', '/docs/a.txt(120)'], ['/docs/a.txt(120)', '/docs/b.txt(80)']]
Explanation: The duplicate addFile fails. The copy succeeds. findFiles returns matching files sorted by size descending, then by name.
Input: [('addUser', 'alice', 10), ('addFileByUser', 'alice', '/u/x.txt', 6), ('copyFile', '/u/x.txt', '/u/x_copy.txt'), ('addFileByUser', 'alice', '/u/y.txt', 4), ('copyFile', '/u/y.txt', '/u/y_copy.txt'), ('getFileSize', '/u/y.txt'), ('findFiles', '/u', '.txt')]
Expected Output: [True, 4, False, 0, False, 4, ['/u/x.txt(6)', '/u/y.txt(4)']]
Explanation: Alice can store x.txt and y.txt exactly up to capacity 10. Both copy attempts fail because each copy would exceed her capacity.
Input: [('addUser', 'bob', 25), ('addFileByUser', 'bob', '/p/a.txt', 10), ('addFileByUser', 'bob', '/p/b.txt', 10), ('addFileByUser', 'bob', '/p/c.txt', 5), ('updateUserCapacity', 'bob', 10), ('getFileSize', '/p/a.txt'), ('getFileSize', '/p/b.txt'), ('getFileSize', '/p/c.txt'), ('findFiles', '/p', '.txt')]
Expected Output: [True, 15, 5, 0, 2, -1, -1, 5, ['/p/c.txt(5)']]
Explanation: Bob uses 25 total. Reducing capacity to 10 removes the largest files first. Between the two size-10 files, '/p/b.txt' is removed before '/p/a.txt' because it is lexicographically larger.
Input: [('findFiles', '/nothing', '.zip'), ('addUser', 'admin', 100), ('addUser', 'anna', 5), ('addUser', 'anna', 7), ('addFileByUser', 'missing', '/m.txt', 1), ('updateUserCapacity', 'missing', 0), ('getFileSize', '/missing.txt')]
Expected Output: [[], False, True, False, -1, -1, -1]
Explanation: This covers edge cases: no matches for findFiles, reserved admin user, duplicate user creation, missing user, and missing file.
Input: [('addUser', 'eve', 20), ('addFileByUser', 'eve', '/e/a.log', 7), ('copyFile', '/e/a.log', '/e/b.log'), ('updateUserCapacity', 'eve', 14), ('findFiles', '/e', '.log')]
Expected Output: [True, 13, True, 0, ['/e/a.log(7)', '/e/b.log(7)']]
Explanation: The copy succeeds because Eve's usage becomes 14, which still fits within capacity 20. Updating capacity to 14 removes nothing.
Hints
- Use one hash map from file path to its metadata so existence checks, copies, and size lookups are O(1) on average.
- For each user, track used space and the set of files they own. During updateUserCapacity, sort only that user's files in the required removal order.