Skip to content

Commit e739b55

Browse files
authored
Merge pull request kubernetes#75585 from tiffanyfay/cache
Updated client-go expiration cache to take in expiration policies
2 parents 1e18477 + bc226a2 commit e739b55

File tree

3 files changed

+32
-24
lines changed

3 files changed

+32
-24
lines changed

staging/src/k8s.io/client-go/tools/cache/expiration_cache.go

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ type ExpirationCache struct {
4848
// ExpirationPolicy dictates when an object expires. Currently only abstracted out
4949
// so unittests don't rely on the system clock.
5050
type ExpirationPolicy interface {
51-
IsExpired(obj *timestampedEntry) bool
51+
IsExpired(obj *TimestampedEntry) bool
5252
}
5353

5454
// TTLPolicy implements a ttl based ExpirationPolicy.
@@ -63,26 +63,29 @@ type TTLPolicy struct {
6363

6464
// IsExpired returns true if the given object is older than the ttl, or it can't
6565
// determine its age.
66-
func (p *TTLPolicy) IsExpired(obj *timestampedEntry) bool {
67-
return p.Ttl > 0 && p.Clock.Since(obj.timestamp) > p.Ttl
66+
func (p *TTLPolicy) IsExpired(obj *TimestampedEntry) bool {
67+
return p.Ttl > 0 && p.Clock.Since(obj.Timestamp) > p.Ttl
6868
}
6969

70-
// timestampedEntry is the only type allowed in a ExpirationCache.
71-
type timestampedEntry struct {
72-
obj interface{}
73-
timestamp time.Time
70+
// TimestampedEntry is the only type allowed in a ExpirationCache.
71+
// Keep in mind that it is not safe to share timestamps between computers.
72+
// Behavior may be inconsistent if you get a timestamp from the API Server and
73+
// use it on the client machine as part of your ExpirationCache.
74+
type TimestampedEntry struct {
75+
Obj interface{}
76+
Timestamp time.Time
7477
}
7578

76-
// getTimestampedEntry returns the timestampedEntry stored under the given key.
77-
func (c *ExpirationCache) getTimestampedEntry(key string) (*timestampedEntry, bool) {
79+
// getTimestampedEntry returns the TimestampedEntry stored under the given key.
80+
func (c *ExpirationCache) getTimestampedEntry(key string) (*TimestampedEntry, bool) {
7881
item, _ := c.cacheStorage.Get(key)
79-
if tsEntry, ok := item.(*timestampedEntry); ok {
82+
if tsEntry, ok := item.(*TimestampedEntry); ok {
8083
return tsEntry, true
8184
}
8285
return nil, false
8386
}
8487

85-
// getOrExpire retrieves the object from the timestampedEntry if and only if it hasn't
88+
// getOrExpire retrieves the object from the TimestampedEntry if and only if it hasn't
8689
// already expired. It holds a write lock across deletion.
8790
func (c *ExpirationCache) getOrExpire(key string) (interface{}, bool) {
8891
// Prevent all inserts from the time we deem an item as "expired" to when we
@@ -95,11 +98,11 @@ func (c *ExpirationCache) getOrExpire(key string) (interface{}, bool) {
9598
return nil, false
9699
}
97100
if c.expirationPolicy.IsExpired(timestampedItem) {
98-
klog.V(4).Infof("Entry %v: %+v has expired", key, timestampedItem.obj)
101+
klog.V(4).Infof("Entry %v: %+v has expired", key, timestampedItem.Obj)
99102
c.cacheStorage.Delete(key)
100103
return nil, false
101104
}
102-
return timestampedItem.obj, true
105+
return timestampedItem.Obj, true
103106
}
104107

105108
// GetByKey returns the item stored under the key, or sets exists=false.
@@ -126,7 +129,7 @@ func (c *ExpirationCache) List() []interface{} {
126129

127130
list := make([]interface{}, 0, len(items))
128131
for _, item := range items {
129-
obj := item.(*timestampedEntry).obj
132+
obj := item.(*TimestampedEntry).Obj
130133
if key, err := c.keyFunc(obj); err != nil {
131134
list = append(list, obj)
132135
} else if obj, exists := c.getOrExpire(key); exists {
@@ -151,7 +154,7 @@ func (c *ExpirationCache) Add(obj interface{}) error {
151154
c.expirationLock.Lock()
152155
defer c.expirationLock.Unlock()
153156

154-
c.cacheStorage.Add(key, &timestampedEntry{obj, c.clock.Now()})
157+
c.cacheStorage.Add(key, &TimestampedEntry{obj, c.clock.Now()})
155158
return nil
156159
}
157160

@@ -184,7 +187,7 @@ func (c *ExpirationCache) Replace(list []interface{}, resourceVersion string) er
184187
if err != nil {
185188
return KeyError{item, err}
186189
}
187-
items[key] = &timestampedEntry{item, ts}
190+
items[key] = &TimestampedEntry{item, ts}
188191
}
189192
c.expirationLock.Lock()
190193
defer c.expirationLock.Unlock()
@@ -199,10 +202,15 @@ func (c *ExpirationCache) Resync() error {
199202

200203
// NewTTLStore creates and returns a ExpirationCache with a TTLPolicy
201204
func NewTTLStore(keyFunc KeyFunc, ttl time.Duration) Store {
205+
return NewExpirationStore(keyFunc, &TTLPolicy{ttl, clock.RealClock{}})
206+
}
207+
208+
// NewExpirationStore creates and returns a ExpirationCache for a given policy
209+
func NewExpirationStore(keyFunc KeyFunc, expirationPolicy ExpirationPolicy) Store {
202210
return &ExpirationCache{
203211
cacheStorage: NewThreadSafeStore(Indexers{}, Indices{}),
204212
keyFunc: keyFunc,
205213
clock: clock.RealClock{},
206-
expirationPolicy: &TTLPolicy{ttl, clock.RealClock{}},
214+
expirationPolicy: expirationPolicy,
207215
}
208216
}

staging/src/k8s.io/client-go/tools/cache/expiration_cache_fakes.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ type FakeExpirationPolicy struct {
3838
RetrieveKeyFunc KeyFunc
3939
}
4040

41-
func (p *FakeExpirationPolicy) IsExpired(obj *timestampedEntry) bool {
41+
func (p *FakeExpirationPolicy) IsExpired(obj *TimestampedEntry) bool {
4242
key, _ := p.RetrieveKeyFunc(obj)
4343
return !p.NeverExpire.Has(key)
4444
}

staging/src/k8s.io/client-go/tools/cache/expiration_cache_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ func TestTTLExpirationBasic(t *testing.T) {
3434
&FakeExpirationPolicy{
3535
NeverExpire: sets.NewString(),
3636
RetrieveKeyFunc: func(obj interface{}) (string, error) {
37-
return obj.(*timestampedEntry).obj.(testStoreObject).id, nil
37+
return obj.(*TimestampedEntry).Obj.(testStoreObject).id, nil
3838
},
3939
},
4040
clock.RealClock{},
@@ -67,7 +67,7 @@ func TestReAddExpiredItem(t *testing.T) {
6767
exp := &FakeExpirationPolicy{
6868
NeverExpire: sets.NewString(),
6969
RetrieveKeyFunc: func(obj interface{}) (string, error) {
70-
return obj.(*timestampedEntry).obj.(testStoreObject).id, nil
70+
return obj.(*TimestampedEntry).Obj.(testStoreObject).id, nil
7171
},
7272
}
7373
ttlStore := NewFakeExpirationStore(
@@ -130,7 +130,7 @@ func TestTTLList(t *testing.T) {
130130
&FakeExpirationPolicy{
131131
NeverExpire: sets.NewString(testObjs[1].id),
132132
RetrieveKeyFunc: func(obj interface{}) (string, error) {
133-
return obj.(*timestampedEntry).obj.(testStoreObject).id, nil
133+
return obj.(*TimestampedEntry).Obj.(testStoreObject).id, nil
134134
},
135135
},
136136
clock.RealClock{},
@@ -168,15 +168,15 @@ func TestTTLPolicy(t *testing.T) {
168168
expiredTime := fakeTime.Add(-(ttl + 1))
169169

170170
policy := TTLPolicy{ttl, clock.NewFakeClock(fakeTime)}
171-
fakeTimestampedEntry := &timestampedEntry{obj: struct{}{}, timestamp: exactlyOnTTL}
171+
fakeTimestampedEntry := &TimestampedEntry{Obj: struct{}{}, Timestamp: exactlyOnTTL}
172172
if policy.IsExpired(fakeTimestampedEntry) {
173173
t.Errorf("TTL cache should not expire entries exactly on ttl")
174174
}
175-
fakeTimestampedEntry.timestamp = fakeTime
175+
fakeTimestampedEntry.Timestamp = fakeTime
176176
if policy.IsExpired(fakeTimestampedEntry) {
177177
t.Errorf("TTL Cache should not expire entries before ttl")
178178
}
179-
fakeTimestampedEntry.timestamp = expiredTime
179+
fakeTimestampedEntry.Timestamp = expiredTime
180180
if !policy.IsExpired(fakeTimestampedEntry) {
181181
t.Errorf("TTL Cache should expire entries older than ttl")
182182
}

0 commit comments

Comments
 (0)