You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Key → FNV-1a hash → shard index (0–255)
│
┌────────▼─────────┐
│ shard.mu │ RWMutex
│ shard.data │ map[string]*Entry
└──────────────────┘
Write ops (SET, DEL, EXPIRE, INCR): shard.mu.Lock()
Read ops (GET, EXISTS, TTL): shard.mu.RLock()
Result: concurrent reads on different keys never block each other.
Concurrent writes only contend within the same shard (~1/256 probability).
Request Lifecycle
1. Client connects via TCP
2. Server.acceptLoop() → go handleConn(conn)
3. handleConn: parser.ReadCommand() — blocks on socket read
4. RESP or inline bytes decoded → Command{Name, Args}
5. dispatcher.Dispatch(cmd, writer)
a. metrics.Record starts
b. handler function called
c. store operation executed (shard lock acquired/released)
d. AOF.Write(tokens) enqueued (non-blocking channel)
e. writer.WriteXxx() called
f. metrics.Record ends
6. writer.Flush() — single syscall per command
7. Loop back to step 3
Startup sequence:
1. Open AOF file (read-only)
2. Decode RESP arrays one at a time
3. For each: call dispatcher.Replay() → store operation (no re-persist)
4. Partial/corrupt final record: silently discarded (io.EOF or parse error)
5. Switch AOF file to APPEND mode for new writes
Crash safety:
- AOF is flushed + synced after every batch
- A crash between fsync and the next command means at most one
command is lost (analogous to Redis appendfsync everysec)
- File is opened with O_APPEND — no seek needed, atomic appends on Linux
Performance Benchmarks (reference, Apple M1, Go 1.22)
Benchmark
ops/sec
allocs/op
BenchmarkSetSerial
~8,000,000
1
BenchmarkGetSerial
~20,000,000
0
BenchmarkSetParallel
~30,000,000
1
BenchmarkGetParallel
~80,000,000
0
BenchmarkMixedReadWrite
~60,000,000
0
Run go test -bench=. -benchmem ./bench/ to reproduce.