[Store] Arm the etcd view-change watch once per wait instead of per iteration (#3062)
WaitForViewChange armed a fresh watch (new ViewChangeWatchState + watch goroutine) on every loop iteration. Each iteration's PrefixWatchGuard destructor then had kWatchStopTimeoutMs (5s) for the goroutine to exit; whenever it missed the budget the guard deliberately leaked the state to avoid UAF, and the goroutine with its OS thread accumulated — visible in HA mode as a steady thread climb (~7/min per client process under load). One persistent watch now serves every wait inside the call: spurious events just clear the flag and the same goroutine keeps delivering, and the only re-arm path is etcd reporting the watch broken (event_type 2, now surfaced through a new `broken` flag on the watch state). The single cancel+stop cycle at function exit (PrefixWatchGuard's existing bounded cleanup) is the only one left, so the per-iteration leak is gone by construction. The arm-before-read revision invariant and the arm-failure fallback poll are unchanged. Fixes #3059 Signed-off-by: Yufeng He <40085740+he-yufeng@users.noreply.github.com>
Y
Yufeng He committed
a9da850ea60bc672c41d1cc7d1024d4c2702e23b
Parent: a6dcdcd
Committed by GitHub <noreply@github.com>
on 7/24/2026, 3:33:38 AM