-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathttlmap.go
110 lines (93 loc) · 2.68 KB
/
ttlmap.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
package main
import (
"sync"
"time"
)
// RemoveCallback is used to have a callback when an entry
// is removed from the cache.
type RemoveCallback func(key interface{}, value interface{})
// TTLMap implements a map where the values expire with TTLs
type TTLMap struct {
entries map[interface{}]interface{}
eMutex sync.Mutex
schedule map[interface{}]*time.Timer
sMutex sync.Mutex
onRemoval RemoveCallback
defaultTTL time.Duration
}
// NewTTLMap creates a TTLMap with no callback function
func NewTTLMap(ttl time.Duration) *TTLMap {
return NewTTLMapWithCallback(ttl, nil)
}
// NewTTLMapWithCallback will create a TTLMap with a callback function
func NewTTLMapWithCallback(ttl time.Duration, callback RemoveCallback) *TTLMap {
return &TTLMap{
make(map[interface{}]interface{}),
sync.Mutex{},
make(map[interface{}]*time.Timer),
sync.Mutex{},
callback,
ttl,
}
}
// ClearSchedule removes expired entries from the schedule
func (ttlmap *TTLMap) clearSchedule(key interface{}) {
ttlmap.sMutex.Lock()
defer ttlmap.sMutex.Unlock()
delete(ttlmap.schedule, key)
}
func (ttlmap *TTLMap) addEntry(key, value interface{}) {
ttlmap.eMutex.Lock()
defer ttlmap.eMutex.Unlock()
ttlmap.entries[key] = value
}
// Add adds an entry to the map using the default TTL
func (ttlmap *TTLMap) Add(key, value interface{}) {
ttlmap.AddWithTTL(key, value, ttlmap.defaultTTL)
}
// AddWithTTL adds an entry with a specified TTL value
func (ttlmap *TTLMap) AddWithTTL(key, value interface{}, ttl time.Duration) {
ttlmap.sMutex.Lock()
defer ttlmap.sMutex.Unlock()
if ttlmap.schedule[key] != nil {
// Reset the ttl for entries that exist already.
ttlmap.schedule[key].Reset(ttl)
} else {
// create a timer and monitor for it to expire, then remove
// the object from the entries
ttlmap.schedule[key] = time.NewTimer(ttl)
go func() {
<-ttlmap.schedule[key].C
ttlmap.Remove(key)
}()
}
// Add the entry
ttlmap.addEntry(key, value)
}
// Remove deletes an entry from the entries
func (ttlmap *TTLMap) Remove(key interface{}) {
ttlmap.eMutex.Lock()
defer ttlmap.eMutex.Unlock()
delete(ttlmap.entries, key)
// remember to clean up the schedule
ttlmap.clearSchedule(key)
}
// Get returns a value from the map
func (ttlmap *TTLMap) Get(key interface{}) (value interface{}) {
ttlmap.eMutex.Lock()
defer ttlmap.eMutex.Unlock()
if value, present := ttlmap.entries[key]; present {
return value
}
return nil
}
// GetAll returns the whole map
func (ttlmap *TTLMap) GetAll() (copied map[interface{}]interface{}) {
ttlmap.eMutex.Lock()
defer ttlmap.eMutex.Unlock()
copied = make(map[interface{}]interface{})
for key, value := range ttlmap.entries {
copied[key] = value
}
return copied
}