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
|
// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
package cache
import (
"time"
)
// Single is a simple in-memory cache that stores a single value until a
// defined time before it is re-fetched. It also supports returning a
// previously-expired value if refreshing the value in the cache fails.
//
// Single is not safe for concurrent use.
type Single[K comparable, V any] struct {
key K
val V
goodUntil time.Time
timeNow func() time.Time // for tests
// ServeExpired indicates that if an error occurs when filling the
// cache, an expired value can be returned instead of an error.
//
// This value should only be set when this struct is created.
ServeExpired bool
}
var _ Cache[int, int] = (*Single[int, int])(nil)
// Get will return the cached value, if any, or fill the cache by calling f and
// return the corresponding value. If f returns an error and c.ServeExpired is
// true, then a previous expired value can be returned with no error.
func (c *Single[K, V]) Get(key K, f FillFunc[V]) (V, error) {
var now time.Time
if c.timeNow != nil {
now = c.timeNow()
} else {
now = time.Now()
}
if c.key == key && now.Before(c.goodUntil) {
return c.val, nil
}
// Re-fill cached entry
val, until, err := f()
if err == nil {
c.key = key
c.val = val
c.goodUntil = until
return val, nil
}
// Never serve an expired entry for the wrong key.
if c.key == key && c.ServeExpired && !c.goodUntil.IsZero() {
return c.val, nil
}
var zero V
return zero, err
}
// Forget implements Cache.
func (c *Single[K, V]) Forget(key K) {
if c.key != key {
return
}
c.Empty()
}
// Empty implements Cache.
func (c *Single[K, V]) Empty() {
c.goodUntil = time.Time{}
var zeroKey K
c.key = zeroKey
var zeroVal V
c.val = zeroVal
}
|