This repository was archived by the owner on Feb 28, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstatcache.go
95 lines (80 loc) · 2.23 KB
/
statcache.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
package executor
import (
"sync"
)
// A StatSet is the cached value.
type statSet struct {
// Latency measures how long an Action takes
Latency Timer
// Success is incremented when an Action does not return an error
Success Counter
// Error is incremented when an Action results in an error
Error Counter
}
// newStatSet creates a statSet from the given src with the provided name.
func newStatSet(src StatSource, name string) *statSet {
return &statSet{
Latency: src.Timer(name),
Success: src.Counter(name + ".success"),
Error: src.Counter(name + ".error"),
}
}
// Cache describes a read-through cache to obtain
type statCache interface {
// get returns a shared statSet for the given name, either from the cache or
// a provided StatSource.
get(name string) *statSet
}
// mutexCache implements statCache, backed by a map and sync.RWMutex
type mutexCache struct {
src StatSource
mtx sync.RWMutex
lookup map[string]*statSet
}
func newMutexCache(src StatSource) statCache {
return &mutexCache{
src: src,
lookup: make(map[string]*statSet),
}
}
func (mc *mutexCache) get(name string) *statSet {
// take a read lock to see if the set already exists
mc.mtx.RLock()
set, ok := mc.lookup[name]
mc.mtx.RUnlock()
if ok { // the set exists, return it
return set
}
// need to take a write lock to update the map
mc.mtx.Lock()
// While waiting for the write lock, another goroutine may have created the
// set. Here, we check again after obtaining the lock before making a new one
if set, ok = mc.lookup[name]; !ok {
set = newStatSet(mc.src, name)
mc.lookup[name] = set
}
mc.mtx.Unlock()
return set
}
type syncMapCache struct {
src StatSource
lookup sync.Map
}
func newSyncMapCache(src StatSource) statCache {
return &syncMapCache{src: src}
}
func (smc *syncMapCache) get(name string) *statSet {
val, _ := smc.lookup.Load(name)
if set, ok := val.(*statSet); ok {
return set
}
// create a new statSet, but don't store it if one was added since the last
// load. This is not ideal since we can't atomically create the set and
// write it.
set, _ := smc.lookup.LoadOrStore(name, newStatSet(smc.src, name))
return set.(*statSet)
}
var (
_ statCache = (*mutexCache)(nil)
_ statCache = (*syncMapCache)(nil)
)