...
1 package ttlcache
2
3 import (
4 "sync"
5 "time"
6 )
7
8 const (
9
10 NoTTL time.Duration = -1
11
12
13
14 PreviousOrDefaultTTL time.Duration = -2
15
16
17
18 DefaultTTL time.Duration = 0
19 )
20
21
22
23 type Item[K comparable, V any] struct {
24
25
26
27
28
29
30
31
32
33 mu sync.RWMutex
34 key K
35 value V
36 ttl time.Duration
37 expiresAt time.Time
38 queueIndex int
39 version int64
40 }
41
42
43 func newItem[K comparable, V any](key K, value V, ttl time.Duration, enableVersionTracking bool) *Item[K, V] {
44 item := &Item[K, V]{
45 key: key,
46 value: value,
47 ttl: ttl,
48 }
49
50 if !enableVersionTracking {
51 item.version = -1
52 }
53
54 item.touch()
55
56 return item
57 }
58
59
60 func (item *Item[K, V]) update(value V, ttl time.Duration) {
61 item.mu.Lock()
62 defer item.mu.Unlock()
63
64 item.value = value
65
66
67 if item.version > -1 {
68 item.version++
69 }
70
71
72 if ttl == PreviousOrDefaultTTL {
73 return
74 }
75
76 item.ttl = ttl
77
78
79
80 item.expiresAt = time.Time{}
81 item.touchUnsafe()
82 }
83
84
85 func (item *Item[K, V]) touch() {
86 item.mu.Lock()
87 defer item.mu.Unlock()
88
89 item.touchUnsafe()
90 }
91
92
93
94 func (item *Item[K, V]) touchUnsafe() {
95 if item.ttl <= 0 {
96 return
97 }
98
99 item.expiresAt = time.Now().Add(item.ttl)
100 }
101
102
103
104 func (item *Item[K, V]) IsExpired() bool {
105 item.mu.RLock()
106 defer item.mu.RUnlock()
107
108 return item.isExpiredUnsafe()
109 }
110
111
112
113 func (item *Item[K, V]) isExpiredUnsafe() bool {
114 if item.ttl <= 0 {
115 return false
116 }
117
118 return item.expiresAt.Before(time.Now())
119 }
120
121
122 func (item *Item[K, V]) Key() K {
123 item.mu.RLock()
124 defer item.mu.RUnlock()
125
126 return item.key
127 }
128
129
130 func (item *Item[K, V]) Value() V {
131 item.mu.RLock()
132 defer item.mu.RUnlock()
133
134 return item.value
135 }
136
137
138 func (item *Item[K, V]) TTL() time.Duration {
139 item.mu.RLock()
140 defer item.mu.RUnlock()
141
142 return item.ttl
143 }
144
145
146 func (item *Item[K, V]) ExpiresAt() time.Time {
147 item.mu.RLock()
148 defer item.mu.RUnlock()
149
150 return item.expiresAt
151 }
152
153
154
155
156 func (item *Item[K, V]) Version() int64 {
157 item.mu.RLock()
158 defer item.mu.RUnlock()
159
160 return item.version
161 }
162
View as plain text