From 00005f6d9ef30c23c80533e1a381c7312a4644ce Mon Sep 17 00:00:00 2001 From: openclaw-bot Date: Fri, 15 May 2026 14:23:37 +0000 Subject: [PATCH] refactor(#1199): share filteredTxs between context-build and main pass MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Item 2/6. computeAnalyticsTopology was running window+region predicates twice over s.packets — once in the pre-pass to build contextPubkeys, once in the main aggregation. Materialize filteredTxs ONCE; both passes iterate the result. Also drops orphan inner-loop comment. Pure refactor — no test files modified for item 2 (per AGENTS.md exemption). --- cmd/server/store.go | 61 ++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 34 deletions(-) diff --git a/cmd/server/store.go b/cmd/server/store.go index 9cf54a63..90484f28 100644 --- a/cmd/server/store.go +++ b/cmd/server/store.go @@ -5305,6 +5305,31 @@ func (s *PacketStore) computeAnalyticsTopology(region string, window TimeWindow) allNodes, pm := s.getCachedNodesAndPM() _ = allNodes // only pm is needed for topology + // Materialize the filtered tx slice ONCE — both the context-build pass + // and the main aggregation pass need the same window+region predicate. + // Two scans of s.packets re-running identical predicates is wasteful at + // the 30k+ packet hot-path scale (#1199 item 2). One filter, two passes + // over the result. + filteredTxs := make([]*StoreTx, 0, len(s.packets)) + for _, tx := range s.packets { + if !window.Includes(tx.FirstSeen) { + continue + } + if regionObs != nil { + match := false + for _, obs := range tx.Observations { + if regionObs[obs.ObserverID] { + match = true + break + } + } + if !match { + continue + } + } + filteredTxs = append(filteredTxs, tx) + } + // Pre-pass: build the full hop-disambiguation context from all in-window // txs BEFORE any resolveHop call. The earlier shape — populating // contextPubkeys lazily during the main scan and reading it from a @@ -5316,22 +5341,7 @@ func (s *PacketStore) computeAnalyticsTopology(region string, window TimeWindow) var contextPubkeys []string { seen := make(map[string]struct{}, 64) - for _, tx := range s.packets { - if !window.Includes(tx.FirstSeen) { - continue - } - if regionObs != nil { - match := false - for _, obs := range tx.Observations { - if regionObs[obs.ObserverID] { - match = true - break - } - } - if !match { - continue - } - } + for _, tx := range filteredTxs { for _, pk := range buildHopContextPubkeys(tx, pm) { if _, ok := seen[pk]; ok { continue @@ -5360,28 +5370,11 @@ func (s *PacketStore) computeAnalyticsTopology(region string, window TimeWindow) observerMap := map[string]string{} // observer_id → observer_name perObserver := map[string]map[string]*struct{ minDist, maxDist, count int }{} - for _, tx := range s.packets { - if !window.Includes(tx.FirstSeen) { - continue - } + for _, tx := range filteredTxs { hops := txGetParsedPath(tx) if len(hops) == 0 { continue } - if regionObs != nil { - match := false - for _, obs := range tx.Observations { - if regionObs[obs.ObserverID] { - match = true - break - } - } - if !match { - continue - } - } - - // Hop-disambiguation context was assembled in the pre-pass above (#1197). n := len(hops) hopCounts[n]++