mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-27 05:57:27 +00:00
8823440f33
In mock mode the unified view is keyed on the fixture data version, which advances on every metric tick, and building it for the default 1,776-resource estate costs about half a second of CPU (many seconds on a starved process). #2778 moved the metrics-target lookup onto the fixture structure revision; the other callers that read only what the estate lists and how it connects still rebuilt the whole view after each tick. At startup they made 42 view requests, all misses, and with no client connected the monitor tick alone rebuilt the estate about every nine seconds. Callers that read identity and topology now share the view built for the current structure revision and operator links (currentStructureUnifiedStateView, GetUnifiedStructureReadState): the Docker-alert prune, the workload chart prewarm, the demo Patrol resolver, and the host-agent evaluation, which also lists nodes only when an offline host names a linked node. The connection-degraded alert feed keeps only platform rows, so it no longer reads the hosts, their desired-config fingerprints or the PBS instances that only feed agent rows and a host alias its snapshot drops. The mock storage chart is not one of them: a linked pool takes its capacity from whichever source was seen last, which a tick can move without a structure change. It keeps the data-version view, read once per request instead of once per uncached pool. The per-node polling lookups of a monitor that keeps real polling in mock mode (linkedHostForNode, getHostAgentTemperatureForNode, carriedTemperatureOutlivesAgentLease) read a host's status, disks and sensors, which a tick moves, so they stay on the data-version view. On pulse-dev (one pinned core, host load 30 to 110, probe builds): a start built the estate view twice before the listener answered with the wiring change alone and once with this; with no client connected the process built the estate 33 times in 299 s and used 12.3 s of CPU over a 180 s window, against twice and 3.3 s with this change.
79 lines
3.0 KiB
Go
79 lines
3.0 KiB
Go
package monitoring
|
|
|
|
import (
|
|
"github.com/rcourtman/pulse-go-rewrite/internal/mock"
|
|
"github.com/rcourtman/pulse-go-rewrite/internal/models"
|
|
"github.com/rcourtman/pulse-go-rewrite/internal/unifiedresources"
|
|
)
|
|
|
|
// cachedMockStructureView returns the mock view the monitor has cached when it
|
|
// was built for the fixture's current structure revision and operator link
|
|
// list, however many metric ticks ago. The second result is false when there is
|
|
// no such view, and the first is then not for use.
|
|
func (m *Monitor) cachedMockStructureView() (monitorUnifiedStateView, bool) {
|
|
structure := mock.FixtureStructureRevision()
|
|
links := m.resourceStoreManualLinks()
|
|
|
|
m.mockUnifiedViewMu.Lock()
|
|
defer m.mockUnifiedViewMu.Unlock()
|
|
reusable := m.mockUnifiedViewValid &&
|
|
m.mockUnifiedViewStructure == structure &&
|
|
sameManualLinks(m.mockUnifiedViewLinks, links)
|
|
return m.mockUnifiedView, reusable
|
|
}
|
|
|
|
// currentStructureUnifiedStateView is currentUnifiedStateView for a caller that
|
|
// reads what the estate lists and how it connects: IDs, names, types, source
|
|
// mappings, parents, operator links and the metrics targets those yield. In
|
|
// mock mode that answers from the cached view for as long as the fixture
|
|
// structure and the link list are unchanged. The view is keyed on the data
|
|
// version otherwise, which advances on every metric tick, so a caller that
|
|
// needs only structure but asked for the data-version view built the whole
|
|
// estate once per tick: about half a second of CPU on an idle core, and on a
|
|
// starved process a build longer than the tick, so every call missed. A
|
|
// caller must not read what a tick moves (status, metric values, timestamps,
|
|
// sensors); the view it gets can be any number of ticks old. Outside mock mode
|
|
// this is currentUnifiedStateView.
|
|
func (m *Monitor) currentStructureUnifiedStateView() monitorUnifiedStateView {
|
|
if m == nil {
|
|
return monitorUnifiedStateView{}
|
|
}
|
|
if mock.IsMockEnabled() {
|
|
if view, ok := m.cachedMockStructureView(); ok {
|
|
return view
|
|
}
|
|
}
|
|
return m.currentUnifiedStateView()
|
|
}
|
|
|
|
// GetUnifiedStructureReadState is GetUnifiedReadStateOrSnapshot for a caller
|
|
// that reads identity and topology only (see currentStructureUnifiedStateView):
|
|
// in mock mode it can be several metric ticks old.
|
|
func (m *Monitor) GetUnifiedStructureReadState() unifiedresources.ReadState {
|
|
if m == nil {
|
|
return nil
|
|
}
|
|
if !mock.IsMockEnabled() {
|
|
return m.GetUnifiedReadStateOrSnapshot()
|
|
}
|
|
return m.currentStructureUnifiedStateView().readState
|
|
}
|
|
|
|
// currentModeStructureReadState is currentModeReadState for a caller that reads
|
|
// identity and topology only.
|
|
func (m *Monitor) currentModeStructureReadState() unifiedresources.ReadState {
|
|
if m == nil {
|
|
return nil
|
|
}
|
|
if mock.IsMockEnabled() {
|
|
return m.currentStructureUnifiedStateView().readState
|
|
}
|
|
return m.currentModeReadState()
|
|
}
|
|
|
|
// structureNodes is NodesSnapshot for a caller that reads the nodes' identity
|
|
// and links only (ID, instance, linked agent).
|
|
func (m *Monitor) structureNodes() []models.Node {
|
|
return nodesSnapshotFromReadState(m.GetUnifiedStructureReadState())
|
|
}
|