Skip to content

Commit f08e0ce

Browse files
committed
replace "shared bool", as part of Do/DoChan return, with refShared, which carries both boolean "shared" indicator as well as actual reference counter
1 parent d2a98c9 commit f08e0ce

File tree

1 file changed

+23
-4
lines changed

1 file changed

+23
-4
lines changed

singleflight/singleflight.go

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
package singleflight // import "golang.org/x/sync/singleflight"
88

99
import "sync"
10+
import "sync/atomic"
1011

1112
// call is an in-flight or completed singleflight.Do call
1213
type call struct {
@@ -40,15 +41,31 @@ type Group struct {
4041
type Result struct {
4142
Val interface{}
4243
Err error
43-
Shared bool
44+
Shared refShared
45+
}
46+
47+
// this encapsulates both "shared boolean" as well as actual reference counter
48+
// callers can call refShared.Decrement to determine when last caller is done using result, so cleanup if needed can be performed
49+
type refShared struct {
50+
shared bool
51+
refCount *int64
52+
}
53+
54+
// Decrement will atomically decrement refcounter and will return new value
55+
func (rs *refShared) Decrement() int64 {
56+
return atomic.AddInt64(rs.refCount, -1)
57+
}
58+
59+
func (rs *refShared) Shared() bool {
60+
return rs.shared
4461
}
4562

4663
// Do executes and returns the results of the given function, making
4764
// sure that only one execution is in-flight for a given key at a
4865
// time. If a duplicate comes in, the duplicate caller waits for the
4966
// original to complete and receives the same results.
50-
// The return value shared indicates whether v was given to multiple callers.
51-
func (g *Group) Do(key string, fn func() (interface{}, error)) (v interface{}, err error, shared bool) {
67+
// The return value shared indicates whether v was given to multiple callers (and a reference counter for callers too).
68+
func (g *Group) Do(key string, fn func() (interface{}, error)) (v interface{}, err error, shared refShared) {
5269
r := <-g.DoChan(key, fn)
5370
return r.Val, r.Err, r.Shared
5471
}
@@ -86,8 +103,10 @@ func (g *Group) doCall(c *call, key string, fn func() (interface{}, error)) {
86103
if !c.forgotten {
87104
delete(g.m, key)
88105
}
106+
//shared := newRefShared(&c.refCount)
107+
shared := refShared{shared: c.refCount > 1, refCount: &c.refCount}
89108
for _, ch := range c.chans {
90-
ch <- Result{c.val, c.err, c.refCount > 1}
109+
ch <- Result{c.val, c.err, shared}
91110
}
92111
g.mu.Unlock()
93112
}

0 commit comments

Comments
 (0)