1
16
17 package cache
18
19 import (
20 "sync"
21 "time"
22
23 "k8s.io/utils/clock"
24 )
25
26
27
28
29
30
31
32
33
34
35
36
37
38 type ExpirationCache struct {
39 cacheStorage ThreadSafeStore
40 keyFunc KeyFunc
41 clock clock.Clock
42 expirationPolicy ExpirationPolicy
43
44
45 expirationLock sync.Mutex
46 }
47
48
49
50 type ExpirationPolicy interface {
51 IsExpired(obj *TimestampedEntry) bool
52 }
53
54
55 type TTLPolicy struct {
56
57
58 TTL time.Duration
59
60
61 Clock clock.Clock
62 }
63
64
65
66 func (p *TTLPolicy) IsExpired(obj *TimestampedEntry) bool {
67 return p.TTL > 0 && p.Clock.Since(obj.Timestamp) > p.TTL
68 }
69
70
71
72
73
74 type TimestampedEntry struct {
75 Obj interface{}
76 Timestamp time.Time
77 key string
78 }
79
80
81 func (c *ExpirationCache) getTimestampedEntry(key string) (*TimestampedEntry, bool) {
82 item, _ := c.cacheStorage.Get(key)
83 if tsEntry, ok := item.(*TimestampedEntry); ok {
84 return tsEntry, true
85 }
86 return nil, false
87 }
88
89
90
91 func (c *ExpirationCache) getOrExpire(key string) (interface{}, bool) {
92
93
94
95 c.expirationLock.Lock()
96 defer c.expirationLock.Unlock()
97 timestampedItem, exists := c.getTimestampedEntry(key)
98 if !exists {
99 return nil, false
100 }
101 if c.expirationPolicy.IsExpired(timestampedItem) {
102 c.cacheStorage.Delete(key)
103 return nil, false
104 }
105 return timestampedItem.Obj, true
106 }
107
108
109 func (c *ExpirationCache) GetByKey(key string) (interface{}, bool, error) {
110 obj, exists := c.getOrExpire(key)
111 return obj, exists, nil
112 }
113
114
115
116 func (c *ExpirationCache) Get(obj interface{}) (interface{}, bool, error) {
117 key, err := c.keyFunc(obj)
118 if err != nil {
119 return nil, false, KeyError{obj, err}
120 }
121 obj, exists := c.getOrExpire(key)
122 return obj, exists, nil
123 }
124
125
126
127 func (c *ExpirationCache) List() []interface{} {
128 items := c.cacheStorage.List()
129
130 list := make([]interface{}, 0, len(items))
131 for _, item := range items {
132 key := item.(*TimestampedEntry).key
133 if obj, exists := c.getOrExpire(key); exists {
134 list = append(list, obj)
135 }
136 }
137 return list
138 }
139
140
141 func (c *ExpirationCache) ListKeys() []string {
142 return c.cacheStorage.ListKeys()
143 }
144
145
146
147 func (c *ExpirationCache) Add(obj interface{}) error {
148 key, err := c.keyFunc(obj)
149 if err != nil {
150 return KeyError{obj, err}
151 }
152 c.expirationLock.Lock()
153 defer c.expirationLock.Unlock()
154
155 c.cacheStorage.Add(key, &TimestampedEntry{obj, c.clock.Now(), key})
156 return nil
157 }
158
159
160
161 func (c *ExpirationCache) Update(obj interface{}) error {
162 return c.Add(obj)
163 }
164
165
166 func (c *ExpirationCache) Delete(obj interface{}) error {
167 key, err := c.keyFunc(obj)
168 if err != nil {
169 return KeyError{obj, err}
170 }
171 c.expirationLock.Lock()
172 defer c.expirationLock.Unlock()
173 c.cacheStorage.Delete(key)
174 return nil
175 }
176
177
178
179
180 func (c *ExpirationCache) Replace(list []interface{}, resourceVersion string) error {
181 items := make(map[string]interface{}, len(list))
182 ts := c.clock.Now()
183 for _, item := range list {
184 key, err := c.keyFunc(item)
185 if err != nil {
186 return KeyError{item, err}
187 }
188 items[key] = &TimestampedEntry{item, ts, key}
189 }
190 c.expirationLock.Lock()
191 defer c.expirationLock.Unlock()
192 c.cacheStorage.Replace(items, resourceVersion)
193 return nil
194 }
195
196
197 func (c *ExpirationCache) Resync() error {
198 return nil
199 }
200
201
202 func NewTTLStore(keyFunc KeyFunc, ttl time.Duration) Store {
203 return NewExpirationStore(keyFunc, &TTLPolicy{ttl, clock.RealClock{}})
204 }
205
206
207 func NewExpirationStore(keyFunc KeyFunc, expirationPolicy ExpirationPolicy) Store {
208 return &ExpirationCache{
209 cacheStorage: NewThreadSafeStore(Indexers{}, Indices{}),
210 keyFunc: keyFunc,
211 clock: clock.RealClock{},
212 expirationPolicy: expirationPolicy,
213 }
214 }
215
View as plain text