Date: 2026-06-05
Time: 13:25
This file is a single-module simulation of Google Drive's backend storage layer, built as a system design interview reference implementation. It owns the core file storage domain: CRUD operations on files and folders, version history, chunked uploads for large files, permission-based sharing, conflict detection for multi-device sync, quota management, and trash/recovery. Everything runs in-memory — no database, no network — isolating the *design decisions* from infrastructure concerns.
Permission — Three-tier enum (READ < WRITE < ADMIN) with a companion PERMISSION_LEVEL dict that maps each variant to an integer for comparison. This is the authorization primitive used everywhere.
FileMetadata — The central entity. Represents both files and folders (discriminated by is_folder). Notable fields:
shared_with: dict[str, Permission] — per-user ACL stored directly on the fileversionvector: dict[str, int] — maps deviceid → version_number, used for conflict detectionisdeleted / deletedat — soft-delete markers for trash semanticsFileVersion — Immutable snapshot of file state at a point in time. Stores both metadata (contenthash, sizebytes) and the actual content: bytes. The version list is the full edit history.
ChunkedUpload — Tracks an in-progress multipart upload session. Holds individual chunks and checksums until completechunkedupload assembles them.
FileStore — The Main ClassSingle class that acts as the entire storage service. Constructor parameters set system-wide policy: maxversions (cap on version history depth, default 100) and defaultquota_bytes (1 GB per user).
Internal state is organized into parallel dictionaries keyed by file_id:
self.files — metadata registryself.content — current file bytesself.versions — version history listsself.chunked_uploads — in-flight upload sessionsself.user_quotas — per-user byte countersself.user_roots — per-user root folder IDs (lazy-created)Folder ops: createfolder, listfolder, getpath — standard tree operations. getpath walks parent pointers to reconstruct the full /a/b/c path.
File CRUD: uploadfile, downloadfile, updatefile, deletefile, movefile, renamefile. Every mutating operation checks permissions and updates quotas.
Versioning: getversions, restoreversion — restoreversion doesn't do a raw rollback; it calls updatefile with the old content, creating a *new* version that happens to match an old one. This preserves the audit trail.
Chunked upload: initchunkedupload → uploadchunk (repeated) → completechunkedupload. Quota is reserved upfront at init, then released-and-reaccounted at completion. abortchunked_upload releases the reservation.
Sharing: share, revoke, getsharedwith — ACL management. Only owner or ADMIN-level users can share.
Conflict detection: detectconflict uses version vectors to distinguish true conflicts (concurrent edits from different devices) from simple staleness. resolveconflict supports two strategies: latestwins (no-op, server version stands) and keepboth (creates a (conflict) copy).
Trash: listtrash, restorefromtrash, emptytrash — soft-delete with time-based permanent deletion (default 30 days, computed via auto_days * 86400 seconds).
Search: Linear scan over all files with substring name matching and optional MIME type filter. Only returns files the user can read.
Soft delete — Files are never immediately removed from self.files. Deletion sets isdeleted=True and records deletedat. Permanent removal only happens in empty_trash based on age.
Lazy root creation — getorcreateroot ensures every user has a root folder, created on first access. This avoids upfront user registration.
Quota reservation — Chunked uploads reserve quota at init time, not completion. This prevents a user from starting multiple uploads that collectively exceed their quota. The reservation is released then re-accounted when the upload finalizes.
Permission inheritance — checkpermission walks up the folder tree via parentfolderid pointers. If any ancestor grants sufficient access, the check passes. This models Google Drive's "shared folder" semantics.
Version vectors for conflict detection — Rather than simple version counters, each file tracks which version each device last wrote. A conflict is detected when another device has a version newer than what the requesting device last saw — distinguishing concurrent edits from sequential ones.
Content-addressed integrity — SHA-256 checksums are computed on upload/update and stored in both FileMetadata.checksum and FileVersion.content_hash.
Imports: All stdlib — hashlib (checksums), math (ceiling division for chunks), uuid (ID generation), dataclasses, enum, typing. No external dependencies.
Imported by: testdesigngoogle_drive.py — the test suite is the sole consumer.
A typical file lifecycle:
1. Upload: upload_file → quota check → generate UUID → compute SHA-256 → create FileMetadata → store content → create initial FileVersion (v1)
2. Edit: updatefile → permission check → quota delta adjustment → new checksum → bump currentversion → update version vector for device → append FileVersion → prune if over max_versions
3. Sync conflict: Device B calls detectconflict(fileid, "deviceB", baseversion=1) → file is at v3, device A wrote v2 and v3 → versionvector["deviceA"] > version_vector.get("deviceB", 0) → returns True
4. Delete: deletefile → soft-delete → if folder, cascade to all descendants via BFS in get_descendants
5. Trash cleanup: emptytrash → filter by deletedat <= cutoff → hard-delete from all stores → release quota
For chunked uploads: initchunkedupload reserves quota → N calls to uploadchunk storing individual chunks → completechunkedupload assembles chunks in order, releases reservation, delegates to uploadfile for the actual storage, then cleans up the upload session.
uploadfile or updatefile is tracked; every byte removed via emptytrash or abortchunked_upload is released. Chunked uploads reserve upfront and release-then-reaccount on completion.downloadfile, updatefile, deletefile, movefile, renamefile, listfolder, and search all call checkpermission.updatefile prunes to maxversions, keeping only the most recent entries.completechunkedupload checks range(total_chunks) and raises on any missing index.checkpermission returns immediately if meta.ownerid == userid.Three exception types are used consistently:
| Exception | Raised when |
|-----------|------------|
| FileNotFoundError | File ID doesn't exist or file is soft-deleted |
| PermissionError | User lacks required permission level |
| ValueError | Quota exceeded, missing chunks, unknown conflict strategy, or version not found |
Errors are raised immediately — nothing is swallowed. Callers (the test suite) are expected to handle them. There's no retry logic or partial-failure recovery. abortchunkedupload and delete_file are the only methods that return bool success/failure instead of raising.
design-google-drive/testdesigngoogle_drive.py — See how conflict detection, chunked uploads, and permission inheritance are exercised in testsdesign-google-drive/designgoogledrive.py:detect_conflict — The version vector logic is the most interview-relevant part; trace through multi-device edit scenariosdesign-google-drive/plan.md — Understand the design decisions and tradeoffs considered before implementationversion-vector-vs-lamport-clock — Why version vectors were chosen over simpler conflict detection; how they scale with device counts3-object-storage/s3objectstorage.py — Compare the object storage design: different chunking, deduplication, and metadata strategies for a related problemgdrive-permission-inheritance — Permission checks walk up the folder tree via parent pointers; access granted on any ancestor grants access to all descendantsgdrive-quota-reservation — Chunked uploads reserve full quota at init and release-then-reaccount at completion, preventing over-commitmentgdrive-version-vector-conflict — Conflict detection uses per-device version vectors, not simple version counters; a conflict requires a *different* device to have written a version the requesting device hasn't seengdrive-soft-delete-cascade — Deleting a folder soft-deletes all descendants via BFS traversal; permanent deletion only occurs in empty_trash after a time-based cutoffgdrive-restore-creates-new-version — restoreversion delegates to updatefile, so restoring to an old version creates a new version entry rather than rolling back the version counter