mirror of
https://github.com/Kpa-clawbot/meshcore-analyzer.git
synced 2026-11-11 11:57:57 +00:00
Fixes #2221. ## Problem `getNeighborGraph` rebuilt `Server.neighborGraph` on the request goroutine once it passed its 5 min TTL. It held `neighborMu` for the whole build, which takes 11.1-11.4 s on a production store. The 5 min recomputer went through the same staleness check. A tick that landed just before the TTL skipped the rebuild and left it to the next request. As a result `/api/nodes/{pubkey}/neighbors` ran at p95 10.4 s and max 11.0 s (57 requests). ## Change - **`getNeighborGraph`** serves the current graph. It builds only when there is none yet, which happens at startup. - **`rebuildNeighborGraph`** builds from the packet store whatever the age of the current graph, outside `neighborMu`, and then swaps the pointer. - `recomputeNeighborGraphCache` calls it first on every tick. - Without a store it keeps the current graph, so tests that inject a graph are unaffected. - **`neighborBuildMu`** serializes builds, so a startup request and the first tick do not both build. Freshness is now bounded by the recompute interval (`neighborGraph.cacheRecomputeIntervalSeconds`, default 5 min) plus one build. Before this change it was the 5 min TTL plus one build, whatever the interval. So the bound is the same only at the default 300: - with a longer interval (for example 3600), `/api/nodes/{pk}/neighbors` can serve a graph up to that old, where before it was about 5 min; - with a shorter interval (for example 30), every tick does a full build, where before there was at most one build per 5 min. The config comment and `config.example.json` now say this (commit `de7ae981`). `IsStale`/`neighborGraphTTL` stay, because `path_inspect.go` still uses them for `store.graph`. ## Perf - **Request path:** after the first build it does no build at all. It takes one mutex and reads one pointer. - **Background:** the recompute tick now always builds, once every 5 min. Before, it built only on the ticks that found the graph stale, and a request built in the other cases. - **Total:** the number of builds stays about the same. Before: `/api/perf` on production shows p95 10404 ms. After: the follow-up comment gives client-side curl timings from staging (40 requests, p95 0.204 s), not `/api/perf`. Staging builds the graph in 1.03 s against 11 s on production, so the two are different instances. ## Tests `neighbor_graph_rebuild_test.go`: - a stale graph is served without a rebuild; - a graph is built when there is none yet; - a recompute tick replaces a graph that is not yet stale; - a recompute without a store keeps the injected graph. The first and third tests fail on master. `go vet` and `go test .` pass in `cmd/server`, and `-race` passes on the neighbor-graph tests. No frontend change. --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>