Mike O'Driscoll dfdf61c383 control/controlclient: cache sortedPeers result across calls
sortedPeers() copies the entire peers map into a slice and sorts it on
every call. With large peer sets this is expensive — at 50k peers,
each call costs ~9ms and 402KB for the MapValues copy and sort.

Cache the sorted result in sortedPeersCache, protected by peersMu.
The cache is invalidated (set to nil) at the start of
updatePeersStateFromResponse, which is the only writer of the peers
map. sortedPeers uses a read-lock fast path with double-checked
locking on upgrade to write lock.

At 50,000 peers:
- Cache hit (repeated calls): 17.7ns, 0 allocs (was 9.2ms, 402KB)
- After peer change: 9.2ms (unchanged — must re-sort)

Fixes tailscale/corp#40144

Signed-off-by: Mike O'Driscoll <mikeo@tailscale.com>
2026-04-13 19:19:07 +00:00
..