59 lines
1.4 KiB
Go
59 lines
1.4 KiB
Go
// I put this here to look at and think about
|
|
// from mod/sumdb/cache.go
|
|
|
|
// Parallel cache.
|
|
// This file is copied from cmd/go/internal/par.
|
|
|
|
package forgepb
|
|
|
|
import (
|
|
"sync"
|
|
"sync/atomic"
|
|
)
|
|
|
|
// parCache runs an action once per key and caches the result.
|
|
type parCache struct {
|
|
m sync.Map
|
|
}
|
|
|
|
type cacheEntry struct {
|
|
done uint32
|
|
mu sync.Mutex
|
|
result interface{}
|
|
}
|
|
|
|
// Do calls the function f if and only if Do is being called for the first time with this key.
|
|
// No call to Do with a given key returns until the one call to f returns.
|
|
// Do returns the value returned by the one call to f.
|
|
func (c *parCache) Do(key interface{}, f func() interface{}) interface{} {
|
|
entryIface, ok := c.m.Load(key)
|
|
if !ok {
|
|
entryIface, _ = c.m.LoadOrStore(key, new(cacheEntry))
|
|
}
|
|
e := entryIface.(*cacheEntry)
|
|
if atomic.LoadUint32(&e.done) == 0 {
|
|
e.mu.Lock()
|
|
if atomic.LoadUint32(&e.done) == 0 {
|
|
e.result = f()
|
|
atomic.StoreUint32(&e.done, 1)
|
|
}
|
|
e.mu.Unlock()
|
|
}
|
|
return e.result
|
|
}
|
|
|
|
// Get returns the cached result associated with key.
|
|
// It returns nil if there is no such result.
|
|
// If the result for key is being computed, Get does not wait for the computation to finish.
|
|
func (c *parCache) Get(key interface{}) interface{} {
|
|
entryIface, ok := c.m.Load(key)
|
|
if !ok {
|
|
return nil
|
|
}
|
|
e := entryIface.(*cacheEntry)
|
|
if atomic.LoadUint32(&e.done) == 0 {
|
|
return nil
|
|
}
|
|
return e.result
|
|
}
|