-
Notifications
You must be signed in to change notification settings - Fork 121
/
item.go
107 lines (90 loc) · 2.27 KB
/
item.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
package ccache
import (
"fmt"
"sync/atomic"
"time"
)
type Sized interface {
Size() int64
}
type TrackedItem[T any] interface {
Value() T
Release()
Expired() bool
TTL() time.Duration
Expires() time.Time
Extend(duration time.Duration)
}
type Item[T any] struct {
key string
group string
promotions int32
refCount int32
expires int64
size int64
value T
next *Item[T]
prev *Item[T]
}
func newItem[T any](key string, value T, expires int64, track bool) *Item[T] {
size := int64(1)
// https://github.com/golang/go/issues/49206
if sized, ok := (interface{})(value).(Sized); ok {
size = sized.Size()
}
item := &Item[T]{
key: key,
value: value,
promotions: 0,
size: size,
expires: expires,
}
if track {
item.refCount = 1
}
return item
}
func (i *Item[T]) shouldPromote(getsPerPromote int32) bool {
i.promotions += 1
return i.promotions == getsPerPromote
}
func (i *Item[T]) Key() string {
return i.key
}
func (i *Item[T]) Value() T {
return i.value
}
func (i *Item[T]) track() {
atomic.AddInt32(&i.refCount, 1)
}
func (i *Item[T]) Release() {
atomic.AddInt32(&i.refCount, -1)
}
func (i *Item[T]) Expired() bool {
expires := atomic.LoadInt64(&i.expires)
return expires < time.Now().UnixNano()
}
func (i *Item[T]) TTL() time.Duration {
expires := atomic.LoadInt64(&i.expires)
return time.Nanosecond * time.Duration(expires-time.Now().UnixNano())
}
func (i *Item[T]) Expires() time.Time {
expires := atomic.LoadInt64(&i.expires)
return time.Unix(0, expires)
}
func (i *Item[T]) Extend(duration time.Duration) {
atomic.StoreInt64(&i.expires, time.Now().Add(duration).UnixNano())
}
// String returns a string representation of the Item. This includes the default string
// representation of its Value(), as implemented by fmt.Sprintf with "%v", but the exact
// format of the string should not be relied on; it is provided only for debugging
// purposes, and because otherwise including an Item in a call to fmt.Printf or
// fmt.Sprintf expression could cause fields of the Item to be read in a non-thread-safe
// way.
func (i *Item[T]) String() string {
group := i.group
if group == "" {
return fmt.Sprintf("Item(%s:%v)", i.key, i.value)
}
return fmt.Sprintf("Item(%s:%s:%v)", group, i.key, i.value)
}