Files
tasks/common/cache/simple.go
Stephan BehnkeandGitHub c9e360a3fb go fix (#9337)
## What changed?

Integrate Go 1.26's new `go fix` into workflow.

NOTE that the changes caused our linter to fire; a [separate
commit](https://github.com/temporalio/temporal/pull/9337/commits/1b23f787aef370098b35829c4d17dcc06230b4c1)
addresses those.

## Why?

Ensure Go code is standardized/modernized.

## How did you test it?
- [ ] built
- [ ] run locally and tested manually
- [x] covered by existing tests
- [ ] added new unit test(s)
- [ ] added new functional test(s)
2026-02-18 09:12:19 -08:00

176 lines
3.7 KiB
Go

package cache
import (
"container/list"
"sync"
"time"
)
var (
// DummyCreateTime is the create time used by all entries in the cache.
DummyCreateTime = time.Time{}
)
type (
simple struct {
sync.RWMutex
accessMap map[any]*list.Element
iterateList *list.List
rmFunc RemovedFunc
}
simpleItr struct {
simple *simple
nextItem *list.Element
}
simpleEntry struct {
key any
value any
}
)
// Close closes the iterator
func (it *simpleItr) Close() {
it.simple.RUnlock()
}
// HasNext return true if there is more items to be returned
func (it *simpleItr) HasNext() bool {
return it.nextItem != nil
}
// Next returns the next item
func (it *simpleItr) Next() Entry {
if it.nextItem == nil {
panic("Simple cache iterator Next called when there is no next item")
}
// nolint:revive
entry := it.nextItem.Value.(*simpleEntry)
it.nextItem = it.nextItem.Next()
// make a copy of the entry so there will be no concurrent access to this entry
entry = &simpleEntry{
key: entry.key,
value: entry.value,
}
return entry
}
func (e *simpleEntry) Key() any {
return e.key
}
func (e *simpleEntry) Value() any {
return e.value
}
// CreateTime is not implemented for simple cache entries
func (e *simpleEntry) CreateTime() time.Time {
return DummyCreateTime
}
// NewSimple creates a new simple cache with given options.
// Simple cache will never evict entries and it will never reorder the elements.
// Simple cache also does not have the concept of pinning that LRU cache has.
// Internally simple cache uses a RWMutex instead of the exclusive Mutex that LRU cache uses.
// The RWMutex makes simple cache readable by many threads without introducing lock contention.
func NewSimple(opts *SimpleOptions) Cache {
if opts == nil {
opts = &SimpleOptions{}
}
return &simple{
iterateList: list.New(),
accessMap: make(map[any]*list.Element),
rmFunc: opts.RemovedFunc,
}
}
// Get retrieves the value stored under the given key
func (c *simple) Get(key any) any {
c.RLock()
defer c.RUnlock()
element := c.accessMap[key]
if element == nil {
return nil
}
return element.Value.(*simpleEntry).Value()
}
// Put puts a new value associated with a given key, returning the existing value (if present).
func (c *simple) Put(key any, value any) any {
c.Lock()
defer c.Unlock()
existing := c.putInternal(key, value, true)
return existing
}
// PutIfNotExist puts a value associated with a given key if it does not exist
func (c *simple) PutIfNotExist(key any, value any) (any, error) {
c.Lock()
defer c.Unlock()
existing := c.putInternal(key, value, false)
if existing == nil {
// This is a new value
return value, nil
}
return existing, nil
}
// Delete deletes a key, value pair associated with a key
func (c *simple) Delete(key any) {
c.Lock()
defer c.Unlock()
element := c.accessMap[key]
if element == nil {
return
}
// nolint:revive
entry := c.iterateList.Remove(element).(*simpleEntry)
if c.rmFunc != nil {
go c.rmFunc(entry.value)
}
delete(c.accessMap, entry.key)
}
// Release does nothing for simple cache
func (c *simple) Release(_ any) {}
// Size returns the number of entries currently in the cache
func (c *simple) Size() int {
c.RLock()
defer c.RUnlock()
return len(c.accessMap)
}
func (c *simple) Iterator() Iterator {
c.RLock()
iterator := &simpleItr{
simple: c,
nextItem: c.iterateList.Front(),
}
return iterator
}
func (c *simple) putInternal(key any, value any, allowUpdate bool) any {
elt := c.accessMap[key]
if elt != nil {
// nolint:revive
entry := elt.Value.(*simpleEntry)
existing := entry.value
if allowUpdate {
entry.value = value
}
return existing
}
entry := &simpleEntry{
key: key,
value: value,
}
c.accessMap[key] = c.iterateList.PushFront(entry)
return nil
}