Senior
type TTLCache interface { Set(k string, v any, ttl time.Duration) Get(k string) (any, bool) Del(k string) bool } // Should not leak memory // get should not return expired // Implementation
sobes.tech AI
Answer from AI
To implement TTLCache in Go that prevents memory leaks and does not return expired values, you can use a structure with a mutex for thread safety, a map to store values, and an expiration time for each key. A mechanism to clean up expired items, such as a periodic goroutine, is also needed.
Example implementation:
package ttlcache
import (
"sync"
"time"
)
type cacheItem struct {
value any
expiration int64 // unix nano timestamp
}
type TTLCache interface {
Set(k string, v any, ttl time.Duration)
Get(k string) (any, bool)
Del(k string) bool
}
type ttlCache struct {
mu sync.RWMutex
items map[string]cacheItem
quit chan struct{}
}
func NewTTLCache(cleanupInterval time.Duration) TTLCache {
c := &ttlCache{
items: make(map[string]cacheItem),
quit: make(chan struct{}),
}
go c.cleanupLoop(cleanupInterval)
return c
}
func (c *ttlCache) Set(k string, v any, ttl time.Duration) {
c.mu.Lock()
defer c.mu.Unlock()
c.items[k] = cacheItem{
value: v,
expiration: time.Now().Add(ttl).UnixNano(),
}
}
func (c *ttlCache) Get(k string) (any, bool) {
c.mu.RLock()
item, found := c.items[k]
c.mu.RUnlock()
if !found {
return nil, false
}
if time.Now().UnixNano() > item.expiration {
// item expired, delete
c.mu.Lock()
delete(c.items, k)
c.mu.Unlock()
return nil, false
}
return item.value, true
}
func (c *ttlCache) Del(k string) bool {
c.mu.Lock()
defer c.mu.Unlock()
if _, found := c.items[k]; found {
delete(c.items, k)
return true
}
return false
}
func (c *ttlCache) cleanupLoop(interval time.Duration) {
ticker := time.NewTicker(interval)
defer ticker.Stop()
for {
select {
case <-ticker.C:
now := time.Now().UnixNano()
c.mu.Lock()
for k, item := range c.items {
if now > item.expiration {
delete(c.items, k)
}
}
c.mu.Unlock()
case <-c.quit:
return
}
}
}
func (c *ttlCache) Close() {
close(c.quit)
}
In this implementation:
- When setting a value, an expiration time is stored.
- When getting a value, it checks if the item has expired; if so, it deletes it and returns false.
- There is a goroutine that periodically cleans up expired entries to prevent memory leaks.
- RWMutex is used for thread safety.