1package ccache 2 3import ( 4 "container/list" 5 "sync/atomic" 6 "time" 7) 8 9type Sized interface { 10 Size() int64 11} 12 13type TrackedItem interface { 14 Value() interface{} 15 Release() 16 Expired() bool 17 TTL() time.Duration 18 Expires() time.Time 19 Extend(duration time.Duration) 20} 21 22type nilItem struct{} 23 24func (n *nilItem) Value() interface{} { return nil } 25func (n *nilItem) Release() {} 26 27func (i *nilItem) Expired() bool { 28 return true 29} 30 31func (i *nilItem) TTL() time.Duration { 32 return time.Minute 33} 34 35func (i *nilItem) Expires() time.Time { 36 return time.Time{} 37} 38 39func (i *nilItem) Extend(duration time.Duration) { 40} 41 42var NilTracked = new(nilItem) 43 44type Item struct { 45 key string 46 group string 47 promotions int32 48 refCount int32 49 expires int64 50 size int64 51 value interface{} 52 element *list.Element 53} 54 55func newItem(key string, value interface{}, expires int64) *Item { 56 size := int64(1) 57 if sized, ok := value.(Sized); ok { 58 size = sized.Size() 59 } 60 return &Item{ 61 key: key, 62 value: value, 63 promotions: 0, 64 size: size, 65 expires: expires, 66 } 67} 68 69func (i *Item) shouldPromote(getsPerPromote int32) bool { 70 i.promotions += 1 71 return i.promotions == getsPerPromote 72} 73 74func (i *Item) Value() interface{} { 75 return i.value 76} 77 78func (i *Item) track() { 79 atomic.AddInt32(&i.refCount, 1) 80} 81 82func (i *Item) Release() { 83 atomic.AddInt32(&i.refCount, -1) 84} 85 86func (i *Item) Expired() bool { 87 expires := atomic.LoadInt64(&i.expires) 88 return expires < time.Now().UnixNano() 89} 90 91func (i *Item) TTL() time.Duration { 92 expires := atomic.LoadInt64(&i.expires) 93 return time.Nanosecond * time.Duration(expires-time.Now().UnixNano()) 94} 95 96func (i *Item) Expires() time.Time { 97 expires := atomic.LoadInt64(&i.expires) 98 return time.Unix(0, expires) 99} 100 101func (i *Item) Extend(duration time.Duration) { 102 atomic.StoreInt64(&i.expires, time.Now().Add(duration).UnixNano()) 103} 104