Knowledge Guide
HomeHands-On BuildsBackend Primitives

Build a Mini Key-Value Store

Build a Mini Key-Value Store (log-structured)

You've built a WAL; now build a real store on top of the same idea. This is a Bitcask-style engine — the design behind Riak: an append-only data file plus an in-memory index (key → file offset). Writes are sequential (fast); reads are one index lookup + one seek (O(1)); durability comes from the append + fsync you already know. It's the clearest way to internalize why log-structured storage (LSM, Kafka) is fast, and where it pays the cost (compaction).

The spec

Why this is fast — and the catch

All writes are sequential appends → no random I/O, no in-place updates, so it saturates disk bandwidth. Reads are O(1) because the index is in RAM. The catch is space amplification: an overwritten or deleted key still occupies bytes in the file until compaction reclaims them. That write-fast / compact-later trade-off is the LSM-tree story — you're building its ancestor.

Reference — core (Go)

type KV struct {
    mu    sync.Mutex
    f     *os.File
    index map[string]int64   // key -> byte offset of latest record
    off   int64
}
// record on disk: [u32 keyLen][u32 valLen][key][val]   (valLen==0 ⇒ tombstone)

func (kv *KV) Put(k, v string) error {
    kv.mu.Lock(); defer kv.mu.Unlock()
    rec := frame(k, v)                       // len-prefixed, like the WAL
    if _, err := kv.f.WriteAt(rec, kv.off); err != nil { return err }
    if err := kv.f.Sync(); err != nil { return err }   // durable
    kv.index[k] = kv.off
    kv.off += int64(len(rec))
    return nil
}
func (kv *KV) Get(k string) (string, bool, error) {
    kv.mu.Lock(); off, ok := kv.index[k]; kv.mu.Unlock()
    if !ok { return "", false, nil }
    return readValueAt(kv.f, off)            // seek + read the value only
}
func (kv *KV) Delete(k string) error {
    kv.mu.Lock(); defer kv.mu.Unlock()
    if _, err := kv.f.WriteAt(frame(k, ""), kv.off); err != nil { return err } // tombstone
    kv.f.Sync(); kv.off += int64(len(frame(k, ""))); delete(kv.index, k)
    return nil
}
// Recover: scan file, index[k] = offset of the *last* record for k; skip torn tail.
// Compact: iterate index (live keys only), copy their current values into a new file, swap.

Reference — the write path (Java, sketch)

public synchronized void put(String k, String v) throws IOException {
    byte[] rec = frame(k, v);               // [keyLen][valLen][key][val]
    long at = off;
    ch.write(ByteBuffer.wrap(rec), at);
    ch.force(true);                         // fsync — durability point
    index.put(k, at);                       // in-memory: key -> offset
    off += rec.length;
}
public synchronized Optional<String> get(String k) throws IOException {
    Long at = index.get(k);
    return at == null ? Optional.empty() : Optional.of(readValueAt(ch, at));
}
// recover(): scan from 0, rebuild index (later offset for a key overwrites earlier);
// compact(): write live entries to newFile, fsync, atomically rename over the old file.

Tests to write

Extensions

What you've mastered

🤖 Don't fully get this? Learn it with Claude

Stuck on Build a Mini Key-Value Store? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.

🎨 Explain it visually

Build the mental picture, not memorization.

I just read a lesson on **Build a Mini Key-Value Store** (Hands-On Builds) and want to truly understand it. Explain Build a Mini Key-Value Store from first principles using ONE vivid real-world analogy and a visual mental model — draw it as ASCII art or a clear step-by-step diagram — with a concrete example using real numbers. Then ask me one question to check I got the mental picture, and wait for my reply. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🤔 Walk me through it (interactive)

Socratic — adapts to where you're stuck.

Teach me **Build a Mini Key-Value Store** interactively. Ask me ONE guiding question at a time, wait for my answer, and adapt to my confusion — build the idea with me step by step instead of explaining it all at once. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧪 Quiz me & fix my gaps

Active recall exposes what you missed.

Quiz me on **Build a Mini Key-Value Store** with 5 questions, easy to tricky, ONE at a time. Tell me if each answer is right; at the end, explain clearly what I got wrong and why. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧠 Make it stick

Intuition + hook + flashcards for long-term memory.

Help me remember **Build a Mini Key-Value Store** for the long term: give the one-sentence intuition, a memorable hook/mnemonic, a tiny worked example, and 3 active-recall flashcards (Q -> A). If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.

📝 My notes