github.com/shijuvar/go@v0.0.0-20141209052335-e8f13700b70c/src/net/singleflight.go (about) 1 // Copyright 2013 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package net 6 7 import "sync" 8 9 // call is an in-flight or completed singleflight.Do call 10 type call struct { 11 wg sync.WaitGroup 12 13 // These fields are written once before the WaitGroup is done 14 // and are only read after the WaitGroup is done. 15 val interface{} 16 err error 17 18 // These fields are read and written with the singleflight 19 // mutex held before the WaitGroup is done, and are read but 20 // not written after the WaitGroup is done. 21 dups int 22 chans []chan<- singleflightResult 23 } 24 25 // singleflight represents a class of work and forms a namespace in 26 // which units of work can be executed with duplicate suppression. 27 type singleflight struct { 28 mu sync.Mutex // protects m 29 m map[string]*call // lazily initialized 30 } 31 32 // singleflightResult holds the results of Do, so they can be passed 33 // on a channel. 34 type singleflightResult struct { 35 v interface{} 36 err error 37 shared bool 38 } 39 40 // Do executes and returns the results of the given function, making 41 // sure that only one execution is in-flight for a given key at a 42 // time. If a duplicate comes in, the duplicate caller waits for the 43 // original to complete and receives the same results. 44 // The return value shared indicates whether v was given to multiple callers. 45 func (g *singleflight) Do(key string, fn func() (interface{}, error)) (v interface{}, err error, shared bool) { 46 g.mu.Lock() 47 if g.m == nil { 48 g.m = make(map[string]*call) 49 } 50 if c, ok := g.m[key]; ok { 51 c.dups++ 52 g.mu.Unlock() 53 c.wg.Wait() 54 return c.val, c.err, true 55 } 56 c := new(call) 57 c.wg.Add(1) 58 g.m[key] = c 59 g.mu.Unlock() 60 61 g.doCall(c, key, fn) 62 return c.val, c.err, c.dups > 0 63 } 64 65 // DoChan is like Do but returns a channel that will receive the 66 // results when they are ready. 67 func (g *singleflight) DoChan(key string, fn func() (interface{}, error)) <-chan singleflightResult { 68 ch := make(chan singleflightResult, 1) 69 g.mu.Lock() 70 if g.m == nil { 71 g.m = make(map[string]*call) 72 } 73 if c, ok := g.m[key]; ok { 74 c.dups++ 75 c.chans = append(c.chans, ch) 76 g.mu.Unlock() 77 return ch 78 } 79 c := &call{chans: []chan<- singleflightResult{ch}} 80 c.wg.Add(1) 81 g.m[key] = c 82 g.mu.Unlock() 83 84 go g.doCall(c, key, fn) 85 86 return ch 87 } 88 89 // doCall handles the single call for a key. 90 func (g *singleflight) doCall(c *call, key string, fn func() (interface{}, error)) { 91 c.val, c.err = fn() 92 c.wg.Done() 93 94 g.mu.Lock() 95 delete(g.m, key) 96 for _, ch := range c.chans { 97 ch <- singleflightResult{c.val, c.err, c.dups > 0} 98 } 99 g.mu.Unlock() 100 } 101 102 // Forget tells the singleflight to forget about a key. Future calls 103 // to Do for this key will call the function rather than waiting for 104 // an earlier call to complete. 105 func (g *singleflight) Forget(key string) { 106 g.mu.Lock() 107 delete(g.m, key) 108 g.mu.Unlock() 109 }