|
7 | 7 | package singleflight // import "golang.org/x/sync/singleflight" |
8 | 8 |
|
9 | 9 | import "sync" |
| 10 | +import "sync/atomic" |
10 | 11 |
|
11 | 12 | // call is an in-flight or completed singleflight.Do call |
12 | 13 | type call struct { |
@@ -40,15 +41,31 @@ type Group struct { |
40 | 41 | type Result struct { |
41 | 42 | Val interface{} |
42 | 43 | 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 |
44 | 61 | } |
45 | 62 |
|
46 | 63 | // Do executes and returns the results of the given function, making |
47 | 64 | // sure that only one execution is in-flight for a given key at a |
48 | 65 | // time. If a duplicate comes in, the duplicate caller waits for the |
49 | 66 | // 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) { |
52 | 69 | r := <-g.DoChan(key, fn) |
53 | 70 | return r.Val, r.Err, r.Shared |
54 | 71 | } |
@@ -86,8 +103,10 @@ func (g *Group) doCall(c *call, key string, fn func() (interface{}, error)) { |
86 | 103 | if !c.forgotten { |
87 | 104 | delete(g.m, key) |
88 | 105 | } |
| 106 | + //shared := newRefShared(&c.refCount) |
| 107 | + shared := refShared{shared: c.refCount > 1, refCount: &c.refCount} |
89 | 108 | for _, ch := range c.chans { |
90 | | - ch <- Result{c.val, c.err, c.refCount > 1} |
| 109 | + ch <- Result{c.val, c.err, shared} |
91 | 110 | } |
92 | 111 | g.mu.Unlock() |
93 | 112 | } |
|
0 commit comments