refactor: fix N+1 queries, stale data, and write amplification in security scanner#2336
Conversation
… security scanner Addresses 6 issues identified by code review panel: 1. Add missing fields (isExcessivePackets, isTimeOffsetIssue, etc.) to DbNode interface, removing all (node as any) type casts 2. Fetch getAllNodes() once per scan and use Map<number, DbNode> for O(1) lookups, eliminating N+1 getNode() queries (~2000 SELECTs on 500 nodes) 3. Fix stale data bug where allNodes snapshot was used after low-entropy flag updates, causing incorrect detail strings on cleared-duplicate nodes 4. Store initial setTimeout handle and clear it in stop() to prevent ghost scans on rapid restart 5. Only write to DB on actual state changes in spam/time-offset detection, reducing write amplification 6. Run spam and time-offset detection in parallel via Promise.all() Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Code ReviewREQUEST_CHANGES — Good improvements in 1. N+1 queries still in sub-scans: 2. 3. Write amplification not fixed in sub-scans: Both sub-methods write on every node every cycle. Only 4. Triple Architecture compliance is good — no raw SQL, no database.ts changes, no new sync methods, tests properly updated. 🤖 Generated with Claude Code |
…Nodes() per cycle runSpamDetection() and runTimeOffsetDetection() now receive the nodeMap built in runScan() instead of each independently calling getAllNodes(). This eliminates 2 redundant database queries per scan cycle. The early- return path (no nodes with public keys) also fetches once and shares. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Addressed all 4 feedback items in commit 8e926de:
All 4 time-offset tests pass, TypeScript compiles clean. |
Code reviewNo issues found. Checked for bugs and CLAUDE.md compliance. 🤖 Generated with Claude Code |
Summary
getNode()calls with singlegetAllNodes()+Map<number, DbNode>lookup — eliminates ~2,000 individual SELECT queries per scan on a 500-node networkallNodeswas fetched before low-entropy flag updates, causing incorrect detail strings when clearing duplicate flags in the same scan cycleDbNodefields:isExcessivePackets,isTimeOffsetIssue,packetRatePerHour,timeOffsetSeconds,packetRateLastChecked,lastTimeSync— removes all(node as any)type castsPromise.all()since they are independentsetTimeouthandle and clear it instop()to prevent scan firing on a stopped serviceTest plan
getAllNodes()instead ofgetNode())🤖 Generated with Claude Code