63 lines
1.5 KiB
Go
63 lines
1.5 KiB
Go
package windviz
|
|
|
|
import (
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// Cache is a small bounded cache of rasterized fields keyed by request
|
|
// parameters and dataset epoch. It is safe for concurrent use.
|
|
//
|
|
// Visualization requests repeat heavily (a frontend re-fetches the same
|
|
// layer as users pan within a tile), so even a tiny cache removes most
|
|
// recomputation. Eviction is simplest-possible: when full, the whole map is
|
|
// cleared. Entries also expire after TTL.
|
|
type Cache struct {
|
|
mu sync.Mutex
|
|
entries map[string]cacheEntry
|
|
max int
|
|
ttl time.Duration
|
|
now func() time.Time
|
|
}
|
|
|
|
type cacheEntry struct {
|
|
field Field
|
|
expires time.Time
|
|
}
|
|
|
|
// NewCache returns a cache holding up to max entries for ttl each.
|
|
func NewCache(max int, ttl time.Duration) *Cache {
|
|
if max <= 0 {
|
|
max = 64
|
|
}
|
|
if ttl <= 0 {
|
|
ttl = 10 * time.Minute
|
|
}
|
|
return &Cache{
|
|
entries: make(map[string]cacheEntry, max),
|
|
max: max,
|
|
ttl: ttl,
|
|
now: time.Now,
|
|
}
|
|
}
|
|
|
|
// Get returns the cached field for key, if present and unexpired.
|
|
func (c *Cache) Get(key string) (Field, bool) {
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
e, ok := c.entries[key]
|
|
if !ok || c.now().After(e.expires) {
|
|
return nil, false
|
|
}
|
|
return e.field, true
|
|
}
|
|
|
|
// Put stores field under key.
|
|
func (c *Cache) Put(key string, field Field) {
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
if len(c.entries) >= c.max {
|
|
c.entries = make(map[string]cacheEntry, c.max)
|
|
}
|
|
c.entries[key] = cacheEntry{field: field, expires: c.now().Add(c.ttl)}
|
|
}
|