One hash lookup, one pread
A get is a constant-time keydir lookup followed by exactly one pread at the recorded offset — bounded at one disk seek worst case, and zero seeks when the page cache is hot.
The writer was sequential because the disk cares. The keydir doesn't — it's a hash, and lookups are O(1). One pread closes the loop.
Scene 03
One hash lookup, one pread
- Watch
- Try it
- Predict
- Capture
Watch a single GET k1. The keydir row pulses, an arrow flies to file 002 at offset 1432, and the pread cursor highlights exactly value_sz bytes — not the whole record (value_pos already skips the header). The pread counter ticks up by one.
Highlighted lines are the ones running in the diagram right now.
struct KeydirEntry:file_id # which .data file holds the live recordvalue_pos # byte offset of the VALUE (header skipped)value_sz # exact length to preadtstamp # last-write timestamp (wins on replay)
def get(key):entry = keydir.get(key) # O(1) hash probeif entry is None:return None # key never existed / deletedfd = fd_cache.open(entry.file_id)buf = pread(fd,n=entry.value_sz, # exactly value_sz bytesoffset=entry.value_pos)return buf # caller may verify CRC
def pread(fd, n, offset):page = (offset // PAGE_SIZE) * PAGE_SIZEif page in page_cache: # HOT — bytes already in RAMreturn copy_from(page_cache[page], offset, n)block = disk.seek_and_read(fd, page) # COLD — one seekpage_cache[page] = blockreturn copy_from(block, offset, n)
Where this sits in Build a Bitcask-style KV store
Scene 03 of 9, in the Anatomy act — Log on disk, hash in RAM — and the four-step write.. get is a constant-time keydir lookup + at most one pread; bounded by one disk seek, zero when the page cache is hot.
Up next. One seek for any read, hot or cold. That ceiling exists because the index lives in RAM. The next scene asks how much RAM.
All 9 scenes in Build a Bitcask-style KV store · Every curriculum