client-go中带过期时间的cache实现,具体在:client-go\tools\cache\expiration_cache.go
cache包下有各种数据结构的实现。本节看一下NewTTLStore创建并返回带有TTLPolicy的ExpirationCache实现:
package main
import (
"k8s.io/client-go/tools/cache"
"log"
"time"
)
func stringKeyFunc(obj interface{}) (string, error) {
key := obj.(string)
return key, nil
}
func main() {
sto := cache.NewTTLStore(stringKeyFunc, 5*time.Second)
sto.Add("key1")
time.Sleep(2 * time.Second)
item, exists, err := sto.Get("key1")
log.Printf("2s item: %v, exists: %v, err: %v", item, exists, err)
for {
time.Sleep(7 * time.Second)
item, exists, err := sto.Get("key1")
log.Printf("time: %v item: %v, exists: %v, err: %v", time.Now(), item, exists, err)
}
}
部分输出如下:
2020/09/09 21:04:51 2s item: key1, exists: true, err: <nil>
2020/09/09 21:04:58 time: 2020-09-09 21:04:58.8331777 +0800 CST m=+9.134970501 item: <nil>, exists: false, err: <nil>
2020/09/09 21:05:05 time: 2020-09-09 21:05:05.8332772 +0800 CST m=+16.135070001 item: <nil>, exists: false, err: <nil>
可以看到5s之后exists为false。
具体实现为:
每次Get的时候都会执行getOrExpire方法,getOrExpire如果过期,则会将其删除。当且仅当它尚未过期时才从timestampedEntry中检索对象。它在删除过程中拥有写锁定。
// getOrExpire retrieves the object from the timestampedEntry if and only if it hasn't
// already expired. It holds a write lock across deletion.
func (c *ExpirationCache) getOrExpire(key string) (interface{}, bool) {
// Prevent all inserts from the time we deem an item as "expired" to when we
// delete it, so an un-expired item doesn't sneak in under the same key, just
// before the Delete.
c.expirationLock.Lock()
defer c.expirationLock.Unlock()
timestampedItem, exists := c.getTimestampedEntry(key)
if !exists {
return nil, false
}
if c.expirationPolicy.IsExpired(timestampedItem) {
klog.V(4).Infof("Entry %v: %+v has expired", key, timestampedItem.obj)
c.cacheStorage.Delete(key)
return nil, false
}
return timestampedItem.obj, true
}