Skip to content

File Storage & Sync — Principal-Level Deep Dive (The Stops)

The "never be blind" companion to the base File Storage docs. The system as a staircase of stops — smallest defensible design first, each bigger stop with its exact trigger — ending in the top-stop (max-scale / deliberately over-engineered) architecture plus a reconciliation table for when each heavy component is overkill and should be removed.

Read the base first: Requirements · Architecture · Deep Dives · Trade-offs.

Say this in an interview: "I'll start with whole-file blob upload and grow it one bottleneck at a time. I know the sharded-metadata, geo-replicated, cold-tiered, content-defined-chunking, E2EE version — but each piece only earns its place when a specific ceiling forces it."


The stops (climb one lever at a time)

Stop Scale target Shape Trigger that forces the NEXT stop
1 · Blob upload/download tiny; single user, few files POST whole file → one object store; GET it back; metadata in one DB no sync; whole-file re-uploads waste bandwidth; no dedup/history
2 · Chunk + metadata/data split moderate chunk + hash files; metadata DB (tree, versions, chunk lists) separate from content-addressed object store; dedup; resumable uploads large files; multi-device users want live sync; bandwidth cost
3 · Sync + notify + delta + sharded metadata (base target) 100Ms of users cursor-based /sync, notification service (push + poll backstop), delta up/download, metadata sharded by namespace, CDN downloads, refcount GC exabytes; global latency; storage cost; offline conflicts; privacy demands
4 · Global: geo-replicated metadata, cross-region blocks, tiering, CDC, E2EE (top stop) exabytes, global metadata geo-replicated + region-homed, cross-region block storage, hot/cold tiering, content-defined chunking, scaled conflict handling, selective/smart sync, optional client-side E2EE (ceiling; real-time co-editing or E2EE mandates become different systems)

Most interviews want Stop 2–3. Reach into Stop 4 only when the prompt says "global / exabytes / data residency / end-to-end encrypted / edited-in-place huge files." Name the trigger each time.


Top-stop architecture (max-scale)

  Client sync engine (content-defined chunking, local chunk cache, selective sync, optional E2EE)
        │ status / PUT blocks / commit / GET sync   (geo-routed to home region)
        ▼
  ┌──────────────────────────┐         ┌───────────────────────────────┐
  │ Metadata Service         │         │ Block Service + Block Store   │
  │  sharded by namespace,   │         │  content-addressed chunks,     │
  │  GEO-REPLICATED,          │◀──────▶│  cross-region replication /    │
  │  namespace HOMED to a     │  refcnt │  erasure coding, HOT/COLD      │
  │  region (commit authority)│         │  TIERING, CDN front            │
  │  strong consistency        │         └───────────────────────────────┘
  └───────────┬──────────────┘                        ▲
              │ on commit                              │ CDN (immutable blocks by hash)
              ▼                                   download path
      ┌──────────────────┐
      │ Notification Svc │  region-aware push "namespace changed" → user's devices + shared-folder members
      └──────────────────┘
  Async pipeline (off critical path): thumbnails/previews, search index, GC mark-and-sweep, virus scan  [disabled under E2EE]
  Per-user quotas + rate limits · audit/compliance · residency routing

Deep dives that only matter at the top stop

Geo-replicated / region-homed metadata (Stop 3 → 4 trigger: global users + data residency + five-nines)

  • Why: a global user base wants low-latency commits near them; regulations (GDPR) require some data stay in-region; a single region is a SPOF.
  • Design: home each namespace to a region that owns its commit authority (keeps commits single-shard, single-writer → preserves strong consistency + the monotonic cursor); replicate for read locality and DR; route by namespace home. Cross-region access round-trips to the home region for commits.
  • Over-engineering watch: only for global latency / residency / five-nines. Single-region multi-AZ metadata serves most; remove geo-replication below that (it adds real consistency complexity).

Cross-region block storage + hot/cold tiering (trigger: exabytes + cost + global reads)

  • Why: most stored bytes are cold; keeping everything hot in one region is expensive and far from distant users.
  • Design: replicate/erasure-code blocks across regions; tier by access (recent/active hot, archival to cheaper, slower cold storage with a retrieval delay); CDN for hot reads. Content addressing makes cross-region caching trivially correct (immutable).
  • Over-engineering watch: only at real exabyte scale / global reads. A single-region object store + CDN is plenty early; remove tiering when everything fits hot cheaply.

Content-defined chunking (trigger: large files edited in place)

  • Why: fixed-size chunking suffers the boundary-shift problem — an insert re-chunks the whole file, destroying dedup + delta savings for edited documents/VM images.
  • Design: rolling-hash (Rabin) boundaries so an edit only changes local chunks. See chunking.
  • Over-engineering watch: only when files are edited in the middle. For write-once media (photos/video), fixed-size is simpler and just as good; remove CDC there.

Async processing pipeline (trigger: previews/search/scan at scale)

  • Why: thumbnails, previews, full-text search, transcoding, and virus scanning are expensive and must stay off the upload critical path.
  • Design: on commit, enqueue jobs (queues + workers); workers process blocks and write derived data/indexes. Idempotent, retryable, DLQ'd.
  • Over-engineering watch: only when those features exist and matter. A pure sync product doesn't need it; and it's fundamentally incompatible with E2EE (server can't read content) — remove it in the E2EE mode.

Client-side E2E encryption (trigger: privacy product / regulatory mandate)

  • Why: the server must not read user content.
  • Design: client encrypts chunks; server stores ciphertext + metadata; per-recipient key exchange for sharing.
  • What it removes: cross-user dedup (ciphertext differs per user), all server-side processing (previews/ search/scan). Convergent encryption can restore some dedup at a security cost. A first-class trade. See E2EE.
  • Over-engineering watch: only when privacy is required. If you need server search/previews/compliance-scan, E2EE is the wrong mode — remove it and keep server-readable storage.

Selective / smart sync (trigger: devices can't hold everything)

  • Why: a user with 2 TB in the cloud and a 256 GB laptop can't materialize every file.
  • Design: sync metadata for the whole tree but download block content on demand (placeholder files hydrate on open); let users pin/unpin folders.
  • Over-engineering watch: only when cloud storage > device storage. Small footprints sync everything; remove it.

Reconciliation table — what forces each heavy component (and when to remove it)

Component Base docs (Stop 2–3) Top stop (Stop 4) Trigger to ADOPT When it's OVERKILL → remove
Metadata sharded by namespace, single region multi-AZ geo-replicated, region-homed commit authority global latency / residency / five-nines one geo, 99.99%
Block storage single-region object store + CDN cross-region + hot/cold tiering exabytes + global reads + cost fits hot cheaply in one region
Chunking fixed-size ~4 MB content-defined (rolling hash) large files edited in place write-once media
Processing none / minimal async previews/search/scan pipeline those features required pure sync product
Encryption TLS + at-rest client-side E2EE privacy / regulatory mandate need server search/previews
Device footprint sync everything selective / smart sync cloud storage > device storage small footprints
Dedup global (with PoP) per-tenant / convergent under E2EE privacy / trust boundaries trusted single-tenant

Lead with Stop 2–3 (metadata/data split + chunking + content-addressed dedup + delta sync + cursor sync with notification + sharded strongly-consistent metadata + refcount GC). When pushed: "for global exabyte scale with data residency, in-place-edited files, and optional E2EE, here's Stop 4 — each piece maps to a ceiling, and below that ceiling I'd remove it."


The 60-second Principal summary

"The defining decision is splitting metadata from data. Metadata — the file tree, versions, per-file ordered chunk-hash list, ACLs, and a per-namespace sync cursor — lives in a sharded, strongly-consistent transactional store where the commit is an atomic single-shard transaction, so you never see half a file tree. The bytes live as immutable ~4 MB content-addressed chunks in an object store, CDN-fronted. The client chunks and hashes locally, asks which hashes are missing, uploads only those, then commits — that one protocol gives me delta sync, global dedup, and resumable uploads. Devices stay live via a notification push plus a cursor-sync poll backstop; conflicts keep both copies rather than lose data; chunks are reference-counted and GC'd conservatively. Pushed to global scale I climb one lever at a time: region-homed geo-replicated metadata for latency and residency, cross-region blocks with hot/cold tiering for cost, content-defined chunking when files are edited in place, an async pipeline for previews and search, selective sync when devices can't hold everything, and client-side E2EE when privacy is mandated — knowing E2EE kills dedup and all server processing. Each piece has a named trigger, and below it I'd remove it."

← Back to File Storage overview · Base deep dives · cheatsheet