summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@lukeshu.com>2023-01-31 11:34:13 -0700
committerLuke Shumaker <lukeshu@lukeshu.com>2023-01-31 12:03:49 -0700
commit7109866d148788773f244eac70cb1984407c7b4a (patch)
tree6b8f8deb94b8b28da48734b25cd07369f997127d
parent721a5d1d37ddcd7f1b50a5ba4ce81952af387f04 (diff)
cachemap: Try to avoid unnecessary large allocations
-rw-r--r--cachemap.go29
1 files changed, 20 insertions, 9 deletions
diff --git a/cachemap.go b/cachemap.go
index 90d2274..bc6a70a 100644
--- a/cachemap.go
+++ b/cachemap.go
@@ -10,7 +10,10 @@ import (
type cacheVal[V any] struct {
wg sync.WaitGroup
- v V
+ // This is a pointer so that LoarOrStore and LoadOrCompute
+ // don't doesn't need to allocate a (potentially large) `V` on
+ // the heap unless they're actually storing it.
+ v *V
}
// The techniques used by CacheMap are similar to the techniques used
@@ -41,7 +44,7 @@ func (m *CacheMap[K, V]) Load(key K) (value V, ok bool) {
return zero, false
}
_value.wg.Wait()
- return _value.v, true
+ return *_value.v, true
}
// LoadAndDelete deletes the value for a key, returning the previous
@@ -56,7 +59,7 @@ func (m *CacheMap[K, V]) LoadAndDelete(key K) (value V, loaded bool) {
return zero, false
}
_value.wg.Wait()
- return _value.v, true
+ return *_value.v, true
}
// LoadOrStore returns the existing value for the key if
@@ -65,9 +68,16 @@ func (m *CacheMap[K, V]) LoadAndDelete(key K) (value V, loaded bool) {
// the value for that key is actively being computed by LoadOrCompute,
// this blocks until the value has been computed.
func (m *CacheMap[K, V]) LoadOrStore(key K, value V) (actual V, loaded bool) {
- _actual, loaded := m.inner.LoadOrStore(key, &cacheVal[V]{v: value})
- _actual.wg.Wait()
- return _actual.v, loaded
+ _value := &cacheVal[V]{}
+ _value.wg.Add(1)
+ _actual, loaded := m.inner.LoadOrStore(key, _value)
+ if loaded {
+ _actual.wg.Wait()
+ } else {
+ _actual.v = &value
+ _actual.wg.Done()
+ }
+ return *_actual.v, loaded
}
// LoadOrCompute returns the existing value for the key if present.
@@ -83,12 +93,13 @@ func (m *CacheMap[K, V]) LoadOrCompute(key K, fn func(K) V) (actual V, loaded bo
if loaded {
_actual.wg.Wait()
} else {
- _actual.v = fn(key)
+ v := fn(key)
+ _actual.v = &v
_actual.wg.Done()
}
- return _actual.v, loaded
+ return *_actual.v, loaded
}
func (m *CacheMap[K, V]) Store(key K, value V) {
- m.inner.Store(key, &cacheVal[V]{v: value})
+ m.inner.Store(key, &cacheVal[V]{v: &value})
}