Overview — Project 2: kvlite
In Project 1 · logwise you built a program that reads data, runs to completion,
and exits. kvlite is the opposite shape: a program that holds data, stays running, and is talked to
by many clients at once. That single change — long-lived shared state — is what pulls in the next
tier of Rust: traits and generics to make the store reusable, Arc/RwLock to share it across threads
without a data race, an append-only log so a restart doesn’t lose everything, and a TCP server to put it
on the network. You’ll meet each one exactly when the build demands it.
What you’re building
Section titled “What you’re building”A small key-value store — a mini-Redis. By the end it speaks a plain-text line protocol you can drive
with nc:
$ nc 127.0.0.1 6380 SET name ada lovelace OK GET name VALUE ada lovelace DEL name DELETED GET name NILUnder that one-line protocol sits a layered design, and each layer is one day’s lesson:
TCP server day 7 std::net, thread-per-connection, the line protocol │ protocol day 7 parse a line -> Request -> Response │ Db day 6 thread-safe + durable: SharedStore + append-only log ╱ ╲ store.rs log.rs day 4/5: Store trait + MemStore + SharedStore / day 6: the WALThe four days
Section titled “The four days”| Day | Page | You build | The Rust it forces |
|---|---|---|---|
| 4 | Traits & generics | a single-threaded store + a REPL | traits, generics, lifetimes-in-context, HashMap |
| 5 | Concurrency | concurrent access from many threads | Arc, Mutex/RwLock, mpsc, Send/Sync |
| 6 | Persistence & errors | survive a restart | append-only log, iterators, thiserror |
| 7 | TCP server | a networked kvlite | std::net, thread-per-connection, the protocol |
Each day teaches its concept, then has you build that slice into the companion crate at rust/kvlite/.
Type the code yourself, run it, and break it on purpose — the compiler’s objection is the lesson.
Why a key-value store is the right teacher
Section titled “Why a key-value store is the right teacher”A KV store is the smallest program that is simultaneously shared, mutable, long-lived, and durable — the four properties that make real systems hard. Hold all four at once and every big Rust idea has a concrete reason to exist:
- Shared + mutable → the borrow checker’s “shared XOR mutable” rule (from The Rust
Mindset) now has to hold across threads. That’s
Arc<RwLock<T>>, and the compiler enforces it with theSend/Synctraits. - Reusable → you don’t want to rewrite the engine for every key/value type, so the store is a trait with a generic implementation.
- Durable → RAM is wiped on exit, so writes go to an append-only log you replay on startup — a job tailor-made for iterators.
The thread
Section titled “The thread”Hold the playbook’s recurring question on every page: what does building this force you to understand —
and what is Rust’s compiler protecting you from? For kvlite the answer sharpens to its most famous
form. The moment two threads touch one HashMap, C would let you race; Rust simply won’t compile the
shared-mutable access until you put it behind a lock — fearless concurrency, checked at compile time.
By Day 7 you’ll have a networked store where the scariest class of bug in systems programming was made
unwritable by the type system.
Begin with Day 4 · Traits & Generics →