Folders are a lie — the flat keyspace and its index

Keys are flat opaque strings with no real directories, so the index is a giant sorted map from key to location that shards by key range — which means all keys sharing a prefix land on one partition that has a throughput ceiling.

Previously

Surviving disk death means the bytes live somewhere other than one disk — so something has to record where; that something is the index, the first plane we crack open.

Scene 03

Folders are a lie — the flat keyspace and its index

  1. Watch
  2. Try it
  3. Predict
  4. Capture
OBJECT KEYSflat opaque strings — slashes are bytesTHE INDEX — sorted map, sharded by key rangeimg/cat.pngimg/dog.pnglogs/2026/06/03/app.loglogs/2026/06/03/db.loglogs/2026/06/04/app.logone string · no directory to lockresolve["" .. "img/")ceiling3,500 PUT/s · 5,500 GET/s per partition→ loc:••••• (data plane)["img/" .. "logs/")ceiling3,500 PUT/s · 5,500 GET/s per partition→ loc:••••• (data plane)["logs/" .. ∞)ceiling3,500 PUT/s · 5,500 GET/s per partition→ loc:••••• (data plane)1 prefix → aggregate:~5,500 GET/s (one partition)no global request limit — spread the keyspace
A key resolves through the sorted map to a (dim) storage location.
What to watch for

Each object is addressed by a key — and a key is one flat string; the slashes in "logs/2026/06/03/app.log" are just bytes, not folders. The map on the right sorts those strings and shards them by range. Try the console-folder toggle: it splits the keys on '/' into a tree, but there is no tree underneath.

Continue unlocks when the animation finishes.
Implementation

Highlighted lines are the ones running in the diagram right now.

Index.resolve
a GET resolves a flat key string to its storage location
def resolve(key):
# key is ONE opaque string; '/' is just a byte.
# No tree walk — binary search the sorted map.
part = partitionForKey(key)
entry = part.lookup(key) # key -> location + metadata
return entry.location
def partitionForKey(key):
# partitions are contiguous lexicographic key ranges,
# so keys sharing a prefix land on ONE partition.
return bisect(partitionBoundaries, key)
Partition.serveRequest
each key-range partition meters its own request rate
# limits are PER partition, not per bucket
PUT_CEILING = 3500 # req/s
GET_CEILING = 5500 # req/s
def serveRequest(req):
rate = self.observedRate(req.kind)
ceiling = (PUT_CEILING if req.kind == PUT
else GET_CEILING)
if rate > ceiling:
return Http503('SlowDown')
return serve(req)
Index.maybeSplit
a saturated partition is gradually split into two
# background loop on the index plane
def maybeSplit(part):
if part.sustainedRate > part.ceiling:
mid = part.medianKey()
# split the range at mid -> two partitions,
# each owning half the keys. Takes minutes,
# so a sudden hot prefix throttles first.
lo, hi = part.splitAt(mid)
partitionBoundaries.insert(mid)

Where this sits in Build an S3-style distributed object store

Scene 03 of 12, in the Name & shape act — The flat keyspace, its index, and immutable objects.. Keys are flat strings; the index maps key→location and shards by range, with a per-prefix throughput ceiling.

Up next. The index records where an object's current bytes are — but what exactly is it pointing at, and what happens to the old bytes when you overwrite a key?

All 12 scenes in Build an S3-style distributed object store · Every curriculum

Built with Arqly
Every scene in Build an S3-style distributed object store builds on the one before it.All 12 Build an S3-style distributed object store scenes