87 lines
1.7 KiB
Go
87 lines
1.7 KiB
Go
package decaymap
|
|
|
|
import (
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
func Zilch[T any]() T {
|
|
var zero T
|
|
return zero
|
|
}
|
|
|
|
// Impl is a lazy key->value map. It's a wrapper around a map and a mutex. If values exceed their time-to-live, they are pruned at Get time.
|
|
type Impl[K comparable, V any] struct {
|
|
data map[K]decayMapEntry[V]
|
|
lock sync.RWMutex
|
|
}
|
|
|
|
type decayMapEntry[V any] struct {
|
|
Value V
|
|
expiry time.Time
|
|
}
|
|
|
|
// New creates a new DecayMap of key type K and value type V.
|
|
//
|
|
// Key types must be comparable to work with maps.
|
|
func New[K comparable, V any]() *Impl[K, V] {
|
|
return &Impl[K, V]{
|
|
data: make(map[K]decayMapEntry[V]),
|
|
}
|
|
}
|
|
|
|
// expire forcibly expires a key by setting its time-to-live one second in the past.
|
|
func (m *Impl[K, V]) expire(key K) bool {
|
|
m.lock.RLock()
|
|
val, ok := m.data[key]
|
|
m.lock.RUnlock()
|
|
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
m.lock.Lock()
|
|
val.expiry = time.Now().Add(-1 * time.Second)
|
|
m.data[key] = val
|
|
m.lock.Unlock()
|
|
|
|
return true
|
|
}
|
|
|
|
// Get gets a value from the DecayMap by key.
|
|
//
|
|
// If a value has expired, forcibly delete it if it was not updated.
|
|
func (m *Impl[K, V]) Get(key K) (V, bool) {
|
|
m.lock.RLock()
|
|
value, ok := m.data[key]
|
|
m.lock.RUnlock()
|
|
|
|
if !ok {
|
|
return Zilch[V](), false
|
|
}
|
|
|
|
if time.Now().After(value.expiry) {
|
|
m.lock.Lock()
|
|
// Since previously reading m.data[key], the value may have been updated.
|
|
// Delete the entry only if the expiry time is still the same.
|
|
if m.data[key].expiry.Equal(value.expiry) {
|
|
delete(m.data, key)
|
|
}
|
|
m.lock.Unlock()
|
|
|
|
return Zilch[V](), false
|
|
}
|
|
|
|
return value.Value, true
|
|
}
|
|
|
|
// Set sets a key value pair in the map.
|
|
func (m *Impl[K, V]) Set(key K, value V, ttl time.Duration) {
|
|
m.lock.Lock()
|
|
defer m.lock.Unlock()
|
|
|
|
m.data[key] = decayMapEntry[V]{
|
|
Value: value,
|
|
expiry: time.Now().Add(ttl),
|
|
}
|
|
}
|