summaryrefslogtreecommitdiff
path: root/cache.go
diff options
context:
space:
mode:
authorJeff Carr <[email protected]>2024-11-28 23:00:29 -0600
committerJeff Carr <[email protected]>2024-11-28 23:00:29 -0600
commit488550a081769f491f326c7949add6cb9f0cc0b4 (patch)
tree15cfbac9c9af70d68b88fc4533f2e0db1b102dee /cache.go
parenta9e35d54295e979566940d60401014296801e553 (diff)
add example code. add sync.onlyOnce
Diffstat (limited to 'cache.go')
-rw-r--r--cache.go58
1 files changed, 58 insertions, 0 deletions
diff --git a/cache.go b/cache.go
new file mode 100644
index 0000000..c139306
--- /dev/null
+++ b/cache.go
@@ -0,0 +1,58 @@
+// 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
+}