Files
kacerrandClaude Fable 5 7219eb5a23 Initial commit: Go SRE interview exercises
Includes solved 02-worker-pool and 09-safe-counter (mutex, atomic, sharded).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GbnJj9ZqEx9nUvzkjdwfMq
2026-08-28 22:18:09 +02:00

55 lines
2.3 KiB
Markdown

# 04 — Log Crunching: Top-N
Looks like a warm-up. It's actually a trap-density championship.
## Trap 1: `bufio.Scanner`'s 64KB guillotine
`Scanner` refuses tokens above 64KB by default and stops with
`bufio.ErrTooLong` — and if you forget to check `sc.Err()`, it stops
*silently*, and your report just... misses the tail of the file. Real-world
lines that exceed 64KB: JSON-formatted logs, stack traces, requests with fat
query strings. The fix:
```go
sc.Buffer(make([]byte, 0, 1024*1024), 1024*1024)
```
An enormous number of production log processors have shipped with this bug.
Checking `sc.Err()` after the loop is the difference between a tool and a liar.
## Trap 2: maps have no order — by design, with a great backstory
Go **deliberately randomizes** map iteration order (a random seed per map, and
the runtime even randomizes the starting bucket) so nobody can accidentally
depend on it. To rank by count you must extract into a slice and sort:
```go
sort.Slice(out, func(i, j int) bool { return out[i].Count > out[j].Count })
```
Since 1.24 maps use a Swiss-table implementation (flat, SIMD-probed, cache
friendlier) — fun fact to drop if asked "what's inside a Go map."
## Trap 3: `strings.Fields` vs `strings.Split`
`Split(s, " ")` produces empty strings for repeated spaces; `Fields` splits on
any run of whitespace (incl. tabs) and never yields empties. For log parsing,
`Fields` is almost always what you mean.
## The senior follow-up: "the file is 500 GB"
Have a ladder ready:
1. **This solution already streams** — memory is O(distinct endpoints), not
O(file). Say that first; many candidates don't realize their answer scales.
2. **Cardinality explosion** (endpoints contain IDs): normalize paths
(`/users/123` → `/users/:id`) or cap the map with count-min sketch /
space-saving algorithm — approximate top-K in bounded memory. Naming
"count-min sketch" in an SRE interview is a mic-drop; it's what real
metrics pipelines do to survive high-cardinality labels.
3. **Parallelize**: shard by hash(endpoint) across workers, merge partials —
map-reduce in one sentence.
4. **Only need top-N, not full sort?** A min-heap of size N gives
O(distinct · log N) instead of O(distinct · log distinct). `container/heap`
exists; nobody remembers its interface; everyone respects you for trying.