Last active
June 7, 2024 11:09
-
-
Save nitishfy/3a35d3fd5912c42de98611672bc69935 to your computer and use it in GitHub Desktop.
Time To Live (TTL) Cache
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"sync" | |
"time" | |
) | |
type Cache[K comparable, V any] struct { | |
data map[K]item[V] | |
mutex sync.Mutex | |
} | |
type item[V any] struct { | |
val V | |
expiryTime time.Time | |
} | |
// NewCache creates a new cache with a default time to live as 5 minutes | |
func NewCache[K comparable, V any]() *Cache[K, V] { | |
c := &Cache[K, V]{ | |
data: make(map[K]item[V]), | |
} | |
// spin a goroutine to delete the items in the map every 5 minutes | |
go func() { | |
for range time.Tick(5 * time.Minute) { | |
c.mutex.Lock() | |
// range over map to check if any item has expired | |
for key, val := range c.data { | |
if val.isExpired() { | |
delete(c.data, key) | |
} | |
} | |
c.mutex.Unlock() | |
} | |
}() | |
return c | |
} | |
// isExpired checks if the item present in the cache has been expired | |
func (i *item[V]) isExpired() bool { | |
return time.Now().After(i.expiryTime) | |
} | |
// Set sets the value in the cache with key-value and time duration | |
func (c *Cache[K, V]) Set(key K, value V, ttl time.Duration) { | |
c.mutex.Lock() | |
defer c.mutex.Unlock() | |
item := item[V]{ | |
val: value, | |
expiryTime: time.Now().Add(ttl), | |
} | |
c.data[key] = item | |
} | |
// Get gets the value of the key | |
func (c *Cache[K, V]) Get(key K) (V, bool) { | |
c.mutex.Lock() | |
defer c.mutex.Unlock() | |
item, found := c.data[key] | |
if !found { | |
var zeroValue V | |
return zeroValue, false | |
} | |
// check if item is expired | |
if item.isExpired() { | |
delete(c.data, key) | |
var zeroValue V | |
return zeroValue, false | |
} | |
return item.val, true | |
} | |
// Remove removes the item from the cache | |
func (c *Cache[K, V]) Remove(key K) { | |
c.mutex.Lock() | |
defer c.mutex.Unlock() | |
delete(c.data, key) | |
} | |
// Pop removes the item from the cache with value returned | |
func (c *Cache[K, V]) Pop(key K) (V, bool) { | |
c.mutex.Lock() | |
defer c.mutex.Unlock() | |
item, found := c.data[key] | |
if !found { | |
var zeroValue V | |
return zeroValue, false | |
} | |
delete(c.data, key) | |
if item.isExpired() { | |
var zeroValue V | |
return zeroValue, false | |
} | |
return item.val, true | |
} | |
func main() { | |
cache := NewCache[string, string]() | |
cache.Set("name", "nitish", 5*time.Second) | |
time.Sleep(6 * time.Second) // Ensure the item expires | |
val, found := cache.Get("name") | |
if !found { | |
fmt.Printf("item not found\n") | |
return | |
} | |
fmt.Println(val) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment