go.temporal.io/server/common/cache/simple.go

175 LOC · 87 covered · 88 uncovered · 22 ranges · 13 concepts · 11 introducers · 5 tests

File neighbourhood

The centred file is linked to every concept that introduces one of its ranges, every test that runs code from the file, and the gray connector concepts standing between those tests and the file's own introducer concepts. Undirected links join concepts to every file where they introduce source and concepts to the tests they introduce; arrows show specialization between the displayed concepts and bridge only concepts omitted from this view. Concept colors match the source ranges below; connector concepts have no source color and are shown in gray.

Focused file, its introducer and connector concepts, their introduced files, and tests that run code from the file

In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the related-file, concept, and source links on this page.

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the related-file, concept, and source links on this page while the interactive map is unavailable.

1 package cache
2
3 import (
4 "container/list"
5 "sync"
6 "time"
7 )
8
9 var (
10 // DummyCreateTime is the create time used by all entries in the cache.
11 DummyCreateTime = time.Time{}
12 )
13
14 type (
15 simple struct {
16 sync.RWMutex
17 accessMap map[any]*list.Element
18 iterateList *list.List
19 rmFunc RemovedFunc
20 }
21
22 simpleItr struct {
23 simple *simple
24 nextItem *list.Element
25 }
26
27 simpleEntry struct {
28 key any
29 value any
30 }
31 )
32
33 // Close closes the iterator
34 > func (it *simpleItr) Close() { simple.go ×5
35 > it.simple.RUnlock()
36 > }
37
38 // HasNext return true if there is more items to be returned
39 > func (it *simpleItr) HasNext() bool { simple.go ×5
40 > return it.nextItem != nil
41 > }
42
43 // Next returns the next item
44 > func (it *simpleItr) Next() Entry { simple.go ×5
45 > if it.nextItem == nil {
46 panic("Simple cache iterator Next called when there is no next item")
47 }
48
49 // nolint:revive
50 > entry := it.nextItem.Value.(*simpleEntry) simple.go ×5
51 > it.nextItem = it.nextItem.Next()
52 > // make a copy of the entry so there will be no concurrent access to this entry
53 > entry = &simpleEntry{
54 > key: entry.key,
55 > value: entry.value,
56 > }
57 > return entry
58 }
59
60 > func (e *simpleEntry) Key() any { simple.go ×1
61 > return e.key
62 > }
63
64 > func (e *simpleEntry) Value() any { simple.go ×2
65 > return e.value
66 > }
67
68 // CreateTime is not implemented for simple cache entries
69 func (e *simpleEntry) CreateTime() time.Time {
70 return DummyCreateTime
71 }
72
73 // NewSimple creates a new simple cache with given options.
74 // Simple cache will never evict entries and it will never reorder the elements.
75 // Simple cache also does not have the concept of pinning that LRU cache has.
76 // Internally simple cache uses a RWMutex instead of the exclusive Mutex that LRU cache uses.
77 // The RWMutex makes simple cache readable by many threads without introducing lock contention.
78 > func NewSimple(opts *SimpleOptions) Cache { simple.go ×5
79 > if opts == nil {
80 > opts = &SimpleOptions{} simple.go ×2
81 > }
82 > return &simple{ simple.go ×5
83 > iterateList: list.New(),
84 > accessMap: make(map[any]*list.Element),
85 > rmFunc: opts.RemovedFunc,
86 > }
87 }
88
89 // Get retrieves the value stored under the given key
90 > func (c *simple) Get(key any) any { simple.go ×1
91 > c.RLock()
92 > defer c.RUnlock()
93 >
94 > element := c.accessMap[key]
95 > if element == nil {
96 > return nil simple.go ×1
97 > }
98 > return element.Value.(*simpleEntry).Value() simple.go ×1
99 }
100
101 // Put puts a new value associated with a given key, returning the existing value (if present).
102 > func (c *simple) Put(key any, value any) any { simple.go ×5
103 > c.Lock()
104 > defer c.Unlock()
105 > existing := c.putInternal(key, value, true)
106 > return existing
107 > }
108
109 // PutIfNotExist puts a value associated with a given key if it does not exist
110 func (c *simple) PutIfNotExist(key any, value any) (any, error) {
111 c.Lock()
112 defer c.Unlock()
113 existing := c.putInternal(key, value, false)
114 if existing == nil {
115 // This is a new value
116 return value, nil
117 }
118 return existing, nil
119 }
120
121 // Delete deletes a key, value pair associated with a key
122 > func (c *simple) Delete(key any) { simple.go ×3
123 > c.Lock()
124 > defer c.Unlock()
125 >
126 > element := c.accessMap[key]
127 > if element == nil {
128 return
129 }
130 // nolint:revive
131 > entry := c.iterateList.Remove(element).(*simpleEntry) simple.go ×3
132 > if c.rmFunc != nil {
133 > go c.rmFunc(entry.value) simple.go ×1
134 > }
135 > delete(c.accessMap, entry.key) simple.go ×3
136 }
137
138 // Release does nothing for simple cache
139 func (c *simple) Release(_ any) {}
140
141 // Size returns the number of entries currently in the cache
142 > func (c *simple) Size() int { simple.go ×1
143 > c.RLock()
144 > defer c.RUnlock()
145 >
146 > return len(c.accessMap)
147 > }
148
149 > func (c *simple) Iterator() Iterator { simple.go ×5
150 > c.RLock()
151 > iterator := &simpleItr{
152 > simple: c,
153 > nextItem: c.iterateList.Front(),
154 > }
155 > return iterator
156 > }
157
158 > func (c *simple) putInternal(key any, value any, allowUpdate bool) any { simple.go ×5
159 > elt := c.accessMap[key]
160 > if elt != nil {
161 > // nolint:revive simple.go ×1
162 > entry := elt.Value.(*simpleEntry)
163 > existing := entry.value
164 > if allowUpdate {
165 > entry.value = value
166 > }
167 > return existing
168 }
169 > entry := &simpleEntry{ simple.go ×5
170 > key: key,
171 > value: value,
172 > }
173 > c.accessMap[key] = c.iterateList.PushFront(entry)
174 > return nil
175 }