Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 21 additions & 22 deletions cmd/server/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,26 +136,25 @@ type DB struct {
nodeRegionTick int64
nodeRegionSF singleflight.Group
nodeRegionFullMu sync.Mutex
// nodeRegionQueryHook (test seam, nil in production) runs once per real
// membership scan, before the query; a non-nil error fails that refresh
// the way a failing scan does.
// nodeRegionColdMu serialises the per-set builds cold requests fall
// back to while the region index build fails (coldNodeRegion).
nodeRegionColdMu sync.Mutex
// nodeRegionQueryHook (test seam, nil in production) runs once per
// per-set refresh, before it reads the region index; a non-nil error
// fails that refresh the way a failing scan does.
nodeRegionQueryHook func() error

// Direct-evidence region placement (#488 M2, region_placement.go).
// regionPlacement is set once at startup, before the first request.
// regionAgg is the global evidence aggregate, owned by the refresh
// that holds regionAggMu; readers only ever see regionSnap, an
// immutable snapshot swapped in after each refresh.
// nodeRegionPerSetHook (test seam, nil in production) runs at the start
// of every per-set build (buildNodeRegionCold).
nodeRegionPerSetHook func()

// Global region indexes the per-set entries are cut from (#618,
// region_index.go): one per region rule, the heard rule's and the
// direct-evidence placement's (#488 M2, region_placement.go).
// regionPlacement is set once at startup, before the first request,
// and selects the one served.
regionPlacement regionPlacementSettings
regionAggMu sync.Mutex
regionAgg *regionEvidenceAgg
regionAggBuilt time.Time
regionSnap atomic.Pointer[regionPlacementSnapshot]
// regionPlacementScanHook (test seam, nil in production) runs at the
// end of every aggregate scan, full or delta, after its rows were
// folded in; a non-nil error fails that scan the way an error part-way
// through the rows does.
regionPlacementScanHook func(full bool) error
regionHeard regionIndex
regionPlaced regionIndex
// identityNamesQueryHook (#410, test seam, nil in production) runs once
// per real hidden-name lookup query, right before it executes, with the
// lower-case keys it looks up.
Expand Down Expand Up @@ -1282,10 +1281,10 @@ func (db *DB) GetNodes(limit, offset int, role, search, before, lastHeard, sortB
}

// The region filter is served from the bounded membership cache in
// nodes_region_cache.go: the IN (...) observation join is evaluated there
// once per region set, not twice per request (COUNT(*) and the page).
// #38's from_pubkey contract — and the trap that comes with it — lives
// with the query, in scanNodeRegionKeys.
// nodes_region_cache.go, cut from the per-IATA region index
// (region_index.go) rather than evaluated twice per request (COUNT(*)
// and the page). #38's from_pubkey contract — and the trap that comes
// with it — lives with the query, in scanHeardRegions.
if codes := normalizeRegionCodes(region); len(codes) > 0 {
keysJSON, err := db.nodeRegionKeysJSON(codes)
if err != nil {
Expand Down
9 changes: 9 additions & 0 deletions cmd/server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,12 @@ func main() {
stopEviction := store.StartEvictionTicker()
defer stopEviction()

// #618: build the per-IATA region index for /api/nodes?region= in the
// background and keep it refreshed, so no request pays the full history
// scan. It reads SQLite only, never the PacketStore or its lock.
stopRegionIndex := database.StartRegionIndexWarmer()
defer stopRegionIndex()

// Steady-state analytics recomputers (issue #1240). Replaces the
// on-request compute-then-cache pattern for the default (region="",
// zero-window) analytics queries with a background refresh loop so
Expand Down Expand Up @@ -594,6 +600,9 @@ func main() {
if stopAnalyticsRecomp != nil {
stopAnalyticsRecomp()
}
// 1d. Stop the region index warmer (#618) for the same reason: it
// cancels a scan in flight and returns once the goroutine has.
stopRegionIndex()

// 2. Gracefully drain HTTP connections (up to shutdownDrainTimeout)
ctx, cancel := context.WithTimeout(context.Background(), shutdownDrainTimeout)
Expand Down
Loading
Loading