perf(tui): precompute maintenance set, eliminate redundant GetAllSites
Replace O(windows × sites) isMonitorInMaintenance with O(1) map lookup. buildMaintSet runs once per refreshLive/handleTabData, not per call site. groupSparkline/groupUptime now use m.sites (already on model) instead of calling engine.GetAllSites() which copies the full map under a mutex.
This commit was merged in pull request #172.
This commit is contained in:
@@ -123,6 +123,7 @@ func (m *Model) refreshLive() {
|
||||
ordered = filterSites(ordered, m.filterText)
|
||||
}
|
||||
m.sites = ordered
|
||||
m.buildMaintSet()
|
||||
m.refreshLogContent()
|
||||
|
||||
if m.selectedID != 0 {
|
||||
|
||||
@@ -156,9 +156,8 @@ func resolveSparklineIndex(x, sparkWidth, dataLen int) int {
|
||||
}
|
||||
|
||||
func (m Model) groupSparkline(groupID int, width int, bg lipgloss.TerminalColor) string {
|
||||
allSites := m.engine.GetAllSites()
|
||||
var childStatuses [][]bool
|
||||
for _, s := range allSites {
|
||||
for _, s := range m.sites {
|
||||
if s.ParentID == groupID && !s.Paused && !m.isMonitorInMaintenance(s.ID) {
|
||||
hist, _ := m.engine.GetHistory(s.ID)
|
||||
if len(hist.Statuses) > 0 {
|
||||
@@ -209,9 +208,8 @@ func (m Model) groupSparkline(groupID int, width int, bg lipgloss.TerminalColor)
|
||||
}
|
||||
|
||||
func (m Model) groupUptime(groupID int) string {
|
||||
allSites := m.engine.GetAllSites()
|
||||
var allStatuses [][]bool
|
||||
for _, s := range allSites {
|
||||
for _, s := range m.sites {
|
||||
if s.ParentID == groupID && !s.Paused && !m.isMonitorInMaintenance(s.ID) {
|
||||
hist, _ := m.engine.GetHistory(s.ID)
|
||||
if len(hist.Statuses) > 0 {
|
||||
|
||||
@@ -21,27 +21,36 @@ type maintFormData struct {
|
||||
}
|
||||
|
||||
func (m Model) isMonitorInMaintenance(monitorID int) bool {
|
||||
return m.maintSet[monitorID]
|
||||
}
|
||||
|
||||
func (m *Model) buildMaintSet() {
|
||||
set := make(map[int]bool)
|
||||
now := time.Now()
|
||||
for _, mw := range m.maintenanceWindows {
|
||||
if mw.Type != "maintenance" {
|
||||
continue
|
||||
}
|
||||
now := time.Now()
|
||||
if mw.StartTime.After(now) {
|
||||
continue
|
||||
}
|
||||
if !mw.EndTime.IsZero() && mw.EndTime.Before(now) {
|
||||
continue
|
||||
}
|
||||
if mw.MonitorID == 0 || mw.MonitorID == monitorID {
|
||||
return true
|
||||
if mw.MonitorID == 0 {
|
||||
for _, s := range m.sites {
|
||||
set[s.ID] = true
|
||||
}
|
||||
break
|
||||
}
|
||||
set[mw.MonitorID] = true
|
||||
for _, s := range m.sites {
|
||||
if s.ID == monitorID && s.ParentID > 0 && mw.MonitorID == s.ParentID {
|
||||
return true
|
||||
if s.ParentID == mw.MonitorID {
|
||||
set[s.ID] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
m.maintSet = set
|
||||
}
|
||||
|
||||
func (m *Model) initMaintHuhForm() tea.Cmd {
|
||||
|
||||
@@ -207,6 +207,7 @@ type Model struct {
|
||||
lastTabLoad time.Time // last dispatch of loadTabDataCmd (throttle)
|
||||
tabSeq int // seq of the newest issued tab-data load
|
||||
|
||||
maintSet map[int]bool
|
||||
bottomPanel bottomPanel
|
||||
detailOpen bool
|
||||
maintCursor int
|
||||
|
||||
@@ -231,6 +231,7 @@ func (m *Model) handleTabData(msg tabDataMsg) (tea.Model, tea.Cmd) {
|
||||
}
|
||||
m.nodes = msg.nodes
|
||||
m.maintenanceWindows = msg.maint
|
||||
m.buildMaintSet()
|
||||
m.clampCursor()
|
||||
return m, nil
|
||||
}
|
||||
|
||||
@@ -389,3 +389,86 @@ func TestDetailRefreshCmd_OnlyWhileDetailOpen(t *testing.T) {
|
||||
t.Error("refresh Cmd issued for an out-of-range cursor")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildMaintSet_GlobalWindow(t *testing.T) {
|
||||
m := newTestModel(&tuiMockStore{})
|
||||
m.sites = []models.Site{
|
||||
{SiteConfig: models.SiteConfig{ID: 1, Name: "a"}},
|
||||
{SiteConfig: models.SiteConfig{ID: 2, Name: "b"}},
|
||||
}
|
||||
m.maintenanceWindows = []models.MaintenanceWindow{
|
||||
{ID: 1, MonitorID: 0, Type: "maintenance", StartTime: time.Now().Add(-time.Hour)},
|
||||
}
|
||||
m.buildMaintSet()
|
||||
if !m.maintSet[1] || !m.maintSet[2] {
|
||||
t.Error("global maint window should mark all monitors")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildMaintSet_TargetedWindow(t *testing.T) {
|
||||
m := newTestModel(&tuiMockStore{})
|
||||
m.sites = []models.Site{
|
||||
{SiteConfig: models.SiteConfig{ID: 1, Name: "a"}},
|
||||
{SiteConfig: models.SiteConfig{ID: 2, Name: "b"}},
|
||||
}
|
||||
m.maintenanceWindows = []models.MaintenanceWindow{
|
||||
{ID: 1, MonitorID: 1, Type: "maintenance", StartTime: time.Now().Add(-time.Hour)},
|
||||
}
|
||||
m.buildMaintSet()
|
||||
if !m.maintSet[1] {
|
||||
t.Error("targeted window should mark monitor 1")
|
||||
}
|
||||
if m.maintSet[2] {
|
||||
t.Error("targeted window should NOT mark monitor 2")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildMaintSet_GroupPropagates(t *testing.T) {
|
||||
m := newTestModel(&tuiMockStore{})
|
||||
m.sites = []models.Site{
|
||||
{SiteConfig: models.SiteConfig{ID: 10, Name: "group", Type: "group"}},
|
||||
{SiteConfig: models.SiteConfig{ID: 11, Name: "child1", ParentID: 10}},
|
||||
{SiteConfig: models.SiteConfig{ID: 12, Name: "child2", ParentID: 10}},
|
||||
{SiteConfig: models.SiteConfig{ID: 20, Name: "other"}},
|
||||
}
|
||||
m.maintenanceWindows = []models.MaintenanceWindow{
|
||||
{ID: 1, MonitorID: 10, Type: "maintenance", StartTime: time.Now().Add(-time.Hour)},
|
||||
}
|
||||
m.buildMaintSet()
|
||||
if !m.maintSet[10] || !m.maintSet[11] || !m.maintSet[12] {
|
||||
t.Error("group maint window should mark group + children")
|
||||
}
|
||||
if m.maintSet[20] {
|
||||
t.Error("unrelated monitor should NOT be marked")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildMaintSet_ExpiredIgnored(t *testing.T) {
|
||||
m := newTestModel(&tuiMockStore{})
|
||||
m.sites = []models.Site{
|
||||
{SiteConfig: models.SiteConfig{ID: 1, Name: "a"}},
|
||||
}
|
||||
m.maintenanceWindows = []models.MaintenanceWindow{
|
||||
{ID: 1, MonitorID: 1, Type: "maintenance",
|
||||
StartTime: time.Now().Add(-2 * time.Hour),
|
||||
EndTime: time.Now().Add(-1 * time.Hour)},
|
||||
}
|
||||
m.buildMaintSet()
|
||||
if m.maintSet[1] {
|
||||
t.Error("expired maint window should not mark monitor")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildMaintSet_IncidentIgnored(t *testing.T) {
|
||||
m := newTestModel(&tuiMockStore{})
|
||||
m.sites = []models.Site{
|
||||
{SiteConfig: models.SiteConfig{ID: 1, Name: "a"}},
|
||||
}
|
||||
m.maintenanceWindows = []models.MaintenanceWindow{
|
||||
{ID: 1, MonitorID: 0, Type: "incident", StartTime: time.Now().Add(-time.Hour)},
|
||||
}
|
||||
m.buildMaintSet()
|
||||
if m.maintSet[1] {
|
||||
t.Error("incident windows should not mark monitors as in maintenance")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user