From 5c9b17039e05cbdb66d2aa954e6dbdfbc0b007c0 Mon Sep 17 00:00:00 2001 From: Jakob Ackermann Date: Wed, 15 Jan 2025 02:05:17 +0000 Subject: [PATCH] FEAT: Add ZoneCache primitive (#3365) --- pkg/zoneCache/zoneCache.go | 86 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 pkg/zoneCache/zoneCache.go diff --git a/pkg/zoneCache/zoneCache.go b/pkg/zoneCache/zoneCache.go new file mode 100644 index 0000000000..db2aa9d553 --- /dev/null +++ b/pkg/zoneCache/zoneCache.go @@ -0,0 +1,86 @@ +package zoneCache + +import ( + "errors" + "sync" +) + +func New[Zone any](fetchAll func() (map[string]Zone, error)) ZoneCache[Zone] { + return ZoneCache[Zone]{fetchAll: fetchAll} +} + +var ErrZoneNotFound = errors.New("zone not found") + +type ZoneCache[Zone any] struct { + mu sync.Mutex + cached bool + cache map[string]Zone + fetchAll func() (map[string]Zone, error) +} + +func (c *ZoneCache[Zone]) ensureCached() error { + if c.cached { + return nil + } + zones, err := c.fetchAll() + if err != nil { + return err + } + if c.cache == nil { + c.cache = make(map[string]Zone, len(zones)) + } + for name, z := range zones { + c.cache[name] = z + } + return nil +} + +func (c *ZoneCache[Zone]) HasZone(name string) (bool, error) { + c.mu.Lock() + defer c.mu.Unlock() + + if err := c.ensureCached(); err != nil { + return false, err + } + _, ok := c.cache[name] + return ok, nil +} + +func (c *ZoneCache[Zone]) GetZone(name string) (Zone, error) { + c.mu.Lock() + defer c.mu.Unlock() + + if err := c.ensureCached(); err != nil { + var z Zone + return z, err + } + z, ok := c.cache[name] + if !ok { + return z, ErrZoneNotFound + } + return z, nil +} + +func (c *ZoneCache[Zone]) GetZoneNames() ([]string, error) { + c.mu.Lock() + defer c.mu.Unlock() + + if err := c.ensureCached(); err != nil { + return nil, err + } + names := make([]string, 0, len(c.cache)) + for name := range c.cache { + names = append(names, name) + } + return names, nil +} + +func (c *ZoneCache[Zone]) SetZone(name string, z Zone) { + c.mu.Lock() + defer c.mu.Unlock() + + if c.cache == nil { + c.cache = make(map[string]Zone, 1) + } + c.cache[name] = z +}