System-design interview · Core interviews
Design a file synchronization service
Design revision publication, offline conflict handling, chunk transfer and device catch-up; keep each workspace's changes in a recoverable order and prevent cleanup from deleting chunks still needed by uploads or saved revisions.
You will learn to
- Separate file bytes from the atomic operation that publishes a revision.
- Trace a changed chunk from one device to another without losing concurrent edits.
- Explain deduplication, partitioning, notification recovery, and version-aware cleanup.
Practice in this chapter
8 interview questions with model answers and follow-ups.
Go to interview practiceUseful foundations: Storage engines and data models · Transaction isolation · Message queues, event logs, delivery guarantees, and backpressure
Workload and timing examples are interview assumptions.
Dotted concept links open the relevant explanation in a new tab.
01Problem and scope
A file synchronization service propagates saved file revisions across devices while preserving edits made offline. The server must record which revision is current, retain committed changes and decide what happens when edits conflict. Copying bytes alone does not solve those problems. For example, clients A and B both edit budget.xlsx from revision 12. If client B commits revision 13 first, client A’s later upload must preserve its conflicting work rather than silently overwrite revision 13.
A revision describes one immutable saved version. A chunk is a piece of file bytes; a revision's manifest lists chunks in order. A 9 MiB file can contain two 4 MiB chunks and a final 1 MiB chunk. If the middle chunk changes, the other two can be reused. A stable file ID survives renames; its path does not. These definitions separate identity, history and storage.
A workspace is the shared collection of files, folders and membership permissions governed by one metadata authority in this design. Choosing it as the transaction boundary lets a file change, its access checks and the corresponding history entry succeed together.
Scope the service to general files up to 1 GiB, shared folders, offline editing and version history. Preserve conflicting binary edits as conflict copies; automatic merging requires file-format-specific semantics. Publication is atomic within one workspace. A cross-workspace move is an explicit copy/delete workflow rather than a global transaction. Character-level simultaneous editing is excluded, and clients expose pending and conflict states when synchronization cannot immediately complete.
02Functional requirements
The server records committed changes in an ordered change log. A device's cursor identifies how far it has safely applied that history. Deletion adds a tombstone, a retained record that tells offline devices to remove a file when they catch up; simply erasing the server row would lose that instruction.
- Commit file revision: All referenced chunks exist durably before the revision becomes current.
- Handle concurrent edits: An unseen current revision is not silently overwritten.
- Rename/move: Stable file identity and an atomic workspace metadata change.
- Delete: A tombstone reaches devices; retained history follows stated retention.
- Catch up: Apply every committed change after the device's cursor or request a fresh snapshot.
- Share/revoke: Server checks current grants at commit and before issuing downloads.
Devices, folders and offline work
Users can create folders, upload, download, rename, move within a workspace, delete, restore retained revisions and share with readers or writers. Desktop clients automatically watch selected folders; mobile clients may list metadata immediately and download bytes on demand. Each device remembers its applied change cursor and unsent edits so reconnecting does not depend on receiving every live notification.
Local versus server completion
“Saved locally,” “uploading” and “synchronized” are distinct statuses. Client A can close the device while work is pending; the local journal must survive restart. A successful server commit returns a revision and a change sequence. Downloading to another device may still be pending. An online hint accelerates discovery but is not the only record of a change. A snapshot for an expired cursor must identify its corresponding log position so concurrent changes are neither skipped nor lost.
03Non-functional requirements
- Latency: Metadata commit p95 below 300 ms inside a region; ordinary connected-device discovery within five seconds.
- Transfer time: File size and bandwidth govern byte completion. A 1 GiB upload over 20 Mb/s takes over seven minutes even without overhead.
- Availability: 99.9% eligible metadata availability. Preserve correctness during conflicting writes or loss of the workspace's authoritative majority.
- Durability: An acknowledged revision, including metadata and referenced chunks, survives one node or availability-zone failure. Replica placement must match this promise.
- Regional recovery: Use a separate, initially asynchronous disaster-recovery policy with a tested recovery point and restore procedure.
- Retention: Keep old revisions and the change log for an illustrative 30 days. Longer legal/product retention has a separate cost; devices beyond the log horizon must resnapshot.
- Authorization: Recheck grants at final commit and before issuing downloads. Revocation during a long upload prevents publication into the workspace.
Commit and recovery invariants
| Invariant | Required result |
|---|---|
| Protected content | Every current revision references durable protected chunks. |
| Expected base revision | A commit based on revision 12 cannot overwrite unseen revision 13. |
| Committed cursor | Every change up to the returned cursor has committed; an earlier allocated position cannot arrive later and be skipped. |
| Disclosure boundary | Previously downloaded files cannot be recalled; issued download tokens have a bounded lifetime. |
These limitations belong in the product contract. Calling the database ACID does not establish cross-device completion, current permission checks, or the lifetime of already issued download capabilities.
04Capacity estimates
Workload assumptions and arithmetic
Assume 500 million accounts, 100 million daily active users, three devices per account and 200 files/account averaging 100 KB. That gives 500M × 200 = 100B files and 100B × 100 KB = 10 PB of current logical content. Versions, replicas and deduplication change the physical total. At an assumed 1 KB of metadata per file, file metadata alone is 100 TB before indexes.
Add five committed changes per active user/day: 100M × 5 / 86,400 = 5,787 commits/s, or about 28,935/s at fivefold peak. At 200 KB of changed bytes per commit, mean upload ingress is about 5,787 × 200 KB = 1.16 GB/s. If each change reaches two other devices, mean change deliveries approach 11,574/s before larger shared folders. Downloads depend on active-device behavior, not merely registered-device count.
Worked estimates
| Resource | Worked estimate | Consequence |
|---|---|---|
| Maximum file chunks | 1 GiB / 4 MiB = 256 |
Bound manifest and commit validation work |
| 10M online devices, 60-second heartbeat | 10M / 60 ≈ 166,667 heartbeats/s |
Connection state needs separate capacity |
| 1M reconnects in one minute | 1M / 60 ≈ 16,667 new sessions/s |
A connection rate is not concurrent connections |
| 100,000 cached 4 MiB chunks | About 391 GiB of bytes | Large-chunk cache admission matters |
Capacity implications and limits
A connections-per-minute figure measures establishment rate, not the number of concurrently active sockets; model these quantities separately. Chunk reuse offers substantial savings for a changed region of a large file, but many 100 KB files fit in one chunk, and compressed spreadsheets may change widely. Measure transferred bytes per committed revision before claiming a fixed deduplication percentage.
05APIs and contracts
Request and response example
Client A starts POST /workspaces/w7/files/f42/uploads with {"baseRevision":12,"requestId":"edit-77","size":9437184}. The server returns session up8, expiry and a list of chunk upload targets or already available workspace-scoped chunks. A manifest commit names ordered chunk identities, expected lengths and total checksum. An uploaded chunk alone never changes the visible file.
Interface contracts
| Operation | Meaning |
|---|---|
PUT /uploads/up8/chunks/1 |
Retry one bounded chunk with checksum and scoped authorization |
POST /uploads/up8/commit with [cA,cD,cC] |
Conditionally publish against base revision 12 |
GET /workspaces/w7/changes?after=880&limit=1000 |
Return committed-prefix changes and next cursor |
GET /files/f42/revisions/13 |
Authorized manifest and short-lived chunk download grants |
POST /files/f42/restore with expected current revision |
Create a new revision referencing retained historical chunks |
GET /workspaces/w7/snapshot |
Consistent file/folder snapshot plus its corresponding committed change sequence for expired cursors |
Validation and response semantics
A conflict returns 409 with the stable conflict-copy identity and current revision; a retry of edit-77 returns the same result. A missing/expired session returns an explicit retry-required error, not permission to publish unprotected chunks. A cursor older than retention returns a resnapshot requirement. Pagination advances only through a committed prefix: allocating sequence 881 before commit and letting 882 become a returned cursor could permanently skip 881. Our workspace owner allocates and publishes sequence positions in serialized metadata transactions.
06Data model and access patterns
Keep the stable file identity separate from its immutable revision history. Each revision names chunks that may also belong to other retained revisions, so the server needs records for both the bytes and their continued use. Upload sessions protect pending work; change-log entries let other devices discover a committed result.
| Record and fields | Responsibility / constraint |
|---|---|
File(workspaceId,fileId,parentId,name,currentRevision,deletedAt) |
Stable file identity and current head. |
Revision(workspaceId,fileId,revision,manifest,author,createdAt) |
Immutable revision and manifest. |
Chunk(workspaceId,chunkId,objectKey,size,checksum,state,retainedRefs) |
Chunk identity, state and retained references. |
Upload(sessionId,requestId,baseRevision,leaseUntil,pinnedChunks,state,result) |
Upload protection and retry state. |
Change(workspaceId,sequence,fileId,action,revision) |
Ordered workspace catch-up entries. |
Workspace(nextSequence,logEpoch) |
Workspace sequence and log epoch. |
Membership |
Readers and writers. |
The same workspace metadata group controls the rows needed to publish and protect chunks. A session pin is a record preventing a chunk from being deleted while an active upload may publish it; a retained reference protects it while a saved revision still uses it. Device cursors acknowledge how far each device has applied the change log; they are not the only history.
Index folder children by (workspaceId,parentId,name) and changes by (workspaceId,sequence). A rename changes the directory entry while preserving f42. Manifests are immutable; restoration creates a new current revision rather than editing old history. The query WHERE workspaceId='w7' AND sequence>880 ORDER BY sequence LIMIT 1000 reads the change log, with a consistent upper committed watermark.
Chunks live in private object storage keyed by workspace and verified identity. Deduplication within that boundary can reuse equal chunks; cross-tenant deduplication is deliberately deferred because a global “does this hash exist?” endpoint can disclose private content. Metadata is authoritative for references and permissions; caches and notification directories are derived. If a giant workspace outgrows one metadata owner, splitting its transactions requires an explicit new protocol. Hashing file IDs across databases without preserving workspace invariants is not a free scale improvement.
A namespace mutation also enforces a unique directory entry (workspaceId,parentId,normalizedName) under the chosen case/Unicode policy. Within the serialized workspace transaction, verify that the target is a folder, the actor can modify both source and destination, and a folder is not moved beneath itself or a descendant. Concurrent rename/move validation must share that serialization; checking the tree before taking the namespace lock leaves a cycle race. File IDs remain stable while directory entries change.
07Basic working design
Whole-file revision commit
A minimal product uses one API, one transactional metadata database and durable file storage. Client A uploads the full 9 MiB file under an immutable temporary revision key. The API verifies it, then transactionally checks base revision 12, writes revision 13, points f42 to 13 and appends change 881. Only after commit does it report that the server saved the revision. If the file transfer fails, no new revision is visible; if commit response is lost, request edit-77 retrieves the saved result.
Device catch-up and local replacement
Client B polls changes after cursor 880, downloads revision 13 to a temporary file, verifies it and replaces the local copy after preserving any unsent edits. It updates its local journal/cursor so a crash can replay safely. The filesystem and local metadata database do not share one atomic transaction: journal the intended replacement, perform the verified rename, then finalize metadata, checking on restart whether that revision is already applied.
Why this baseline is useful
This baseline transfers whole files and polls periodically. It can be useful for a small team and already handles the essential revision conflict. Backups include both metadata and immutable files. Adding chunking or WebSockets later should improve efficiency, not be required to rescue an unclear correctness model. The initial commit and retry record remain the anchor for the rest of the interview.
Bytes exist before one metadata transaction publishes the new revision and change entry.
Read each connection in order
- sync1. Upload full file / base 12Desktop sync clients → Sync application
- sync2. Store and verify revision bytesSync application → Durable immutable file storage
- sync3. Commit head, result and changeSync application → SQL revisions and workspace log
- sync4. Poll changes after 880Desktop sync clients → Sync application
- sync5. Revision 13 and bytesSync application → Desktop sync clients
08Find the baseline flaws
Whole-file transfer is the baseline's efficiency limit. The other examples show why two tempting shortcuts—accepting the last upload and using the largest allocated sequence as a cursor—would break the conflict and recovery guarantees already established. Scaling must retain those guarantees.
| Bottleneck / counterexample | Evidence and design consequence |
|---|---|
| Whole-file transfer amplification | Client A changes 4 MiB in a 9 MiB file. Whole-file upload and download transfer 9 MiB each, even though 5 MiB is unchanged. A failed transfer near completion may repeat most of that work. At the broader assumed 1.16 GB/s changed-byte workload, systematic retransmission multiplies network cost and sync time. Chunking gives bounded retry units; it does not eliminate the need to commit a complete manifest. |
| Unseen concurrent edits | Now client B commits revision 13 while client A remains offline at base 12. Last-write-wins by upload time would make client A overwrite client B without seeing the committed work. Client timestamps do not fix this: clocks differ, and recency does not imply intent to replace unseen changes. The server must check baseRevision atomically with currentRevision and preserve a conflict result. |
| Allocated versus committed cursor | A second counterexample is log ordering. Writer A allocates 881 then stalls; B allocates and commits 882; client B receives 882 and saves that cursor; A later commits 881. A query for changes after 882 will never return 881. A monotonically increasing allocation counter is not necessarily commit order. Serializing workspace publication or exposing only a proven contiguous committed watermark closes this hole. We choose serialization per workspace because it also supports atomic rename and conflict checks without cross-owner transactions. |
09Improve the design, step by step
Add fixed-size chunk transfer and a local client index. The trigger is repeated whole-file retransmission. A chunker splits large files, an indexer compares manifests, a watcher reports filesystem events, and a local database remembers revisions and pending operations. Only changed chunks move; retries repeat at most a chunk. Costs are client CPU, metadata and shifted boundaries after insertions. Whole-file transfer remains simpler for small files; content-defined boundaries become worthwhile if large shifted files dominate measured traffic.
Separate byte endpoints from metadata and add protected upload sessions. Long transfers trigger separate block-serving capacity with health-aware balancing, bounded buffers and resumable sessions. Metadata commits stay responsive while bytes move. Cleanup could now delete a chunk just before publication. In one metadata transaction, replace the upload session’s protection with the saved manifest’s references. A single pool is preferable until concurrency measurements justify isolation.
Use a durable change log plus notification gateways. Empty polls from millions of devices trigger long polling or persistent connections. Gateways send a lightweight “changes available” hint, and clients catch up using their cursors. This lowers discovery delay without storing infinite private queues. It costs connection memory, heartbeats and reconnect management. Per-device durable response queues are a valid architectural alternative, but require bounded retention and cleanup; the log offers shared recovery history.
Partition by workspace and replicate its authority. The 100 TB metadata estimate and 29,000 peak commits/s trigger many logical workspace partitions. Each has a replicated owner; different workspaces proceed independently. This preserves local transactions but makes an exceptionally large workspace a hot owner. Alternatives include directory/file partitions with an explicit shared-log and transaction protocol, or a distributed transactional database. Neither “consistent hashing” nor a NoSQL label automatically fixes one hot workspace or supplies global ACID behavior.
Letters identify chunks. Vertical arrows mark content reused by the next manifest.
Remember: A new file revision can reuse old bytes.
Read the diagram
- Compare manifests A B C D and A B X D.
- A, B and D are reused. Only missing chunk X needs uploading.
- Validate the chunks before publishing the revision and retaining their references.
Try from memoryWhich content must be transferred if the receiver already has A, B, C and D?
Only X. Revision 2 then names A, B, X and D in that order.
Fixed-size chunking places boundaries at fixed byte offsets, so inserting bytes near the start can change many later chunks. Content-defined chunking chooses boundaries from patterns in the content instead; unchanged regions can then keep matching even after their offsets shift. It can reduce retransmission for that workload, but requires more boundary-detection work and measurement.
Add chunk and manifest caches only where reuse is measured. A byte cache should not make a current permission decision, and many cold small files may be cheaper to serve directly.
10Detailed architecture
Desktop client responsibilities
The desktop client contains four responsibilities, not four mandatory backend services: watcher detects local changes, chunker computes/reconstructs pieces, indexer schedules uploads/downloads, and the local database records manifests, revisions and durable pending work. The client also merges remote metadata with unsent local edits and shows conflicts. Mobile clients use the same revision protocol while choosing lazy byte download.
Workspace metadata and chunk authority
On the server, metadata APIs route workspace w7 to its current owning replica group. That group owns file heads, manifests, chunk-reference/pin metadata, membership, request results and the ordered change log. Byte gateways authorize exact chunk operations and serve private object storage through an optional cache. Object durability and metadata durability have separate implementations but meet the same acknowledged-failure contract.
Notification hints and session directory
An outbox or committed-change relay sends hints to notification gateways, whose directory maps devices to live connections. Hints may be duplicated or missed. Devices recover from the shared log, so an offline device does not require an unbounded gateway queue. Cleanup workers act through the metadata authority before deleting unreferenced chunk generations. Background deduplication, if used, likewise changes references through authority rather than silently swapping arbitrary bytes.
Commit boundary and independent recovery
The server replies after one transaction saves the manifest, current revision, change entry and request result. Other devices catch up, caches fill and unused bytes are removed afterward. A workspace migration copies and catches up its log, fences the old ownership epoch, and then switches routing; merely changing a configuration pointer risks two concurrent owners.
Capture a stable local byte version
Before hashing or uploading, the client must capture one stable local byte version. Use an immutable staging snapshot or copy made under an appropriate filesystem/application lock; read every chunk from that captured version. Hashing a live file while an application rewrites it can otherwise produce a manifest mixing two saves even when each chunk checksum is valid. When the platform cannot provide a reliable capture, detect concurrent modification and retry or show a pending/conflict state rather than promising an application-consistent snapshot from a watcher event alone.
Client journals and server change logs recover missed work. A workspace owner atomically transfers chunk protection while publishing revisions.
Read each connection in order
- sync1. Journal base 12 and edit-77Client watcher, chunker and indexer → Client journal and manifest database
- sync2. Reserve / commit upload up8Client watcher, chunker and indexer → Metadata and sync API
- sync3. Route workspace w7Metadata and sync API → Workspace owner router
- sync4. Guarded manifest transactionWorkspace owner router → Workspace metadata and change log
- replication5. Replicate committed stateWorkspace metadata and change log → Workspace authority replicas
- sync6. Upload or fetch scoped cDClient watcher, chunker and indexer → Authorized chunk gateways
- sync7. Authorized cache lookupAuthorized chunk gateways → Hot chunk and manifest caches
- sync8. Store / fetch immutable chunkAuthorized chunk gateways → Private immutable chunk storage
- async9. Read committed changesWorkspace metadata and change log → Committed-change relay
- async10. Hint that w7 changedCommitted-change relay → Notification gateways and directory
- async11. Notify client to check change logNotification gateways and directory → Client watcher, chunker and indexer
- sync12. Read after cursor 880Client watcher, chunker and indexer → Metadata and sync API
- sync13. Guard pin/reference removalReference and session collector → Workspace metadata and change log
- async14. Delete DELETING generationReference and session collector → Private immutable chunk storage
11Write path and acknowledgement
Before making a revision current, the server checks permission and the expected base revision, protects its durable chunks, and saves a change entry in the same commit. The successful trace below uses file f42 in workspace w7, request edit-77, and current base revision 12; the later conflict example considers an intervening commit.
- Client A's watcher reports a change. Its local database records that f42 began at revision 12 with
[cA,cB,cC]. The chunker produces[cA,cD,cC], and the indexer journals edit-77 before sending network work. - The server authorizes client A and reserves session up8 with base 12, a finite lease and pins for reusable chunks cA/cC. It rejects chunk claims outside w7's authorized namespace.
- Client A uploads only cD. The byte endpoint verifies length/checksum and records the immutable object's durable availability. The session pins protect the chunk while publication remains allowed.
- Commit locks the session, f42, workspace sequence state and referenced chunk metadata in a deterministic order. It verifies the active session, current grant, all chunk states and
currentRevision=12. - In one transaction, create revision 13, transfer protection to retained manifest references, point f42 to 13, append committed change 881, and save edit-77's successful result. The workspace sequence advances with this commit.
- After required replication acknowledges, return revision 13/sequence 881. Lost responses recover by edit-77. A conflict records a stable conflict-copy result instead of modifying the winner's head.
- A change hint is emitted. Chunk reclamation happens later after no active pin or retained manifest references the object. Upload success alone never means that the file became current.
For a 1 GiB file, at most 256 fixed 4 MiB chunks bound manifest validation. Batch operations where safe, but do not remove the checks that prevent a partial manifest from being accepted.
12Read and delivery path
Device synchronization recovers from the durable change log, independently of live notification delivery. This trace advances a second device from cursor 880 through committed change 881 and applies revision 13 safely.
- Client B receives a hint or reconnects and requests changes after 880. The server verifies current workspace membership and returns committed change 881 with an upper watermark that cannot skip an earlier uncommitted publication.
- Its indexer journals that f42 revision 13 is to be applied. If it has unsent local changes, preserve them and follow the conflict protocol before replacing local bytes.
- Fetch revision 13's immutable manifest
[cA,cD,cC]. Existing local chunks cA/cC are verified and reused; request only cD with a short-lived workspace-scoped download grant. - The byte gateway validates the grant before a cache hit or origin read. A miss fetches private storage, verifies transfer integrity and streams bounded chunks. A hot-file cache changes latency, not permission ownership.
- Reconstruct to a temporary location, verify the whole intended file, and replace the local file. The recovery journal handles a crash after replacement but before the local metadata update by recognizing the already-applied revision.
- Advance the durable local cursor only after the change is safely applied or the local recovery journal durably records everything needed to finish applying it after a crash. A repeated page or hint therefore does not create another user-visible revision.
13Correctness deep dive
Concurrent revision outcome
First consider client A and client B competing from base 12. Both may upload valid chunks. The workspace owner serializes their commit transactions. Client B wins and sets the head to 13. Client A's transaction then observes current 13, records its immutable manifest as conflict copy f42-conflict-edit77, and returns that identity without changing f42's head. Retry edit-77 returns the same conflict. The design preserves both byte sets rather than relying on timestamp order.
Chunk collection uses the same authority
The second race is publication versus a chunk collector. Keep chunk-state and protection metadata under the same workspace transaction boundary as manifest publication.
| Operation | Guard checked under metadata locks | Effect |
|---|---|---|
| Pin chunk for upload | Chunk AVAILABLE; session valid | Add live session protection |
| Commit manifest | Session valid; every chunk AVAILABLE and protected | Add retained references and release session pins atomically |
| Expire session | Session deadline passed and not committed | Close session and release its pins |
| Select chunk for deletion | Zero retained references and zero valid pins | Mark DELETING; future pins/commits reject it |
| Delete bytes | Chunk remains DELETING for exact generation | Idempotent object removal and completion record |
Publication versus collection proof
Retained-history references
Retained historical revisions count as references, not just the current file head. Otherwise restoring revision 12 could fail after its old middle chunk cB was reclaimed. The protocol is workspace-local; a later cross-workspace deduplication scheme needs its own reference authority rather than assuming this transaction spans every tenant.
Conflict copies are real publications
The workspace owner serializes the expected-revision check with publication. A stale base creates a stable conflict result, not silent data loss.
Read each connection in order
- syncUpload cD for base 12Client A → Chunk store
- syncCommit different edit, base 12Client B → Workspace owner
- returnHead 13 and change 881 committedWorkspace owner → Client B
- syncCommit edit-77, base 12Client A → Workspace owner
- syncHead 13: commit conflict, refs and changeWorkspace owner → Workspace owner
- blocked409 and stable conflict-copy ID: reply lostWorkspace owner → Client A
- syncRetry edit-77 after timeoutClient A → Workspace owner
- returnSame conflict result, head unchangedWorkspace owner → Client A
14Failure and recovery
| Failure / trigger | User outcome, surviving state and recovery |
|---|---|
| Crash after chunks but before commit | up8 and its pins survive; client A sees pending, not synchronized. Retry resumes the same request. If the session expires, cleanup first closes its publication right, then reclaims unreferenced bytes. A response lost after commit instead returns the saved result, so the client does not create revision 14 accidentally. |
| Workspace authority partition | A majority may continue; an isolated old owner must be fenced and cannot acknowledge commits. Client A keeps editing locally with pending status. Read-only cached metadata is not permission to upload or overwrite. After reconnection, the server evaluates the client’s actual base revision and may create a conflict. This sacrifices online progress during isolation to prevent split histories. Region failure follows the separately declared recovery objective, not the single-zone promise. |
| Reconnect storm | One million devices reconnecting in a minute means about 16,667 sessions/s before change queries and downloads. Gateways apply jittered exponential backoff, stagger snapshot work and cap per-workspace catch-up concurrency. Prioritize small metadata pages while rate-limiting bulk downloads, so one backlog does not prevent unrelated renames. Clients retain durable pending queues and show progress. |
| Lost notification or gateway crash | No committed revision is lost because cursor catch-up reads the log. Presence in a connection directory is a lease, not proof a device has applied a change. Observe the oldest unsynchronized cursor and distinguish disconnected devices from a server propagation backlog. Files already on a revoked device cannot be remotely made secret again. |
15Operations, security, and cost
Commit, conflict and integrity signals
Monitor commit p95/p99, conflict rate by file format, unsynchronized-device age, chunk retry bytes, pending-session age, DELETING backlog and integrity failures. Verify log cursor monotonicity against committed watermarks. An accepted revision with an absent chunk is a critical integrity incident; a delayed notification is a different, recoverable latency incident. Track both instead of aggregating them into one sync-success count.
Chunk-reuse economics
Deduplication economics depend on reuse. For a 9 MiB file whose middle 4 MiB changes, uploading one chunk saves 5/9 ≈ 56% of that upload compared with full retransmission. For an average 100 KB file that changes entirely, fixed chunking saves no bytes and adds bookkeeping. Inline deduplication avoids transfer but adds lookup latency and privacy controls; post-process deduplication keeps ingestion simpler but temporarily stores and transfers duplicates. Hashes locate candidate equality; verify length and, where required, bytes rather than presenting hashing as mathematical uniqueness.
Scoped transfer and authorization
Encrypt transport and storage, scope chunk tokens to object, operation and expiry, and recheck grants at publication. Exclude secret filenames and contents from telemetry. Quotas include historical revisions, not just current file size, or repeated edits can bypass storage budgeting.
Recovery and migration drills
Recovery tests include restoring revision 12 after revision 13 and deletion, restarting after local rename but before cursor persistence, reconnecting beyond log retention, and racing session expiry with commit. Migration tests copy a workspace, replay committed changes, compare directory listings/manifests, fence the old owner and verify no stale epoch can publish. Repartitioning a hot workspace is a product-level consistency change requiring explicit design review, not routine modulo arithmetic.
Delta encoding inside a changed chunk
A further bandwidth optimization is delta encoding inside a changed chunk: upload a patch against an explicitly identified retained base instead of the whole chunk. The receiver reconstructs the full new immutable chunk and verifies its checksum before it becomes eligible for a manifest. This differs from reusing an unchanged chunk. Patches add CPU, base-retention dependencies and retry complexity, so use them only when measured small edits save enough bytes.
16Decision ledger and limitations
| Decision | Chosen benefit | Cost / limitation | Change trigger |
|---|---|---|---|
| Fixed 4 MiB chunks | Bounded retries and simple manifests | Insertions can shift later boundaries | Content-defined chunks win measured bytes/CPU tradeoff |
| Workspace-local metadata transactions | Atomic head, references and ordered changes | One huge workspace can bottleneck | Explicit distributed transaction/log protocol |
| Durable log and cursors | Shared offline recovery without per-device infinite queues | Resnapshot after retention | Very small device population favors simpler queues |
| Conflict copies for binary edits | Preserves both users' work | Manual resolution | Format-specific merge semantics are available |
| Workspace-authorized deduplication | Reuse without global existence leakage | Misses some cross-tenant savings | A reviewed possession/privacy design justifies it |
Functional partitioning into separate user, file and chunk stores simplifies ownership but can make joins and atomic checks cross databases. Alphabetical pathname ranges support some ordered scans but skew as popular prefixes grow and renames move keys. Hashing file IDs spreads independent records but requires directory indexes and may break workspace-local transactions. Consistent hashing reduces movement when owners change; it does not solve one hot file or workspace by itself.
Caches can retain manifests and popular chunks with size-aware admission and least-recently-used (LRU) eviction, but a 4 MiB chunk consumes far more memory than a small metadata row. Health checks and load-aware admission, not round-robin alone, protect overloaded byte endpoints. No chosen store is exempt from its actual transaction and replication contract; modern key-value systems may provide conditional writes or transactions, and partitioned SQL remains viable.
17Interview closing
“I designed a shared file workspace that preserves offline edits and makes every accepted revision recoverable. Each commit checks its expected base revision. An intervening edit creates a recoverable conflict result rather than silently overwriting unseen work. The client has a watcher, chunker, indexer and durable local journal, while the server separates byte transfer from workspace metadata authority.
“Chunks upload first under protected sessions. A workspace transaction validates membership, base revision and protected chunks, then commits the manifest, current head, request result and ordered change entry. Device hints only accelerate discovery; cursors over a committed prefix recover missed notifications. Collection cannot delete a chunk that publication is still allowed to reference.
“The workload is around 5,800 average commits per second and ten petabytes of current logical bytes, so I partition independent workspaces and measure chunk reuse. The main remaining bottleneck is a very large workspace, not the number of WebSocket servers. My next tests are concurrent binary edits and restoration after garbage collection.”
If the interviewer demands automatic spreadsheet merging, ask which format semantics and conflict rules are acceptable. That requirement needs a merge-aware document service; last-write-wins plus a sync transport does not satisfy it.
Practise the interview questions
Say your answer aloud before opening the model answer. Then answer the follow-up and compare the reasoning.
Why not overwrite the remote file as soon as a chunk arrives?
Reveal a model answer
I need a complete, meaningful version. Publishing a partly uploaded file could let client B download missing or mismatched chunks. I upload immutable chunks first and change the manifest pointer only after validation.
Interviewer follow-up
What if the final metadata write fails?
Reveal the follow-up answer
The previous revision remains current. I retry the same commit identity; unreferenced uploads are eventually reclaimed.
What the answer must demonstrate: Look for a publication boundary, not an assumed transaction across services.
Two offline devices edit the same spreadsheet. How do you avoid losing data?
Reveal a model answer
Each commit names its base revision. If client A started at revision 12 but client B has already committed revision 13, the server must reject the stale overwrite and preserve A’s immutable bytes as a stable conflict copy. Retrying the same request returns that conflict result. This protects both versions without assuming that generic binary files can be merged. The conflict-copy transaction must retain its chunks and append its own discoverable workspace change, while still checking current write permission. Otherwise an apparently preserved conflict could disappear when the upload session expires.
Interviewer follow-up
Could you merge automatically?
Reveal the follow-up answer
Only for a file format with a tested merge rule. A generic byte merge can produce a corrupt spreadsheet even when individual chunks look valid.
What the answer must demonstrate: Do not equate eventual convergence with preserving user intent.
A device misses every push notification for a day. How does it recover the correct folder state?
Reveal a model answer
Push is only a hint. On reconnect, the device reads the durable change log after its last applied cursor—for example, after 880—and applies each committed change. It advances the cursor only after applying a change or durably recording the information needed to finish applying that change after a crash. It does not infer synchronization from the absence of notifications.
Interviewer follow-up
What if change 881 has been deleted by retention?
Reveal the follow-up answer
The server returns a cursor-expired response. The device obtains a consistent namespace snapshot with its log watermark, reconciles unsent local edits, and then applies changes after that watermark.
What the answer must demonstrate: A notification channel must not be the only history.
Why not ask a global server whether each chunk hash already exists?
Reveal a model answer
It could reduce uploads, but a global existence test can reveal whether another tenant holds a guessed document. I start with workspace-authorized deduplication and verified bytes. This matches our workspace-local pin/reference authority; tenant-wide or cross-workspace reuse would need a separately designed shared-reference and authorization protocol.
Interviewer follow-up
Does a strong hash guarantee identity?
Reveal the follow-up answer
It makes accidental collisions extremely unlikely, but the storage invariant should include collision handling and byte verification where required.
What the answer must demonstrate: Separate probability from enforcement and privacy.
Which work belongs on the client?
Reveal a model answer
The watcher detects edits, the chunker divides content, the local metadata database remembers revisions and cursors, and the indexer schedules changes. That lets an offline device resume without rescanning or retransmitting everything. Before chunking, capture a stable local byte version; a watcher notification alone does not make a concurrently edited file consistent.
Interviewer follow-up
What changes on a phone?
Reveal the follow-up answer
I would use on-demand downloads, network and battery policies, and bounded retries while keeping the same version protocol.
What the answer must demonstrate: Name responsibilities and why local state matters.
What breaks if we hash every file independently across database servers?
Reveal a model answer
Point reads distribute well, but a folder listing and a workspace change stream now cross shards. I would partition ordinary workspaces together and explicitly split oversized ones.
Interviewer follow-up
Why not just use a larger SQL server?
Reveal the follow-up answer
That is a sensible first growth step; the estimated metadata volume and peak writes eventually justify partitioning. SQL remains usable after that decision.
What the answer must demonstrate: Avoid treating a database category as a scaling plan.
Why is a database-generated increasing sequence not automatically a safe sync cursor?
Reveal a model answer
Allocation order can differ from commit order. If 881 is allocated and stalls while 882 commits, a device that advances to 882 can miss 881 forever. I serialize workspace publication including the counter, or expose only a verified contiguous committed watermark. Our design chooses the former within each workspace.
Interviewer follow-up
Can you share one counter across every workspace?
Reveal the follow-up answer
That would create unnecessary global contention. A cursor is scoped to a workspace and log epoch; independent workspaces can commit concurrently. Cross-workspace views need explicit composition rather than pretending the sequences form one order.
What the answer must demonstrate: Distinguish allocated IDs from a committed log prefix.
You checked that a chunk exists, but collection deletes it before the manifest commits. Where is the fix?
Reveal a model answer
The session pins and retained-reference metadata share the workspace authority with publication. Commit locks the chunk rows, requires AVAILABLE, and transfers protection from session pins to the manifest in one transaction. Collection may mark DELETING only with zero references and pins. Whichever transition wins makes the competing guard fail.
Interviewer follow-up
Why do historical revisions matter?
Reveal the follow-up answer
Their manifests still promise restoration. They retain references until history expires; considering only the current head would let collection break an old acknowledged revision.
What the answer must demonstrate: Publication and cleanup must check and change the same protection records; waiting a guessed interval cannot replace that check.
Blank-page exercise · 45 minutes
Build the answer yourself
Design shared file synchronization with offline editing, version history and 4 MiB chunk transfer. Explain publication, device catch-up and collection, then resolve two clients committing changes based on revision 12 after one has already published revision 13.
- Define the publication invariant and conflict policy.
- Calculate files, metadata bytes, change QPS, and changed-byte traffic.
- Trace one changed chunk and one missed notification.
- Explain upload cleanup without breaking old revisions.
- Compare workspace, range, and hash partitioning.
Check that each component and design decision follows from your requirements and workload.
Recall the key ideas
Answer from memory before opening each card. Explain why the choice works and what it costs. Revisit missed cards tomorrow.
Design a file synchronization serviceWhat makes a revision visible?Recall first, then reveal
All chunks exist, then one conditional transaction publishes the manifest, current pointer, and change entry.
Bytes first; pointer last.
Return to lessonDesign a file synchronization serviceClient A edits base revision 12 while revision 13 is current. What should the commit do?Recall first, then reveal
Reject the stale overwrite and preserve the conflicting work as a conflict revision.
Compare the base; preserve both.
Return to lessonDesign a file synchronization serviceCan old chunks be deleted when the current file changes?Recall first, then reveal
Only when no retained revision or active upload can reference them.
History owns bytes too.
Return to lessonFinal revision
Summary and interview notes
File synchronization preserves both users’ work when one edits an older revision. One workspace transaction saves the new revision, protects its chunks, records the retry result and appends the change. Device journals and cursors let interrupted uploads and downloads resume safely.
Remember these points
- Capture one stable local byte version before chunking; independently valid chunks can still belong to different saves.
- Commit against the expected base revision; a conflict copy must retain its own bytes and appear in the change log.
- A safe cursor is a committed workspace prefix, not just the largest sequence number allocated.
- Session pins become retained revision references atomically; collection must first prevent future publication of the exact generation.
- A 4 MiB change in a 9 MiB file saves about 56% of upload bytes, while an entirely changed 100 KB file gets no such saving.
Interview tips
- Interleave two commits based on revision 12 and show both the winning head and the discoverable conflict result.
- Pause sequence 881 while 882 commits to test whether the cursor can skip work.
- Crash the client after local file replacement but before journal/cursor finalization, then explain recovery.
Important qualifications
- Workspace-local transactions deliberately bound the atomicity scope; cross-workspace moves and shared deduplication need another protocol.
- A filesystem event or before/after timestamp check alone does not guarantee an application-consistent snapshot.
- Previously downloaded files cannot be recalled after revocation; issued download capabilities have their stated lifetime.
Technical references
- Dropbox file access guideOfficial examples of file revisions, metadata, and cursor-based change traversal.
- Amazon S3 multipart upload overviewDocuments multipart upload completion, retries, checksums, and incomplete-upload management.
- PostgreSQL constraintsSupports explicit database constraints rather than assumed application-only uniqueness.
Practice marks stay in this browser.