Files
YMhut-box-C-/server/unified-management/internal/web/dashboard_cache.go
T

86 lines
1.8 KiB
Go

package web
import (
"sync"
"time"
)
type dashboardCacheEntry struct {
value map[string]any
expiresAt time.Time
building chan struct{}
}
type dashboardSnapshotCache struct {
mu sync.Mutex
ttl time.Duration
generation uint64
entries map[string]*dashboardCacheEntry
}
func newDashboardSnapshotCache(ttl time.Duration) *dashboardSnapshotCache {
if ttl <= 0 {
ttl = 5 * time.Second
}
return &dashboardSnapshotCache{ttl: ttl, entries: map[string]*dashboardCacheEntry{}}
}
func (c *dashboardSnapshotCache) Get(key string, build func() (map[string]any, error)) (map[string]any, bool, error) {
for {
now := time.Now()
c.mu.Lock()
entry := c.entries[key]
if entry != nil && entry.value != nil && now.Before(entry.expiresAt) {
value := entry.value
c.mu.Unlock()
return value, true, nil
}
if entry != nil && entry.building != nil {
ready := entry.building
c.mu.Unlock()
<-ready
continue
}
generation := c.generation
ready := make(chan struct{})
c.entries[key] = &dashboardCacheEntry{building: ready}
c.mu.Unlock()
value, err := build()
c.mu.Lock()
if generation != c.generation {
if current := c.entries[key]; current != nil && current.building == ready {
delete(c.entries, key)
}
close(ready)
c.mu.Unlock()
if err != nil {
return nil, false, err
}
continue
}
if err != nil {
delete(c.entries, key)
close(ready)
c.mu.Unlock()
return nil, false, err
}
c.entries[key] = &dashboardCacheEntry{value: value, expiresAt: time.Now().Add(c.ttl)}
close(ready)
c.mu.Unlock()
return value, false, nil
}
}
func (c *dashboardSnapshotCache) Invalidate() {
c.mu.Lock()
c.generation++
for key, entry := range c.entries {
if entry.building == nil {
delete(c.entries, key)
}
}
c.mu.Unlock()
}